> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.pinnacle.sh/v-2/webhooks/form-events/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.pinnacle.sh/_mcp/server. # Form Events POST Receive `FORM.SUBMISSION` events via webhook when a recipient completes a Pinnacle form. Fires once per successful submit — and again on every edit when the form was created with `can_update: true`. The payload includes the full form metadata, the submitter's answers (both keyed by `key` in `submission.data` and as a resolved `submission.fields` snapshot ready to render), and the conversation the form was sent in. `conversation` is only populated when the form was dispatched via `POST /forms/send` with a `to` recipient — it's null for URL-only sends and for forms whose URL was shared through any other channel (e.g. an RCS card built with `POST /send`). `sender` is hoisted to the event root so you can route on it without walking into the submission object. **Before trusting the payload, verify the `PINNACLE-SIGNING-SECRET` header matches the signing secret of the webhook this event was delivered to.** Respond with a `200` to acknowledge receipt — any non-2xx response causes Pinnacle to retry with exponential backoff. Reference: https://docs.pinnacle.sh/webhooks/form-events ## Request ### Headers - `PINNACLE-SIGNING-SECRET` (string, required) — Secret for verifying the authenticity of the request. Starts with `pss-` and is unique for each webhook. Find it at [webhooks](https://app.pinnacle.sh/dashboard/development/webhooks). ### Payload - `type` (enum, required) - Allowed values: `FORM.SUBMISSION` - `sender` (string, required) — Top-level sender identifier — same value as `submission.from`. Exposed at the event root so you can route on it without digging into the submission object. - `conversation` (FormSubmissionEventConversation, required) — Conversation between the sender and the recipient the form was delivered to. Only populated when the form was dispatched via `POST /forms/send` with a `to` recipient — that's the only call that opens a conversation tied to a form submission. Null in every other case, including: - `POST /forms/send` without a `to` (URL-only mints — no message is sent, so no conversation exists). - Submissions to a form whose URL was shared by any other means (e.g. an RCS card built with `POST /send`, a chat message, a marketing email, or a link on your site). The recipient isn't tied to a Pinnacle conversation in those flows. - `form` (FormSubmissionEventForm, required) — Form summary carried on the FORM.SUBMISSION event. - `submission` (FormSubmissionEventSubmission, required) — The submitted answers plus a resolved snapshot of each form field. ## Types ### FormSubmissionEventConversation Conversation between the sender and the recipient the form was delivered to. Only populated when the form was dispatched via `POST /forms/send` with a `to` recipient — that's the only call that opens a conversation tied to a form submission. Null in every other case, including: - `POST /forms/send` without a `to` (URL-only mints — no message is sent, so no conversation exists). - Submissions to a form whose URL was shared by any other means (e.g. an RCS card built with `POST /send`, a chat message, a marketing email, or a link on your site). The recipient isn't tied to a Pinnacle conversation in those flows. - `id` (string, required) — Conversation public id (`convo_*`). - `from` (string, required) — Sender identifier on the conversation — the RCS agent id (`agent_*`) or E.164 phone number that sent the form. - `to` (string, required) — Recipient phone number (E.164) the form was delivered to. ### FormSubmissionEventForm Form summary carried on the FORM.SUBMISSION event. - `id` (string, required) — Form id the submission belongs to (starts with `form_`). - `url` (string, required) — Public shareable URL of the form (`https://forms.pinnacle.sh/{form_id}`). - `name` (string, required, nullable) — Human-readable name of the form. Null if the form was created without a name. ### FormSubmissionEventSubmission The submitted answers plus a resolved snapshot of each form field. - `id` (string, required) — Submission id (starts with `fsub_`). Uniquely identifies this submission. - `from` (string, required) — Sender identifier that originally sent this form — RCS agent id (`agent_*`) or E.164 phone number. - `to` (string, required, nullable) — Recipient phone number (E.164) the form was delivered to. Null for URL-only sends where `to` was omitted at send time. - `data` (map from string to any, required) — Submitted answers keyed by field `key`. Each value's shape depends on the field type: - `text`, `email`, `phone`, `url`, `textarea`, `select`, `radio` → string - `number` → number - `checkbox` (single) → boolean - `checkbox` (multi), `multiselect` → array of strings - Skipped optional field → null - `fields` (list of FormSubmittedField, required) — Resolved snapshot of the form definition paired with the submitted value — ready to render without a separate `get_form` call. - `ip_address` (string, required, nullable) — IP address the submission was POSTed from. Null if unavailable. - `user_agent` (string, required, nullable) — User-Agent header of the browser that submitted the form. Null if unavailable. - `submitted_at` (string, required) — ISO 8601 timestamp of when the submission was completed. Updated on each edit for `can_update: true` forms. ### FormSubmittedField Snapshot of a single form field paired with the value the recipient submitted. - `key` (string, required) — Programmatic key of the field from the form definition. - `label` (string, required) — Label as shown to the recipient when they filled out the form. - `type` (string, required) — The field type from the form definition (e.g. `text`, `select`, `checkbox`). - `value` (FormSubmissionAnswer, required) — The value submitted for this field. ### FormSubmissionAnswer The value submitted for a single form field. Shape depends on the field type: - `text`, `email`, `phone`, `url`, `textarea`, `select`, `radio` → string - `number` → number - `checkbox` (single) → boolean - `checkbox` (multi), `multiselect` → array of strings - Skipped optional field → null > One API for RCS, iMessage, MMS, and SMS. Build, test, and scale every channel — send your first message in minutes, not weeks.