All docs
3 min read Last updated:

Payload

Custom webhooks only. When you add a destination without picking a built-in provider, Formspring POSTs the JSON below to your URL and signs the raw body with X-Formspring-Signature. Built-in providers (Slack, Mailchimp, HubSpot, …) use each vendor’s own JSON shape and do not send this envelope or the HMAC header.

Headers

text
X-Formspring-Signature: t=<unix>,v1=<hmac_sha256_hex>
X-Formspring-Event:     submission.created
X-Formspring-Delivery:  <delivery row id>
Content-Type:           application/json
User-Agent:             formspring/1.0 (webhook delivery)

The signature is computed as HMAC_SHA256(whsec_…, "<t>.<raw_body>") where <t> is the t= unix timestamp and <raw_body> is the exact JSON string we POST. This is the industry-standard t=…,v1=… HMAC convention so existing verification code can be reused.

There is no separate X-Formspring-Timestamp header; parse the timestamp from the signature prefix.

Envelope (api_version 2026-05-07)

json
{
  "event": "submission.created",
  "api_version": "2026-05-07",
  "data": {
    "id": "01HFXX0X9R7KZJVN9VS6TG2C5T",
    "form_id": "r2EdO-orF-3S",
    "created_at": "2026-05-07T16:09:10Z",
    "status": "processed",
    "payload": {
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "message": "Loved the docs."
    },
    "consent_snapshot": [],
    "assigned_to_user_id": null,
    "due_at": null,
    "resolved_at": null,
    "files": [
      {
        "field": "resume",
        "original_name": "cv.pdf",
        "mime": "application/pdf",
        "size_bytes": 184213
      }
    ]
  }
}
Field Type Notes
event string Currently submission.created for clean submissions.
api_version string Version of this envelope; bump when breaking changes ship.
data.id string Submission id (ULID-style). Use as your idempotency key.
data.form_id string The form’s public id (/f/{form_id}).
data.created_at ISO 8601 When the submission was stored.
data.status string Submission workflow status at send time.
data.payload object Raw submitted fields.
data.consent_snapshot array Consent records captured with the submission.
data.assigned_to_user_id int|null Inbox assignment when set.
data.due_at string|null ISO 8601 due time when set.
data.resolved_at string|null ISO 8601 when resolved.
data.files array File metadata only (field, name, mime, size). Binary downloads use signed routes in the app, not inline URLs in this payload.

Size and reliability

Large payloads may be truncated at ingestion time; very heavy file bodies are never inlined. Failed deliveries are retried automatically with exponential backoff (see Retries →).

What’s next