An outgoing webhook sends a signed message to an address of yours whenever something important happens in Rutba CRM. Use it to start work in another system: notify a channel, add a row to a sheet through an automation tool, or update your own software.
Before you start
- Who can do it: owners and administrators of the company.
- Plan: available when your plan includes API access.
- An HTTPS address that accepts
POSTrequests on the standard port 443. Automation tools such as Zapier, Make or n8n give you one when you create a webhook trigger.
Add a webhook
- In the sidebar open Contacts, then click API keys, then Webhooks.
- Under Add webhook, enter the HTTPS address.
- Under Send when, tick one or more events:
| Event | Sent when |
|---|---|
| A new lead arrives | A new contact is created from a store order, a website form or a channel message. Contacts added by hand, imported or created through the API do not send it |
| A store order is confirmed | A store order reaches a sale status (paid, processing, completed or delivered) for the first time. Imported past orders do not send it |
| A quote is accepted | A customer or a team member accepts a quote |
| A deal is won | A deal is marked as won |
- Click Add webhook.
- A box shows the signing secret, starting with
whsec_. Copy it now: it is shown only once.
A company can have up to 5 webhooks, counting paused ones and those created through the API, which appear on the same page. Removed webhooks do not count. A webhook's address and events cannot be changed after it is added: to change them, add a new webhook and remove the old one.
Pause or remove a webhook
Each webhook on the Webhooks page has two buttons:
- Pause stops sending. Events that happen while it is paused are not queued for it. Deliveries that were already waiting stay waiting, and Resume sends them.
- Remove takes the webhook off the list at once. It never sends again, deliveries still waiting for it are marked Skipped, and it no longer counts towards the 5. A removed webhook cannot be turned back on: to use the address again, add it as a new webhook, which gets a new signing secret.
Its past deliveries stay in Recent events until they are 30 days old.
What is sent
Each delivery is a POST with a JSON body:
{
"id": "DELIVERY_ID",
"event": "order_confirmed",
"occurred_at": "2026-11-08T09:30:00Z",
"data": {
"contact": {"id": "CONTACT_ID", "name": "Sample Customer", "email": "customer@example.com", "phone": "+966500000001"},
"subject": "order:ORDER_ID",
"amount_minor": 125050,
"currency": "SAR"
}
}
| Field | Meaning |
|---|---|
event |
lead_created, order_confirmed, quote_accepted or deal_won |
data.contact |
The contact's current ID, name, email and phone |
data.subject |
What the event is about: contact:, order:, quote: or deal: followed by its ID |
data.amount_minor |
The amount in the smallest unit of the currency, such as 125050 for 1250.50. Empty for a new lead |
data.currency |
The currency of the amount. Empty for a new lead |
And three headers:
| Header | Value |
|---|---|
X-Webhook-Event |
The event name |
X-Webhook-Delivery |
The delivery ID, the same as id. Use it to ignore a repeat |
X-Webhook-Signature |
t=TIMESTAMP,v1=SIGNATURE |
Check the signature
SIGNATURE is the hex HMAC-SHA256 of TIMESTAMP.BODY, keyed with the signing secret, where BODY is the raw body exactly as received. Check it before you trust a delivery:
$body = file_get_contents('php://input');
preg_match('/t=(\d+),v1=([a-f0-9]+)/', $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '', $parts);
$expected = hash_hmac('sha256', ($parts[1] ?? '').'.'.$body, getenv('WEBHOOK_SECRET'));
$fresh = abs(time() - (int) ($parts[1] ?? 0)) <= 300;
if (! $fresh || ! hash_equals($expected, $parts[2] ?? '')) {
http_response_code(403);
exit;
}
// Answer 2xx quickly, then do the work.
The same scheme is used for webhooks created through the API; see Webhooks.
Delivery and retries
- Deliveries go out within about a minute of the event, up to 50 a minute for each company.
- Your address must answer with a 2xx status within 5 seconds. Redirects are not followed.
- A failed delivery is tried again after 1 minute, 5 minutes, 30 minutes and 2 hours: 5 attempts in all. After that it is marked Failed.
- After 10 deliveries in a row have failed, the webhook is paused. Fix your address, then click Resume.
- A delivery is sent only once for each webhook, event and subject, even if the event happens again.
- Events that happen while a webhook is paused are not queued for it.
- A delivery still waiting after 30 days is dropped as Skipped, and so is one whose contact has been erased. The delivery history is kept for 30 days.
- The address is checked before every send: addresses inside private networks are refused.
Test it
- Add a webhook with a test address from your automation tool, or a request inspector you control.
- Send a website form with new details. This creates a new lead.
- Within a minute, your address receives
lead_created, and Recent events on the Webhooks page shows it as Delivered with the answer code.
Troubleshooting
| What you see | What to do |
|---|---|
| Use an https address with no port or password. | Use https://, no :port, no user name or password, and no # part |
| This company has reached 5 webhooks. | Paused webhooks still count. Click Remove on one you no longer need, then add the new one |
| Failed with a code such as 401 or 404 | Your address refused the delivery. Check the address and that it accepts POST without a login |
| Failed with no code | Your address did not answer within 5 seconds, could not be reached, or points to a private network |
| The webhook shows Paused | 10 deliveries in a row failed. Fix the cause and click Resume |
| Nothing for A new lead arrives | Contacts added by hand or imported do not send it. Test with a form, a store order or a message |
Last updated 2026-11-08