> ## Documentation Index
>
> Fetch the complete documentation index at: https://lithi.ai/llms.txt
>
> Use this file to discover all available pages before exploring further.

---
title: Submit work over REST
description: >-
  Take one input from a prepared snapshot to a verified result over REST. Covers the
  seven request objects, approval, polling, and how to recover an outcome you never
  saw.
route: /docs/compute/clients/rest
page_id: docs-compute-clients-rest
page_type: howTo
content_layer: guided documentation
surface_profile: guided_docs
audience: Developers integrating Compute directly over HTTP
voice: D
reader_question: How do I take one input from quote to result over REST?
primary_action: Read the released work API reference
source_locale: en-US
source_status: APPROVED
source_version: docs-compute-clients-rest-en-us-2026-09-05-v1
last_updated: '2026-09-05'
robots: index
claim_registry_pinned: true
claim_registry_resync: "npm run governed:tsx -- scripts/build-compute-public-claim-registry.ts --write"
---

## Before you start

You need a work key and the current API description. That description is the source for hosts, paths, headers, request schemas and error schemas.

Your base URL and current API version appear in the portal under developer settings, and in the API description you download. Do not copy either from an example.

Generate your request and response types from the description rather than hand-writing them. It moves with each contract release.

## Prepare one input

A request carries seven objects: `workflow`, `input`, `parameters`, `quality`, `policy`, `output` and `limits`.

The `input` object points at a frozen snapshot, never at live data. Give it a `version_id` and a `content_sha256` so the run stays repeatable.

```json
{
  "workflow": { "id": "eval.semantic_grade.v1", "version": "current-compatible" },
  "input": {
    "kind": "tabular",
    "adapter": "<from the workflow descriptor>",
    "location": "<your registered source>",
    "credential_ref": "<secret reference, never a secret>",
    "snapshot": { "version_id": "<snapshot id>", "content_sha256": "<digest>" },
    "format": "parquet",
    "item_id_field": "row_id"
  },
  "parameters": {},
  "quality": { "preset": "verified" },
  "policy": { "profile_id": "<your profile>" },
  "output": { "format": "parquet" },
  "limits": {
    "deadline": "PT6H",
    "maximum_price": { "currency": "USD", "amount": "<the ceiling you set>" }
  }
}
```

Four quality presets are released: standard, verified, high assurance and custom evaluation. Take the exact spelling from the schema you downloaded.

A `profile=` convenience string is not an eighth object. It resolves into `policy`, `quality`, `output` and `limits`.

## Quote, then approve

Send that request to the quote operation first. The quote comes back carrying `non_authorizing = true`, an expiry and a signature.

Read the maximum charge it states, then approve as a separate act. Nothing runs until you do.

If admission answers `REPLAN_REQUIRED`, your quote no longer matches what you submitted. Request a new quote and approve that one.

## Submit and poll

Submit the approved work, then read the job by its identifier. Job states are `ADMITTED`, `RUNNING`, `AWAITING_REVIEW`, `PARTIAL`, `CANCELLING`, `CANCELLED`, `FAILED` and `SUCCEEDED`.

Every response is an envelope. It carries `request_id`, the operation, the contract release, a typed state, an evidence class, `observed_at`, `valid_until` and a structured `next_action`.

Stop trusting a read once its `valid_until` has passed. Read again rather than extending it.

## Read the result

Fetch `result-manifest.json` first. It is written last, and it binds every file, count, schema, release and retention rule in the bundle.

The presence of part files never means the run finished. Accepted rows sit under `data/part-*`, with `failures/`, `abstentions/` and `disagreements/` beside them.

Read `provenance.json` for the input, workflow, model, schema and envelope digests. Keep `receipt.json` with your own record of the run.

## Recover an outcome you never saw

A dropped connection tells you nothing about whether the work was admitted. Read the job's status before you resend anything.

An exact replay returns the prior result. The same identity carrying a different payload is equivocation, and it refuses rather than choosing between them.

See [the released work API reference](/docs/compute/reference/work-api) for per-operation schemas, and [how to retry without creating a second charge](/docs/compute/jobs/idempotency-and-retries) before you resend.
