Errors worth branching on
These five failures cover the upload create + download (POST /api/v1/files, GET /api/v1/files//download), hammered by attachment pickers across the dashboard. Each block below is a full { error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the error handling guide.
401 — Unauthorized
A 401 on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.
403 — Forbidden
A 403 means the key authenticated but the operation is gated by scope — check the key’s scopes on the developer page; a 403 is never a data-not-found shape.
422 — Schema
A 422 means the payload did not match the request schema — branch on error.details.field and resend with an allow-listed MIME type on the upload instead of blind-retrying the same body.
429 — Rate
The Retry-After header and error.details.retry_after are both set on every 429 — resend the SAME request after the lower of the two.
402 — Feature gate
Poll the scan status and retry the download once scan_status flips to clean. The full recovery walk — the scan state machine, polling bounds, and how to escalate a wrong verdict — is on FILE_SCAN_QUARANTINED recovery.
60-second retry matrix
Worked request and response samples
Copy the request as written, substitute your own ids, and compare the response envelope — a success in the same shape the numbered error sections spell out.
Upload a file
POST /api/v1/files/upload
Binary uploads land here first — the returned file_id is the handle every downstream surface (imports, fax, knowledge, email) accepts.
Request