Jobs & polling
Lifecycle
queued → processing → succeeded
→ failed
→ timed_out
queued → cancelledTransitions 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.
resultis only populated aftersucceeded.creditsChargedreflects 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.