Webhooks
Listen for events from your Zoneless instance so your platform can automatically react to changes — such as when a connected account completes onboarding or a payout is sent.
Zoneless sends webhook events to your platform as HTTP POST requests containing a JSON Event object. This lets you respond to asynchronous events like account status changes, completed payouts, and new transfers without polling the API.
How it works
- Register a webhook endpoint URL via the Platform Dashboard or the Webhook Endpoints API.
- Zoneless sends a POST request to your URL whenever a subscribed event occurs.
- Your handler verifies the signature, processes the event, and returns a
2xxresponse.
Create a handler
Set up an endpoint that accepts POST requests with a JSON payload. Your handler should:
- Verify the webhook signature using the
Zoneless-Signatureheader. - Handle the event based on its
typefield. - Return a
2xxresponse quickly, before any complex processing.
import express from 'express';
import { Zoneless } from '@zoneless/node';
const app = express();
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');
const endpointSecret = 'whsec_z_...';
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['zoneless-signature'];
let event;
try {
event = zoneless.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.log('Webhook signature verification failed.', err.message);
return res.sendStatus(400);
}
switch (event.type) {
case 'checkout.session.completed':
const session = event.data.object;
// Fulfill the order
break;
case 'account.updated':
const account = event.data.object;
if (account.payouts_enabled) {
// The connected account has completed onboarding
}
break;
case 'payout.paid':
const payout = event.data.object;
// The payout was sent to the wallet
break;
case 'transfer.created':
const transfer = event.data.object;
// A transfer was created to a connected account
break;
default:
console.log('Unhandled event type', event.type);
}
res.json({ received: true });
});
app.listen(4242, () => console.log('Running on port 4242'));
Verify signatures
Zoneless signs every webhook event by including a signature in the Zoneless-Signature header. Always verify this signature to confirm the event was sent by your Zoneless instance and not a third party.
The header contains a timestamp (t) and a signature (v1). The signature is an HMAC-SHA256 hash of {timestamp}.{payload}, using the endpoint's signing secret as the key.
import express from 'express';
import { Zoneless } from '@zoneless/node';
const app = express();
const zoneless = new Zoneless('sk_live_z_YOUR_API_KEY', 'https://api.zoneless.com');
const endpointSecret = 'whsec_z_...';
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['zoneless-signature'];
let event;
try {
event = zoneless.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
res.status(400).send('Webhook Error: ' + err.message);
return;
}
// Handle the event
switch (event.type) {
case 'account.updated':
const account = event.data.object;
console.log('Account updated:', account.id);
break;
default:
console.log('Unhandled event type', event.type);
}
res.json({ received: true });
});
Event types
When registering a webhook endpoint, specify which event types to subscribe to. Use ["*"] to receive all events. See Types of events for the full list of available event types.
Retries
Zoneless does not currently retry failed webhook deliveries. If your endpoint returns a non-2xx response or is unreachable, the event will not be re-sent. Automatic retries with exponential backoff are a planned future addition.
In the meantime, you can use the Events API to list and retrieve events you may have missed.
Best practices
- Handle duplicate events. Log processed event IDs and skip duplicates. Use
data.object.idalong withevent.typeto identify unique events. - Only subscribe to events you need. Listening for all events puts unnecessary load on your server.
- Process events asynchronously. Push events onto a queue and process them in the background to handle traffic spikes.
- Use HTTPS in production. Your webhook endpoint must be publicly accessible over HTTPS in live mode.
- Verify every request. Always verify the
Zoneless-Signatureheader to confirm events originate from your Zoneless instance.
