Portal Community

Example 1: Rich Product Catalog with Interactive List

Scenario: A customer sends "menu" to your business number. Respond with a scrollable interactive list showing your product categories and items so they can select what to order.

{
  "AccessToken": "{{ credentials.whatsapp_access_token }}",
  "PhoneNumberId": "{{ credentials.whatsapp_phone_number_id }}",
  "operation": "message/sendInteractiveList",
  "To": "{{ vars.customer_phone }}",
  "BodyText": "Welcome to FreshMart! Browse our menu and tap an item to order.",
  "ButtonTitle": "View Menu",
  "Sections": [
    {
      "title": "Fresh Produce",
      "rows": [
        { "id": "prod_apples", "title": "Apples (1kg)", "description": "$3.50 — Crisp red apples, locally grown" },
        { "id": "prod_bananas", "title": "Bananas (bunch)", "description": "$2.20 — Ripe yellow bananas" },
        { "id": "prod_tomatoes", "title": "Tomatoes (500g)", "description": "$2.80 — Vine-ripened tomatoes" }
      ]
    },
    {
      "title": "Dairy",
      "rows": [
        { "id": "prod_milk", "title": "Full Cream Milk (2L)", "description": "$4.10 — Fresh from local farms" },
        { "id": "prod_cheese", "title": "Cheddar Cheese (200g)", "description": "$5.50 — Mature cheddar" }
      ]
    }
  ]
}
Expected outcome: Customer taps "View Menu" and sees the scrollable list. When they select an item, a reply webhook arrives with reply_list_row_id set to the selected row's ID (e.g. prod_milk). Use a sendAndWait or webhook trigger to capture the selection and build the order.

Example 2: sendAndWait Order Confirmation Flow

Scenario: After building an order summary, send it to the customer on WhatsApp and wait for their "Yes" or "No" reply before processing payment. The workflow suspends until the customer responds.

{
  "AccessToken": "{{ credentials.whatsapp_access_token }}",
  "PhoneNumberId": "{{ credentials.whatsapp_phone_number_id }}",
  "operation": "message/sendAndWait",
  "To": "{{ vars.customer_phone }}",
  "Text": "Hi {{ vars.customer_name }}, your order summary:\n\n{{ vars.order_items_formatted }}\n\n*Total: {{ vars.order_total }}*\n\nReply *YES* to confirm and proceed to payment, or *NO* to cancel.",
  "TimeoutSeconds": 300
}
Behaviour: The workflow suspends after sending. On the success port, reply_text contains the customer's reply. Use a Switch node to branch on the reply — route "YES" to the payment processing branch and "NO" to the cancellation branch. On the timeout port (5 minutes with no reply), route to an order expiry notification.

Example 3: Media Upload and Share Document

Scenario: Generate an invoice PDF (stored in a BizFirst variable as base64), upload it to WhatsApp media hosting, then send it to the customer as a document message with a caption.

Step 1 — Upload the file to WhatsApp:

{
  "AccessToken": "{{ credentials.whatsapp_access_token }}",
  "PhoneNumberId": "{{ credentials.whatsapp_phone_number_id }}",
  "operation": "media/upload",
  "FileData": "{{ vars.invoice_pdf_base64 }}",
  "MimeType": "application/pdf",
  "Filename": "Invoice_{{ vars.invoice_number }}.pdf"
}

Step 2 — Send the document using the returned media_id:

{
  "AccessToken": "{{ credentials.whatsapp_access_token }}",
  "PhoneNumberId": "{{ credentials.whatsapp_phone_number_id }}",
  "operation": "message/sendDocument",
  "To": "{{ vars.customer_phone }}",
  "DocumentUrl": null,
  "DocumentBase64": "{{ nodes.uploadInvoice.output.media_id }}",
  "Filename": "Invoice_{{ vars.invoice_number }}.pdf",
  "Caption": "Invoice #{{ vars.invoice_number }} — {{ vars.invoice_total_formatted }}. Due: {{ vars.invoice_due_date }}. Questions? Reply here."
}
Expected outcome: The PDF is uploaded once and sent to the customer with a readable filename and caption. Using media/upload before sending is preferred over direct URL delivery when the source file is dynamically generated rather than hosted on a public URL.

Example 4: Group Announcement with Interactive Buttons

Scenario: Send a staff announcement to a WhatsApp group asking members to acknowledge they have read it. Use interactive buttons for quick replies.

Step 1 — Send buttons message to group:

{
  "AccessToken": "{{ credentials.whatsapp_access_token }}",
  "PhoneNumberId": "{{ credentials.whatsapp_phone_number_id }}",
  "operation": "message/sendInteractiveButtons",
  "To": "{{ vars.group_id }}",
  "Header": "Policy Update — Action Required",
  "BodyText": "A new data security policy has been issued. All staff must acknowledge receipt by {{ vars.deadline_date }}.\n\nDocument: {{ vars.policy_doc_url }}",
  "Buttons": [
    { "id": "ack_read", "title": "I have read it" },
    { "id": "ack_questions", "title": "I have questions" },
    { "id": "ack_later", "title": "Remind me later" }
  ],
  "Footer": "HR Department — {{ vars.policy_version }}"
}
Expected outcome: Group members see the announcement with three tappable buttons. Button tap replies arrive as webhook events with reply_button_id set to the tapped button's ID. A parallel webhook trigger workflow captures these responses and records acknowledgements in your HR system.

Example 5: Template Message for Appointment Reminder

Scenario: 24 hours before a scheduled appointment, trigger a pre-approved Meta template message to remind the patient of their booking details.

{
  "AccessToken": "{{ credentials.whatsapp_access_token }}",
  "PhoneNumberId": "{{ credentials.whatsapp_phone_number_id }}",
  "operation": "message/sendTemplate",
  "To": "{{ vars.patient_phone }}",
  "TemplateName": "appointment_reminder_v2",
  "LanguageCode": "en_US",
  "Components": [
    {
      "type": "header",
      "parameters": [
        { "type": "text", "text": "{{ vars.clinic_name }}" }
      ]
    },
    {
      "type": "body",
      "parameters": [
        { "type": "text", "text": "{{ vars.patient_first_name }}" },
        { "type": "text", "text": "{{ vars.appointment_date }}" },
        { "type": "text", "text": "{{ vars.appointment_time }}" },
        { "type": "text", "text": "{{ vars.doctor_name }}" },
        { "type": "text", "text": "{{ vars.clinic_address }}" }
      ]
    },
    {
      "type": "button",
      "sub_type": "url",
      "index": 0,
      "parameters": [
        { "type": "text", "text": "{{ vars.reschedule_token }}" }
      ]
    }
  ]
}
Expected outcome: Patient receives a structured appointment reminder with clinic name in the header, their name, date, time, doctor, and clinic address in the body, and a personalised "Reschedule" button linking to https://clinic.example.com/reschedule/{{ vars.reschedule_token }}. This is sent outside the 24-hour window and requires an approved template — no free-form messaging policy applies.