To receive inbound messages and status updates, configure a webhook in the Pinnacle Dashboard:
Navigate to Development > Webhooks and click Create new webhook. Give it a descriptive name and enter your endpoint URL. For local development, use an ngrok tunnel.
After creation, copy the signing secret (prefixed pss_) and store it in your environment as PINNACLE_SIGNING_SECRET.
Attach one or more phone numbers or RCS agent IDs to the webhook so it receives their events. You can attach and detach senders in the dashboard or in bulk via POST /webhooks/attach and POST /webhooks/detach.
For sandbox numbers, ensure you’ve whitelisted the recipient device and verified the 4-digit PIN before testing.
You can configure additional HTTP headers that Pinnacle includes on every webhook delivery — for example, a static API key, an internal routing token, or a tracing identifier. Set them in the dashboard when creating or editing a webhook, or pass an optional headers map to POST /webhooks/attach. Headers can be supplied whether you’re creating a new webhook or attaching an existing one by ID:
Header rules:
^[A-Za-z0-9][A-Za-z0-9_-]*$ — start with a letter or digit, then letters, digits, -, or _.PINNACLE-SIGNING-SECRET header is reserved for signature verification — any attempt to set it is silently stripped.Overwrite semantics when using webhookId:
headers replaces the entire stored header map on that webhook.headers leaves the stored headers unchanged.{} clears all custom headers from the webhook.Pinnacle SDKs provide a process() method to securely handle incoming webhook requests:
PINNACLE-SIGNING-SECRET in the headers.MessageEvent or UserEvent objects.For full code examples in TypeScript, Python, and Ruby, see the SMS quickstart and RCS quickstart receive guides.
When a recipient fills out a form delivered via POST /forms/send, a FORM.SUBMISSION event is delivered to every webhook subscribed to the sender. The payload differs from message events — there is no message or status field; instead the event carries a resolved snapshot of the form definition paired with the submitted values so you can render or route on the response without an extra get_form call.
Payload shape:
Notes:
sender at the event root is convenience-duplicated from submission.from so you can route on it without unwrapping.conversation is null when the form was minted URL-only (no to at send time). In that case submission.to is also null.can_update=true forms, each edit fires a fresh FORM.SUBMISSION event with the updated values.submission.fields, even those the recipient left blank — check value for null or an empty array.When you send an RCS message with a fallback configured and the RCS message cannot be delivered (e.g., the recipient’s device doesn’t support RCS), the system will automatically send the fallback SMS/MMS message instead.
Fallback events are delivered to two different webhooks:
RCS agent’s webhook receives a MESSAGE.STATUS event with:
status: FALLBACK_SENTfallbackMessage: Details of the SMS/MMS message that was sent instead, including its message ID, type, sender, recipient, text, and any media URLs.Fallback phone number’s webhook receives MESSAGE.STATUS events related to the fallback message that was sent.