Webhook integration
A webhook is an HTTP request the platform sends you when something happens. The Socialift Python SDK gives your endpoint the building blocks for Meta webhooks: verify_challenge answers the GET check, verify_request validates X-Hub-Signature-256 over the raw body, parse_events splits a delivery into events and dedupe_key gives a stable key for dropping repeats. Forwarding events to your CRM is your code.
Updated:
What is a webhook and how is it different from an API?
A webhook is an HTTP request a server sends to your address the moment an event occurs. With a normal API you make the request and wait for a response; with a webhook the platform calls you instead. That is why you hear about a new Direct message or a submitted lead shortly after it happens, without polling.
With Meta this happens in two stages: the address is first confirmed by a GET request (hub.mode, hub.verify_token, hub.challenge), then events arrive as POST requests carrying an HMAC-SHA256 signature in the X-Hub-Signature-256 header.
The practical difficulty is computing that signature correctly: the HMAC is taken over the raw byte stream. If you parse the JSON and re-serialise it, whitespace and field order change and the signature will not match.
Connecting a Meta webhook
Expose an endpoint
You need an HTTPS address that supports both GET and POST.
Answer the verification request
If hub.verify_token in the GET request matches your value, return hub.challenge as plain text.
Verify the signature
Compare the X-Hub-Signature-256 value with an HMAC-SHA256 of the raw body computed with your app secret.
Split the events
One delivery may contain several objects and several changes. Turn each into a separate event.
Deduplicate
Meta sends no event ID and may redeliver. Build the key from the payload (
leadgen_id, messagemid, comment ID) —dedupe_key(event)in the SDK — and store it in a unique column.Respond quickly
Return 200 immediately and push heavy work onto a queue — otherwise Meta marks the delivery as failed.
Verifying the signature correctly
The code below shows the standard check from Meta's documentation without the SDK. In the Socialift SDK the same check is verify_request(app_secret, body, headers), which you call from your own endpoint.
import hmac, hashlib
def verify(raw_body: bytes, header: str, app_secret: str) -> bool:
# the header looks like: "sha256=abcdef..."
if not header or not header.startswith("sha256="):
return False
expected = hmac.new(
app_secret.encode(), raw_body, hashlib.sha256
).hexdigest()
# constant-time comparison — protects against timing attacks
return hmac.compare_digest(expected, header.split("=", 1)[1])Note that raw_body is the raw bytes your framework received. Computing over json.dumps(request.json) will almost always fail to match.
What the Socialift SDK gives you
Signature verification
verify_request(app_secret, body, headers) checks X-Hub-Signature-256 in constant time and returns False when the signature is missing or wrong — answer 403.
Event splitting
The entry/changes/messaging structure is flattened into one stream of events.
Duplicate removal
Meta provides no event ID; dedupe_key(event) builds a stable key from the payload. Store it in a unique column and no duplicate deal reaches your CRM.
Retries on Meta's side
If your endpoint does not answer, Meta retries for up to 36 hours — stay idempotent with dedupe_key. The SDK's RetryPolicy covers outgoing API calls only; forwarding events to your CRM and retrying that is your code.
Lead payload fetch
A leadgen event carries only IDs (leadgen_id, form_id, page_id). Fetch the answers with fb.lead(leadgen_id, page_token) and map them to name/phone/email with socialift.leads.normalize(). For Pages connected in the dashboard the server does this itself — leads appear under GET /crm/leads in the Playground.
Diagnostics
The dashboard's “Statistika” (Statistics) page shows SDK activations and API/Playground calls with error counts. Webhook deliveries are not shown there — log them in your endpoint.
Which events arrive
| Event | Typical CRM action | ||
|---|---|---|---|
| New Instagram Direct message | yes | no | Create or update a contact and deal |
| Comment on a post | yes | yes | Create a task, queue a reply |
| Lead Ads form submitted | yes | yes | Create a lead, assign an owner |
| Access revoked | yes | yes | Mark the connection as broken |
yesnoScroll the table sideways
Notes and limits
Instagram comment webhooks need the app in Live mode, Advanced Access for comments and a public account. Leads from Instagram ads arrive as the Facebook Page's leadgen event. LinkedIn webhooks exist only for apps with an approved use case; Socialift's LinkedIn client does not handle them — data is fetched by request.
Security checklist for a webhook endpoint
- Never process a request whose signature you have not verified.
- Keep verify_token and app_secret out of source control — use environment variables.
- Expose the endpoint over HTTPS only.
- Cap the request body size and harden JSON parsing.
- Queue events: the delivery response must be 200, processing happens afterwards.
- Store the dedupe key and timestamp (
entry.time) — for dedupe and for audit.
Frequently asked questions
How do webhooks work?
When an event happens on the platform, it sends a POST request to your HTTPS address. The body carries the event payload and the header carries a signature. You verify the signature and return 200 to acknowledge receipt.
Why doesn't my webhook signature match?
The most common cause is computing the signature over re-serialised JSON instead of the raw body. The second is the wrong app secret. The third is a proxy or framework mutating the request body.
Can the same event arrive twice?
Yes. Meta retries a failed delivery for up to 36 hours, so duplicates are normal. Meta sends no event ID: build the key from the payload (dedupe_key in the SDK) and keep it in a unique column.
Could I poll instead of using webhooks?
Technically yes, but polling burns rate limits and increases reaction time. For messages and leads a webhook is the right answer; polling only makes sense as a fallback.
Sources
Related pages
Wire up webhooks today
Get a token and verify your first Meta event with verify_request.
Get a free token →