Webhooks
Receive real-time notifications about payment events
Overview#
Webhooks allow you to receive real-time notifications when events occur in your Yassir Payment account. Instead of polling our API for updates, we push event data to your server as they happen.
When you create a service during onboarding, you provide a webhookUrl. Yassir will send a POST request to this URL whenever a payment event occurs.
When Webhooks Fire#
Webhooks are sent after the following events:
| Event | Description |
|---|---|
| Proceed (success) | Payment completed successfully via Yassir Cash |
| Proceed (failure) | Payment was rejected (e.g., insufficient balance) |
| Pre-authorization | Funds were successfully reserved |
| Capture | Reserved funds were captured (full or partial) |
| Release | Reserved funds were released back to the user |
| Refund | A full or partial refund was processed |
Webhook Payload#
All webhook events are sent as a POST request with a JSON body in the following format:
{
"actionId": "order_12345",
"remoteStatus": "The amount was deposited successfully",
"remoteStatusCode": 2,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}{
"actionId": "order_12345",
"remoteStatus": "The amount was deposited successfully",
"remoteStatusCode": 2,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}Payload Fields#
| Field | Type | Description |
|---|---|---|
actionId | string | Your unique identifier from the original payment intent (e.g., your order ID) |
remoteStatus | string | Human-readable status message |
remoteStatusCode | number | Numeric status code (see table below) |
contextType | string | Always "ORDER" |
orderId | string | The Yassir payment ID |
additionalData | object | Additional data (may be empty) |
Status Codes (remoteStatusCode)#
| Code | Status | Description |
|---|---|---|
2 | Succeeded | Payment completed or captured successfully |
3 | Rejected | Payment was rejected by the provider |
4 | Refunded | A refund was processed — full or partial. The code is the same for both; query the payment to compare the refunded amounts. |
10 | Reversed / Released | Pre-authorized funds were released |
13 | Pre-Authorized | Funds reserved, awaiting capture or release |
14 | Auto-Refunded | An automatic refund was processed |
Example Payloads#
// Payment succeeded
{
"actionId": "order_12345",
"remoteStatus": "The amount was deposited successfully",
"remoteStatusCode": 2,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}// Payment succeeded
{
"actionId": "order_12345",
"remoteStatus": "The amount was deposited successfully",
"remoteStatusCode": 2,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}// Pre-authorization completed
{
"actionId": "order_12345",
"remoteStatus": "Pre-authorized",
"remoteStatusCode": 13,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}// Pre-authorization completed
{
"actionId": "order_12345",
"remoteStatus": "Pre-authorized",
"remoteStatusCode": 13,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}// Refund processed — full and partial refunds both emit code 4.
// Query the payment to compare refundedAmount vs transactionAmount.
{
"actionId": "order_12345",
"remoteStatus": "Transaction was refunded",
"remoteStatusCode": 4,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}// Refund processed — full and partial refunds both emit code 4.
// Query the payment to compare refundedAmount vs transactionAmount.
{
"actionId": "order_12345",
"remoteStatus": "Transaction was refunded",
"remoteStatusCode": 4,
"contextType": "ORDER",
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"additionalData": {}
}Setting Up Webhooks#
Configure your endpoint
Create an HTTP endpoint on your server to receive webhook events. The endpoint must be publicly accessible and use HTTPS.
Register the webhook URL
Provide your webhook URL as the webhookUrl when creating your service during merchant onboarding. All payment events for that service will be sent to this URL.
Handle events
Process the webhook event and return a 2xx response:
app.post('/webhooks/yassir', async (req, res) => {
const event = req.body;
switch (event.remoteStatusCode) {
case 2: // Succeeded
await handlePaymentSuccess(event.actionId, event.orderId);
break;
case 3: // Rejected
await handlePaymentFailure(event.actionId);
break;
case 4: // Refunded (full or partial — fetch the payment for the amounts)
await handleRefund(event.actionId);
break;
case 10: // Released
await handleRelease(event.actionId);
break;
case 13: // Pre-authorized
await handlePreAuth(event.actionId, event.orderId);
break;
case 14: // Auto-refunded
await handleRefund(event.actionId);
break;
}
res.status(200).send('OK');
});app.post('/webhooks/yassir', async (req, res) => {
const event = req.body;
switch (event.remoteStatusCode) {
case 2: // Succeeded
await handlePaymentSuccess(event.actionId, event.orderId);
break;
case 3: // Rejected
await handlePaymentFailure(event.actionId);
break;
case 4: // Refunded (full or partial — fetch the payment for the amounts)
await handleRefund(event.actionId);
break;
case 10: // Released
await handleRelease(event.actionId);
break;
case 13: // Pre-authorized
await handlePreAuth(event.actionId, event.orderId);
break;
case 14: // Auto-refunded
await handleRefund(event.actionId);
break;
}
res.status(200).send('OK');
});Best Practices
- Respond to webhooks within 30 seconds
- Process webhook data asynchronously for long operations
- Handle duplicate events using idempotency (use
actionId+remoteStatusCodeas a key) - Always use the
remoteStatusCode(not the text status) for programmatic logic