Agents: this page is also Markdown; every page is in llms.txt.
Errors
Errors come back as JSON with a stable code for your program and a message written for a person. Branch on the code; show or log the message.
Calling a Task
Calls use OpenAI's error shape, so every OpenAI SDK raises its usual exception class (RateLimitError for a 429, and so on):
{"error": {"message": "support-triage is still training v1. It answers once v1 merges.", "type": "invalid_request_error", "param": "model", "code": "model_not_ready"}}
| Status | Code | Why | What to do |
|---|---|---|---|
| 400 | invalid_json |
The body isn't a JSON object | Send JSON with Content-Type: application/json |
| 400 | invalid_model |
model is missing or malformed |
Set it to a Task name, or name@vN |
| 400 | invalid_messages |
messages is empty, or a message has no valid role |
Send at least one message with role system, user, assistant or tool |
| 400 | invalid_parameter |
A parameter is out of range, such as max_tokens over the Task's ceiling |
Read param and the message for the allowed range |
| 400 | unsupported_parameter |
A parameter Facet doesn't take, such as n above 1 |
Leave it unset |
| 401 | invalid_api_key |
The key is missing, revoked, expired or not a Facet key | Send Authorization: Bearer fct_... with a live key |
| 403 | workspace_suspended |
The workspace is suspended | An Owner writes to support@halfspacelabs.com |
| 404 | model_not_found |
No Task by that name for this key, or no such version | Check the name; a key limited to one Task can't call others |
| 409 | model_not_ready |
The Task's first version is still being built | Wait until v1 is live; its Overview shows when |
| 409 | version_archived |
A pinned version was archived | Restore it from its Version page, or call the live version |
| 429 | rate_limit_exceeded |
Too many calls or tokens this minute, or too many in flight | Wait for Retry-After seconds and retry; see Limits |
| 429 | spend_limit_reached |
The workspace reached its monthly spend limit | An Owner raises it in Settings, Billing, or wait for next month |
| 503 | pool_unavailable |
The model is starting or briefly unavailable | Retry after Retry-After seconds |
| 503 | adapter_unavailable |
This version couldn't load just now | Retry; if it persists, write to us with the x-facet-request-id |
| 5xx | pool_error |
Something failed on our side | Retry once; then write to us with the request ID |
The API and your agent
The /v1 API and the MCP tools share one shape. A refusal that needs someone's approval names who:
{"error": {"code": "strict_merge", "message": "merge protection is Strict: a Task owner approves each Ready Change", "approvers": [{"id": "usr_...", "name": "Dana", "email": "dana@example.com"}]}}
| Status | Code | Why | What to do |
|---|---|---|---|
| 400 | invalid |
A field is missing or malformed | Read the message |
| 401 | unauthenticated |
No session or key | Sign in, or send Authorization: Bearer fct_... |
| 403 | csrf |
A browser write without its CSRF token | Use the web app, or send a key instead of a cookie |
| 403 | not_allowed |
Your role or key doesn't cover this | Ask an Owner for a role that does |
| 403 | not_task_owner |
Only the Task's owners may do this | Ask a Task owner |
| 403 | not_workspace_owner |
Only workspace Owners may do this | Ask an Owner |
| 403 | agent_never_approves |
Facet's own agent can't approve or merge its own work | A person approves |
| 403 | not_ready |
Only a Ready change merges | Wait until it's Ready |
| 403 | spend_limit_reached |
The month's spend is at the limit | An Owner raises it, or wait for next month |
| 403 | quote_over_limit |
The quote doesn't fit in what's left this month | Raise the spend limit, or approve a smaller plan |
| 403 | free_allowance_used |
The free allowance doesn't cover it | An Owner picks a plan |
| 403 | draft_limit |
This month's drafts are used | Add a card for more, or wait for next month |
| 403 | draft_busy |
As many drafts as allowed are being written | Wait for one to finish |
| 403 | draft_budget |
This draft spent its budget | Start a new draft |
| 403 | workspace_suspended |
The workspace is suspended; you can still sign in and read | An Owner writes to support@halfspacelabs.com |
| 404 | not_found |
No such thing in this workspace | Check the ID and the workspace |
| 409 | strict_merge |
Approve each merge is on for this Task | One of approvers approves the merge |
| 409 | loosens_expectation |
Lowering a bar, removing or making an Expectation optional | One of approvers approves it |
| 409 | conflict |
It changed while you were editing | Reload and try again |
| 409 | needs_card |
This needs a card on file | An Owner adds one in Settings, Billing |
| 409 | workspace_deleting |
The workspace is being deleted | An Owner can undo it within 7 days |
| 422 | (varies) | An import Facet can't take | The message says why |
| 429 | rate_limited |
Too many calls this minute | Wait for Retry-After seconds; see Limits |
| 500 | internal |
Something failed on our side | Retry; then write to us |
Retrying
- Retry
429and503after theRetry-Afterheader. The OpenAI SDKs do this on their own. - Don't retry
400,401,403,404or409unchanged: something has to change first. - Retry a
500once, then write to support@halfspacelabs.com with the request ID.