Refund Tracker

Track refund and partial refund decisions from the order.updated webhook event.

Use the refund_tracker array in the order.updated webhook event to track refund and partial refund decisions.

Refund Tracker Webhook

Amwal sends refund tracker updates in the order.updated webhook event. Your webhook handler should read data.refund_tracker to identify whether each refund record is pending, refunded, cancelled, or failed.

Store each refund tracker record against the related order in your system so your operations, support, or finance teams can track the refund lifecycle.

Event Fields

FieldTypeDescription
event_typestringThe webhook event name. For refund tracker updates, this is order.updated.
dataobjectThe order payload associated with the refund update.
data.refund_trackerarray | nullList of refund tracker records. It can be null when no refund tracker is available for the order.
data.refund_tracker[].idstringUnique identifier for the Amwal refund tracker record.
data.refund_tracker[].rrnstringBank Refund Reference Number returned for the refund tracker record.
data.refund_tracker[].amountstringRefund amount for this tracker record.
data.refund_tracker[].statusstringRefund decision status. Use this value to identify whether the refund is pending, refunded, cancelled, or failed.
data.refund_tracker[].gateway_key_typestringGateway key type returned for the refund tracker record.
data.refund_tracker[].gateway_transaction_idstringGateway transaction identifier returned for the refund record.

Refund Status Values

The data.refund_tracker[].status field can contain one of these values:

ValueStatusDescription
PPendingThe refund request is waiting for a final decision.
RRefundedThe refund was completed.
CCancelledThe refund was cancelled.
FFailedThe refund failed.

Refund Tracker Object Example

The refund_tracker field is returned as an array of refund status records.

"refund_tracker": [
  {
    "id": "9876",
    "rrn": "xxxx RRN Number xxxxx",
    "amount": "202.95",
    "status": "R",
    "gateway_key_type": "RefundReference",
    "gateway_transaction_id": "trx id"
  }
]
💡

Check the status field on each refund tracker record to determine your next action: wait on P, mark the refund complete on R, stop refund processing on C, and escalate failures on F.

Example Payload

The order.updated webhook includes the order or transaction payload in data. The sample below uses dummy data and shows a refund tracker where one refund record is completed and another is pending.

{
  "event_type": "order.updated",
  "data": {
    "id": "order_123456789",
    "ref_id": "merchant-order-1001",
    "status": "refunded",
    "type": "PRODUCTION",
    "amount": "250.00000",
    "discount": "25.00000",
    "shipping": "15.00000",
    "taxes": "10.00000",
    "total_amount": "250.00",
    "payment_amount": "250.00",
    "refunded_amount": "150.00",
    "fees": "0.00000",
    "amwal_fee": "2.50",
    "amwal_tax_vat": "0.38",
    "convenience_fee": "0.00",
    "merchant_payout": "97.12",
    "payment_method": "Card",
    "payment_option": "Pay In Full",
    "paymentBrand": "VISA",
    "funding_method": "credit",
    "card_type": "CREDIT",
    "card_last_4_digits": "1234",
    "card_payment_brand": "VISA",
    "issuer": "Demo Bank",
    "card_bank_issuer": "demo bank",
    "created_at": "2026-04-28T20:41:00.356051+03:00",
    "merchant_id": "merchant_123456789",
    "merchant_business_name": "Demo Store",
    "merchant_country_code": "SA",
    "store_domain": "https://demo-store.example.com",
    "client_email": "[email protected]",
    "client_first_name": "Example",
    "client_last_name": "Customer",
    "client_phone_number": "+966500000000",
    "refund_tracker": [
      {
        "id": "refund_tracker_1001",
        "rrn": "123456789012",
        "amount": "100.00",
        "status": "R",
        "gateway_key_type": "RefundReference",
        "gateway_transaction_id": "refund_trx_1001"
      },
      {
        "id": "refund_tracker_1002",
        "rrn": "123456789013",
        "amount": "50.00",
        "status": "P",
        "gateway_key_type": "RefundReference",
        "gateway_transaction_id": "refund_trx_1002"
      }
    ],
    "address_details": {
      "city": "Riyadh",
      "state": "Riyadh Province",
      "country": "SA",
      "street1": "Example Street",
      "postcode": "12345",
      "first_name": "Example",
      "last_name": "Customer",
      "email": "[email protected]"
    },
    "shipping_details": {
      "id": "standard_shipping:1",
      "tax": 1.5,
      "label": "Standard shipping",
      "price": 15
    },
    "is_refundable": false,
    "installment_tracker": null,
    "order_details": null,
    "failure_reason": null
  }
}

Use the exact data.refund_tracker[].status value from the payload when updating each refund record in your system. Other fields in data provide transaction, customer, merchant, payment, shipping, and refund context that you can store for reconciliation or support workflows.

Handle refund tracker updates

Use the refund_tracker array in your order.updated handler to process each refund decision and update your internal refund state.

async function handleOrderUpdated(webhook) {
  try {
    const refundTracker = webhook?.data?.refund_tracker;

    if (!Array.isArray(refundTracker)) {
      console.log('No refund tracker records found for this event.');
      return { status: 'ignored' };
    }

    if (refundTracker.length === 0) {
      console.log('Refund tracker is present but empty.');
      return { status: 'empty' };
    }

    for (const record of refundTracker) {
      switch (record.status) {
        case 'R':
          console.log(`Refund completed for tracker ${record.id}: ${record.amount}`);
          break;

        case 'C':
          console.log(`Refund cancelled for tracker ${record.id}`);
          break;

        case 'P':
          console.log(`Refund pending for tracker ${record.id}`);
          break;

        case 'F':
          console.error(`Refund failed for tracker ${record.id}`);
          break;

        default:
          console.warn(`Unknown refund status for tracker ${record.id}: ${record.status}`);
      }
    }

    return { status: 'processed', records: refundTracker.length };
  } catch (error) {
    console.error('Failed to process refund tracker:', error.message);
    return { status: 'error', message: error.message };
  }
}

const webhookPayload = {
  event_type: 'order.updated',
  data: {
    refund_tracker: [
      {
        id: '9876',
        rrn: 'xxxx RRN Number xxxxx',
        amount: '202.95',
        status: 'R',
        gateway_key_type: 'RefundReference',
        gateway_transaction_id: 'trx id'
      },
      {
        id: '9877',
        rrn: 'xxxx RRN Number yyyyy',
        amount: '50.00',
        status: 'P',
        gateway_key_type: 'RefundReference',
        gateway_transaction_id: 'trx id 2'
      }
    ]
  }
};

handleOrderUpdated(webhookPayload).then(result => {
  console.log('Processing result:', result);
});

Expected output:

Refund completed for tracker 9876: 202.95
Refund pending for tracker 9877
Processing result: { status: 'processed', records: 2 }

Recommended Processing

When you receive an order.updated event with refund tracker records:

  • Treat data.refund_tracker[].status as the source of truth for each refund decision.
  • Support the P, R, C, and F status values in your order management system.
  • Update each refund record independently because refund_tracker is an array and can contain multiple refund or partial refund records.
  • Mark a refund as completed only when the tracker status is R.
  • Keep the refund pending when the tracker status is P.
  • Stop refund processing when the tracker status is C.
  • Notify your support or operations team when the tracker status is F.
  • Keep the original webhook payload for audit and reconciliation.