Webhooks and events overview

How Wingspan V3 tells your system that something changed, through webhook pushes and a 30-day event log you can read back.

This page explains how Wingspan tells your system that something changed, so you can react to payments, files, and account changes without polling every resource.

Wingspan gives you two ways to receive the same events:

  • Webhook push. You create a subscription with an HTTPS URL. When an event you subscribed to happens, we POST it to that URL, signed with a secret only you and Wingspan know.
  • The event log. Every event is also stored for 30 days at GET /v3/platform/events. You read it with a cursor, from where you left off.

Push is fast but best effort. The event log is the durable record. A reliable integration uses both: push for speed, the log to catch anything push missed. The rest of this section shows how.

Coming from V1? V1 had one webhook "preference" per account at /integrations/webhooks/preference, you chose the shared secret, and each push carried a full copy of the invoice or payee. In V3 you can have many subscriptions, Wingspan generates the secret, each push is a small reference you look up, and you can recover missed events from the event log.

What an event looks like

Every event is a small, signed reference to a resource. It tells you what happened and which resource changed. It doesn't carry the whole resource.

{
  "id": "5f0c1d7e9a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d",
  "type": "Invoice.Paid",
  "routingSubject": { "type": "Account", "id": "Qm4xT8vLp2RzW6nYc0aBd3" },
  "createdAt": "2026-09-24T14:30:02Z",
  "eventCreatedAt": "2026-09-24T14:30:00Z",
  "apiVersion": "2026-03-27",
  "occurrenceId": "9e8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c8b7a6f5e4d3c2b1a0f9e8d",
  "payloadProjection": { "id": "WebhookResourceId", "version": 1, "sha256": "..." },
  "actorProjection": { "id": "WebhookSubjectSafeActor", "version": 1, "sha256": "..." },
  "publicEnvelope": { "id": "Invoice.PaidEnvelope", "version": 1, "sha256": "..." },
  "data": { "id": "H7kP2wQx9LmN4vRt6yZa1b" },
  "actor": { "kind": "Person", "disclosure": "Redacted" }
}
FieldWhat it means
idThis event's unique ID, a 64-character hex string. Use it to spot duplicate deliveries.
type{Resource}.{Event}, for example Invoice.Paid. See Event types.
routingSubjectThe Account, Organization, or Person this copy of the event is for.
occurrenceIdThe ID of the change itself. When one change concerns two parties (a payer and a payee), each gets its own event with a different id and the same occurrenceId.
createdAtWhen Wingspan recorded the event in the event log.
eventCreatedAtWhen the change happened.
apiVersionThe date-based version the event was written in. It never changes after the event is created.
dataThe resource's id, plus its status and externalId on events that include them.
actorWho made the change: Person, ServiceAccount, or System. The id is included only when you're allowed to see it; otherwise disclosure is Redacted.
context, parent, confirmationExtra fields on some event types. See Event types.

The projection and envelope fields identify the exact schema the event was built from. Most consumers can ignore them.

Why events are references, not full resources

A V1 push carried the whole invoice. That made the payload large, could expose fields a recipient shouldn't see, and went stale the moment the invoice changed again. A V3 event is a pointer: when you receive Invoice.Paid, call GET /v3/payments/invoices/{invoiceId} with data.id to read the current invoice. The resource API is always the source of truth.

Scopes: whose events you receive

Every subscription, and every event log query, picks exactly one scope:

ScopeReceives events for
AccountOne Account. Set shouldIncludeDescendants: true to also include its child Accounts.
OrganizationThe Organization itself. Set shouldIncludeAccounts: true to also include events for Accounts in the Organization.
PersonOne Person, and only yourself. Used for Person-level events such as notifications.

Scopes never widen on their own. An Organization scope doesn't include Person events, and an Account scope doesn't include sibling Accounts. See Create a subscription.

How the pieces fit

sequenceDiagram
    participant W as Wingspan
    participant Y as Your endpoint
    participant Q as Your queue
    W->>Y: POST event (signed)
    Y->>Y: Verify signature
    Y->>Q: Enqueue event
    Y-->>W: 200 OK
    Q->>W: GET the resource by data.id
    Note over Q,W: Later, on a schedule
    Q->>W: GET /v3/platform/events?page[token]=resumeCursor
    W-->>Q: Any events push missed, plus a new resumeCursor

Pages in this section

  1. Create a subscription: choose a scope and events, create the subscription, and store the secret.
  2. Verify signatures: check Wingspan-Signature in Node.js or Python.
  3. Delivery and retries: the retry schedule, what counts as success, and a checklist for a reliable consumer.
  4. Recover missed events: read the event log with a saved cursor.
  5. Event types: every event you can subscribe to today.
  6. Paid vs DepositConfirmed: what each payment event does and doesn't tell you.

Related pages


Did this page help you?