Portal Community
Webhook-first architecture: The WhatsApp Cloud API is designed around webhooks for real-time message delivery. The message/getMany operation is intended for historical lookups, audits, and reporting — not for polling inbound messages in real-time. For live inbound message processing, use a WebhookTrigger node configured with your WhatsApp webhook endpoint.

When to Use

Configuration

Connection

FieldRequiredDescription
accessTokenRequiredPermanent System User access token. Store in BizFirst Credentials Manager.
phoneNumberIdRequiredNumeric string ID of the WhatsApp Business phone number to query.
apiVersionOptionalMeta Graph API version. Defaults to v18.0.

Operation

FieldRequiredDescription
limitOptionalMaximum number of messages to return per page. Default: 20. Maximum: 100. Use with after cursor for pagination.
afterOptionalCursor string from the previous response's paging.cursors.after field. Use to retrieve the next page of results.
beforeOptionalCursor string from the previous response's paging.cursors.before field. Use to retrieve the previous page.
statusFilterOptionalFilter by message status: sent, delivered, read, or failed. Omit to return all statuses.
sinceOptionalUnix timestamp (seconds). Only return messages sent on or after this time.
untilOptionalUnix timestamp (seconds). Only return messages sent on or before this time.

Sample Configuration

{
  "resource": "message",
  "operation": "getMany",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "limit": "50",
  "statusFilter": "failed",
  "since": "{{ $input.reportStartTimestamp }}",
  "until": "{{ $input.reportEndTimestamp }}"
}

Validation Errors

ErrorCause
accessToken is requiredThe accessToken field is empty.
phoneNumberId is requiredThe phoneNumberId field is empty.
100 (Meta)Invalid cursor value — the pagination cursor is expired or malformed. Start from the beginning without a cursor.
803 (Meta)Phone number not found or not accessible with the provided access token.

Output

Success Port

FieldTypeDescription
messagesarrayArray of message objects. Each object contains id, type, status, timestamp, to, and from fields.
countnumberNumber of messages in the current page.
hasNextPagebooleantrue if there are more results beyond this page.
afterCursorstringCursor to pass as after to retrieve the next page. Empty when hasNextPage is false.
beforeCursorstringCursor to pass as before to go back to the previous page.
rawResponsestringFull raw JSON from the Meta API including the complete paging object.

Error Port

FieldTypeDescription
statusstring"failed" or "error".
errorCodestringMeta error code or BizFirst validation code.
errorMessagestringHuman-readable error description.
rawResponsestringRaw API error response.

Sample Output

{
  "messages": [
    {
      "id": "wamid.HBgLMTQxNTU1NTI2NzEVAgARGBI2QzM4NjhGQTExMjQ3RDMAA",
      "type": "text",
      "status": "delivered",
      "timestamp": "1716700412",
      "to": "14155552671",
      "from": "123456789012345"
    },
    {
      "id": "wamid.HBgLMTQxNTU1NTI2NzEVAgARGBI3QzM4NjhGQTExMjQ3REMAA",
      "type": "template",
      "status": "read",
      "timestamp": "1716700250",
      "to": "14155559999",
      "from": "123456789012345"
    }
  ],
  "count": 2,
  "hasNextPage": true,
  "afterCursor": "QVFIUkphYnNENjFiVzJGdkZAbmFfWEJBZAlBZT...",
  "beforeCursor": "QVFIUkphYnNENjFiVzJGdkZAbnBfWEJBZAlBZT...",
  "rawResponse": "..."
}

Expression Reference

ValueExpressionNotes
All messages array{{ $output.getMsgs.messages }}Pass to a Loop node to process each message individually.
First message ID{{ $output.getMsgs.messages[0].id }}Access individual message fields using array index notation.
Total in page{{ $output.getMsgs.count }}Use in condition checks before processing the array.
Has more results{{ $output.getMsgs.hasNextPage }}Use in a Loop condition to drive paginated fetching.
Next page cursor{{ $output.getMsgs.afterCursor }}Pass as the after parameter in the next call for the next page.

Node Policies & GuardRails

Policy AreaRecommendation
Credential storageStore the access token in BizFirst Credentials Manager. Never inline in configuration.
Pagination patternFor large result sets, implement a Loop node that iterates pages using the afterCursor value until hasNextPage is false. Avoid retrieving more data than needed — use since/until and statusFilter to narrow the dataset.
Avoid real-time pollingDo not call this operation in a tight polling loop to detect new inbound messages. Use a WebhookTrigger node instead. The Graph API has read rate limits that apply to this operation.
Data retentionMeta does not retain message data indefinitely. For long-term compliance records, store messages in your own database via webhooks at the time of delivery. Do not rely on this operation for historical data older than the Meta retention period.
Limit sizeKeep limit to 50 or fewer in production to reduce response latency and payload size. Use filters to narrow results rather than retrieving large pages and filtering client-side.
Error portConnect the error port. Expired pagination cursors (error 100) require restarting pagination from the beginning rather than retrying with the same cursor.

Examples

Failed Message Daily Report

{
  "resource": "message",
  "operation": "getMany",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "limit": "100",
  "statusFilter": "failed",
  "since": "{{ $input.yesterdayStartTimestamp }}",
  "until": "{{ $input.yesterdayEndTimestamp }}"
}

A ScheduledTrigger fires each morning at 7 AM. A Function node calculates yesterday's start and end Unix timestamps. This node retrieves all failed messages from yesterday. A Loop node iterates the results and stores each in a MongoDB node for the daily failure report. hasNextPage drives a conditional loop for full pagination.

Campaign Delivery Rate Check

{
  "resource": "message",
  "operation": "getMany",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "limit": "100",
  "since": "{{ $input.campaignStartTimestamp }}",
  "until": "{{ $input.campaignEndTimestamp }}",
  "after": "{{ $input.paginationCursor }}"
}

A reporting workflow pages through all messages sent during a campaign window. Each page's messages array is counted by status in a Function node (delivered, read, failed). When hasNextPage is false, the totals are written to a GSheets node as the campaign delivery report.