Pipes.bot

Message Types

All WhatsApp message types delivered over the WebSocket connection.

Every incoming WhatsApp message arrives as a whatsapp_message event. The data.type field determines the shape of the payload.

Which messages you receive depends on your connection scope:

  • User-scoped connections receive all messages from all your activated pool numbers
  • Conversation-scoped connections receive only messages matching the specified conversationId

Envelope structure

All messages share this common structure:

{
  "type": "whatsapp_message",
  "data": {
    "messageId": "msg_abc123",
    "conversationId": "conv_xyz789",
    "poolNumberId": "pool_123",
    "poolNumberPhoneNumber": "+15551234567",
    "fromNumber": "+15559876543",
    "fromName": "Jane Doe",
    "text": "Message text or caption",
    "timestamp": "2025-01-15T10:30:00.000Z",
    "label": "support",
    "type": "text",
    "body": "Message text or caption"
  }
}

Common fields

FieldTypeDescription
messageIdstringUnique message identifier
conversationIdstringPipes.bot conversation ID (use this for replies)
poolNumberIdstringPool number that received the message
poolNumberPhoneNumberstringPool number's phone number
fromNumberstringSender's WhatsApp number
fromNamestring?Sender's WhatsApp profile name
textstringText content or caption
timestampstringISO 8601 timestamp
labelstring?Activation label, if one was set
typestringMessage type (see sections below)
bodystringSame as text — the message body

Additional fields appear depending on the message type.

Text

{
  "type": "text",
  "body": "Hello from WhatsApp!",
  "text": "Hello from WhatsApp!"
}

The simplest message type. text and body both contain the message content.

Image

{
  "type": "image",
  "body": "Check this out",
  "text": "Check this out",
  "media": {
    "mediaId": "aBcDeFgHiJkLmNoPqRs1t",
    "downloadUrl": "/v1/media/download/aBcDeFgHiJkLmNoPqRs1t",
    "mimeType": "image/jpeg",
    "byteSize": 245120
  }
}

Images include an optional caption in body/text. See Media Handling for download details.

Audio

{
  "type": "audio",
  "media": {
    "mediaId": "aBcDeFgHiJkLmNoPqRs1t",
    "downloadUrl": "/v1/media/download/aBcDeFgHiJkLmNoPqRs1t",
    "mimeType": "audio/ogg",
    "byteSize": 52480
  }
}

Includes voice notes and audio file attachments.

Video

{
  "type": "video",
  "body": "Watch this",
  "text": "Watch this",
  "media": {
    "mediaId": "aBcDeFgHiJkLmNoPqRs1t",
    "downloadUrl": "/v1/media/download/aBcDeFgHiJkLmNoPqRs1t",
    "mimeType": "video/mp4",
    "byteSize": 1048576
  }
}

Videos include an optional caption.

Document

{
  "type": "document",
  "body": "Here's the invoice",
  "text": "Here's the invoice",
  "media": {
    "mediaId": "aBcDeFgHiJkLmNoPqRs1t",
    "downloadUrl": "/v1/media/download/aBcDeFgHiJkLmNoPqRs1t",
    "mimeType": "application/pdf",
    "fileName": "invoice.pdf",
    "byteSize": 102400
  }
}

Documents include the original fileName and an optional caption.

Sticker

{
  "type": "sticker",
  "media": {
    "mediaId": "aBcDeFgHiJkLmNoPqRs1t",
    "downloadUrl": "/v1/media/download/aBcDeFgHiJkLmNoPqRs1t",
    "mimeType": "image/webp",
    "byteSize": 25600
  }
}

Location

{
  "type": "location",
  "location": {
    "latitude": 37.7749,
    "longitude": -122.4194,
    "name": "San Francisco",
    "address": "San Francisco, CA, USA"
  }
}
FieldTypeDescription
latitudenumberLatitude coordinate
longitudenumberLongitude coordinate
namestring?Location name
addressstring?Full address string

Location messages do not include a media object.

Contacts

{
  "type": "contacts",
  "contacts": [
    {
      "name": { "formatted_name": "Jane Doe" },
      "phones": [{ "phone": "+15559876543", "type": "CELL" }]
    }
  ]
}

The contacts array follows WhatsApp's native contact structure. Each contact may include name, phones, emails, addresses, org, and urls fields.

Reaction

{
  "type": "reaction",
  "reaction": {
    "messageId": "msg_original123",
    "emoji": "👍"
  }
}
FieldTypeDescription
messageIdstringID of the message being reacted to
emojistring?The emoji. Absent when the reaction has been removed

Unsupported

Messages that don't match any recognized type are delivered as type: "unsupported". The original WhatsApp payload is preserved so you can inspect it if needed.

Handling all types

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

  const msg = event.data;

  switch (msg.type) {
    case "text":
      console.log("Text:", msg.body);
      break;

    case "image":
    case "audio":
    case "video":
    case "document":
    case "sticker":
      if (msg.media?.unavailable) {
        console.log("Media unavailable");
      } else {
        console.log("Download:", msg.media.downloadUrl);
        console.log("MIME:", msg.media.mimeType);
        console.log("Size:", msg.media.byteSize, "bytes");
      }
      if (msg.body) console.log("Caption:", msg.body);
      break;

    case "location":
      console.log("Location:", msg.location.latitude, msg.location.longitude);
      break;

    case "contacts":
      console.log("Contacts:", msg.contacts.length);
      break;

    case "reaction":
      if (msg.reaction.emoji) {
        console.log("Reaction:", msg.reaction.emoji, "on", msg.reaction.messageId);
      } else {
        console.log("Reaction removed on", msg.reaction.messageId);
      }
      break;

    default:
      console.log("Unsupported type:", msg.type);
  }
});

On this page