Skip to content

Send a DM

POST
/v1/social/conversations/{id}/messages

Sends a direct message into an existing conversation, through the account that owns the thread. Side effects match the panel: the AI auto-reply is paused for the bridged contact and the send lands on that contact’s timeline.

Platform windows still apply. WhatsApp only accepts a free-form reply within 24 hours of the customer’s last message; outside it, and for an expired Meta token, the response is 409 with error: provider_rejected and the network’s own reason in details.ProviderCode. Requires scope social:write.

id
required
integer
Idempotency-Key
string
<= 255 characters

A unique string of your choosing (a UUID works). The first request with this key runs normally and its response is stored for 24 hours; a retry with the same key returns that stored response verbatim, with Idempotency-Replayed: true, instead of writing again. Reusing a key with a different body returns 409.

At least one of text or mediaUrl must be present.

object
text
string
<= 8000 characters
mediaUrl

Publicly reachable URL of an image

string
idempotencyKey

Forwarded to the network so a retry is de-duplicated upstream as well as here. The Idempotency-Key header is used when this is omitted.

string
replyToMessageId

External id of the message being replied to

string

Message accepted by the network.

One message inside a social DM thread.

object
id
integer
conversationId
integer
externalMessageId
string
platform
string
direction
string
Allowed values: inbound outbound
senderExternalId
string
nullable
senderName
string
nullable
text

Empty on an attachment-only message.

string
nullable
attachmentUrl

Attachment link. Inbound network media is rewritten to a signed proxy path on this host (relative, no credentials needed); outbound and already-public URLs pass through unchanged.

string
nullable
attachmentType
string
nullable
Allowed values: image video audio file
replyToExternalMessageId
string
nullable
transcript

Speech-to-text for a voice note.

string
nullable
transcriptStatus
string
nullable
Allowed values: pending processing done failed unsupported
translation

Inbound, the message rendered in the operator’s language. Outbound, the operator’s original wording (text then holds what the participant received).

string
nullable
translationStatus
string
nullable
status
string
Allowed values: pending sent delivered read failed
errorMessage
string
nullable
sentAt
string format: date-time
nullable
deliveredAt
string format: date-time
nullable
readAt
string format: date-time
nullable
createdAt
string format: date-time

The request body or parameters failed validation.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "bad_request",
"message": "at least one of name, username, phone is required"
}

Missing or invalid bearer token.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "unauthorized",
"message": "Invalid bearer principal"
}

The workspace’s plan does not include this module. The social inbox needs channel_social_inbox and the post scheduler needs marketing_social_scheduler; details.FeatureKey names the one that is missing. Upgrading unlocks it, there is nothing to retry.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "payment_required",
"message": "your plan does not include this feature; upgrade to unlock it",
"details": {
"FeatureKey": "marketing_social_scheduler",
"UpgradeRequired": true
}
}

The API key does not have the required scope for this operation.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "forbidden",
"message": "scope contacts:write is required"
}

The requested resource does not exist or is not owned by the caller.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "not_found",
"message": "contact not found"
}

The request collides with existing state: a duplicate externalId, an Idempotency-Key replayed with a different body or still in flight, or a permanent delete blocked by records that still reference the contact.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "conflict",
"message": "a contact with externalId 'shopify-cust-88213' already exists",
"details": {
"existingContactId": 4821
}
}

Per-key rate limit exceeded. Retry after the time indicated by X-RateLimit-Reset.

Standard error envelope for all v1 error responses.

object
error

Machine-readable error code.

string
Allowed values: bad_request not_found conflict unauthorized forbidden payment_required provider_rejected rate_limited internal_error
message

Human-readable explanation of the error.

string
details

Optional structured context (field-level validation errors, etc.).

nullable
Example
{
"error": "rate_limited",
"message": "rate limit exceeded"
}
X-RateLimit-Limit
integer

Maximum requests allowed per minute for this key.

X-RateLimit-Remaining
integer

Requests remaining in the current window.

X-RateLimit-Reset
integer

Unix timestamp (seconds) when the rate limit window resets.