Send WhatsApp Cloud API Templates from GHL Workflows

Send WhatsApp Cloud API templates from GHL Workflows

Use this webhook when you want a GoHighLevel Workflow to send an official WhatsApp Cloud API template message through WAsndr.

https://panel.wasndr.com/webhookDML-cloud/workflow/template/send

This endpoint is designed for GHL Workflow Custom Webhook actions. It is different from the regular GHL SMS step/custom SMS provider path.


What this webhook does

The webhook sends a WhatsApp Cloud API template message using an explicit JSON payload from your GHL Workflow.

It supports:

  • Template name
  • Template language
  • Template variables
  • GHL contact ID
  • Recipient phone number
  • Workflow metadata
  • Idempotency keys to prevent duplicate sends
  • Optional selected WhatsApp Cloud API phone number

This is the recommended production path for workflow automations that need to send WhatsApp messages reliably.


When should I use this webhook?

Use this webhook when a GHL Workflow should send an approved WhatsApp template, especially when the message may be sent outside the WhatsApp 24-hour customer service window.

Good use cases include:

  • Appointment reminders
  • Booking confirmations
  • Lead follow-ups
  • Missed-call follow-ups
  • Re-engagement messages
  • Payment reminders
  • Onboarding messages
  • Order or service updates
  • Any automation that must use a pre-approved WhatsApp template

When should I not use this webhook?

Do not use this endpoint for:

  • Manual inbox replies
  • Internal notes
  • Email messages
  • Phone call or voicemail events
  • Unapproved free-form WhatsApp text
  • Regular SMS messages that should stay as SMS
  • Cold outreach without proper WhatsApp opt-in

For normal conversations, use the WAsndr inbox or the regular GHL conversation/SMS provider integration.


Why not just use a normal GHL SMS step?

A normal GHL SMS step can be routed through WAsndr’s custom SMS provider, but that payload does not reliably tell WAsndr that the message came from a workflow or that it should use a WhatsApp template.

WhatsApp Cloud API has stricter rules than SMS:

  • Free-form messages usually require an open 24-hour customer service window.
  • Messages outside that window must use approved templates.
  • Template name, language, and variables should be explicit.

For production WhatsApp automation, use this dedicated webhook instead of pretending every SMS step is a WhatsApp message.


Requirements

Before using this webhook, your subaccount must have:

  1. WAsndr GHL Cloud integration installed.
  2. An active WhatsApp Cloud API number connected.
  3. An approved WhatsApp template.
  4. The workflow template webhook enabled in WAsndr.
  5. A workflow webhook secret generated by WAsndr.

If you do not have the webhook secret yet, contact your WAsndr admin or support.


How to generate the workflow webhook secret

The secret is generated inside WAsndr for each GHL Cloud subaccount/install. It is not the same as your GHL marketplace credentials and it is not your WhatsApp Cloud API token.

At the moment, this is generated through the WAsndr backend/admin endpoint. A workspace admin can rotate a new secret with:

POST https://panel.wasndr.com/workspace/{locationUuid}/ghl-cloud/template-webhook/rotate-secret

Example request:

curl -X POST "https://panel.wasndr.com/workspace/{locationUuid}/ghl-cloud/template-webhook/rotate-secret" \
  -H "Authorization: Bearer YOUR_WASNDR_DASHBOARD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enable": true}'

The response includes the secret one time only:

{
  "enabled": true,
  "endpointUrl": "https://panel.wasndr.com/webhookDML-cloud/workflow/template/send",
  "secretPrefix": "dml_wh_abc12",
  "hasSecret": true,
  "lastUsedAt": null,
  "secret": "FULL_SECRET_VALUE_SHOWN_ONCE",
  "message": "Store this secret now. It will not be shown again."
}

Copy the secret value immediately and store it somewhere safe. After this response, WAsndr only keeps a hash and the prefix; the full secret cannot be viewed again.

Use the returned secret in your GHL Custom Webhook header:

Authorization: Bearer FULL_SECRET_VALUE_SHOWN_ONCE

You can check whether a secret exists with:

GET https://panel.wasndr.com/workspace/{locationUuid}/ghl-cloud/template-webhook/config

You can enable or disable the webhook with:

POST https://panel.wasndr.com/workspace/{locationUuid}/ghl-cloud/template-webhook/enable
POST https://panel.wasndr.com/workspace/{locationUuid}/ghl-cloud/template-webhook/disable

If you do not have access to these WAsndr admin endpoints yet, contact your WAsndr admin/support and ask them to rotate a GHL Cloud workflow template webhook secret for your subaccount.


GHL Workflow setup

In your GHL Workflow, add a Custom Webhook action.

Use:

Method: POST
URL: https://panel.wasndr.com/webhookDML-cloud/workflow/template/send
Content-Type: application/json

Add one of these authentication headers:

Authorization: Bearer YOUR_WORKFLOW_WEBHOOK_SECRET

or:

X-DML-Workflow-Secret: YOUR_WORKFLOW_WEBHOOK_SECRET


Example payload

{
  "type": "DML_SEND_WHATSAPP_CLOUD_TEMPLATE",
  "version": "2026-05-03",
  "locationId": "{{location.id}}",
  "contactId": "{{contact.id}}",
  "recipient": {
    "phone": "{{contact.phone}}"
  },
  "template": {
    "name": "appointment_reminder",
    "language": {
      "code": "en_US"
    },
    "variables": {
      "body": [
        "{{contact.first_name}}",
        "{{appointment.start_time}}"
      ]
    }
  },
  "metadata": {
    "idempotencyKey": "{{contact.id}}-appointment-reminder-{{appointment.id}}",
    "source": "ghl_workflow_custom_webhook",
    "workflowId": "{{workflow.id}}",
    "actionId": "send-whatsapp-template",
    "executionId": "{{workflow.execution_id}}"
  },
  "options": {
    "previewText": "Appointment reminder sent via WhatsApp"
  }
}


Required fields

locationId

The GHL location/subaccount ID.

"locationId": "{{location.id}}"

template.name

The exact approved WhatsApp template name.

"name": "appointment_reminder"

template.language

The template language code.

"language": { "code": "en_US" }

metadata.idempotencyKey

A unique key for this intended send. This prevents duplicate WhatsApp messages if GHL retries the webhook.

"idempotencyKey": "{{contact.id}}-{{workflow.id}}-{{appointment.id}}"

metadata.source

Must be:

"source": "ghl_workflow_custom_webhook"


Template variables

If your WhatsApp template has body placeholders, pass them in template.variables.body in the same order as the template placeholders.

Example template:

Hi {{1}}, your appointment is scheduled for {{2}}.

Payload:

"variables": {
  "body": [
    "John",
    "Monday at 2:00 PM"
  ]
}

You can also send header text or URL button variables when your approved template requires them.

Example:

"variables": {
  "headerText": "Appointment Reminder",
  "body": ["John", "Monday at 2:00 PM"],
  "buttons": [
    {
      "type": "url",
      "index": 0,
      "value": "booking-123"
    }
  ]
}


Optional fields

recipient.phone

Use this when the contact phone is available in the workflow payload.

"recipient": {
  "phone": "{{contact.phone}}"
}

If this is not provided, WAsndr may try to resolve the phone from the GHL contact ID.

contactId

The GHL contact ID. Recommended for tracking and conversation mapping.

"contactId": "{{contact.id}}"

conversationId

Use this if your workflow has access to the GHL conversation ID.

"conversationId": "{{conversation.id}}"

options.previewText

A local preview label that appears in WAsndr tracking.

"previewText": "Appointment reminder sent via WhatsApp"

options.phoneNumberId

Use this only if your subaccount has multiple WhatsApp Cloud API numbers and you need to select a specific one.

"phoneNumberId": "YOUR_WASTARTER_PHONE_NUMBER_ID"


Idempotency: avoiding duplicate messages

GHL may retry webhooks. To prevent duplicate WhatsApp sends, every request must include a stable metadata.idempotencyKey.

Good examples:

{{contact.id}}-{{workflow.id}}-{{appointment.id}}
{{contact.id}}-payment-reminder-{{invoice.id}}
{{contact.id}}-missed-call-followup-{{workflow.execution_id}}

If the same idempotency key is sent again, WAsndr will not send the WhatsApp message a second time.


Success response

Example successful response:

{
  "success": true,
  "data": {
    "idempotencyKey": "contact123-appointment-reminder-appointment456",
    "messagePkId": 12345,
    "providerMessageId": "wamid.xxx",
    "status": "sent",
    "templateName": "appointment_reminder",
    "templateLanguage": "en_US"
  }
}


Duplicate response

If the same idempotency key was already processed, the webhook may return:

{
  "success": true,
  "duplicate": true,
  "data": {
    "idempotencyKey": "contact123-appointment-reminder-appointment456",
    "status": "sent",
    "templateName": "appointment_reminder",
    "templateLanguage": "en_US"
  }
}

This means the duplicate was safely ignored.


Common errors

UNAUTHORIZED_TEMPLATE_WEBHOOK

The webhook secret is missing or invalid.

Check that your Custom Webhook action includes one of these headers:

Authorization: Bearer YOUR_WORKFLOW_WEBHOOK_SECRET

or:

X-DML-Workflow-Secret: YOUR_WORKFLOW_WEBHOOK_SECRET

TEMPLATE_WEBHOOK_DISABLED

The workflow template webhook is not enabled for this GHL subaccount.

INVALID_LOCATION_ID

The payload is missing locationId.

INVALID_TEMPLATE_PAYLOAD

The template name, language, or variables are invalid.

INVALID_IDEMPOTENCY_KEY

metadata.idempotencyKey is missing or longer than allowed.

IDEMPOTENCY_IN_PROGRESS

A request with the same idempotency key is already being processed.

IDEMPOTENCY_PREVIOUSLY_FAILED

A previous request with the same idempotency key failed. Use a new idempotency key if you intentionally want to retry.


Best practices

  • Use this endpoint for production WhatsApp workflow automations.
  • Use approved WhatsApp templates for outbound workflow messages.
  • Always include a stable idempotency key.
  • Keep your webhook secret private.
  • Do not paste the secret into public docs, notes, or screenshots.
  • Test with a small internal contact before enabling customer-facing automations.
  • Do not use this endpoint for spam or contacts who have not opted in.

Summary

Use this webhook when a GHL Workflow needs to send an official WhatsApp Cloud API template message through WAsndr.

Use the regular GHL SMS/custom provider path for convenience messages. Use this dedicated webhook for reliable production automations that require template name, language, variables, idempotency, and better tracking.