Every non-2xx response from the Formo Public API uses the same envelope:Documentation Index
Fetch the complete documentation index at: https://docs.formo.so/llms.txt
Use this file to discover all available pages before exploring further.
| Field | Type | Notes |
|---|---|---|
code | string | Stable, machine-readable identifier. Branch on this. |
message | string | Human-readable description. Wording may change between releases — never branch on message. |
doc_url | string | Anchored link into this page. Agents can fetch it for context. |
param | string? | Dotted path to the offending field, when applicable (body.trigger_filters.0.value). |
details | object? | Code-specific extras. For INVALID_VALIDATION_REQUEST this is a { fieldPath: message } map of every Zod failure. |
GET /v0/alerts/alrt_… returns the alert directly.
Handling errors well
- Branch on
code, notmessageor status alone. Status families collide (most validation issues are400 BAD_REQUEST); thecodeenum disambiguates. - Follow
doc_urlfor context. AI agents can fetch the matching section of this page to learn how to fix the request without escalating to a human. - Retry only the safe codes.
429 TOO_MANY_REQUESTS,503 SERVICE_UNAVAILABLE, and5xx INTERNAL_SERVER_ERRORare retry-safe with exponential backoff. 4xx codes other than429indicate a client bug; retrying without changes will fail the same way. - Pair retries with
Idempotency-Keyon POST/PUT/PATCH/DELETE so the server can de-dupe duplicates. See Idempotency.
Reference
bad_request
HTTP: 400
The request was syntactically valid but semantically wrong — a constraint that Zod can’t express was violated (e.g. trying to delete a board that has charts, exceeding the per-project board limit). message describes the specific rule that failed; do not retry without changes.
invalid_validation_request
HTTP: 400
A request field failed schema validation. details is a { fieldPath: message } map of every failure across body, query, and params.
unauthorized
HTTP: 401
The API key is missing, malformed, or revoked. Check that the request includes Authorization: Bearer formo_… and that the key still exists in Team Settings → API Keys.
forbidden
HTTP: 403
The API key is valid but lacks the required scope for this endpoint. The message names the missing scope (e.g. API key missing required scope: alerts:write). Issue a new key with the right scopes — scopes can’t be added to an existing key.
not_found
HTTP: 404
The resource does not exist or is not visible to this API key’s workspace. Note that workspace isolation makes “exists in another workspace” indistinguishable from “doesn’t exist” — both return 404.
conflict
HTTP: 409
The request conflicts with current resource state (e.g. creating a resource whose unique key already exists).
idempotency_in_progress
HTTP: 409
Another request with the same Idempotency-Key is currently in flight from this workspace. Wait for it to complete (typically under 1 second) and replay your request — the server will return the cached response.
invalid_idempotency_key
HTTP: 400
The Idempotency-Key header exceeded 255 characters, or the key was reused for a request whose method, path, or body differs from the original. Generate a fresh UUID v4 per logical operation. See Idempotency.
invalid_chain_id
HTTP: 400
The chain parameter is not a supported EVM chain ID. See Supported Chains for the full list.
too_many_requests
HTTP: 429
The per-workspace rate limit has been exceeded. Inspect the RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset response headers and back off until RateLimit-Reset. Use exponential backoff with jitter for retries.
context_limit_exceeded
HTTP: 400
An AI request (chat / Ask AI) carried more tokens than the model can accept. Start a fresh conversation or trim the prompt.
service_unavailable
HTTP: 503
A downstream service the endpoint depends on (Tinybird, AI provider, RPC) is offline or degraded. Retry with exponential backoff; the request itself is fine.
internal_server_error
HTTP: 5xx
An unexpected error inside Formo. The error has been captured in our monitoring; retry with exponential backoff. If it persists, include the response timestamp when contacting support so we can correlate it to the captured exception.