AccountingKitDocs

Webhooks

Receive AccountingKit events and configure Xero callbacks.

Customer webhooks

Register an HTTPS destination through POST /v1/webhook-endpoints with one or more event types:

  • connection.created
  • connection.updated
  • connection.disconnected
  • sync.completed
  • invoice.updated
  • invoice.payment_changed
  • invoice.paid
  • automation.succeeded
  • automation.failed

The response includes a signing secret once. Store it in your secret manager.

Deliveries include the event ID, event type, creation time, environment, and data. Verify the HMAC signature against the exact raw request body before parsing JSON. Deduplicate on event ID and return a successful response quickly; webhook delivery is retried as a durable operation.

The signature is sent in AccountingKit-Signature as t=<unix-seconds>,v1=<hex-hmac>. The signed message is <timestamp>.<exact-raw-body>. AccountingKit-Event carries the event ID. The Node SDK provides constructWebhookEvent(rawBody, signature, signingSecret), which performs constant-time signature comparison, rejects payloads outside a five-minute replay window, and validates the event envelope before returning it.

Xero webhooks

For a customer-owned Xero app, configure the callback URL shown in the console:

POST /webhooks/xero/{provider_app_id}

The opaque path identifies the registered app, allowing AccountingKit to load its encrypted webhook key before parsing or trusting the request body. The hosted trial app retains POST /webhooks/xero. Both routes validate X-Xero-Signature before persisting any event. The receiver stores the minimal parsed event and its operation/outbox record in one transaction; it never stores the raw webhook body and acknowledges without waiting for a Xero API call.

Invoice events enqueue a targeted live invoice read and emit invoice.updated with a constrained, provider-neutral payment snapshot. When the live amount paid, amount due, or status differs from the previously cached invoice, AccountingKit also emits invoice.payment_changed. A transition from any non-paid state to paid emits invoice.paid. Consumers can therefore update operational paid fields and alerts without guessing from the original Xero notification. Other supported Xero categories currently enqueue a full connection sync. The webhook payload is a change notification; the subsequent Xero read remains the source of truth. Event IDs, sequence cursors, and gaps are scoped to the Xero app. A gap queues reconciliation only for active connections created with that app.

The same invoice pipeline runs on a configurable 15-minute safety-net schedule and through POST /v1/connections/:connection_id/sync. This catches provider events that never arrived while preserving the same event identity, payment state comparison, signed delivery, and PDF refresh contract.

Every invoice event includes document.refresh_required, the invoice.download_pdf provider action, both AccountingKit and Xero invoice IDs, and a provider revision. Consumers that cache a rendered invoice must replace that snapshot before presenting or sending it; the original PDF is not a timeless representation of a mutable Xero invoice.

Delivery operations

Each outbound delivery has persisted attempts, response status, response body excerpt, next attempt, and terminal state. Operators can correlate a delivery with its operation and request ID without exposing signing secrets or accounting payloads in logs.

After correcting the destination, requeue a terminal delivery with POST /v1/webhook-deliveries/:delivery_id/replay, an Idempotency-Key, and a non-empty reason. The original delivery and attempt history remain intact.

On this page