PayOrc
Webhook

Webhooks Notification

Set up webhook notifications for payment events — real-time order status updates delivered to your server.

Webhooks Notification

Version: 3.0.0

Automate your Online integration with web-hook data and eliminate manual order management effort in the process.

Webhook Flow

Enabling Webhooks

In your PayOrc dashboard, configure the following:

  • Enable/Disable — Toggle webhook notifications on or off.
  • URL — The fully qualified (secure) URL on your server to which web-hook data will be posted.
  • notification-secret — Your secret will be posted in the header for additional security.

Your webhook endpoint should respond with a 200 OK status code to acknowledge receipt. If the webhook delivery fails, PayOrc may retry the delivery.

Webhook Event Types

The following event types trigger webhook notifications:

Event TypeDescription
AUTHTransaction authorized — funds reserved but not yet captured
AUTH_REVERSALCard tokenization (Add Card) — authorization voided; m_payment_token returned
AWAIT_3DSWaiting for 3D Secure authentication from the customer
CAPTUREFunds have been captured and debited from the customer's account
PARTIALLY_CAPTUREDA portion of the authorized amount has been captured
REFUNDFull refund processed — funds returned to the customer
PARTIALLY_REFUNDEDA portion of the captured amount has been refunded
VOIDTransaction voided — the authorization has been cancelled
FAILEDTransaction failed due to decline, insufficient funds, or other error
EXITOrder timeout — the order was pending for 30+ minutes without completion
INVOICE_CREATEDInvoice created for SADAD bank transfer payments
CANCELOrder cancelled by the merchant or system
TIMEOUTTransaction timeout — the processing window expired

Processing Logic

Use the action and status fields to determine how to update your order:

SUCCESS ORDER:

if(action==AUTH and status==SUCCESS)
{
  //update order as AUTHORISED and ready to capture
}
if(action==CAPTURE and status==SUCCESS)
{
  //update order as CAPTURED
}

FAILED ORDER:

if(action==AUTH and status==FAILED)
{
  //update order as FAILED
}
if(action==CAPTURE and status==FAILED)
{
  //update order as FAILED
}

AWAIT_3DS:

if(action==AWAIT_3DS and status==SUCCESS)
{
  //update order as AWAIT_3DS
}

REFUND SUCCESS:

if(action==REFUND and status==SUCCESS)
{
  //update order as REFUNDED
}

REFUND FAILED:

if(action==REFUND and status==FAILED)
{
  //send mail to customer
}

AUTH REVERSAL (Add Card) SUCCESS:

if(action==AUTH_REVERSAL and status==SUCCESS)
{
  // store m_payment_token for Pay by Token (CAUTH)
}

parameters and custom_data are arrays of single-key objects (alphaepsilon). Values are echoed from order create when provided; otherwise each value is typically an empty string "".

Webhook Payload Structure

Every webhook notification contains the following JSON payload:

{
    "action": "AUTH",
    "status": "SUCCESS",
    "order_status": "AUTHORISED",
    "m_order_id": "your-order-123",
    "p_order_id": "1000010108",
    "p_request_id": "1000013993",
    "psp_ref_id": "8902217",
    "transaction_id": "1000010658",
    "is_live": false,
    "terminal_label": "paymob-terminal-01",
    "remark": "",
    "reason": "",
    "currency": "AED",
    "amount": "280.00",
    "channel": "ORD API",
    "channel_id": "PL-001",
    "shipping_fee": "30.00",
    "convenience_fee": "50.00",
    "customer_details": {
        "name": "John Doe",
        "email": "[email protected]",
        "code": "91",
        "mobile": "9876543210",
        "m_customer_id": "CUST-001"
    },
    "billing_address": {
        "address_line_1": "123 Main Street",
        "address_line_2": "",
        "city": "Springfield",
        "state": "",
        "country": "US",
        "pincode": ""
    },
    "shipping_address": {
        "address_line_1": "456 Ship Ave",
        "address_line_2": "",
        "city": "Springfield",
        "state": "",
        "country": "US",
        "pincode": ""
    },
    "ip_country": "AE",
    "psp": "PAYMOB",
    "payment_method": "DEBIT CARD",
    "m_payment_token": "ZXh...",
    "transaction_time": "16-02-2026 12:57:58",
    "payment_method_data": {
        "scheme": "VISA",
        "card_country": "POLAND",
        "card_type": "DEBIT",
        "mask_card_number": "4111****1111",
        "expiry_month": "12",
        "expiry_year": "2045"
    },
    "apm_name": "",
    "apm_identifier": "",
    "sub_merchant_identifier": "0000001181",
    "parameters": [
        { "alpha": "" },
        { "beta": "" },
        { "gamma": "" },
        { "delta": "" },
        { "epsilon": "" }
    ],
    "custom_data": [
        { "alpha": "" },
        { "beta": "" },
        { "gamma": "" },
        { "delta": "" },
        { "epsilon": "" }
    ]
}

For Add Card (AUTH REVERSAL), the same payload shape is used with action: "AUTH_REVERSAL" and a non-empty m_payment_token when tokenization succeeds.

Payload Fields Reference

FieldTypeDescription
actionStringTransaction action that triggered the webhook. Examples: AUTH, AUTH_REVERSAL, AWAIT_3DS, CAPTURE, REFUND, VOID, EXIT, INVOICE_CREATED, CANCEL, TIMEOUT, FAILED, SALE (channel-dependent).
statusStringOverall transaction execution status. Will be "SUCCESS" for all cases (AUTHORISED, AWAIT_3DS, CAPTURED, REFUNDED, VOID, EXIT, INVOICE_CREATED, TIMEOUT, CANCELLED, PARTIALLY_CAPTURED, PARTIALLY_REFUNDED) OR "FAILED" only when the transaction failed. Even statuses like EXIT, TIMEOUT, CANCELLED, AWAIT_3DS, and INVOICE_CREATED will have status "SUCCESS". Only when order_status is "FAILED" will status be "FAILED".
order_statusStringDetailed order status from the system. Provides the specific state of the order. Possible values: AUTHORISED, AWAIT_3DS, CAPTURED, REFUNDED, PARTIALLY_CAPTURED, PARTIALLY_REFUNDED, VOID, FAILED, CANCELLED, TIMEOUT, EXIT, INVOICE_CREATED. This is the detailed status that shows exactly what happened with the order.
m_order_idStringOrder ID provided by the merchant.
p_order_idStringOrder ID generated by the PayOrc platform.
p_request_idStringUnique PayOrc ID for the transaction event.
psp_ref_idStringReference ID received from the PSP.
transaction_idStringUnique PayOrc transaction identifier for follow-up actions.
is_liveBooleanIndicates whether the transaction was processed in live mode.
terminal_labelStringTerminal label or identifier used for processing the transaction.
currencyStringTransaction currency (ISO 4217).
amountStringTransaction amount (e.g. "1.00").
shipping_feeStringShipping charges applied to the transaction.
convenience_feeStringConvenience or service fee applied to the transaction.
channelStringPayment initiation channel.
channel_idStringUnique identifier of the channel (e.g., payment link ID).
customer_detailsObjectCustomer information provided during order creation.
customer_details.nameStringCustomer full name.
customer_details.emailStringCustomer email address.
customer_details.codeStringCountry calling code of the customer.
customer_details.mobileStringCustomer mobile number.
customer_details.m_customer_idStringMerchant-side customer identifier.
billing_addressObjectBilling address of the customer.
billing_address.address_line_1StringBilling address line 1.
billing_address.address_line_2StringBilling address line 2.
billing_address.cityStringBilling city.
billing_address.stateStringBilling state / province.
billing_address.countryStringBilling country code.
billing_address.pincodeStringBilling postal / ZIP code.
shipping_addressObjectShipping address of the customer (same keys as billing_address).
ip_countryStringCountry detected from the customer's IP address.
remarkStringAdditional remarks related to the transaction.
reasonStringFailure or informational reason code.
pspStringPayment service provider name.
payment_methodStringPayment method used by the customer.
m_payment_tokenStringPayment token generated for the transaction (important for AUTH REVERSAL / Add Card).
transaction_timeStringDate and time when the transaction was processed.
payment_method_dataObjectCard or payment instrument details.
payment_method_data.schemeStringCard scheme (e.g. VISA).
payment_method_data.card_countryStringCard issuing country.
payment_method_data.card_typeStringCard type (e.g. DEBIT, CREDIT).
payment_method_data.mask_card_numberStringMasked card number.
payment_method_data.expiry_monthStringCard expiry month (MM).
payment_method_data.expiry_yearStringCard expiry year (YYYY).
apm_nameStringName of the alternative payment method.
apm_identifierStringIdentifier for the alternative payment method.
sub_merchant_identifierStringSub-merchant identifier mapped with the PSP.
parametersArrayMerchant metadata echoed from order create — array of { "alpha" }{ "epsilon" } objects.
custom_dataArrayCustom data echoed from order create — same array shape as parameters.

Code Examples: Webhook Handler

const express = require('express');
const app = express();

app.post('/payorc/webhook', express.json(), (req, res) => {
  const { action, status, order_status, m_order_id, p_order_id, transaction_id } = req.body;

  console.log(`Webhook: ${action} | ${status} | Order: ${m_order_id}`);

  // Process based on action and status
  switch (action) {
    case 'AUTH':
      if (status === 'SUCCESS') {
        // Update order as AUTHORISED and ready to capture
        updateOrderStatus(m_order_id, 'AUTHORISED');
      } else {
        // Authorization failed
        updateOrderStatus(m_order_id, 'FAILED');
      }
      break;

    case 'AUTH_REVERSAL':
      if (status === 'SUCCESS') {
        // Store m_payment_token for Pay by Token (CAUTH)
        savePaymentToken(m_order_id, req.body.m_payment_token, req.body.customer_details?.m_customer_id);
      } else {
        updateOrderStatus(m_order_id, 'FAILED');
      }
      break;

    case 'CAPTURE':
      if (status === 'SUCCESS') {
        // Order captured — fulfill
        updateOrderStatus(m_order_id, 'CAPTURED');
      } else {
        updateOrderStatus(m_order_id, 'FAILED');
      }
      break;

    case 'AWAIT_3DS':
      // Customer is completing 3D Secure authentication
      updateOrderStatus(m_order_id, 'AWAIT_3DS');
      break;

    case 'REFUND':
      if (status === 'SUCCESS') {
        updateOrderStatus(m_order_id, 'REFUNDED');
      } else {
        // Refund failed — notify customer
        sendRefundFailedEmail(m_order_id);
      }
      break;

    case 'VOID':
      updateOrderStatus(m_order_id, 'VOID');
      break;

    case 'FAILED':
      updateOrderStatus(m_order_id, 'FAILED');
      break;

    case 'EXIT':
    case 'TIMEOUT':
    case 'CANCEL':
      updateOrderStatus(m_order_id, order_status);
      break;

    default:
      console.log(`Unhandled action: ${action}`);
  }

  // Always respond 200 OK quickly
  res.status(200).send('OK');
});

app.listen(3000, () => console.log('Webhook server running on port 3000'));

Best Practices

Idempotency: Always use the p_order_id or transaction_id from the webhook payload to check if you've already processed this event. Webhooks may be delivered more than once due to retries — your handler must be idempotent.

1. Process Async, Respond Fast

Your webhook endpoint should return a 200 OK within 5 seconds. Queue heavier processing (database updates, email notifications, inventory changes) to a background worker.

2. Implement Idempotency

Store processed webhook IDs (using p_request_id or transaction_id) to prevent duplicate processing.

3. Log Everything

Maintain a detailed log of every webhook received, including the full payload, timestamp, and processing result. This is invaluable for debugging and reconciliation.

4. Handle All Event Types

Even if you only expect certain events (e.g., AUTH and CAPTURE), always handle all event types gracefully. Unknown events should be logged but not cause errors.

5. Use HTTPS Only

Webhook URLs must use HTTPS. PayOrc will not deliver webhooks to HTTP endpoints to protect sensitive payment data in transit.

On this page