Webhooks
Webhooks push real-time event notifications to your server when something happens in your Oak account — a payment completes, a refund is issued, a transfer lands, etc. Register an HTTPS endpoint, store the signing secret, and verify incoming payloads to keep your system in sync without polling.
import { createOakClient, createWebhookService } from '@oaknetwork/api';
const client = createOakClient({ ... });
const webhooks = createWebhookService(client);
Methods
| Method | Description |
|---|---|
register(webhook) | Register a new webhook |
list() | List all registered webhooks |
get(id) | Get a webhook by ID |
update(id, webhook) | Update a webhook |
toggle(id) | Toggle a webhook on or off |
delete(id) | Delete a webhook |
listNotifications(params?) | List webhook notifications |
getNotification(id) | Get a specific notification |
Register a webhook
const result = await webhooks.register({
url: 'https://your-server.com/webhooks/oak',
description: 'Production webhook',
});
if (result.ok) {
const webhook = result.value.data;
console.log('Webhook ID:', webhook.id);
console.log('Secret:', webhook.secret); // store this — used to verify signatures
}
The
secretis only returned onregister. Store it securely — you need it to verify incoming webhook signatures.
List webhooks
const result = await webhooks.list();
if (result.ok) {
for (const wh of result.value.data) {
console.log(`${wh.id} — ${wh.url} — active: ${wh.is_active}`);
}
}
Update a webhook
const result = await webhooks.update('wh_abc123', {
url: 'https://your-server.com/webhooks/oak-v2',
description: 'Updated endpoint',
});
Toggle a webhook
Enable or disable a webhook without deleting it:
const result = await webhooks.toggle('wh_abc123');
if (result.ok) {
console.log('Active:', result.value.data.is_active);
}
Delete a webhook
const result = await webhooks.delete('wh_abc123');
if (result.ok) {
console.log('Deleted:', result.value.data.success);
}
Notifications
List all notifications that have been sent to your webhooks:
const result = await webhooks.listNotifications({
limit: 20,
offset: 0,
});
if (result.ok) {
console.log(`Total notifications: ${result.value.data.count}`);
for (const n of result.value.data.notification_list) {
console.log(` ${n.id} — event: ${n.event} — ack: ${n.is_acknowledged}`);
}
}
Get a specific notification:
const result = await webhooks.getNotification('notif_abc123');
if (result.ok) {
console.log('Event:', result.value.data.event);
console.log('Category:', result.value.data.category);
console.log('Payload:', result.value.data.data);
}
Signature verification
The SDK exports utilities to verify incoming webhook signatures using HMAC-SHA256 with timing-safe comparison.
Verify a signature
import { verifyWebhookSignature } from '@oaknetwork/api';
const isValid = verifyWebhookSignature(
JSON.stringify(req.body), // raw payload string
req.headers['x-oak-signature'], // signature from header
process.env.WEBHOOK_SECRET!, // secret from register()
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
Verify and parse in one step
parseWebhookPayload combines signature verification with JSON parsing, returning a Result:
import { parseWebhookPayload } from '@oaknetwork/api';
const result = parseWebhookPayload<PaymentEvent>(
JSON.stringify(req.body),
req.headers['x-oak-signature'],
process.env.WEBHOOK_SECRET!,
);
if (!result.ok) {
return res.status(result.error.status).json({ error: result.error.message });
}
const event = result.value;
switch (event.event) {
case 'payment.completed':
// handle payment completion
break;
case 'payment.failed':
// handle payment failure
break;
}
res.json({ received: true });
Express.js example
import express from 'express';
import { parseWebhookPayload } from '@oaknetwork/api';
const app = express();
app.post('/webhooks/oak', express.raw({ type: 'application/json' }), (req, res) => {
const result = parseWebhookPayload(
req.body.toString(),
req.headers['x-oak-signature'] as string,
process.env.WEBHOOK_SECRET!,
);
if (!result.ok) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Handle the verified event
console.log('Received event:', result.value.event);
res.json({ received: true });
});
Always verify webhook signatures before processing payloads. Use
express.raw()(notexpress.json()) to preserve the raw body for signature verification.
Webhook data types
RegisterRequest
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The URL to receive webhook events |
description | string | No | Human-readable description |
Webhook data (response)
| Field | Type | Description |
|---|---|---|
id | string | Webhook ID |
url | string | Registered URL |
description | string | Description |
secret | string | Signing secret (only on register) |
is_active | boolean | Whether the webhook is active |
Notification
| Field | Type | Description |
|---|---|---|
id | string | Notification ID |
event | string | null | Event type |
category | string | null | Event category |
data | any | Event payload |
is_acknowledged | boolean | Whether the notification was acknowledged |