Hooks
Hooks are different actions that can be triggered when a contact replies to a send from a campaign. There are currently 2 hook types available:
SMS Hook
When a contact replies to a send from this campaign, an SMS hook will send them another SMS.
The SMS hook has the following options:
- Content: The content 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 to the contact that replied to the send.
- This option can work together with the "Destinations" option. If you have both options checked, the SMS will be sent to both the contact that replied to the send, and the phone numbers in the "Destinations" field.
Webhook
When a contact replies to a send from this campaign, a webhook will send an HTTP request to the URL you provide. Webhooks have the following options:
URL: The URL to send the request to.
Method: The HTTP method/verb to use when sending the request (
GETorPOST).Body: The JSON body to send with the request.
- You can use various templates to fill in the body with data from the contact that replied to the send. See below for more info
Encode Into URL: If checked, the JSON body will be encoded into the URL search parameters, instead of being sent as the body of the request.
For example, if you have the following JSON body:
{ "name": "{{contact.firstname}}" }Then encoding it into the URL will send the following URL:
https://example.com?name=John
Headers: The headers to send with the request. Must be valid JSON.
You will not be charged for sending a Web hook, but you do have to have a balance of at least 1 credit.
Retry Policy & Handling Duplicates
Dripcel will retry sending the webhook up to 3 times if the webhook times out (after waiting 10 seconds).
Your system should therefore be able to handle duplicate requests. You can use the dripcel-idemptotency-key header to identify duplicate requests. This header will be the same for all retries of the same webhook.
Templates
You can use various templates to fill in the body with data from the contact that replied to the send. The format is the same as copy templates ({{template}}).
Fields
There are 4 objects available:
Contact Type
The contact that replied to the send. A contact has all the default and custom fields:
type Contact = {
_id: string;
cell: string;
firstname?: string;
lastname?: string;
idnumber?: string;
email?: string;
gross_income?: string;
household_income?: string;
date_of_birth?: string;
car_ownership?: string;
gender?: string;
employment_status?: string;
job_title?: string;
country?: string;
province_or_state?: string;
city?: string;
postal_code?: string;
credit_score?: string;
lead_source?: string;
opt_in_status?: string;
preferred_contact_method?: string;
signup_date?: string;
customer_status?: string;
parental_status?: string;
relationship_status?: string;
education_level?: string;
home_ownership_status?: string;
c1?: unknown; // Type depends on your custom field types
// ...
c10?: unknown;
/** A list of the IDs of the tags that the contact has */
tag_ids: string[];
validated?: {
/** Date of last validation */
at: Date;
/** Whether the number was reachable */
reachable: boolean;
};
/** The date they were created */
createdAt: Date;
};
Reply Type
The reply that the contact sent. The following fields are available:
type Reply = {
/** The cell number the message was sent _from_ */
To: string;
/** The content of the message */
Message: string;
/** The cell number of the replying contact */
Msisdn: string;
/** The date the message was received */
Received: Date;
/** The ID of the campaign that the send belongs to, if it was a campaign send */
campaign_id?: string;
/** The kind of reply */
kind: "optOut" | "optIn" | "unknown";
};
Campaign Type
The campaign that the send belongs to.
type Campaign = {
/** Unique ID of the campaign */
_id: string;
/** The organisation this campaign belongs to */
org_id: string;
/** The user who created this campaign */
createdBy: string;
/** The name of the campaign */
name: string;
/** Optional description of the campaign */
description?: string;
/** The kind of campaign */
kind: ["recurring", "welcome", "once-off"];
/** Whether the campaign is active */
active: boolean;
/** Categories associated with the campaign */
categories: string[];
/** IDs of tags included in the campaign */
tag_ids: string[];
/** IDs of tags excluded from the campaign */
nin_tag_ids: string[];
/** Opt-out level setting */
optOutLevel?: ["campaign", "tag", "global"];
/** Whether an opt-in confirmation is required */
optin_confirmation?: boolean;
/** Whether a recommendation confirmation is required */
recommendation_confirmation?: boolean;
/** How campaign copy is generated */
getCopyMethod?: ["First", "Random", "Least", "best-optin-ratio"];
/** Maximum number of SMS parts allowed */
maxSMSParts: number;
/** The send window hours of the campaign */
send_window_hours?: Record<string, any>;
/** Contact send counts */
contactSendCounts: Record<string, any>;
/** Contact creation timestamps */
contactCreatedAt: Record<string, any>;
/** Record of last sent times */
lastSent: Record<string, any>;
/** Record of last reply times */
lastReply: Record<string, any>;
/** Record of last click times */
lastClick: Record<string, any>;
/** Click counts per contact */
contactClickCounts: Record<string, any>;
/** Reachable contacts within the last N days */
reachableInLastDays?: number;
/** Assigned Income per lead */
incomePerLead: number;
/** Default sale value */
defaultSaleValue: number;
/** IDs of included segments */
segment_ids: string[];
/** IDs of excluded segments */
nin_segment_ids?: string[];
/** Country code associated with this campaign */
country: string;
/** Delivery method */
deliveryMethod: ["standard", "reverse", "transactional"];
/** Tracking link configuration */
trackingLink?: Record<string, any>;
/** Configuration for welcome messages */
welcomeConfig?: {
/** Delay in days before sending welcome message */
delayDays: number;
/** Content of the welcome message */
content: string;
/** Whether to update last sent date */
updateLastSent: boolean;
};
};
Campaign2 encompasses Email as well as Marketplace campaigns.
All campaigns will eventually be migrated to Campaign2.
type Campaign2 = {
/** Unique ID of the campaign */
_id: string;
/** The organization this campaign belongs to */
org_id: string;
/** The name of the campaign */
name: string;
/** Whether this campaign is active */
active: boolean;
/** Optional campaign description */
description?: string;
/** Categories assigned to this campaign */
categories: string[];
/** Targeting configuration for the campaign */
targeting: {
/** How far back to look for reachable contacts (in days) */
reachability_days?: number | null;
/** included/excluded Tag IDs */
tag_ids: {
$in: string[];
$nin: string[];
};
/** included/excluded Segment IDs */
segment_ids: {
$in: string[];
$nin: string[];
};
/** Event-based filters for triggering or segmentation */
events: {
/** Type of contact event (e.g., optin, click, sale) */
action: [
"last_sent",
"last_click",
"last_reply:optIn",
"last_reply:optOut",
"last_reply:unknown",
"send_count",
"click_count"
];
/** Channel the event occurred on */
channel: "email" | "sms";
/** Source of the event */
source: string;
/** Whether the event must exist */
exists?: boolean;
/** Optional numeric value for the event */
value?: number;
/** Comparison operator used for evaluation */
operator: "$eq" | "$gte" | "$lte" | "$exists";
}[];
};
/** Channel configuration for sending messages */
channels: {
/** SMS channel configuration */
sms: {
/** Linked global template IDs */
template_ids: string[];
/** Maximum SMS message parts */
max_parts: number;
};
/** Email channel configuration */
email: {
/** Linked global template IDs */
template_ids: string[];
/** Optional configuration set name */
configuration_set_name?: string;
};
};
/** Tracking link configuration */
tracking_link: Record<string, any>;
/** Opt-out level setting */
opt_out_level: ["campaign", "org"];
/** Hook settings for post-send or triggered actions */
hooks: {
/** IDs of hook templates or functions */
hook_ids: string[];
/** Optional custom JSON data made available to hooks */
custom_data?: string | null;
};
/** Configuration for recurring sends */
recurring_sends: {
/** The active sending window in hours */
window: {
/** Minimum hour (0–23) when sends can begin */
min_hours: number;
/** Maximum hour (0–23) when sends can end */
max_hours: number;
};
};
/** Financial configuration */
financials: {
/** Optional income value per opt-in event */
income_per_optin?: number | null;
/** Optional income value per click event */
income_per_click?: number | null;
/** Optional income value per sale event */
income_per_sale?: number | null;
};
/** Legal configuration and compliance */
legal: {
/** Whether user consent confirmation is required */
consent_confirmation?: boolean;
/** Whether recommendation confirmation is required */
recommendation_confirmation?: boolean;
};
/** Marketplace linkage, if applicable */
marketplace?: {
/** Associated offer ID from marketplace */
offer_id: string;
/** Buyer organization ID from marketplace */
buyer_org_id: string;
};
};
Send Type
The send that the reply belongs to (this is the same as the send log from the GET /send-logs endpoint).
type Send = {
/** The ID of the end */
_id: string;
/** The organization that owns this send */
org_id: string;
/** The campaign this send belongs to */
campaign_id?: string;
/** Optional integration data per external system */
integrations?: {
/** DripCRM integration information */
dripcrm?: {
/** The conversation ID in DripCRM */
conversationId: string;
};
};
/** When this send should start */
to_start_at: Date;
/** The trigger that caused this send to occur (e.g., manual, scheduled, event-driven) */
trigger: [
"recurringSend",
"hook",
"manualBulk",
"manualSingle",
"manualCampaign",
"welcome",
"test"
];
/** NOT AVAILABLE ❌
* To see the count/list of destinations for this send, use the GET /send-logs endpoint
*/
destinations: undefined;
/** The channel of the send */
channel?: ["sms", "email"];
/** Marketplace linkage, if applicable */
marketplace?: {
/** Associated offer ID from marketplace */
offer_id: string;
/** Buyer organization ID from marketplace */
buyer_org_id: string;
};
/** Custom variables available for templating */
variables?: Partial<Record<string, string>>;
};
Other Types
now - The current date and time:
/** The current date and time */
let now: Date;
Example
So, for example, if you wanted to send the contact's first name, the message they replied back with, and the name of the campaign they replied to:
{
"name": "{{contact.firstname}}",
"message": "{{reply.Message}}",
"campaign": "{{campaign.name}}",
"send_id": "{{send._id}}"
}
Would send the following JSON:
{
"name": "John",
"message": "Hello",
"campaign": "My Campaign",
"send_id": "5f9b3b7b7b7b7b7b7b7b7b7b"
}
Options
You can also pass options to the templates using the following format: {{template|option}}. These define how the field value is parsed. The options available are:
date:format- The field value will be parsed as a datestring in the specifiedformat. Refer to the different formats available.- If no format is provided, the default format will be used
yyyy-MM-ddTHH:mm:ss.
- If no format is provided, the default format will be used
cell- Only applies to the{{contact.cell}}field. Determines how the cell will be formatted:cell:local- The cell will be formatted as a local cell number (e.g.0821234567).cell:plus- The cell will be formatted as a cell number with a plus sign (e.g.+27821234567).cell:trailing- The cell will be formatted as just the trailing digits (e.g.821234567).- The default is to format the cell in MSISDN format (e.g.
27821234567).
Fallback Values
If a field is not available, you can provide a fallback value using the following format: {{template?fallback}}.
For example, if you wanted to send the contact's firstname, or "Unknown" if it's not available:
{ "name": "{{contact.firstname?Unknown}}" }
All together
You can use all of the above together to create a template like this:
{
"name": "{{contact.firstname?Unknown}}",
"cell": "{{contact.cell|cell:local}}",
"message": "{{reply.Message}}",
"campaign": "{{campaign.name}}",
"date": "{{reply.Received|date:yyyy-MM-dd?Unknown}}"
}