Send Custom Message
Send a message to a customer inside a conversation that is already open. Unlike Send Template — which is used to start the conversation — this endpoint assumes the customer already started a conversation or recently replied to a template, so the service window is still active.
POST https://api.platica.mx/v1/messages Before sending, verify the conversation is within the service window. Query Get Conversation and make sure canSendDirectMessage is true. If it is closed, first use Send Template to reopen it.
Available for WhatsApp, Instagram, and Facebook. Message-type support varies by channel — see the Message types section.
Request body
{
"channelId": "521234567890",
"conversationId": "521234567890",
"content": "¡Hola! ¿En qué puedo ayudarte?",
"client": {
"name": "José",
"customFields": {
"placas": "ABC123"
}
}
} Body parameters
| Field | Type | Description | Required |
|---|---|---|---|
channelId | string | Internal channel ID OR the agent's phone number (E.164 format without +) | ✓ |
conversationId | string | Customer phone number in E.164 format without + | ✓ |
content | string | object | Message content. If a string, sent as text. For media and interactive messages, use an object — see Message types | ✓ |
type | enum | text, image, video, file, audio, interactive, email. Optional when content is a string | — |
client | object | Customer information to update (upsert) | — |
campaignId | string | ID of the campaign the message is attributed to. If omitted, it is logged under the api campaign | — |
delay | number | Delay in milliseconds (3,000 – 86,400,000) | — |
scheduleTime | string | Scheduled send date/time (ISO 8601). Maximum 1 year in the future | — |
If the client object is sent, the profile information is updated (or created if it does not exist), giving the AI agent immediate access to the new data.
Message types
content can be plain text or a structured object. When it is an object, you must specify type, and the shape of content depends on the type.
Text
Shorthand form:
{
"channelId": "521234567890",
"conversationId": "521234567890",
"content": "¡Hola! ¿En qué puedo ayudarte?"
} Explicit form:
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "text",
"content": { "text": "¡Hola! ¿En qué puedo ayudarte?" }
} Image
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "image",
"content": {
"image": {
"url": "https://cdn.assets.com/foto.jpg",
"caption": "Aquí está la foto que me pediste"
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.image.url | string | Public https:// image URL | ✓ |
content.image.caption | string | Caption text shown under the image | — |
Video
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "video",
"content": {
"video": {
"url": "https://cdn.assets.com/video.mp4",
"caption": "Mira este video"
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.video.url | string | Public https:// video URL | ✓ |
content.video.caption | string | Caption text shown under the video | — |
Document / file
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "file",
"content": {
"file": {
"url": "https://cdn.assets.com/factura.pdf",
"filename": "factura-2025-09.pdf",
"caption": "Tu factura del mes"
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.file.url | string | Public https:// file URL | ✓ |
content.file.filename | string | Name the customer sees for the file | — |
content.file.caption | string | Caption shown next to the file | — |
Audio
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "audio",
"content": {
"audio": {
"url": "https://cdn.assets.com/nota.ogg"
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.audio.url | string | Public https:// audio URL | ✓ |
Interactive messages
Interactive messages (buttons, lists, and flows) are available only on WhatsApp.
Up to 3 buttons per message. The customer taps one and the API receives the reply as a regular message with the id of the selected button.
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "interactive",
"content": {
"type": "button",
"body": { "text": "¿Quieres confirmar tu cita?" },
"action": {
"buttons": [
{ "id": "confirmar", "title": "Sí, confirmar" },
{ "id": "reagendar", "title": "Reagendar" },
{ "id": "cancelar", "title": "Cancelar" }
]
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.body.text | string | Main message text | ✓ |
content.header | object | Optional header ({ type: "text", text }) | — |
content.footer.text | string | Small text shown below the buttons | — |
content.action.buttons[].id | string | Button identifier. You receive it back when the customer taps the button | ✓ |
content.action.buttons[].title | string | Visible button text (max 20 characters recommended) | ✓ |
Up to 10 rows in total, distributed across one or more sections. The customer opens the list, taps a row, and the API receives the reply with the id of the chosen row.
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "interactive",
"content": {
"type": "list",
"body": { "text": "Elige el horario que prefieras" },
"action": {
"button": "Ver horarios",
"sections": [
{
"title": "Esta semana",
"rows": [
{ "id": "lun-10", "title": "Lunes 10:00", "description": "Disponible" },
{ "id": "mar-12", "title": "Martes 12:00", "description": "Disponible" }
]
}
]
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.body.text | string | Main message text | ✓ |
content.action.button | string | Text on the button that opens the list | ✓ |
content.action.sections[].title | string | Section title | — |
content.action.sections[].rows[].id | string | Row identifier. You receive it back when the customer taps it | ✓ |
content.action.sections[].rows[].title | string | Visible row text | ✓ |
content.action.sections[].rows[].description | string | Secondary text shown below the title | — |
To send a published WhatsApp Flow, provide flow_id (or flow_name) and the CTA text. The API generates the flow_token automatically and correlates the customer's response with the send.
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "interactive",
"content": {
"type": "flow",
"body": { "text": "Completa tu registro en menos de un minuto" },
"action": {
"parameters": {
"flow_id": "1234567890",
"flow_cta": "Empezar"
}
}
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.body.text | string | Main message text | ✓ |
content.action.parameters.flow_id | string | ID of the published WhatsApp Flow. Alternative: flow_name | ✓¹ |
content.action.parameters.flow_name | string | Name of the published Flow. Alternative to flow_id | ✓¹ |
content.action.parameters.flow_cta | string | Text of the button that opens the Flow | ✓ |
¹ Send flow_id or flow_name, not both.
Instruction to the agent
An instruction is not sent to the customer: it acts on the agent operating the conversation. It is useful when you are supervising the chat through the API and want the agent to wait or resume control. The mode field defines the behavior.
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "instruction",
"content": {
"text": "Espera a que el cliente confirme la cita antes de continuar.",
"mode": "wait"
}
} | Field | Type | Description | Required |
|---|---|---|---|
content.text | string | Instruction or context the agent should consider | ✓ |
content.mode | enum | wait or resume | ✓ |
Behavior by mode
wait: records the instruction as a system message in the history and leaves the conversation waiting for the customer's next message. The agent does not reply immediately; when the next customer message arrives, it reads the instruction as context.resume: marks the conversation as resumed and prompts the agent to continue the flow using the instruction as guidance. The agent can decide whether to reply to the customer based on its own logic.
{
"channelId": "521234567890",
"conversationId": "521234567890",
"type": "instruction",
"content": {
"text": "Continúa con el flujo de venta y ofrece un descuento del 10%.",
"mode": "resume"
}
} Instructions also support delay and scheduleTime. A scheduled instruction runs at the configured time, not earlier. For example, you could schedule a resume with a follow-up message for tomorrow at 9:00.
Scheduling
Just like in Send Template , you can send the message immediately, after a delay, or at a specific date and time.
Delayed send (delay):
- Minimum:
3000ms (3 seconds) - Maximum:
86400000ms (24 hours) - Example:
"delay": 5000sends the message in 5 seconds
Scheduled send (scheduleTime):
- ISO 8601 format
- Must be a future date
- Cannot be more than 1 year in the future
- Examples:
"2025-07-01T18:40:00"— Mexico time (UTC-6)"2025-07-01T18:40:00Z"— UTC time"2025-07-01T18:40:00-06:00"— With a specific time zone
You cannot use delay and scheduleTime in the same request.
The service window is validated at the moment of actual send, not at scheduling time. If you schedule a message and the window closes before it runs, the send will fail.
| Field | Type | Description |
|---|---|---|
client.name | string | Customer full name |
client.firstname | string | First name |
client.lastname | string | Last name |
client.email | string | Email address |
client.birthdate | string | Date of birth (dd/mm/yyyy) |
client.gender | enum | Gender: male or female |
client.company | string | Company name |
client.country | enum | ISO 3166-1 alpha-2 code (e.g. MX, US) |
client.state | string | State of residence |
client.city | string | City of residence |
client.address | string | Full address |
client.postalCode | string | Postal code |
client.customFields | map | Key-value object with the custom fields defined in the workspace. See Custom Fields for what's available. |
client.owners | array | Responsible-user emails |
Response
The response shape depends on whether the message is sent immediately, with a delay, or scheduled.
Immediate send:
{
"messageId": "msg_123xyz",
"status": "sent",
"timestamp": "2025-02-14T12:00:00Z"
} With delay:
{
"messageId": "msg_123xyz",
"status": "delayed",
"timestamp": "2025-02-14T12:00:00Z",
"executeAt": "2025-02-14T12:00:05.000Z",
"delayMs": 5000
} With scheduleTime:
{
"messageId": "msg_123xyz",
"status": "scheduled",
"timestamp": "2025-02-14T12:00:00Z",
"executeAt": "2025-07-01T00:40:00.000Z",
"scheduledTime": "2025-07-01T18:40:00"
} | Field | Type | Description |
|---|---|---|
messageId | string | ID of the created message. Use it to track its status in the campaign |
status | enum | sent, delayed, or scheduled |
timestamp | string | Date/time when the request was processed (ISO 8601 UTC) |
executeAt | string | Date/time when the message will be sent (ISO 8601 UTC). Only present in delayed or scheduled sends |
delayMs | number | Configured delay in milliseconds. Only present when delay was used |
scheduledTime | string | Original scheduleTime value sent in the request. Only present when scheduleTime was used |
Common errors
| Code | Case |
|---|---|
400 | Invalid schema, delay outside the allowed range, delay and scheduleTime sent together, or invalid scheduleTime |
404 | No agent was found for the given channelId, or the customer has no open conversation on that channel |
422 | The conversation exists but the service window is closed. Send a template with Send Template to reopen it |
Channel rules
- Templates are required to start the conversation. Once the customer replies, the service window stays open for 24 hours and you can send any message type until it closes.
- Every customer message resets the window.
- Supports text, images, videos, files, audio, buttons, lists, and flows.
Instagram and Facebook
- Support text, images, videos, files, and audio. Interactive messages (buttons, lists, flows) are not available outside WhatsApp.
- These platforms may have windows and policies different from WhatsApp's; always check
canSendDirectMessagebefore sending.
Checking status
Confirm your message was delivered:
- From the platform's inbox.
- Using the Get Conversation endpoint.