Hooks
Hooks let you trigger actions when a contact replies to a campaign send. They extend your campaigns with automated follow-ups or integrations.
Currently, Dripcel supports two hook types:
SMS Hook
Webhook
SMS Hook
An SMS Hook automatically sends an SMS when a contact replies to a campaign.
Options:
Content – The text of the SMS to send.
Destinations – A comma-separated list of phone numbers to send the SMS to.
Send to Replying Contact – If checked, the SMS will be sent directly to the contact who replied.
You can use both options together — sending the SMS to the replying contact and to the additional phone numbers in Destinations.
Webhook
A Webhook Hook sends an HTTP request to a specified URL when a contact replies. This is commonly used to integrate with external systems (e.g., CRMs, analytics, or custom apps).
Options:
URL – The destination URL for the request.
Method – HTTP method:
GETorPOST.Body – JSON body to send. You can insert templates to include contact, campaign, reply, or send data.
Encode Into URL – If checked, the JSON body is encoded into URL query parameters instead of being sent in the request body.
Headers – Custom HTTP headers in valid JSON format.
Example:
JSON body:
{ "name": "{{contact.firstname}}" }
Encoded into URL →
https://example.com?name=John
Retry Policy & Duplicate Handling
Dripcel retries failed webhooks up to 3 times, with a 10-second timeout each.
Your system must handle duplicate requests.
Use the
dripcel-idempotency-keyheader to identify retries — it is identical for all attempts of the same webhook.
Templates in Webhooks
Templates work like campaign content templates ({{template}}). They allow you to insert live data into webhook payloads.
Available Objects
Contact
Contains all default and custom fields, plus metadata.
type Contact = { _id: string; cell: string; firstname?: string; lastname?: string; idnumber?: string; email?: string; c1?: unknown; // depends on custom field type ... c10?: unknown; tag_ids: string[]; validated?: { at: Date; reachable: boolean }; createdAt: Date; };
Reply
Information about the reply message.
type Reply = { To: string; // number message was sent from Message: string; // reply content Msisdn: string; // replying contact’s number Received: Date; // timestamp of reply campaign_id?: string; kind: "optOut" | "optIn" | "unknown"; };
Campaign
The campaign associated with the reply.
type Campaign = { _id: string; name: string; createdAt: Date; tag_ids: string[]; segment_ids: string[]; incomePerLead?: number; defaultSaleValue?: number; };
Send
The original send that triggered the reply.
type Send = { _id: string; campaign_id?: string; message: string; triggeredBy: string; startDeliveryAt: string; destinations: undefined; // see GET /send-logs for details };
Other
now – the current date/time.
Example
Webhook body with templates:
{ "name": "{{contact.firstname}}", "message": "{{reply.Message}}", "campaign": "{{campaign.name}}", "send_id": "{{send._id}}" }
Webhook output after substitution:
{ "name": "John", "message": "Hello", "campaign": "My Campaign", "send_id": "5f9b3b7b7b7b7b7b7b7b7b7b" }
Template Options
Date Formatting:
{{reply.Received|date:yyyy-MM-dd}}→2025-10-03Cell Formatting:
cell:local→0821234567cell:plus→+27821234567cell:trailing→821234567Default → MSISDN (
27821234567)
Fallback Values:
{{contact.firstname?Unknown}}→Unknownif field missing
Combined Example
{ "name": "{{contact.firstname?Unknown}}", "cell": "{{contact.cell|cell:local}}", "message": "{{reply.Message}}", "campaign": "{{campaign.name}}", "date": "{{reply.Received|date:yyyy-MM-dd?Unknown}}" }