String API
Feed Builder API

Errors

One envelope, the status mapping, and the two refusals that are not what they look like.

Every refusal on this API has the same body:

{
  "error": {
    "type": "invalid_request_error",
    "code": "approve_required",
    "message": "…",
    "param": "publish.approve",
    "request_id": "req_…"
  }
}

Switch on type to decide whether to retry, fix the request, or escalate; code is the specific reason within that family. param names the offending field when there is one, and is omitted rather than sent empty.

request_id matches the x-string-request-id response header and our log line, so quote it when you ask us about a request.

Status codes

StatusConditionRetriable
400Invalid argument, out of rangeNot until you change the request
401Bad or missing API keyNo
404Unknown buildNo
409Already exists, failed precondition, abortedAfter the build's state changes
413Body over 1 MiBNo
429Rate limited — honour Retry-AfterYes
499The request was already cancelled upstreamn/a
501Recognised but not served (see below)No
503Our key store or core is unreachableYes
504Upstream timeoutYes
500Anything else, with a deliberately generic messageMaybe

Retry-After on a 429 is always present and never zero.

Three answers that are not what they look like

409, not 400, for a state conflict

Input sent to a build that has finished, or a gate answered after it stopped being pending, is a 409. Your request is already correct — the build moved. A 400 would send you to re-read JSON that has nothing wrong with it. Resolve it by re-reading the build's state, not by editing your body.

501, not 400, for an unserved mode

mode: "autonomous", mode: "fast" and publication.policy: "auto" return 501 with codes mode_not_supported and publication_policy_not_supported. The request is well formed and names a mode this API documents; the missing capability is ours. See Limits.

503, not 401, when our key store is down

An unreachable key store answers 503 precisely so that you do not rotate a working key during our incident.

There is no 403

A build owned by another organization returns a byte-identical 404 to an unknown id — same status, same code, same message, built from the id you supplied. Nothing inspects the id, the organization, or the message to choose between them.

That is deliberate: a distinguishable answer would be an oracle, letting a caller walk build ids and learn which ones are real. Do not write client code that tries to tell the two apart, because nothing distinguishes them.