Jobs & polling

Lifecycle

queued → processing → succeeded
                    → failed
                    → timed_out
queued → cancelled

Transitions are enforced server-side; terminal states cannot change.

Submit

POST /api/v1/recognition/jobs
Authorization: Bearer sgk_…
Idempotency-Key: unique-per-request      # optional but recommended

{
  "operation": "text",
  "challenge": { "kind": "synthetic", "fixture": "sg-text-hello", "category": "text" },
  "metadata": { "origin": "ci" }          // optional
}

Poll

GET /api/v1/recognition/jobs/{id}

// terminal success
{ "status": "succeeded", "result": { "type": "text", "value": "hello" }, … }

// terminal failure — errorCode is stable and machine-readable
{ "status": "failed", "errorCode": "invalid_request", "errorMessage": "…" }
  • Poll no faster than once per second per job.
  • result is only populated after succeeded.
  • creditsCharged reflects the final billing outcome.

Idempotency

The same idempotency key + identical payload replays the original job (no duplicate charge). The same key with a different payload returns 409 idempotency_conflict. Keys are scoped per account and retained for 24 hours.

Retries

Transient provider failures retry with exponential backoff (up to the job's max attempts). Permanent failures (invalid request, unsupported operation) fail immediately. Failed and timed-out jobs release their credit reservation — you are not charged for provider outages.