# 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: `GET` or `POST`.
* **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-key` header 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-03`
* **Cell Formatting**:
  * `cell:local` → `0821234567`
  * `cell:plus` → `+27821234567`
  * `cell:trailing` → `821234567`
  * Default → MSISDN (`27821234567`)
* **Fallback Values**: `{{contact.firstname?Unknown}}` → `Unknown` if 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}}" }`