Consume webhooks
Receive payment status updates, handle retries, and keep your handler idempotent.
Whenever a payment's status changes, ARYZE POSTs a JSON body to the webhook URL
configured on your API key. There is one event type today:
payment.status_updated.
Configure your webhook URL
Webhook URLs are set per API key in the dashboard at Open Finance → API Keys. You can update the URL without rotating the key. The endpoint must be HTTPS and reachable from the public internet — non-HTTPS URLs are rejected on save.
Event shape
{
"event": "payment.status_updated",
"transactionId": "2f1a3e8c-9b7d-4a11-8c6f-d3e5e9b1a2c0",
"mastercardPaymentId": "mcob_8f3c2a...",
"status": "COMPLETED",
"amount": 100.50,
"currencyCode": "EUR",
"timestamp": "2026-04-21T14:32:10Z"
}Prop
Type
Your merchant reference and any metadata you sent on POST /v1/payments/initiate
are not included in the webhook. Look them up by transactionId against
your own store — you should have saved them when you created the payment.
Acknowledge quickly, process later
Return 200 OK as soon as you've persisted the event. Do the real work
(fulfilment, emails, accounting) in a background job. ARYZE treats any non-2xx
response as failure and retries.
import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhooks/aryze', async (req, res) => {
const event = req.body;
try {
await saveEventIfNew(event); // idempotency check
res.status(200).json({ received: true });
} catch (err) {
console.error('Webhook persistence failed', err);
res.status(500).json({ error: 'retry please' });
return;
}
// Off the request path — don't await this.
enqueueFulfilmentJob(event).catch(console.error);
});
app.listen(3000);Idempotency
ARYZE may deliver the same event more than once (retries, network retransmits,
or the same transaction moving through the same terminal state). Store each
event by transactionId + status and skip work you've already done.
async function saveEventIfNew(event: WebhookEvent) {
const key = `${event.transactionId}:${event.status}`;
const inserted = await db.webhookEvents.insert({
key,
payload: event,
receivedAt: new Date(),
}).onConflict('key').ignore();
if (!inserted) throw new DuplicateEvent(key);
}Retry policy
If your endpoint doesn't return a 2xx response within 10 seconds, ARYZE retries.
Prop
Type
There is no HMAC signature on webhook requests today. Until signing is
available, use an unguessable webhook URL (for example, include a long random
segment) and cross-check every event by fetching the transaction with
GET /v1/payments/{transactionId} before acting on it.