Outbound webhook
PropDrop sends a signed POST to your gateway for AI and team replies and key lead events, with X-PropDrop-Signature, an Idempotency-Key and retries.
The outbound webhook is for your own messaging gateway: n8n, a non-Meta WhatsApp provider, or an internal system. PropDrop POSTs signed JSON to your URL, and your gateway delivers the message to the customer or does whatever it needs with the event.
Do you need it?
If you connected WhatsApp, Messenger, Instagram or Telegram directly in PropDrop, you don't need it for replies: PropDrop sends them itself. Use it if you run your own gateway, or want another system to know when a lead is qualified, requests a viewing or is handed to your team. You'll usually pair it with the inbound webhook.
This page is for whoever sets up the gateway. Available on all plans.
Who can set it up: owner and managers.
Turn it on
Open “Send replies to your gateway (outbound webhook)”
In Settings → Channels & integrations, under Advanced, switch it on.
Enter the Outbound URL
It must start with https:// and be publicly reachable. Save; you'll see "Outbound URL saved".
Generate the signing secret
Click Generate new secret. The secret (starting with pd_out_) is shown only once: copy it into your gateway and click I've copied it. Lost it? Generate a new one; the old one stops working immediately.
Switching it off clears the URL ("Outbound webhook turned off"), and any delivery still waiting for a retry is marked Failed.
When we send
Every request carries an event in the X-PropDrop-Event header:
| Event | Sent when |
|---|---|
message.created | The AI agent or your team replies in a conversation that isn't tied to a channel connected in PropDrop (e.g. conversations that came in through the inbound webhook). Website chat replies are never sent, the customer already sees them |
lead.qualified | The agent qualified the lead and scored it (hot / warm / cold) |
viewing.requested | The customer asked for a viewing (a request, not a confirmed slot: your team confirms) |
handoff | The agent handed the conversation to your team |
lead.qualified, viewing.requested and handoff are sent for every conversation, on any channel, as long as a URL is set.
The request
POST https://gateway.example.com/propdrop
Content-Type: application/json
User-Agent: PropDrop-Webhooks/1.0
X-PropDrop-Event: message.created
Idempotency-Key: 9b2e…
X-PropDrop-Signature: sha256=<hex HMAC-SHA256(secret, body)>The body always uses the same envelope:
{
"event": "message.created",
"id": "9b2e…",
"agency_id": "…",
"created_at": "2026-10-09T12:00:00.000Z",
"data": { }
}id is the same value as the Idempotency-Key.
What's in data
An AI agent reply (sender = ai):
{
"message_id": "…",
"conversation_id": "…",
"channel": "whatsapp",
"sender": "ai",
"text": "Hi Ahmed! We have 3-bedroom apartments in New Cairo starting from …",
"contact": { "name": "Ahmed Ali", "phone": "+201001234567", "instagram": null }
}A reply from your team (sender = agent):
{
"message_id": "…",
"conversation_id": "…",
"channel": "whatsapp",
"sender": "agent",
"text": "…",
"contact": { "name": "Ahmed Ali", "phone": "+201001234567", "instagram": null }
}AI replies and team replies use the same shape; only sender differs (ai or agent). The customer is always in contact (name, phone, instagram).
Verify the signature
X-PropDrop-Signature = sha256= + the hex HMAC-SHA256 of the raw request body with your secret. Compute the same and reject anything that doesn't match:
import { createHmac, timingSafeEqual } from "node:crypto";
function isFromPropDrop(rawBody, header, secret) {
if (!header?.startsWith("sha256=")) return false;
const expected = createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const got = header.slice(7);
return got.length === expected.length && timingSafeEqual(Buffer.from(got, "hex"), Buffer.from(expected, "hex"));
}Use the raw body
Sign-check the exact text you received, before any JSON.parse or re-serialising.
Responses and retries
- Answer with any 2xx within 8 seconds and the delivery counts as Delivered.
- No answer, a non-2xx status, or a redirect (3xx; we don't follow redirects) means a retry after about 1 minute, then about 5 minutes later: 3 attempts in total, after which the delivery is marked Failed.
- Every retry sends exactly the same bytes, with the same signature and
Idempotency-Key.
Idempotency-Key
The same event can reach you more than once (e.g. you answered late and we retried). Store the Idempotency-Key and ignore any request whose key you've already seen, so the same message is never sent to a customer twice. On our side, a given key is only ever queued once.
Recent deliveries
Below the settings you'll find the last 10 deliveries with their event, status (Delivered, Retrying, Failed) and attempt count. If you see failures, check your URL is up and answers 2xx quickly.
Connect Telegram
Create a Telegram bot with your company's name in minutes, paste its token into PropDrop, and the AI agent answers everyone who messages it.
Inbound webhook
Push customer messages and leads from your website forms or a custom WhatsApp gateway into PropDrop with a signed POST, and the AI agent answers them.