---
title: "Submit the decision and resume the run"
method: POST
path: "/v1/decision-tasks/{id}/submit"
tags: ["Apps"]
---

# Submit the decision and resume the run

`POST /v1/decision-tasks/{id}/submit`

## Request

- Base URL: `https://api.talonic.com`
- URL: `https://api.talonic.com/v1/decision-tasks/{id}/submit`
- Auth: HTTP bearer

`outcome` is validated against the task's output contract, every evidence locator must exist in the frozen input package, and a decision rationale is mandatory. Rejections journal a `rejected` event. Submit is idempotent per claimant + epoch.

## Path parameters

- `id` string, uuid, required

## Request body

- DecisionTaskSubmit
  - `execution_epoch` integer, required
  - `outcome` object, required: `single`: validated against the task's output contract. `verdict_matrix`: `{ subjects: [{ subject_key, rule_outcomes: { <rule id>: passed | failed | indeterminate }, auto?, detail? }] }` over the version's declared `logic.rules`; `rolled_outcome`, `substantive_passes` and `auto` are recomputed by the platform (a disagreeing advisory `auto` is journaled `decision_rejected` and overridden). `record_set`: `{ fields: [{ key, label?, data_type }], records: [{ source_record_id?, values }] }` (`key` must match `^[a-z][a-z0-9_]{0,63}$` and `data_type` one of `string`, `number`, `date`, `boolean`, `object`, `array`; a submission violating either is rejected as `decision_rejected`), where each entry of `values` is either a bare value or `{ value, confidence?, status? }` (`status` one of filled, empty, flagged, pending_approval). Under the version's `record_set_output.mode = derive` the platform materializes a NEW `app_run` record set and ignores `confidence`/`status`; under `mode = promote` it appends cell versions into `record_set_output.target` (an `app_run` set the app holds a `write` grant on), matching rows by `source_record_id` against the target's record ids and columns against the target's fields, under the version's autonomy contract (`observe` rejects any value output, `propose` lands cells `pending_approval`, a value below `confidence_floor` is flagged and not written). Whole body ≤ `apps.submit_max_bytes` (413).
  - `confidence` number
  - `evidence` string[], required: Provenance locators the decision relied on. Each must exist in the frozen input package, or parse as `db:{connectionId}:{table}:{rowKey}:{column}` / `ref:{referenceDataId}:{rowKey}:{column}` against a resource the app holds a `read` grant on: such locators are accepted as attestations (recorded `{ locator, external: true }`, journaled `evidence_attested`, never resolved). Anything else is 422 `evidence_outside_grants`; `api:` is reserved. An empty block is accepted only when the app allows unevidenced decisions.
  - `rationale` string, required: Decision rationale — never private chain-of-thought.
  - `service_version` string: Build identifier of the deciding service; recorded in `decided_by.label`.

## Response `200`

Submitted task metadata.

- DecisionTaskMetadata
  - `id` string, uuid, required
  - `customer_id` string, uuid, required
  - `run_id` string, uuid, required
  - `app_id` string, uuid, required
  - `status` 'available' | 'claimed' | 'submitted' | 'released' | 'failed' | 'timed_out' | 'cancelled', required
  - `execution_epoch` integer, required
  - `input_package_ref` string: Where the frozen package lives; `run` in v1.
  - `lease_seconds` integer
  - `claimed_by` string, nullable: The claimant: an API key id, or `oauth:<client_id>:<user_id>` for an OAuth session.
  - `claimed_at` string, date-time, nullable
  - `lease_expires_at` string, date-time, nullable
  - `heartbeat_at` string, date-time, nullable
  - `sla_deadline_at` string, date-time, required: Hard decision deadline; heartbeats never extend the lease past it.
  - `submitted_at` string, date-time, nullable
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required

## Other responses

- `400`: The request is invalid.
- `401`: Missing or invalid API key.
- `403`: The API key does not have the required scope.
- `404`: The requested resource was not found.
- `409`: The request conflicts with the current resource state.
- `413`: The uploaded file exceeds the size limit.
- `422`: The request is well-formed but violates the declared task contract.
- `429`: Daily rate limit exceeded.

---

[API](https://skmtc.dev/talonic/apis/talonic-api.md) · [All operations](https://skmtc.dev/talonic/apis/talonic-api/llms.txt) · [OpenAPI document](https://skmtc.dev/talonic/apis/talonic-api/revisions/678fe5f8c9c3?raw)
