Who can use this feature?
A wehhook is a way for Chili Piper to communicate with another system. Without that system having to constantly ask for updates, Chili Piper will actively push data to that system in order for it to be used in reporting, data warehouses, or for triggering automations.
Chili Piper allows you to send booked meeting data to webhooks of your choice. You are not limited by the number of webhooks you have.
The Custom Webhooks feature can be found within the Integrations pane in the Command Center.
Creating a Webhook
From the webhook management page, you will see a button to "Create Custom Webhook". Clicking this presents you with the type of webhook you would like to create.
You can have multiple webhook types have the same webhook URL, and multiple webhook URLs for the same type.
-
For New Meeting
- Triggers for every new meeting booked, regardless of the source, we will push information to this location.
-
For Meeting Update
- Triggered whenever a meeting is updated, for example if it's reassigned or rescheduled.
-
For Canceled Meeting
- Triggers when a user or prospect cancels the meeting from any via source.
Once you select an option, the setup is simple - paste in your webhook URL into the text field provided and click "Create".
Be sure to click "Enabled" on the status after creating in order for it to be active.
Managing Webhooks
All webhooks created will appear in the integration menu in the order they were created:
The 3 dots within the row provide a menu to delete the webhook entirely if needed.
Once added and "Enabled" a webhook will begin capturing responses immediately. If the target webhook URL is set up to receive them, it should begin receiving data as soon as the next action type is triggered.
Webhook Request Body (Schema)
The webhook will send to the target URL with the following body format provided.
Note that example data has been provided for clarity below but may differ from actual results:
{
"meetingIdChili": "123e4567-e89b-12d3-a456-426614174000",
"meetingTitle": "🔥 Demo Meeting: Support Call",
"meetingDescription": "Looking forward to our meeting. \n\nIf you need to reschedule,
please click the link below: https://calendar.example.com/reschedule/123e4567-e89b-12d3-a456-426614174000\n\nIf
you would like to cancel, please click the link below: https://fire.chilipiper.com/cancel/123e4567-e89b-12d3-a456-426614174000\n\nEmail:
demo@example.com",
"meetingLocation": "https://example.zoom.us/j/1234567890",
"meetingStartTime": "2025-03-21T20:30:00Z",
"meetingEndTime": "2025-03-21T20:45:00Z",
"primaryGuestTimeZone": "America/New_York",
"hostEmail": "host@example.com",
"hostFullName": "Alex Johnson",
"hostIdChili": "987f6543-b21a-45c3-b123-5678d9e0f123",
"assigneeEmail": "support@example.com",
"assigneeFullName": "Jordan Smith",
"assigneeIdChili": "654f3210-c98b-44d3-b432-890a1b2c3d45",
"primaryGuestEmail": "demo@example.com",
"primaryGuestDataFields": {
"Email": "demo@example.com"
},
"additionalGuests": [
{
"email": "guest1@example.com",
"fullName": "Taylor Williams"
}],
"bookerEmail": "booker@example.com",
"bookerName": "Chris Davis",
"bookerIdChili": "f123a456-789b-12d3-c456-789e012f3456",
"workspaceName": "Customer Experience",
"workspaceIdChili": "abcd1234-5678-90ef-1234-567890abcdef",
"productFeatureType": "ConciergeRouter",
"productFeatureName": "new-router-name",
"productFeatureIdChili": "123abc45-def6-7890-ghi1-234jklmno567",
"distributionName": "Demo Distribution",
"distributionIdChili": "zxy9876-wvut-5432-srqp-1098onmlkjh",
"meetingTypeName": "Support Session",
"meetingTypeIdChili": "mnop1234-qrst-5678-uvwx-9012yzabcdef",
"type": "Created"
}
Most data provided will have common-sense values as provided by the prospect or Meeting Type during the booking process. Please refer to the below for additional values and information:
#####IdChili (UUID / hexadecimal )
Several values provided will be UUID or hex values of internal assets. These are often unique to that asset, so for example each meeting will have its own unique ID. Each assignee, booker, or prospect will have their own unique ID.
These IDs are stored internally so an assignee will always have the same UUID or hex value.
If you ever have questions or want to troubleshoot a meeting, these IDs can be directly referenced by Chili Piper's Customer Love team in order to help track down more information within our database.
meetingTitle, meetingDescription, meetingLocation (string)
These values are derived from the associated Meeting Type that the meeting was booked for
primaryGuestDataFields(object: {string:string})
If a guest form was filled out during the process of booking, or if form data was provided via API, this data will be presented with the data field name and value.
productFeatureType
Outlines the source of this meeting. Possible values include (but may not be limited to):
- ConciergeRouter
- HandoffRouter
- RoundRobinSchedulingLink
- ChatPlaybook
- DistroRouter
- OwnershipSchedulingLink
productFeatureName
This also corresponds to the source of the meeting. In the case of a "ConciergeRouter" booking for example, Chili Piper will include the router slug of the router used to book.
meetingTypeName
Directly references the Meeting Type used to book the meeting. This can be an excellent way to additionally track the source of a meeting or specific campaign if you use unique Meeting Types for unique campaigns.
type (string)
Possible values directly correlate to the action type selected.
- Created
- Updated
- Deleted
Webhook Signature Verification
Chili Piper signs every webhook payload so you can verify that incoming requests genuinely came from Chili Piper and were not tampered with in transit. Signature verification is optional, but recommended for any endpoint that triggers automations or writes to a data store.
How It Works
Every webhook request Chili Piper sends includes two additional headers:
| Header | Description |
|---|---|
X-Chili-Signature |
HMAC-SHA256 signature of the payload (hex-encoded) |
X-Chili-Timestamp |
Unix timestamp (seconds) when the request was signed |
To verify a request, you recompute the signature on your end using your unique signing secret and compare it to the value in the X-Chili-Signature header.
Requesting Your Webhook Secret
Each tenant has its own unique webhook signing secret. For security, this secret is not displayed in the Command Center.
To obtain your secret:
- Create your webhook in the Integrations section of the Command Center (see Creating a Webhook above) and enable it.
- Email support@chilipiper.com to request your webhook signing secret. Please include the name of your instance (tenant) and the webhook you created so the team can locate the correct key.
- Store the secret securely in your application (for example, as an environment variable). Never commit it to source control or expose it in client-side code.
Note: If you ever need to rotate your signing secret — for example, if you suspect it has been exposed — email support@chilipiper.com to request a rotation. Rotating the secret immediately invalidates the previous one, so be sure to update your verification code with the new value as soon as the rotation is complete.
Verifying Signatures
Step 1: Extract the signature and timestamp from the X-Chili-Signature and X-Chili-Timestamp headers.
Step 2: Construct the signed payload by concatenating the timestamp and the raw request body, separated by a period:
{timestamp}.{raw_request_body}Step 3: Compute the expected signature using HMAC-SHA256 with your webhook secret.
Step 4: Compare your computed signature to the value in the X-Chili-Signature header using a constant-time comparison.
Code Examples
Node.js:
const crypto = require('crypto');
function verifyWebhookSignature(secret, timestamp, body, signature) {
const payload = `${timestamp}.${body}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Usage in Express
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) = {
const signature = req.headers['x-chili-signature'];
const timestamp = req.headers['x-chili-timestamp'];
const body = req.body.toString();
if (!verifyWebhookSignature(WEBHOOK_SECRET, timestamp, body, signature)) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
});Python:
import hmac
import hashlib
def verify_webhook_signature(secret: str, timestamp: str, body: str, signature: str) - bool:
payload = f"{timestamp}.{body}"
expected = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Go:
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
func verifyWebhookSignature(secret, timestamp, body, signature string) bool {
payload := timestamp + "." + body
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(payload))
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}Preventing Replay Attacks
To protect against replay attacks, verify that the timestamp is recent — for example, within 5 minutes of the current time:
const MAX_AGE_SECONDS = 300; // 5 minutes
function isTimestampValid(timestamp) {
const now = Math.floor(Date.now() / 1000);
return Math.abs(now - parseInt(timestamp)) < MAX_AGE_SECONDS;
}Troubleshooting
| Issue | Solution |
|---|---|
| Signature mismatch | Ensure you're verifying against the raw request body, not a re-serialized/parsed JSON object. |
| Empty signature header | Confirm your webhook is created and enabled in the Command Center, then verify you've received your signing secret from support. |
| Verification fails after a rotation | Update your code with the new secret provided by support@chilipiper.com. |
| Haven't received your secret | Email support@chilipiper.com with your instance name and webhook details to request it. |
Comments
0 comments
Please sign in to leave a comment.