The error body
Every error has the same shape:{
"code": "capabilityNotSupported",
"message": "This account can't perform this operation.",
"details": { "capability": "message:edit" },
"requestId": "req_tz4a98xxat96iws9zmbrgj3a"
}
| Field | Use |
|---|---|
code | Branch on this. It is the contract |
message | Readable, and safe to show a person. It can change |
details | null, or the object documented for that code |
requestId | Also in the X-Request-Id header. Include it when you contact support |
errors.ts
class InboxError extends Error {
constructor(
readonly status: number,
readonly code: string,
message: string,
readonly details: Record<string, unknown> | null,
readonly requestId: string,
) {
super(message);
}
}
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
const response = await fetch(`https://inboxapp.com/api/v2${path}`, {
...init,
headers: {
Authorization: `Bearer ${process.env.INBOX_API_TOKEN}`,
"Content-Type": "application/json",
...init.headers,
},
});
if (response.ok) {
return response.status === 204 ? (undefined as T) : response.json();
}
const body = await response.json();
throw new InboxError(
response.status,
body.code,
body.message,
body.details,
body.requestId,
);
}
Request errors
| Status | Code | When | Fix |
|---|---|---|---|
| 400 | invalidRequest | A parameter or body field is wrong | details.issues lists each path and message |
| 400 | invalidCursor | The cursor is malformed, or used with other filters | Restart from the first page |
| 401 | unauthorized | The token is missing, malformed or revoked | Check the Authorization header |
| 403 | planRequired | The team’s plan lacks details.feature | Upgrade, or add the Advanced API add-on |
| 403 | workspaceLocked | Billing is paused or past due, or the trial ended | Resolve billing in Inboxapp |
| 403 | platformNotAvailable | The resource is on a platform your team can’t use | Use a platform from GET /platforms |
| 429 | rateLimited | A team limit was reached | Wait for Retry-After. See Rate limits |
| 500 | internal | Something failed on our side | Retry, then contact support with the requestId |
Not found
threadNotFound, messageNotFound, contactNotFound, accountLinkNotFound, memberNotFound, tagNotFound, statusNotFound: all 404. The ID doesn’t exist in your team, or the object was deleted.
A lookup by platform identity never returns 404. It returns an empty data array.
Conflicts
| Status | Code | When | Fix |
|---|---|---|---|
| 409 | accountLinkDisconnected | The account is offline or paused | See details.status, and Account links |
| 409 | integrationSetupRequired | The account needs setup in Inboxapp before it can act | Finish the setup in the app |
| 409 | sendInProgress | A send with this idempotency key is still running | Retry shortly with the same key |
| 409 | nameTaken | A tag or status with this name exists | Use the existing one, or another name |
The platform said no
| Status | Code | When | Fix |
|---|---|---|---|
| 422 | capabilityNotSupported | The account link lacks details.capability | Check capabilities before calling |
| 422 | threadRestricted | The platform disabled details.capability in this thread | Check the thread’s restrictions |
| 422 | mutationWindowClosed | Too long since the message was sent | See the windows in Platforms |
| 422 | messageNotModifiable | This message can’t be edited or deleted. See details.reason | — |
| 422 | contentRejected | The content is too long or was refused. See details.detail | Shorten or change it |
| 422 | recipientUnavailable | The person can’t be messaged from this account | See details.reason |
| 422 | profileAmbiguous | The contact has several profiles on this platform | Send with a profile target |
| 422 | platformNotSupported | platform isn’t the account link’s platform | Use one in details.supported |
| 422 | idempotencyKeyReused | The key was used with a different body | Use a new key |
| 422 | tagLimitReached | The team has details.max tags | Delete unused tags |
The platform failed
| Status | Code | When | Fix |
|---|---|---|---|
| 429 | platformRateLimited | The platform is limiting this account | Wait details.retryAfterSeconds, or use another account |
| 502 | platformError | The platform returned an error | Retry later |
| 502 | sendUnconfirmed | The platform may have delivered the message | Don’t resend. details.messageId is the stored message |
| 503 | platformUnavailable | The platform can’t be reached | Wait details.retryAfterSeconds, then retry |
After
sendUnconfirmed, never retry with a new idempotency key: the person
may receive the message twice.What to retry
| Retry with backoff | Don’t retry |
|---|---|
429, 500, 502 platformError, 503, 409 sendInProgress | Every other 4xx, sendUnconfirmed |
Idempotency-Key.