Skip to content
Skip to content

Use the Compute REST API

How to take one input from preparation to quote, approved job and result over HTTP, with a safe example you can run offline.

Updated

Use REST in four bounded stages: prepare the input, request a quote, submit an approved job, and read its result. Your application or agent keeps the goal, context and final decision; REST exposes the current operations for the request. First translate the task brief into the selected operation, prepared artifact, output contract and verification checks.

REST carries that declared request; it does not accept a free-form prompt in place of the operation. Keep the returned identifiers so a lost connection doesn't make you start the work again. With service access, POST /v1/quotes is a remote assessment or quote that prices work without approving it; POST /v1/jobs requests approved execution within the account's scope and charge ceiling.

The code sample stays local by injecting its transport. It constructs an HTTP request object and decodes synthetic response data without opening a connection or submitting work.

Start with the account and request contract

Use an approved Compute account and a key with the scopes needed for your task. The API description declares https://lithi.ai as its server. Send the key only in the Authorization: Bearer … header, obtained from your protected credential store.

Send JSON bodies as application/json with UTF-8, and request JSON responses with Accept: application/json. Keep credentials out of URLs, request bodies, source files, logs and command-line arguments. Provider enrollment isn't part of customer API setup.

ActionMethod and pathRequired scope
Read capabilitiesGET /v1/capabilitiesjobs:read
Prepare an artifactPOST /v1/artifacts/preparemodels:write
Complete an artifactPOST /v1/artifacts/completemodels:write
Request a quotePOST /v1/quotesquotes:read
Submit a jobPOST /v1/jobsjobs:write
Read a jobGET /v1/jobs/{id}jobs:read
Read its resultGET /v1/jobs/{id}/resultjobs:read
Request cancellationPOST /v1/jobs/{id}/canceljobs:write

A scope permits only its authorized account and operation. The actor text in a request doesn't grant permission. Use the exact declared scope even when its name differs from the action's description.

1. Prepare and bind the input

Choose the exact operation and model reference for your authorized workflow. Prepare the input through its artifact flow; the job request refers to an encrypted artifact, not a local path or an inline file.

Artifact preparation requires account_id, artifact_id, data_profile, ciphertext_bytes, chunk_count, chunk_root_digest and destination_id. Retain the returned upload_id, chunk_size, max_chunks, expires_at and digest.

Transfer the bytes using the authority for that upload. Complete it with the same account, artifact and upload identifiers, plus ciphertext_manifest_digest, chunk_root_digest and capability_digest. Preparation alone isn't proof of upload or completion.

The JSON metadata request must fit 65,536 bytes. Artifact byte bounds are separate. Preserve the file count, byte count and token estimate that the quote and job bind; do not adjust them just to pass validation.

2. Request a quote for the exact request

POST /v1/quotes accepts QuoteRequest, not a generic seven-object TaskSpec. Supply the account, exact work identifiers, input bounds and their digest, verification-policy digest, destination, engine, data profile, priority, maximum charge, capacity bounds, delegation mode and expiry.

Use an Idempotency-Key for this POST. The response is HTTP 200 with ok: true and data containing status: "signed" plus a LithiQuoteV1 quote.

Review the quote's maximum charge, input and policy bindings, and expiry. Obtain the applicable approval before submission. A returned signature doesn't itself approve paid execution.

3. Submit the approved job and retain its handle

POST /v1/jobs accepts LiveBoundedLithiJobV1. Its payload identifiers are contract_id: "LithiJobV1" and schema_version: "lithi-job.v1". Include the required correlation fields, account and actor fields, artifact input, output contract, execution settings, delivery identifiers and quote_id.

Keep task_id equal to workflow_run_id; use a distinct trace_id. Send the same idempotency_key in the job body and the HTTP Idempotency-Key header. Preserve the approved payload bytes for recovery.

The documented success is HTTP 202 with a JobProjection inside data: job_id, state, state_version, digest and p_next_action. Save that job_id before any later step. HTTP acceptance isn't completed execution.

4. Read status and results

Read GET /v1/jobs/{id} using the existing job UUID. Its state is a bounded string, not a universal uppercase enum. Keep the returned state version and handle an unfamiliar state without calling it success.

Read GET /v1/jobs/{id}/result for the result projection. It contains job_id, encrypted_artifact_id, result_digest, evidence_digest and delivery_state. The delivery states are pending, delivering, delivered and failed.

Use the result's authorized retrieval flow to obtain and verify its bytes. The JSON projection is not an inline result bundle, transcript or download URL. A delivery failure is a reason to investigate the existing delivery, not automatically rerun Compute.

Reporting is a separate authority. A monthly impact report needs separate permission and an approved reporting API or file path; it does not appear as another REST work operation in this guide. Use the monthly Compute impact report and the Impact Reports API when your account grants that access.

Check HTTP handling without a network call

This complete Python example constructs a real HTTP request object and decodes a synthetic response. Its credential, identifier and digest are fixture data. The injected transport never opens a connection or submits work.

import json
from urllib.parse import urlsplit
from urllib.request import Request

job_id = "11111111-1111-4111-8111-111111111111"
fixture_token = "lthi_cmp_0123456789abcdef." + "A" * 43
request = Request(
    "https://api.example.test/v1/jobs/" + job_id,
    headers={"Accept": "application/json"},
    method="GET",
)
request.add_header("Authorization", "Bearer " + fixture_token)

def synthetic_transport(req):
    assert urlsplit(req.full_url).hostname == "api.example.test"
    assert urlsplit(req.full_url).path == "/v1/jobs/" + job_id
    assert req.get_method() == "GET" and req.data is None
    assert req.get_header("Authorization") == "Bearer " + fixture_token
    body = {"ok": True, "data": {
        "job_id": job_id, "state": "accepted", "state_version": 1,
        "digest": "a" * 64, "p_next_action": "none",
    }}
    return 200, {"Content-Type": "application/json"}, json.dumps(body).encode()

status, headers, body = synthetic_transport(request)
assert status == 200 and headers["Content-Type"] == "application/json"
envelope = json.loads(body)
assert set(envelope) == {"ok", "data"} and envelope["ok"] is True
job = envelope["data"]
assert set(job) == {"job_id", "state", "state_version", "digest", "p_next_action"}
assert job["job_id"] == job_id
print(job["state"], job["state_version"])

The output is accepted 1. This tests request construction and envelope handling only. Production callers also validate complete response schemas, bounded response bytes, timeouts and typed errors.

Recover before replaying

A dropped connection leaves the submission outcome unknown. Read the existing job when you have its handle. Preserve the original idempotency key and body when recovering the same intent; generating a new key is not a safe substitute for finding out what happened.

Treat invalid JSON, fields or bounds as corrections, not retryable load. REST errors contain ok: false, error.code and p_next_action. Do not assume a request_id, validity timestamp, message or field-path list appears in every error.

Handle RATE_LIMITED using Retry-After when supplied. Recheck access for UNAUTHENTICATED or FORBIDDEN. A local HTTP timeout does not cancel the remote job; cancellation is the separate POST operation, followed by a status read.

Use the work API reference for the exact request, response, error and idempotency contract of each operation.

See Kit contents for the supplied local modules and Kit helper reference for exact exports.

Was this page helpful?