Skip to main content

Errors

The error envelope​

Almost all 4xx / 5xx responses share one shape:

{
"detail": "human-readable message",
"code": "optional.stable.code"
}
  • detail is a human-readable explanation. On this envelope it is always a string.
  • code is a stable, machine-readable reason such as no_valid_urls or quota_exceeded_videos. It is present only when the failure has a stable reason and absent (or null) otherwise, so branch on its presence rather than assuming it is there.

Three cases do not follow the envelope exactly, so check the type of detail before reading it:

  1. Schema validation returns FastAPI's array form (next section).
  2. A downstream error body the gateway cannot interpret is relayed as-is rather than rewritten.
  3. An error raised outside the API surface, such as an edge proxy, can arrive as an opaque body with no envelope at all.

Validation errors (422 array form)​

A request rejected by schema validation returns FastAPI's list form: detail is an array of field errors instead of a string.

{
"detail": [
{
"loc": ["body", "url"],
"msg": "Field required",
"type": "missing"
}
]
}

Any endpoint that declares a body can return this. The common case is sending an over-length items array to POST /api/v1/videos/batch.

note

422 is not always the array form. Some routes raise their own 422 with the string envelope and a code, for example POST /api/v1/videos/batch/upload-sheet on an unsupported file type or a sheet with no url column. Branching on typeof detail handles both.

Special codes​

upstream_error_too_large​

This code is produced by the gateway itself, not by the failing service. It means a downstream error body was too large to relay. The HTTP status code is preserved, but the per-item reasons are gone. Retry with fewer items to get the detailed response.

rejected on sheet upload​

Sheet parse failures on POST /api/v1/videos/batch/upload-sheet (413 and 422) carry one extra sibling key when code is no_valid_urls: rejected, the number of rows dropped while parsing the sheet. Those rows were never recorded in any batch.

{
"detail": "No valid URL rows found in the sheet",
"code": "no_valid_urls",
"rejected": 12
}

Job failures are not HTTP errors​

A video that fails to index still returns 200 from GET /api/v1/jobs/{job_id}; the failure is in the body as status: "failed" with a stable reason_code and the raw error text. Branch on reason_code, not on the HTTP status.

HTTP status codes​

HTTPMeaningHandling
401Missing or invalid API key.Check the Authorization: Bearer ... header. See Authentication.
403Key used outside the public API roots (/api/v1, /api/v1.1).API keys do not open dashboard routes. See Authentication.
404Referenced video, job or ad not found.Typo, or the resource belongs to another organization. GET /api/v1/usage also returns 404 when no quota plan exists for the organization yet.
409Ad not ready.The ad_id exists but its status is not ready (still resolving, or failed). Poll GET /api/v1/ads/{ad_id} and retry once it is ready.
413Upload too large.On sheet upload: the file exceeds the 10 MB cap or has more valid URL rows than one batch accepts (currently 500). Split into multiple sheets.
422Request body failed validation.Fix the request. detail names the offending field (array form) or carries a code (envelope form).
500Upstream service error.Usually safe to retry. For file uploads, check the batch or video first; see Usage and limits.
503Quota datastore temporarily unavailable.Returned by GET /api/v1/usage. Retry.

Retry guidance​

  • 500 is usually retry-safe. The gateway relays an upstream failure; the request itself is usually fine. The exception is a file upload, which has no dedup key: look the batch or video up before resending.
  • 503 on GET /api/v1/usage is transient. Retry.
  • 409 resolves itself once the ad finishes resolving. Poll the ad, do not resubmit the screening blindly.
  • upstream_error_too_large means the request was too big for the error path, not that it failed permanently. Retry with fewer items.
  • 4xx other than the above will not change on retry. Fix the request.
tip

POST /api/v1/videos is idempotent for a URL that is still being indexed: resubmitting returns the existing video_id / job_id with created: false, so retrying a submission after a network error does not start a duplicate pipeline.