Portal Community

When to Use

Configuration

Connection

FieldRequiredDescription
accessTokenRequiredPermanent System User access token from Meta Business Manager. Store in BizFirst Credentials Manager and reference via {{ $credentials.whatsAppToken }}.
phoneNumberIdRequiredNumeric string ID of the sending WhatsApp Business phone number (e.g. 123456789012345).
apiVersionOptionalMeta Graph API version, e.g. v18.0. Defaults to v18.0.

Operation

FieldRequiredDescription
toRequiredRecipient's WhatsApp phone number with country code, no + prefix (e.g. 14155552671). Must be a registered WhatsApp user.
textRequiredThe message body text. Maximum 4096 characters. Plain text only — WhatsApp does not support markdown or HTML in text messages.
previewUrlOptionalSet to true to enable URL preview cards when the text contains a URL. Default is false.

Sample Configuration

{
  "resource": "message",
  "operation": "sendText",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "to": "{{ $input.customerPhone }}",
  "text": "Hi {{ $input.customerName }}, your order #{{ $input.orderId }} has shipped! Track it here: https://track.example.com/{{ $input.trackingCode }}",
  "previewUrl": "true"
}

Validation Errors

ErrorCause
accessToken is requiredThe accessToken field is empty or missing.
phoneNumberId is requiredThe phoneNumberId field is empty or missing.
to is requiredThe to field is empty or missing.
text is requiredThe text field is empty or missing.
131026 (Meta)Recipient phone number is not a valid WhatsApp account.
131047 (Meta)Re-engagement message — the 24-hour customer service window has expired. Use message/sendTemplate instead.
131056 (Meta)Rate limit exceeded for this phone number. Implement exponential backoff and retry.

Output

Success Port

Fires after Meta confirms the message was accepted for delivery. The messageId is the unique WhatsApp message ID (wamid) and should be stored if you need to send a reaction or delete the message later.

FieldTypeDescription
messageIdstringUnique WhatsApp message ID (e.g. wamid.HBgLMTQxNTU1NTI2NzE...). Retain this for reaction, deletion, or tracking purposes.
phoneNumberIdstringThe sending phone number ID used for this message.
tostringThe recipient phone number as provided.
statusstring"sent" on success.
errorCodestringEmpty on success.
errorMessagestringEmpty on success.
rawResponsestringFull raw JSON response from the Meta API.

Error Port

Fires when Meta rejects the request or when the network call fails. Always connect the error port to a logging or alerting node in production workflows.

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

Sample Output

{
  "messageId": "wamid.HBgLMTQxNTU1NTI2NzEVAgARGBI2QzM4NjhGQTExMjQ3RDMAA",
  "phoneNumberId": "123456789012345",
  "to": "14155552671",
  "status": "sent",
  "errorCode": null,
  "errorMessage": null,
  "rawResponse": "{\"messaging_product\":\"whatsapp\",\"contacts\":[{\"input\":\"14155552671\",\"wa_id\":\"14155552671\"}],\"messages\":[{\"id\":\"wamid.HBgLMTQxNTU1NTI2NzEVAgARGBI2QzM4NjhGQTExMjQ3RDMAA\"}]}"
}

Expression Reference

ValueExpressionNotes
Message ID{{ $output.sendMsg.messageId }}Store this to send a reaction or delete the message in a later node.
Recipient number{{ $output.sendMsg.to }}Echoes back the to value supplied. Use for confirmation logging.
Status{{ $output.sendMsg.status }}"sent" on success. Use in an IfCondition node to branch on outcome.
Error code{{ $output.sendMsg.errorCode }}Non-null on error port. Log to a database or monitoring node.
Full API response{{ $output.sendMsg.rawResponse }}Raw JSON string. Parse with a JsonTransform node for advanced field access.

Node Policies & GuardRails

Policy AreaRecommendation
Credential storageAlways store the access token in BizFirst Credentials Manager. Reference it via {{ $credentials.whatsAppToken }}. Never paste the raw token into node configuration.
24-hour messaging windowText messages may only be sent within 24 hours of the recipient's last inbound message. For outbound-only or marketing messages, use message/sendTemplate with a Meta-approved template.
Rate limitsDefault Tier 1 allows 1,000 unique recipients per 24 hours. In bulk workflows, pace sends through a Delay node and handle 429 errors with retry logic.
Phone number formatThe to field must not contain a + prefix, spaces, or dashes. Always sanitise the number in a Function or DataMapping node before passing it to this operation.
Opt-in complianceOnly send messages to users who have explicitly opted in to receive WhatsApp communications from your business. Store opt-in records and check them before including a number in any send workflow.
Error port handlingAlways connect the error port. Unhandled 131047 errors (expired window) silently drop messages that should have been sent as templates instead.
PII protectionDo not include sensitive personal data, passwords, or payment card numbers in message text. WhatsApp messages are end-to-end encrypted to the device but may be logged server-side in your BizFirstAI workflow audit trail.

Examples

OTP Verification Code

{
  "resource": "message",
  "operation": "sendText",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "to": "{{ $input.phoneNumber }}",
  "text": "Your BizFirstAI verification code is: {{ $input.otpCode }}\n\nThis code expires in 10 minutes. Do not share it with anyone.",
  "previewUrl": "false"
}

Sends a one-time passcode to the user's WhatsApp number during account verification. The workflow upstream generates a 6-digit code, stores it in the session with a 10-minute TTL, and passes it to this node via $input.otpCode.

Shipment Tracking Alert with Link Preview

{
  "resource": "message",
  "operation": "sendText",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "to": "{{ $input.customerPhone }}",
  "text": "Your order #{{ $input.orderId }} is on its way! Track your delivery: https://track.example.com/{{ $input.trackingId }}",
  "previewUrl": "true"
}

The previewUrl: true option causes WhatsApp to fetch and display a rich link card for the tracking URL, showing the page title and thumbnail. This increases click-through rate compared to a plain URL.

Dynamic Appointment Reminder

{
  "resource": "message",
  "operation": "sendText",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "to": "{{ $input.patientPhone }}",
  "text": "Reminder: You have an appointment with {{ $input.doctorName }} tomorrow at {{ $input.appointmentTime }}.\n\nLocation: {{ $input.clinicAddress }}\n\nReply YES to confirm or call {{ $input.clinicPhone }} to reschedule.",
  "previewUrl": "false"
}

A ScheduledTrigger node fires this workflow 24 hours before each appointment. Patient data is sourced from the CRM and passed as input variables. The free-form text format is valid here because appointment reminders fall within the 24-hour conversation window after the patient originally booked.