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.
The inbound webhook is the way in: any system of yours can send PropDrop a customer message or a new lead. For example:
- A "Request details" form on your website.
- Your own WhatsApp or SMS gateway (not Meta).
- A tool like n8n collecting leads from ads or from portal lead exports.
The message lands in the inbox like any channel, the customer is saved in your contacts, and the AI agent replies. The agent's reply goes out through the outbound webhook, so your gateway delivers it to the customer.
PropDrop doesn't pull from property portals
PropDrop doesn't connect directly to Property Finder, Bayut or Aqarmap. If you get leads there, a system of yours (like n8n) has to send them to this URL in the format below.
This page is for whoever builds the integration. Available on all plans. Who can set it up: owner and managers.
Setup
Copy the Inbound URL
In Settings → Channels & integrations, under Advanced, open Receive messages and leads (inbound webhook) and copy the URL. It looks like:
https://…/api/webhooks/inbound/<your company ID>Generate the signing secret
Click Generate new secret and copy it (it starts with pd_in_). It's shown only once. It's a different secret from the outbound one. Generating a new one stops the old one immediately.
Sign every request
Every request must carry:
X-PropDrop-Signature: sha256=<hex HMAC-SHA256(secret, raw body)>That's an HMAC-SHA256 of the exact raw body with your secret. Requests without a valid signature are rejected.
Request format
POST https://…/api/webhooks/inbound/<your company ID>
Content-Type: application/json
X-PropDrop-Signature: sha256=…{
"channel": "whatsapp",
"source": "portal",
"external_id": "lead-48213",
"sent_at": "2026-10-09T12:00:00+02:00",
"text": "I'm interested in the apartment in New Cairo, what's the price?",
"contact": { "name": "Ahmed Ali", "phone": "+201001234567" }
}| Field | Required? | Details |
|---|---|---|
contact.phone or contact.instagram | One of them | Phone numbers are normalised for your company's country (e.g. 01001234567 becomes +201001234567) |
contact.name | No | Up to 120 characters |
contact.email | No | A valid email |
text | Yes (or attachments) | Up to 4,000 characters |
channel | No | whatsapp (default), sms, email, web, instagram, messenger, telegram |
source | No | Where a new contact came from. portal records them as a Property portal lead. Also web, phone, referral, manual, import and the channel names |
external_id | No (but recommended) | Your ID for this message, up to 200 characters. A repeat with the same ID is ignored, so retries are safe |
sent_at | No | When it was sent, ISO 8601 with a time zone |
attachments | No | Up to 10 (below) |
Attachments
"attachments": [
{ "type": "image", "url": "https://example.com/plan.jpg", "mime": "image/jpeg", "name": "plan.jpg" },
{ "type": "location", "lat": 30.0131, "lng": 31.4914, "label": "Fifth Settlement" }
]type is image, audio, video, document or location. URLs must start with https://; we copy the file and keep it in the conversation.
Responses
| Status | Meaning |
|---|---|
202 | Accepted: {"ok": true, "event_id": "…"}. The message is processed next and the agent replies |
400 | invalid_json, or invalid with issues naming the bad fields |
401 | invalid_signature: missing or wrong signature |
403 | agency_inactive: the company account is suspended |
404 | not_found: wrong URL |
413 | too_large: the body is over 256 KB |
If a request was accepted (202) and processing then fails, we retry it automatically a bit later.
How the customer is matched
- We look the customer up by phone (or Instagram handle). If they exist, the message is added to them; if not, a new contact is created with the
sourceyou sent. - If they already have an open conversation on the same channel, the message joins it.
If you also connected WhatsApp in PropDrop
If the same customer has an open WhatsApp conversation on your number connected in PropDrop, and your request uses "channel": "whatsapp", the message joins that conversation and the reply goes out from your connected number, not your gateway. If your gateway is a different number, use "channel": "sms" or another channel so the conversations don't mix.
Quick test
BODY='{"text":"I want an apartment in New Cairo","contact":{"name":"Test","phone":"+201001234567"},"external_id":"test-1"}'
SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"
curl -X POST "$INBOUND_URL" -H "Content-Type: application/json" -H "X-PropDrop-Signature: $SIG" -d "$BODY"If you get 202, open Conversations: you'll find the chat and the agent's reply, and the reply goes to your outbound webhook if it's set.
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.
Public page
Your company's mini-site with listings, projects, offers and contact buttons on one shareable link. How to turn it on and set its address and look.