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-signatureverification failing? - How do I create a Basiq webhook subscription (
POST /notifications/webhooks)? - How do I handle
user.created,connection.activated,consent.revokedortransactions.updatedevents? - Why doesn't the Basiq webhook payload contain the account or transaction data?
Verification (core)
| Header | Value |
|---|---|
webhook-id | Unique message ID, the same if the message is resent |
webhook-timestamp | Unix seconds of the attempt |
webhook-signature | One 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.
| Group | Events |
|---|---|
| User | user.created, user.updated, user.deleted |
| Connection | connection.created, connection.activated, connection.invalidated, connection.deleted |
| Consent | consent.created, consent.updated, consent.revoked, consent.expired, consent.reminder, consent.warning |
| Data | account.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
2xxquickly, 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.173and3.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
- references/overview.md - Event catalog, thin payload, delivery notes
- references/setup.md - Creating subscriptions with the API, secret, test messages
- references/verification.md - Library and manual verification, header fallback, debugging