Create an App
Create a decision app with POST /v1/apps, or draft one from a plain-language description via POST /v1/apps/proposals: name, mode, rules, and access hints.
POST /v1/apps creates an app shell: a workspace-unique slug, a display_name, and a mode (rules, assisted, or external). The response is the app's manifest with version: null — nothing decides yet. You then save logic as a draft version ([PUT /v1/apps/:id/logic](app-logic)), publish it, and enable the app. The slug follows the grammar [a-z0-9][a-z0-9-]{1,62}[a-z0-9] (3–64 chars) and becomes immutable at the first publish; display_name renames freely at any time.
The describe-first path is POST /v1/apps/proposals: send a plain-language description (20–2000 chars) of the decision you want automated, and the platform compiles it into a structured proposal — suggested name and slug, a mode, the policy restated as rule sentences with parameters, a drafted output contract, trigger defaults, the inputs it thinks the app needs, access_needed hints (which data products or reference tables to grant), and open_questions where your description was ambiguous. Nothing persists: the proposal is a draft on the wire, and the client turns an accepted proposal into a real app via POST /v1/apps plus PUT /:id/logic.
Requests to either endpoint need the operate tier (senior_member and up for sessions; an operate grant or legacy write scope for keys). A duplicate slug is rejected with 409 and the message naming the taken slug, so creation is safe to retry with a new slug. Mode autonomous is reserved for a later release and rejected with 422 wherever content is validated.
Deletion is the reverse ceremony, deliberately heavier: DELETE /v1/apps/:id requires the owner tier and is refused while the app is enabled or while other apps consume its output as an input binding (check [GET /v1/apps/:id/dependents](app-versions) first). Deleting removes configuration only — the run journal and sealed decision records survive by design, carrying no foreign key to the app.
/v1/appsBody
curl
curl -s -X POST https://api.talonic.com/v1/apps \
-H "Authorization: Bearer tlnc_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"slug": "load-auto-billing",
"display_name": "Load auto-billing",
"mode": "rules"
}'Response (201)
{
"app_id": "app_8f591d2d85c5990a",
"id": "80afca3e-c66c-4f07-abbf-78913ee80dff",
"slug": "load-auto-billing",
"display_name": "Load auto-billing",
"description": "Load auto-billing",
"version": null,
"content_hash": null,
"mode": "rules",
"enabled": false,
"contract": null,
"output_contract": null,
"triggers": null,
"thresholds": null,
"fallback": null,
"display": null,
"endpoints": {
"mcp": "apps/load-auto-billing",
"rest": "/v1/apps/80afca3e-c66c-4f07-abbf-78913ee80dff"
}
}/v1/apps/proposalsBody
Response (201) — proposal excerpt
{
"proposal": {
"display_name": "Rate Card Billing Validator",
"slug": "rate-card-billing-validator",
"mode": "rules",
"summary": "The app checks every delivered load against its rate card and holds any load where the billed amount differs from the rate card amount by more than 2 percent.",
"policy_sentences": [
"IF the billed amount for a delivered load differs from the rate card amount by more than 2 percent THEN hold the load."
],
"rules": [
{
"sentence": "IF the billed amount for a delivered load differs from the rate card amount by more than 2 percent THEN hold the load.",
"applies_to": null,
"params": { "threshold": 0.02 }
}
],
"fallback": "hold",
"output_contract": {
"type": "object",
"required": ["decision"],
"properties": { "decision": { "enum": ["approve", "hold"] }, "note": { "type": "string" } }
},
"triggers": { "manual": true, "api": true },
"inputs_needed": ["delivered loads", "rate card"],
"access_needed": [
{ "resource_type": "data_product", "hint": "delivered loads" },
{ "resource_type": "reference_table", "hint": "rate card" }
],
"open_questions": [
"How is the percentage difference calculated (relative to billed or rate card amount)?",
"How does the rate card match to a delivered load (by route, carrier, load type)?"
]
}
}Answer the open_questions before you publish — they are exactly the ambiguities that would otherwise surface later as indeterminate card results or unexpected holds. Feed the answers back either by refining the rule sentences before compiling, or as guidance on [POST /v1/apps/:id/logic/compile](app-logic).