All articles
Help / Developers
Webhooks and signatures
Get each new message as JSON at your own URL, signed so you can check it came from InboxPanda.
Add a webhook
Open the inbox's Settings, then Where messages go, and paste your URL in Webhook. It works with Zapier, Make, n8n or your own server. The URL must be public: addresses on a private network are refused.
Each real message is posted once Panda has read it. Spam isn't sent.
What's sent
A POST with a JSON body, shortened here:
{
"inbox": { "id": "your-form-id", "name": "Contact" },
"intent": { "id": "sales", "name": "Sales lead" },
"submission": {
"id": "…",
"createdAt": "2026-10-26T09:14:03.000Z",
"data": { "name": "Ana", "email": "ana@example.com", "message": "Do you ship to Lisbon?" },
"ai": {
"intent": "sales",
"confidence": 0.94,
"urgent": false,
"gist": "Asks whether you ship to Lisbon.",
"summary": "Ana wants to know if you deliver to Lisbon, and how long it takes.",
"facts": [{ "label": "City", "value": "Lisbon" }]
}
}
}
data holds the form's fields as sent. For email, submission.source is "email" and submission.subject is set. intent is null when Panda didn't classify the message. More fields may be added: ignore the ones you don't use.
Check the signature
Every request has an x-signature header: sha256= followed by the HMAC-SHA256 of the raw body, keyed with your signing secret. Find the secret under Signing secret, next to the webhook.
Compute it over the body exactly as received, before parsing:
import { createHmac, timingSafeEqual } from "node:crypto"
function signed(rawBody, header, secret) {
const expected = Buffer.from("sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex"))
const got = Buffer.from(header ?? "")
return got.length === expected.length && timingSafeEqual(got, expected)
}
If the secret leaks, rotate it in the same place. Requests are signed with the new one at once.
Deliveries
Answer with any 2xx status within 5 seconds. Redirects aren't followed. A failed delivery isn't retried: Connections shows it with the reason, and the message is still in your inbox.
Send a test posts a sample to your webhook and says whether it was delivered. See Email, Slack and webhook notifications.