Skip to main content

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:
List endpoints return a page object instead — see Pagination.

Error Response

A 4xx or 5xx answers with a flat error object:
Some 4xx responses add an 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

Common Errors

There is no separate machine-readable error code, and no nested error 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. message is always the constant "Validation failed"; the detail is in errors, one entry per rejected constraint.
Solution: show 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 Retry-After header with the same number of seconds as retryAfter.
Solution: wait 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 billing object carries the numbers so you do not have to parse them out of the message.
A credits-based company gets the same object in its own units — "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 on statusCode. 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

Retrying a write is not free of consequences — nothing deduplicates it. See Retrying a Write Safely below.

Validation Error Handling

A rejected request body answers 400 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

There is no Idempotency-Key header. No endpoint reads one, and sending it has no effect — the request is processed as if it were absent. This page previously showed a worked Idempotency-Key example; it never did anything, and it is gone.
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 POST on a timeout without checking. A gateway timeout does not mean the write did not happen. Read before you retry: a GET /contacts?search=… or a GET /conversations?contactId=… tells you whether the first attempt landed.
  • Keep your own key. Put your own identifier in metadata on 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. 5xx and 429 are worth another attempt with backoff. A 4xx other than 429 will fail again identically; retrying it just delays the error.

Logging and Monitoring

Log errors for debugging and monitoring:

Best Practices

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