API reference
API errors, limits, and retries
Check the HTTP status before using a response's data. Errors use this shape:
{
"error": {
"code": "INSUFFICIENT_SCOPE",
"message": "The API key does not have the required scope.",
"request_id": "example-request-id"
}
}
Save the status, error code, and X-Request-Id response header for troubleshooting. Do not log credentials, signing secrets, private download URLs, or customer message bodies. When contacting support, share the request ID and operation rather than the secret.
Common responses
| Status | Meaning | What to do |
|---|---|---|
400 | Invalid fields, cursor, or missing idempotency key | Check the endpoint schema. Unknown JSON fields are rejected. |
401 | Missing, invalid, revoked, or expired credentials | Check the active connection. Refresh an expired OAuth access token or replace invalid credentials. |
402 | Message sending requires billing | Confirm the workspace's billed subscription before sending again. |
403 | Missing permissions, read-only resource, blocked or opted-out recipient | Check the error code and access. Do not repeatedly retry denied actions. |
404 | Missing or inaccessible resource | Verify the ID and connection scope; access restrictions can also produce this response. |
409 | Idempotency, resource version, capacity, or sender-state conflict | Resolve the specific conflict before retrying. Fetch a changed resource again before editing. |
410 | Expired or consumed upload | Create a new reservation for a new intended send. |
413 | Request, attachments, or response too large | Reduce body or attachment size, or lower the list page size. |
415 | Unsupported content type | Use the endpoint's required JSON or binary MIME type. |
429 | Rate budget exhausted | Wait for Retry-After, then retry with backoff. |
503 | Service temporarily unavailable | Retry with backoff; preserve the original idempotency key and body for writes. |
Contact capacity and creation limits
CONTACT_LIMIT_REACHED(409): the workspace has reached its stored contact limit. Existing contacts can still be updated. Contact Waveline Support if you need more capacity; do not keep retrying the same create request.CONTACT_CREATE_RATE_LIMITED(429): too many contacts were created by workspace integrations in a short period. Wait forRetry-Afterbefore retrying, and preserve the original idempotency key and request body.
Rate limits and request sizes
Requests share connection and workspace limits. Successful responses can expose RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset, plus a rate_limit object containing limit, remaining, and reset_at. Use the returned values rather than hard-coding a limit. 429 responses include Retry-After in seconds. A connection with remaining capacity can still be limited by workspace-wide request limits.
Keep concurrent requests bounded. After transient errors, use increasing delays with jitter so many jobs do not retry at once. Respect Retry-After when present.
| Limit | Value |
|---|---|
| JSON request body | 64 KiB |
| JSON response | 4 MiB |
| Binary upload | 5 MiB |
| Contact, call, and message page size | 1–100; default 50 |
| Phone-number page size | 1–100; default 20 |
| Cursor lifetime | 24 hours |
| Message text | 1,600 characters |
| Message attachments | Up to 10; 5 MiB total |
Pagination and filters
Paginated endpoints return data and next_cursor. Keep the same credentials, endpoint, filters, ordering, and limit when following a cursor, and stop when next_cursor is null. IDs are decimal strings and can exceed JavaScript's safe integer range; keep them as strings.
Contacts, calls, and messages default to order=oldest, which pages by ascending stable record ID. Use order=newest to start with the newest records and continue toward older records. Do not change the order while following a cursor.
For these lists, created_after is inclusive and created_before is exclusive. Include an explicit time zone. The filters apply to calls' start_time and to contacts' and messages' created_at; they do not find later edits to older contacts.
Conversations use most-recent-activity order, and their date filters apply to the last activity. A conversation that receives a new message while you page can appear again, so deduplicate by conversation ID. Pages are live results, not a frozen snapshot.
Phone numbers, contact notes, contact-property lists, call recordings, and message attachments also support cursor pagination. Their supported filters and ordering differ; use the relevant endpoint parameters rather than applying the contact-list options to every list. Teammate pagination is available only through the personal assistant connection described in API access and permissions.
Inbox and subscription lists return their complete authorized collections and do not accept pagination filters. Webhook delivery history accepts limit and returns recent records without a cursor or date range.
Idempotency for writes
Operations requiring Idempotency-Key accept 8–128 visible ASCII characters. Persist a unique key with each intended operation. Preserve the exact JSON body, path, and key when retrying an uncertain outcome.
Contact writes replay saved responses for seven days, subject to current resource access. Subscription creation retains its identity for seven days and returns current metadata and its signing secret; a disabled or deleted subscription rejects replay. Message-send deduplication is permanent. Subscription state changes are repeatable, and binary upload retries use the reserved upload ID instead of a separate idempotency header.
After the contact-write retention window, reconcile the existing resource before issuing another create. A new idempotency key represents a new operation and can create duplicates. Never resolve a send timeout by blindly creating a new key.