Get started
Responses and errors
Every answer has one of two shapes. Test `error.code`, never the text.
Success: data
HTTP/1.1 200 OK{ "data": { "items": [ { "id": "9c1f…", "status": "open", "unreadCount": 2 } ], "nextCursor": "MjAyNi0wOS0xOFQw…", "hasMore": true }}Refusal: error
HTTP/1.1 409 Conflict{ "error": { "status": 409, "code": "window_closed", "message": "The 24-hour customer service window is closed: only an approved template can be sent.", "detail": "…", "requestId": "a1b2c3d4" }}codeis stable and documented below.messageis in English.detailis the specific reason, and may be in French.requestIdidentifies the call in our logs and inGET /api-requests: quote it if you need help.- Some refusals carry
datawith more facts —template_holes_unfilledlists the unfilled placeholders indata.issues.
Pagination
Lists are cursor-paginated: pass limit, then send back nextCursor as cursor until it is null. Cursors are opaque; do not build them.
let cursordo { const url = new URL('https://coplace.io/api/v1/inbox/conversations') url.searchParams.set('limit', '100') if (cursor) url.searchParams.set('cursor', cursor) const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.COPLACE_KEY}` } }) const body = await res.json() if (body.error) throw new Error(`${body.error.code}: ${body.error.message}`) for (const conversation of body.data.items) handle(conversation) cursor = body.data.nextCursor} while (cursor)Error codes
bad_request- The request could not be read. Check that the body is valid JSON.
unauthorized- Missing or invalid API key. Send
Authorization: Bearer cop_…. forbidden- This key's role does not allow this call.
not_found- Not found — or it belongs to another workspace.
method_not_allowed- This method is not allowed on this address.
conflict- The request conflicts with the current state of the resource.
payload_too_large- The request body is too large.
unsupported_media_type- This content type is not accepted here.
invalid_request- A field is missing or invalid.
detailsays which one. rate_limited- Too many calls: 600 per minute per key. Wait and retry.
internal_error- Something went wrong on our side. Retry; if it persists, send us the
requestId. upstream_error- The messaging provider refused or failed.
detailcarries its reason. unavailable- The service is temporarily unavailable. Retry shortly.
upstream_timeout- The messaging provider did not answer in time. Retry.
api_key_revoked- This API key has been revoked. Create a new one in the console.
api_keys_not_installed- API keys are not available on this instance.
window_closed- The 24-hour customer service window is closed: only an approved template can be sent.
idempotency_key_requiredidempotencyKeyis required: 8 to 200 characters, unique per message.idempotency_key_conflict- This
idempotencyKeywas already used for a different message. no_recipient- The contact has no address on this channel.
template_required- A template is required here.
template_not_approved- This template is not approved by Meta yet.
template_wrong_channel- This template belongs to another WhatsApp number.
template_variables_invalid- The template variables do not match its placeholders.
template_holes_unfilled- Some template placeholders have no value.
template_not_applicable- This template cannot be sent on this conversation.
template_locked- This template is under review and cannot be changed now.
already_submitted- This template was already submitted.
never_submitted- This template was never submitted to Meta.
plan_limit- Your plan's limit is reached for this month.
queue_not_supported- This message cannot be queued. Send it without
queue. webhook_url_not_https- The webhook address must start with https://.
file_missing- No file was sent.
file_too_large- The file is too large for this channel.
empty_file- The file is empty.
unsupported_file_type- This file type is not accepted on this channel.
file_type_refused- This file type is refused.
caption_unsupported- This kind of file cannot carry a caption.
channel_requiredchannelIdis required.unknown_channel- No such channel in this workspace.
ambiguous_channel- Several channels match: pass
channelId. no_channel- No active channel can reach this contact.
channel_not_meta- This channel is not a WhatsApp number connected through Meta.
meta_token_missing- The WhatsApp connection is not configured on this instance.
assignee_required- Choose who the conversation is assigned to.
identity_taken- Another contact already has this phone number or email address.
attribute_exists- An attribute with this key already exists.
confirmation_required- Erasing a contact needs the confirmation field.
confirmation_mismatch- The confirmation does not match the contact.
consent_missing- The contact has not agreed to receive marketing messages, or has opted out.
contact_blocked- This contact is blocked.
not_whatsapp- This only works on WhatsApp conversations.
store_failed- The event could not be stored. It will be retried.
already_approved- This template is already approved: it cannot be submitted again.
attachment_unreachable- An attachment address could not be read;
data.urlnames it. attachment_unsupported- That type of attachment is not accepted on this channel.
invalid_attachment- An attachment has no
url, or there are more than 5. invalid_category- That label does not exist in the workspace.
invalid_form- The interactive form breaks a WhatsApp limit;
detailsays which. invalid_link- The
linkis unreadable: it needs anexternalId. invalid_recipient- An address in
ccorbccis unreadable, or there are more than 10. invalid_sincesinceis not a readable date or epoch.media_expired- The file is no longer available.
no_identity- The contact needs a phone number or an email address.
not_emailcc,bccandattachmentsonly exist on email.quote_unavailable- The quoted message has no identifier at the provider and cannot be quoted.
retention_not_installed- Data retention is not installed on this workspace.