Passthrough Messages
Send template messages, interactive buttons, lists, CTA URL buttons, and other advanced WhatsApp message types via the passthrough endpoint.
The passthrough endpoint forwards your message payload directly to Meta's Cloud API, giving you access to every WhatsApp message type — templates, interactive buttons, list messages, locations, contacts, and reactions.
POST /v1/messages/passthrough
Authorization: Bearer YOUR_API_KEY
Content-Type: application/jsonBoth pool (pk_) and BYON (ak_) keys are accepted, but template messages require a BYON ak_ key.
Simple text messages
For sending plain text messages on BYON numbers, use the dedicated send endpoint:
POST /v1/messages/app/send
Authorization: Bearer ak_your_app_key
Content-Type: application/json| Field | Type | Description |
|---|---|---|
poolNumberId | string | Required. Your BYON number ID |
toNumber | string | Required. Recipient phone number |
text | string | Required. Message text |
curl -X POST https://api.pipes.bot/v1/messages/app/send \
-H "Authorization: Bearer ak_your_app_key" \
-H "Content-Type: application/json" \
-d '{
"poolNumberId": "pn_abc123",
"toNumber": "5511999999999",
"text": "Hello! Your order has been shipped."
}'The response uses the same format as passthrough:
{
"messaging_product": "whatsapp",
"contacts": [
{ "input": "5511999999999", "wa_id": "5511999999999" }
],
"messages": [
{ "id": "wamid.abc123..." }
]
}For templates, interactive messages, location, contacts, and reactions, use the passthrough endpoint below.
Routing fields
The routing fields depend on your API key type. These fields are stripped before forwarding to Meta.
BYON (ak_ key):
| Field | Type | Description |
|---|---|---|
messaging_product | string | Required. Always "whatsapp" |
poolNumberId | string | Required. Your BYON number ID |
to | string | Required. Recipient phone number |
type | string | Required. Message type |
Pool (pk_ key):
| Field | Type | Description |
|---|---|---|
conversationId | string | Required. Target conversation |
type | string | Required. Message type |
Sending template messages
Send a pre-approved template with dynamic parameters. Templates let you initiate conversations outside the 24-hour service window.
curl -X POST https://api.pipes.bot/v1/messages/passthrough \
-H "Authorization: Bearer ak_your_app_key" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"type": "template",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"template": {
"name": "order_confirmation",
"language": { "code": "en_US" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Maria" },
{ "type": "text", "text": "ORD-4521" },
{ "type": "text", "text": "January 20" }
]
}
]
}
}'Template with media header
{
"messaging_product": "whatsapp",
"type": "template",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"template": {
"name": "shipping_update",
"language": { "code": "en_US" },
"components": [
{
"type": "header",
"parameters": [
{
"type": "image",
"image": { "link": "https://example.com/tracking-map.jpg" }
}
]
},
{
"type": "body",
"parameters": [
{ "type": "text", "text": "ORD-4521" },
{ "type": "text", "text": "Jan 20, 2025" }
]
}
]
}
}Template with button parameters
For templates with dynamic URL buttons, pass the variable portion:
{
"messaging_product": "whatsapp",
"type": "template",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"template": {
"name": "order_tracking",
"language": { "code": "en_US" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "ORD-4521" }
]
},
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [
{ "type": "text", "text": "ORD-4521" }
]
}
]
}
}Interactive reply buttons
Send a message with up to 3 reply buttons. When the user taps a button, you receive a webhook with the button ID.
curl -X POST https://api.pipes.bot/v1/messages/passthrough \
-H "Authorization: Bearer ak_your_app_key" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"type": "interactive",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"interactive": {
"type": "button",
"header": {
"type": "text",
"text": "Confirm your appointment"
},
"body": {
"text": "You have an appointment on Jan 20 at 3:00 PM. Would you like to confirm?"
},
"footer": {
"text": "Reply within 24 hours"
},
"action": {
"buttons": [
{
"type": "reply",
"reply": { "id": "confirm", "title": "Confirm" }
},
{
"type": "reply",
"reply": { "id": "reschedule", "title": "Reschedule" }
},
{
"type": "reply",
"reply": { "id": "cancel", "title": "Cancel" }
}
]
}
}
}'Button constraints
- Max 3 buttons per message
- Button
titlemax 20 characters - Button
idmax 256 characters
Interactive list messages
Send a message with a selectable list of up to 10 items grouped into sections.
{
"messaging_product": "whatsapp",
"type": "interactive",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"interactive": {
"type": "list",
"header": {
"type": "text",
"text": "Our Menu"
},
"body": {
"text": "Browse our menu and pick your items:"
},
"footer": {
"text": "Prices may vary"
},
"action": {
"button": "View Menu",
"sections": [
{
"title": "Pizzas",
"rows": [
{ "id": "margherita", "title": "Margherita", "description": "$12.00" },
{ "id": "pepperoni", "title": "Pepperoni", "description": "$14.00" }
]
},
{
"title": "Drinks",
"rows": [
{ "id": "cola", "title": "Cola", "description": "$3.00" },
{ "id": "water", "title": "Water", "description": "$2.00" }
]
}
]
}
}
}List constraints
- Max 10 rows total across all sections
- Max 10 sections
- Row
titlemax 24 characters - Row
descriptionmax 72 characters - Action
buttontext max 20 characters
Interactive CTA URL buttons
Send a message with a call-to-action button that opens a URL when tapped.
curl -X POST https://api.pipes.bot/v1/messages/passthrough \
-H "Authorization: Bearer ak_your_app_key" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"type": "interactive",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"interactive": {
"type": "cta_url",
"header": {
"type": "text",
"text": "Visit our store"
},
"body": {
"text": "Check out our latest products and promotions."
},
"footer": {
"text": "Free shipping on orders over $50"
},
"action": {
"name": "cta_url",
"parameters": {
"display_text": "Shop Now",
"url": "https://example.com/store"
}
}
}
}'CTA URL fields
| Field | Type | Description |
|---|---|---|
interactive.type | string | Must be "cta_url" |
interactive.header | object | Optional. Text header |
interactive.body | object | Required. Message body text |
interactive.footer | object | Optional. Footer text |
interactive.action.name | string | Required. Must be "cta_url" |
action.parameters.display_text | string | Required. Button label (max 20 characters) |
action.parameters.url | string | Required. HTTPS URL to open |
CTA URL constraints
display_textmax 20 charactersurlmust use HTTPS
Sending location messages
{
"messaging_product": "whatsapp",
"type": "location",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"location": {
"latitude": "-23.5505",
"longitude": "-46.6333",
"name": "Pipes.bot HQ",
"address": "Av. Paulista, 1000 - São Paulo"
}
}Sending contact cards
{
"messaging_product": "whatsapp",
"type": "contacts",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"contacts": [
{
"name": { "formatted_name": "Support Team", "first_name": "Support" },
"phones": [
{ "phone": "+15551234567", "type": "WORK" }
],
"emails": [
{ "email": "support@example.com", "type": "WORK" }
]
}
]
}Sending reactions
React to a received message with an emoji:
{
"messaging_product": "whatsapp",
"type": "reaction",
"poolNumberId": "pn_abc123",
"to": "5511999999999",
"reaction": {
"message_id": "wamid.abc123...",
"emoji": "👍"
}
}To remove a reaction, send an empty emoji string.
Response
All passthrough responses are returned directly from Meta:
{
"messaging_product": "whatsapp",
"contacts": [
{ "input": "5511999999999", "wa_id": "5511999999999" }
],
"messages": [
{ "id": "wamid.abc123..." }
]
}Error handling
Meta errors are forwarded as-is. Common errors:
| Meta error code | Meaning |
|---|---|
131047 | Re-engagement message outside window |
131026 | Message undeliverable (user not on WA) |
131053 | Media upload failed |
132000 | Template parameter count mismatch |
132015 | Template is paused |
132012 | Template parameter format mismatch |
Pipes.bot-level errors:
| Status | Code | Description |
|---|---|---|
400 | INVALID_REQUEST | Missing type, routing fields, or invalid JSON |
401 | UNAUTHORIZED | Missing or invalid API key |
403 | BYON_ONLY | Template messages require a BYON ak_ key |
403 | WINDOW_CLOSED | Service window expired (pool users only) |
429 | RATE_LIMITED | 60 requests/minute exceeded |
502 | META_UNREACHABLE | Could not reach Meta's API |
Complete example
Send a template with buttons, then handle the button reply:
const API_KEY = "ak_your_app_key";
const BASE = "https://api.pipes.bot";
// Send a template message
const res = await fetch(`${BASE}/v1/messages/passthrough`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messaging_product: "whatsapp",
type: "template",
poolNumberId: "pn_abc123",
to: "5511999999999",
template: {
name: "appointment_reminder",
language: { code: "en_US" },
components: [
{
type: "body",
parameters: [
{ type: "text", text: "Dr. Smith" },
{ type: "text", text: "January 20 at 3:00 PM" },
],
},
],
},
}),
});
const result = await res.json();
console.log("Sent template:", result.messages?.[0]?.id);When the user replies to a button, you receive a webhook event:
{
"type": "whatsapp_message",
"data": {
"type": "interactive",
"messageId": "wamid.xyz...",
"fromNumber": "5511999999999",
"interactive": {
"type": "button_reply",
"button_reply": {
"id": "confirm",
"title": "Confirm"
}
}
}
}Then send a follow-up interactive message:
await fetch(`${BASE}/v1/messages/passthrough`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messaging_product: "whatsapp",
type: "interactive",
poolNumberId: "pn_abc123",
to: "5511999999999",
interactive: {
type: "button",
body: {
text: "Your appointment is confirmed! Would you like a reminder?",
},
action: {
buttons: [
{ type: "reply", reply: { id: "remind_1h", title: "1 hour before" } },
{ type: "reply", reply: { id: "remind_1d", title: "1 day before" } },
{ type: "reply", reply: { id: "no_remind", title: "No thanks" } },
],
},
},
}),
});