Agent skill

Basiq Webhooks Skill

Receive and verify Basiq (basiq.io, Australian open banking / CDR data API) webhooks. Use when setting up a Basiq webhook endpoint, creating a webhook subscription, debugging webhook-id / webhook-timestamp / webhook-signature (Standard Webhooks) verification with a whsec_ secret, or handling events like user.created, connection.activated, consent.revoked, consent.expired, account.updated and transactions.updated.

Install this skill

npx skills add hookdeck/webhook-skills --skill basiq-webhooks


Basiq is an Australian open-banking (CDR) data API covering users, consents, connections, accounts and transactions. Its webhooks are thin notifications: they say what happened and link to the event and the affected object, and you fetch the data from the Basiq API. Deliveries follow the Standard Webhooks scheme with webhook-id, webhook-timestamp and webhook-signature headers.

When to Use This Skill

  • How do I receive Basiq webhooks?
  • How do I verify a Basiq webhook signature?
  • Why is my Basiq webhook-signature verification failing?
  • How do I create a Basiq webhook subscription (POST /notifications/webhooks)?
  • How do I handle user.created, connection.activated, consent.revoked or transactions.updated events?
  • Why doesn't the Basiq webhook payload contain the account or transaction data?

Verification (core)

HeaderValue
webhook-idUnique message ID, the same if the message is resent
webhook-timestampUnix seconds of the attempt
webhook-signatureOne or more space-separated v1,<base64> entries

Signed content is {webhook-id}.{webhook-timestamp}.{raw body}, HMAC-SHA256, base64 output. The key is the base64-decoded part of the endpoint's secret after whsec_. Each endpoint has its own secret. Basiq has no webhook SDK; the examples use standardwebhooks (npm, PyPI), which compares in constant time and tries every v1 entry.

const { Webhook } = require('standardwebhooks');

// rawBody: exact request body string, NOT re-serialised JSON
function verifyBasiq(rawBody, h, secret = process.env.BASIQ_WEBHOOK_SECRET) {
  // webhook-* headers; fall back to svix-* when webhook-id is absent (Hookdeck reads either)
  const p = h['webhook-id'] ? 'webhook' : 'svix';
  new Webhook(secret).verify(rawBody, {
    'webhook-id': h[`${p}-id`],
    'webhook-timestamp': h[`${p}-timestamp`],
    'webhook-signature': h[`${p}-signature`],
  }, { jsonParse: false }); // throws on a bad signature or stale timestamp -> respond 400
}

BASIQ_WEBHOOK_SECRET holds the full whsec_... value. Read the body raw (express.raw({ type: '*/*' })) and parse it only after the check.

Retries and replays. The library always enforces a fixed 5-minute timestamp window. Hookdeck retries and replays resend the original webhook-timestamp, so the library rejects a late retry after 5 minutes. If deliveries reach you through Hookdeck, or you replay old events, use the manual verifier in references/verification.md, where the window can be dropped or widened.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Envelope

{
  "eventTypeId": "user.created",
  "eventId": "f2f567b6bbb213c40a2875105327bb37b44a38ab8861b64074e2978b98d1f7c7",
  "links": {
    "event": "https://au-api.basiq.io/events/f2f567b6bbb2...",
    "eventEntity": "https://au-api.basiq.io/users/88a85f64-5717-4562-b3fc-2c963f66af88"
  }
}

The event type is the top-level eventTypeId. No resource data is inlined: call links.event or links.eventEntity (with your Basiq API token) to get it. Dedupe on the webhook-id header.

Common Event Types

Basiq documents these 15 event types. The list may not be exhaustive: GET /events/types returns the current set.

GroupEvents
Useruser.created, user.updated, user.deleted
Connectionconnection.created, connection.activated, connection.invalidated, connection.deleted
Consentconsent.created, consent.updated, consent.revoked, consent.expired, consent.reminder, consent.warning
Dataaccount.updated, transactions.updated

Details: references/overview.md and Basiq's webhook docs.

Delivery Notes

  • Basiq documents no retry schedule, response timeout or ordering guarantee. Acknowledge with a 2xx quickly, queue the work, and make handlers idempotent.
  • A new subscription can take up to 15 minutes to start delivering.
  • Sent messages are listable with GET /notifications/webhooks/{webhookId}/messages.
  • Deliveries come from 13.238.192.210, 3.24.252.173 and 3.104.17.39.

Environment Variables

BASIQ_WEBHOOK_SECRET=whsec_xxxxx   # per-endpoint signing secret; handlers fail closed (500) without it

The POST /notifications/webhooks response includes the endpoint's secret. See references/setup.md.

Local Development

# Express / Next.js (use 8000 for FastAPI). No install or account required.
npx hookdeck-cli listen 3000 basiq --path /webhooks/basiq

Create a subscription pointing at the printed URL, then send a test message with POST /notifications/messages/test.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 11, 2026

View on GitHub →