Skip to content
Get an API key

Get started

Responses and errors

Every answer has one of two shapes. Test `error.code`, never the text.

Success: data

HTTP

HTTP/1.1 200 OK{ "data": { "items": [ { "id": "9c1f…", "status": "open", "unreadCount": 2 } ], "nextCursor": "MjAyNi0wOS0xOFQw…", "hasMore": true }}

Refusal: error

HTTP

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" }}
  • code is stable and documented below. message is in English. detail is the specific reason, and may be in French.
  • requestId identifies the call in our logs and in GET /api-requests: quote it if you need help.
  • Some refusals carry data with more facts — template_holes_unfilled lists the unfilled placeholders in data.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.

Node.js

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. detail says 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. detail carries 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_required
idempotencyKey is required: 8 to 200 characters, unique per message.
idempotency_key_conflict
This idempotencyKey was 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_required
channelId is 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.url names 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; detail says which.
invalid_link
The link is unreadable: it needs an externalId.
invalid_recipient
An address in cc or bcc is unreadable, or there are more than 10.
invalid_since
since is 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_email
cc, bcc and attachments only 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.