Error response shape
Every error response body contains the following fields:The HTTP status code of the response (e.g.
404, 422, 429). Mirrors the HTTP status on the response itself.A stable string identifier for the error category (e.g.
NotFoundIssue). See the taxonomy below. This value is frozen — it will not be renamed in /v1.A human-readable description of what went wrong. Useful for logging and debugging; do not rely on the exact wording in application logic.
Optional structured detail about the error — for example, which field failed validation or what the applicable rate limit is.
A unique identifier for this specific request, generated by Topo’s API gateway. Always include this value when contacting support — it’s the fastest way to locate your request in our logs.
Internal trace identifier. Present in non-production environments for debugging.
Internal span identifier. Present in non-production environments for debugging.
Error taxonomy
Thetype field uses a frozen set of values. Branch first on status_code, then use type as a stable refinement for more specific handling.
The
type identifiers listed below are frozen and will not be renamed in /v1. Adding a new error type is an additive change; renaming an existing one is breaking and would require /v2.type | HTTP status | When it occurs |
|---|---|---|
ValidationIssue | 400 | The request body or query parameters failed validation — a required field is missing, a value is the wrong type, etc. |
UnauthorizedIssue | 401 | The Authorization header is missing, malformed, or contains an invalid key |
UnauthorizedIssue | 403 | The API key is valid but lacks the required scope for this endpoint |
NotFoundIssue | 404 | The requested resource does not exist or does not belong to your workspace |
CommitIssue | 409 | The operation conflicted with the current state of the resource — for example, a concurrent modification or uniqueness constraint |
BusinessIssue | 422 | The operation is not allowed given the current state — for example, enrolling a contact who is already excluded |
RateLimitIssue | 429 | Your organization or API key has exceeded a rate limit |
InternalServerIssue | 500 | An unexpected error occurred on Topo’s side |
ValidationIssue (400)
Returned when the request itself is malformed. Check themessage and data fields for specifics about which field or parameter is invalid.
UnauthorizedIssue (401 / 403)
A401 means no valid key was provided; a 403 means the key is valid but does not have the required scope. Check the data.required field to see which scope is needed.
NotFoundIssue (404)
Returned when a resource ID does not exist or belongs to a different workspace. Topo deliberately returns 404 (rather than 403) for cross-workspace resources to avoid leaking the existence of records.RateLimitIssue (429)
Returned when your organization exceeds the allowed request rate. See the rate limits section below for how to handle this response.Rate limits
Topo enforces rate limits per organization across three time windows simultaneously: per second, per minute, and per day. All three windows are active on every request. Every API response includes headers that tell you your current rate limit state:| Header | Description |
|---|---|
X-RateLimit-Limit-second | Maximum requests allowed per second |
X-RateLimit-Remaining-second | Requests remaining in the current second |
X-RateLimit-Reset-second | Unix timestamp when the second window resets |
X-RateLimit-Limit-minute | Maximum requests allowed per minute |
X-RateLimit-Remaining-minute | Requests remaining in the current minute |
X-RateLimit-Reset-minute | Unix timestamp when the minute window resets |
X-RateLimit-Limit-day | Maximum requests allowed per day |
X-RateLimit-Remaining-day | Requests remaining in the current day |
X-RateLimit-Reset-day | Unix timestamp when the day window resets |
Retry-After | Seconds to wait before retrying (present only on 429 responses) |
429 with a RateLimitIssue error body:
Handling rate limits
Read the Retry-After header
On a
429 response, read the Retry-After header value (in seconds) and wait at least that long before retrying.Apply exponential backoff
If you continue to receive
429 responses, increase your wait time exponentially with jitter to avoid synchronized retries across parallel workers.Debugging tips
- Branch on
status_codefirst for broad categories (auth, not found, server error), then usetypeto distinguish sub-cases like401vs403. - Don’t match on
message— the human-readable message text is for display only and may change over time. Usetypefor logic. - Log
datafor validation errors — it contains field-level detail that helps you identify what to fix in your request. - 5xx errors are Topo-side — if you receive a
500 InternalServerIssue, the issue is not with your request. Retry with backoff and contact support if it persists, providing therequest_id.