Errors
Every status code the Buni.ai public API returns, what the error body looks like, and whether to retry.
Errors are JSON with an error message. A few add fields: the version error adds code and supportedVersions, the quota error adds quota, and a failed sync run adds invocationId and status.
{ "error": "Insufficient token scope" }Match on the status code, not the message text. Messages can be reworded.
Status codes
| Status | Example error | Cause | Retry? |
|---|---|---|---|
200 | - | Sync run finished, or a stored result was replayed (idempotentReplay: true). | - |
201 | - | Polling trigger registered. | - |
202 | - | Async run accepted, or an earlier run with the same idempotency key is still in progress. | - |
400 | Unsupported API version | Path version is not v1. Body also has code: "UNSUPPORTED_API_VERSION" and supportedVersions: ["v1"]. | No |
400 | Bot message API is only available for chatbot projects | Wrong project type for the endpoint. Also Automation projects must use the automation trigger API, Automation trigger API is only available for automation projects, External API access is not supported for this project type. | No |
400 | Provide either runAt or delaySeconds, not both | Invalid scheduling fields. See Scheduling. | No |
400 | pollKey is required | Missing required field or query parameter. | No |
401 | Missing API token | No Authorization: Bearer or x-api-key header. | No |
401 | Invalid API token | Unknown, revoked or expired token, or a token for another project. | No |
403 | Insufficient token scope | Token lacks the endpoint's scope. | No |
403 | External API access is disabled for this project | Enable External API is off. | After it is switched on |
403 | Token does not match invocation | Reading or changing a run another token started. | No |
403 | Unauthorized | approve or reject sent with an API token. | No |
404 | Project not found | Wrong orgId or projectId, or the project was deleted. | No |
404 | Invocation not found | Wrong invocationId, or it belongs to another organization. | No |
404 | Polling state not found | No polling trigger with that pollKey. | No |
409 | Only scheduled invocations can be modified | Cancel or reschedule on a run that is not SCHEDULED, or on a sync run. | No |
422 | Event has already been replayed | Dead-letter replay of an event already replayed, a missing event, or a replay that failed. | Depends on error |
429 | Rate limit exceeded | Per-token rate limit. See the X-RateLimit-* headers. | Yes, after X-RateLimit-Reset |
429 | Monthly API call quota exceeded | Plan quota used up. Body has quota.limit and quota.used. | Next billing period |
500 | Payload is missing required keys: customerId | Sync run failed, including trigger validation. Body has invocationId and status: "FAILED". | Fix the request first |
500 | Flow sync trigger failed | Unexpected server error. | Yes, with the same idempotency key |
502 | Failed to resume the automation after recording the decision | An approval decision was recorded but the run did not resume. Dashboard only. | - |
503 | Unable to validate monthly API quota | Quota check unavailable. | Yes, with backoff |
The Webhook trigger URL has its own set of responses, including 405, 409, 410 and 413.
Retry safely
Only retry 429, 500 and 503, and network errors. Send an x-idempotency-key with every trigger call so that a retry after a timeout cannot start a second run. Back off exponentially: for example 1, 2, 4 and 8 seconds, capped at a few attempts.
A 500 from a sync endpoint that includes invocationId means the run itself failed. Read error, and see the run's steps with GET /external-invocations/{invocationId}, before sending it again.