Pipes.bot

Sending Messages

Send text and media messages to WhatsApp conversations via the REST API.

Send outbound WhatsApp messages through the Pipes.bot REST API. You can send text, images, audio, video, documents, and stickers — either by referencing a media ID, providing a URL, or sending base64 data inline.

All send operations use the same endpoint:

POST /v1/messages/send
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Sending text

{
  "conversationId": "conv_xyz789",
  "text": "Thanks for reaching out! We'll get back to you shortly."
}

Response

{
  "success": true,
  "messageId": "wamid.abc123...",
  "conversationId": "conv_xyz789"
}

Sending media

Include a media field to send media. Pipes.bot auto-detects the input mode based on the value.

Using a media ID

Reference a previously received or uploaded file by its 21-character media ID. The file keeps its 48-hour TTL and can be reused across multiple sends.

{
  "conversationId": "conv_xyz789",
  "media": "aBcDeFgHiJkLmNoPqRs1t",
  "caption": "Here's that photo"
}

Using a URL

Provide an HTTPS URL and Pipes.bot fetches the file for you. Private and internal addresses are blocked (SSRF protection).

{
  "conversationId": "conv_xyz789",
  "media": "https://example.com/files/report.pdf",
  "caption": "Monthly report"
}

Using base64

Send file data inline as a base64-encoded string. The mimeType field is required.

{
  "conversationId": "conv_xyz789",
  "media": "iVBORw0KGgoAAAANSUhEUg...",
  "mimeType": "image/png",
  "fileName": "screenshot.png",
  "caption": "See attached"
}

Request fields

FieldTypeDescription
conversationIdstringRequired. Target conversation ID
textstring?Text content. Used as caption for media messages if caption is absent
mediastring?Media ID, HTTPS URL, or base64 data. Either text or media must be provided
mimeTypestring?MIME type. Required for base64 mode
fileNamestring?File name. Optional, used for base64 mode
captionstring?Media caption (max 1024 chars). Takes precedence over text

Uploading media

Upload media independently before sending. This is useful when you want to reuse the same file across multiple messages or conversations.

POST /v1/media/upload
Authorization: Bearer YOUR_API_KEY

Multipart file upload

curl -X POST https://api.pipes.bot/v1/media/upload \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@photo.jpg"

JSON with URL

curl -X POST https://api.pipes.bot/v1/media/upload \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/files/photo.jpg" }'

JSON with base64

curl -X POST https://api.pipes.bot/v1/media/upload \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "data": "iVBORw0KGgo...", "mimeType": "image/png", "fileName": "chart.png" }'

Upload response

{ "mediaId": "aBcDeFgHiJkLmNoPqRs1t" }

Use the returned mediaId in the media field of the send endpoint. Uploaded media expires after 48 hours.

Supported media types

WhatsApp enforces format and size limits per media type:

TypeMax sizeAccepted formats
Image5 MBimage/jpeg, image/png
Audio16 MBaudio/aac, audio/mp4, audio/mpeg, audio/amr, audio/ogg
Video16 MBvideo/mp4, video/3gpp
Sticker500 KBimage/webp
Document100 MBAny MIME type

Files that don't match a specific media type (image, audio, video, sticker) are sent as documents.

24-hour service window

WhatsApp enforces a 24-hour messaging window. You can only send outbound messages within 24 hours of the customer's last inbound message. After the window expires, the API returns:

{ "error": "Service window expired...", "code": "SERVICE_WINDOW_EXPIRED" }

The window resets each time the customer sends a new message.

Rate limits

The API enforces 60 requests per minute per API key across all endpoints. Rate limit headers are included in every response:

HeaderDescription
X-RateLimit-LimitMaximum requests per window (60)
X-RateLimit-RemainingRequests remaining in this window
X-RateLimit-ResetUnix timestamp when window resets

Exceeding the limit returns 429 Too Many Requests.

Error reference

StatusCodeDescription
400INVALID_REQUESTMissing required fields or invalid input
400INVALID_MEDIAUnsupported MIME type or file exceeds size limit
400INVALID_URLURL blocked by SSRF protection
400FETCH_FAILEDCould not fetch media from URL
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENConversation or media belongs to another tenant
403SERVICE_WINDOW_EXPIREDLast inbound message is older than 24 hours
404NOT_FOUNDConversation or media ID not found
410MEDIA_EXPIREDReferenced media has expired (48-hour TTL)
429RATE_LIMITEDToo many requests, retry after reset
500META_UPLOAD_FAILEDFailed to upload media to WhatsApp
500SEND_FAILEDWhatsApp rejected the message

Complete examples

Send a text reply

const response = await fetch("https://api.pipes.bot/v1/messages/send", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    conversationId: "conv_xyz789",
    text: "Thanks for your message!",
  }),
});

const result = await response.json();
console.log("Sent:", result.messageId);

Forward a received image with a new caption

// msg.media.mediaId from a received whatsapp_message event
const response = await fetch("https://api.pipes.bot/v1/messages/send", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    conversationId: "conv_xyz789",
    media: msg.media.mediaId,
    caption: "Forwarding this image",
  }),
});

Upload then send to multiple conversations

// Upload once
const uploadRes = await fetch("https://api.pipes.bot/v1/media/upload", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com/promo-banner.jpg",
  }),
});

const { mediaId } = await uploadRes.json();

// Send to multiple conversations
for (const convId of conversationIds) {
  await fetch("https://api.pipes.bot/v1/messages/send", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      conversationId: convId,
      media: mediaId,
      caption: "Check out our latest offer!",
    }),
  });
}

Receive an image and send it back processed

ws.on("message", async (raw) => {
  const event = JSON.parse(raw.toString());
  if (event.type !== "whatsapp_message") return;

  const msg = event.data;

  if (msg.type === "image" && msg.media && !msg.media.unavailable) {
    // Download the original
    const imageBuffer = await downloadMedia(msg.media.mediaId, API_KEY);

    // Process (your logic)
    const processed = await addWatermark(imageBuffer);

    // Send back as base64
    await fetch("https://api.pipes.bot/v1/messages/send", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        conversationId: msg.conversationId,
        media: processed.toString("base64"),
        mimeType: "image/jpeg",
        caption: "Here's your watermarked image",
      }),
    });
  }
});

On this page