Get started
Errors and conventions
The error envelope, every error code, cursor pagination, money, soft deletes and rate limits.
The rules that apply to every endpoint.
Errors
Every error has the same shape:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "priceAmount must be 0 or more; priceCurrency must be at most 3 characters",
"details": {
"issues": [
{ "path": "priceAmount", "message": "priceAmount must be 0 or more" },
{ "path": "priceCurrency", "message": "priceCurrency must be at most 3 characters" }
]
},
"correlationId": "c0a8012e-…"
}
}| Field | Use it for |
|---|---|
code | Branching in code. Stable; it will not change wording. |
message | Showing to a person. Written to be read, and safe to display as-is. |
details | Structured context. For validation errors, details.issues[].path names the field, so you can put each message next to its form input. |
correlationId | Quoting when you report a problem. It links the failure to the server logs. |
The value that failed validation is never echoed back, since it might be a password.
Error codes
| Status | code | When |
|---|---|---|
400 | UNSUPPORTED_PROVIDER | The providerKey is not a platform this API supports. |
400 | UNSUPPORTED_CAPABILITY | The channel cannot do what was asked, such as media on a text-only platform. |
401 | UNAUTHORIZED | Missing, malformed, revoked or expired token, or a token from the wrong plane. |
401 | INVALID_WEBHOOK_SIGNATURE | An inbound webhook failed its signature check. |
403 | FORBIDDEN | Authenticated, but not allowed to do this. |
404 | NOT_FOUND | Does not exist, or belongs to another organization. The two are deliberately indistinguishable. |
409 | CONFLICT | A unique value is taken: an email at signup, a slug you asked for, an account connected elsewhere. |
409 | CONCURRENT_MODIFICATION | Someone else changed the record first. Re-read and retry. |
409 | CONNECTION_UNAVAILABLE | The channel connection is disconnected, revoked or disabled. |
409 | REPLY_WINDOW_CLOSED | The platform's reply window has passed. WhatsApp allows free-form replies for 24 hours after the customer's last message. |
413 | PAYLOAD_TOO_LARGE | The upload is over the limit, such as a catalogue over 5 MB. |
422 | VALIDATION_FAILED | The request body or query failed validation. See details.issues. |
422 | GUARDRAIL_VIOLATION | A reply broke one of the organization's guardrails. |
429 | RATE_LIMITED / QUOTA_EXCEEDED | Too many requests, or a plan limit reached. Back off and retry later. |
500 | INTERNAL_ERROR | Unexpected. Report it with the correlationId. |
502 | PROVIDER_API_ERROR | The messaging platform returned an error. |
503 | LLM_UNAVAILABLE / EMBEDDING_UNAVAILABLE | A model provider is unreachable. Retry with backoff. |
Pagination
List endpoints use cursors, not page numbers. Page numbers skip or repeat rows when records are added while you page through.
curl "https://api.getengageai.app/products?limit=50" -H "Authorization: Bearer $ENGAGE_API_KEY"{
"items": [ … ],
"nextCursor": "eyJpZCI6Ij…",
"hasMore": true
}Pass nextCursor back unchanged as cursor for the next page. When hasMore is false, nextCursor is null and you have everything.
curl "https://api.getengageai.app/products?limit=50&cursor=eyJpZCI6Ij…" -H "Authorization: Bearer $ENGAGE_API_KEY"limit defaults to 25 and is capped at 100. Treat the cursor as opaque: do not parse it or build one yourself. GET /search is not paginated; see Search.
Money
Amounts are integers in the currency's minor unit, with an ISO 4217 currency code alongside:
| You mean | Send |
|---|---|
| £135.00 | "priceAmount": 13500, "priceCurrency": "GBP" |
| $19.99 | "priceAmount": 1999, "priceCurrency": "USD" |
| ¥1000 | "priceAmount": 1000, "priceCurrency": "JPY" |
Decimals are rejected. Floating point cannot represent most prices exactly, and a rounding error here is a wrong price quoted to a customer. The CSV import is the one place that accepts 135.00; it converts the text without using floating point.
Identifiers and timestamps
- IDs are UUIDs.
- Timestamps are ISO 8601 in UTC, for example
2026-10-16T09:30:00.000Z. - Your own identifiers, such as a product
skuor a documentsourceRef, are unique within your organization. Sending one you already have updates that record instead of creating a duplicate. That makes it safe to replay a whole feed.
Deletes
Deletes are soft. A deleted product or document stops being used for replies immediately, but conversations that referenced it stay readable. A deleted record returns 404 from then on.
Unknown fields
Fields the API does not recognise are dropped without an error. If a value you sent does not appear to have any effect, check its spelling against the API reference.
Rate limits
- Signup is limited per IP address: 5 a minute and 20 a day.
- Outbound messages follow each platform's own limit, shared across all servers. You do not need to throttle your own calls to stay under a platform's sending limit.
- A
429response means slow down. Retry with exponential backoff.