Overview
The InstaView API uses standard HTTP status codes and returns structured error responses to help you diagnose and handle issues in your integration.Response Structure
Whether a call succeeded is carried by the HTTP status code, not by a field in the body. Read the status first, then the body.Success Response
The body is the resource. There is no wrapper around it:Error Response
A 4xx or 5xx answers with a flat error object:errors array holding the individual problems — a failed
validation lists one entry per rejected field, and an invalid conversation flow lists one
entry per bad block, each with the path of the block it is on:
Every response also carries an
x-trace-id header holding the same trace id as the body’s
traceId. Quote it when you write to support — it is the fastest way for us to find the
exact request. It is present on success responses too, which have no body field for it.HTTP Status Codes
- 2xx Success
- 4xx Client Errors
- 5xx Server Errors
Common Errors
There is no separate machine-readable error code, and no nestederror object: the body is the
flat one shown above. Branch on statusCode, and use message for the detail — the sections
below give the real wording for the cases you are most likely to hit.
Authentication Errors
Unauthorized
No
Authorization header, or one that is not a bearer token.Unauthorized
The key does not exist, has been revoked, has expired, has been suspended, or the request came
from an address outside the key’s IP allowlist.
All of those answer with the same sentence on purpose. A message that distinguished
“revoked” from “never existed” would confirm which keys are real to whoever is guessing, so
the reason is written to your audit log rather than to the response. Check the key in the
dashboard, or quote the
traceId to support.Permission Errors
Forbidden
The key authenticated, but does not carry the scope the route requires. The message names the
scopes that were needed.Solution: add the scope to the key, or use a key that already has it. See
Scopes and Permissions.
Forbidden
The resource exists but belongs to a different company.
Several routes answer
404 rather than 403 in this situation — GET /jobs/{id} and
DELETE /jobs/{id} among them — so that an id belonging to another company is
indistinguishable from one that never existed. Do not branch on the status to tell a
permission problem from a missing resource; the reference page for each endpoint says which
it returns.Validation Errors
Bad Request
One or more fields failed validation. Solution: show
message is always the constant "Validation failed";
the detail is in errors, one entry per rejected constraint.errors to whoever made the request — the entries are already written for
a human. Note that an unknown property is a rejection, not something we ignore.Unprocessable Entity
A custom agent’s conversation flow is structurally valid JSON but not a usable flow. Each
entry carries the path of the block it is on.
Resource Errors
Not Found
The id names nothing your key can reach: it does not exist, it has been deleted, or — on the
routes noted above — it belongs to another company.
Conflict
The write cannot be applied to the resource in its current state.
Rate Limiting
Too Many Requests
This response carries the limit that was hit alongside the usual fields, and a Solution: wait
Retry-After
header with the same number of seconds as retryAfter.retryAfter seconds, then retry with exponential backoff. See
Rate Limiting.Billing Errors
402 is the billing code and 403 is the permissions one. Anything you cannot do because of
money answers 402; anything you cannot do because of who you are answers 403. You can switch on
the status alone, without reading the message.
Payment Required
The company has no active or trialing subscription, so nothing can be scheduled.Solution: subscribe. See Billing.
Payment Required
There is a subscription, but the request costs more than the company has left — or it would
cross the monthly spending cap. A A credits-based company gets the same object in its own units —
billing object carries the numbers so you do not have to
parse them out of the message."billingSystem": "credits"
with requiredCredits and availableCredits — matching the split
GET /billing/usage already returns. Read billingSystem
first and then the matching pair; do not assume minutes.suggestedAction is one of purchase_minutes, upgrade_plan, increase_spending_cap or
contact_support. billing is absent when there are no figures to report, so treat a
missing object as “unknown”, never as zero.Solution: top up, raise the cap, or split the request into batches you can afford.The two numbers answer two different questions. requiredMinutes - availableMinutes is how
much to buy to run the request unchanged. To split it instead, size the next batch
against availableMinutes alone: with 12 minutes left and a 5-minute agent, two conversations
fit — the 38-minute difference is not a batch of anything.Error Handling Patterns
Basic Error Handling
Two things a bare request does not do for you: bound how long it can take, and treat a non-2xx answer as a failure. Without the first, a stalled service leaves the call pending forever; without the second, the error body parses just as happily as a job would and the code carries on as though it had one.Comprehensive Error Handler
Branch onstatusCode. There is no code field to switch on, and the cases that share a
status are separated by message rather than by a machine-readable discriminator — so treat
the message as text for a human, and let the status drive the control flow.
Retry with Exponential Backoff
Validation Error Handling
A rejected request body answers400 with message: "Validation failed" and an errors array
holding one string per rejected constraint. The strings are written for a human and are not
keyed by field, so match them to your form fields yourself if you need to place them:
Retrying a Write Safely
Retries are not deduplicated for you. What that means depends on the method:
So the only case that needs care is
POST, and the risk that matters is a duplicate
conversation: a timeout you retry can place two calls.
Do this instead
- Never retry a
POSTon a timeout without checking. A gateway timeout does not mean the write did not happen. Read before you retry: aGET /contacts?search=…or aGET /conversations?contactId=…tells you whether the first attempt landed. - Keep your own key. Put your own identifier in
metadataon the way in (metadata.externalId), and search for it before retrying. It is the cheapest way to make your side of the exchange idempotent, and it survives your process restarting. - Only retry the retryable.
5xxand429are worth another attempt with backoff. A4xxother than429will fail again identically; retrying it just delays the error.
Logging and Monitoring
Log errors for debugging and monitoring:Best Practices
Always Bound the Request and Check the Status
Always Bound the Request and Check the Status
Provide Context in Errors
Provide Context in Errors
Don't Expose Sensitive Data
Don't Expose Sensitive Data
Implement Circuit Breakers
Implement Circuit Breakers
Next Steps
Rate Limiting
Handle rate limits properly
Best Practices
Production-ready patterns
Authentication
Fix authentication errors
API Reference
See all error codes per endpoint