Receive real-time notifications when events happen in your Expereon account.
Instead of polling the API for changes, configure webhook endpoints to receive HTTP POST requests whenever invoices, payments, or other resources change state.
Create a webhook endpoint via the API or the Expereon dashboard:
curl -X POST "https://api.expereon.org/api/v1/settings/webhooks" \
-H "X-API-Key: exp_prod_xxxxxxxxxxxx" \
-H "X-API-Secret: your-secret-key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/expereon",
"eventTypes": ["BOOKING_CREATED", "BOOKING_UPDATED", "PAYMENT_COMPLETED"],
"authMethod": "NONE",
"signingSecret": "whsec_your_secret_here"
}'
authMethod is one of NONE, BASIC_AUTH, or API_KEY.
BASIC_AUTH and API_KEY additionally require an auth header name and value.
The optional signingSecret field is independent of authMethod and can be
set alongside any of the three to enable payload signature verification.
2xx status within 10 seconds
You can register a webhook using a sandbox API key against the same
api.expereon.org host the same way you would in production - sandbox is a
key-prefix on the same host, not a separate host.
environment
field - this is not yet modeled. The sandbox reset endpoint
(POST /api/v1/settings/api-keys/sandbox/reset) does not remove your
webhook registrations; it only clears sandbox API keys, sandbox logs, sandbox
invoices, and sandbox bookings.
| Event | Description |
|---|---|
BOOKING_CREATED | A new booking was created |
BOOKING_UPDATED | A booking was updated |
PAYMENT_COMPLETED | A payment was successfully processed |
DISPUTE_INITIATED | Buyer raised a dispute on the invoice |
Every webhook delivery is a JSON POST request with a flat body keyed by event
(not a nested envelope). The event name is also sent in the X-Expereon-Event header.
{
"event": "BOOKING_CREATED",
"bookingId": "bk_xyz789",
"bookingReference": "BK-2024-001",
"status": "CONFIRMED",
"totalPrice": "1500.00",
"currency": "USD"
}
Every webhook request includes an X-Webhook-Signature header with the value
sha256=<base64-signature>, an HMAC-SHA256 signature of the request body,
base64-encoded, using your signing secret.
// Node.js example
const crypto = require('crypto');
function verifyWebhook(body, signatureHeader, secret) {
const signature = signatureHeader.replace(/^sha256=/, '');
const expected = crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('base64');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhooks/expereon', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const isValid = verifyWebhook(req.rawBody, signature, 'whsec_your_secret');
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
switch (event.event) {
case 'BOOKING_CREATED':
// Handle new booking
break;
case 'PAYMENT_COMPLETED':
// Handle completed payment
break;
}
res.status(200).send('OK');
});
If your endpoint fails to respond with 2xx, Expereon retries with geometric
backoff: 5 minutes * 2^n (5, 10, 20, 40 minutes, ...), bounded by a 24-hour
maximum delivery lifetime. After 24 hours, the delivery is marked as failed.
Use the test endpoint to send a sample event to your webhook:
curl -X POST "https://api.expereon.org/api/v1/settings/webhooks/{webhookId}/test" \
-H "X-API-Key: exp_prod_xxxxxxxxxxxx" \
-H "X-API-Secret: your-secret-key"
This sends {"event": "test", "message": "Webhook test from Expereon"} to your
endpoint. Use this to verify your handler and signature validation work correctly.
200 OK immediately, then process the event asynchronouslyX-Webhook-Signature before processing