# Shukria Payments — Integration Guide

Accept card payments on your site with one JavaScript call.

You integrate once. Shukria handles the connection to the payment networks, and that
connection can change without you changing anything — your code, your callbacks, and the
data you receive stay the same.

---

## Contents

- [Quick start](#quick-start)
- [Parameters](#parameters)
- [The payment result](#the-payment-result)
- [Checking payment status](#checking-payment-status)
- [Handling every outcome](#handling-every-outcome)
- [Going live](#going-live)
- [Postman collection](#postman-collection)
- [Troubleshooting](#troubleshooting)
- [Support](#support)

---

## Quick start

### 1. Include the widget

```html
<script src="https://shukriapg.ariticapp.com/pgpayments/shukria-payment-widget.js"></script>
```

### 2. Take a payment

```js
ShukriaPayment.process({
  merchantId:    'YOUR_MERCHANT_ID',
  merchantKey:   'YOUR_MERCHANT_KEY',

  amount:        6297.90,
  currency:      'AED',
  orderId:       'ORD_' + Date.now(),

  customerName:  'Meghana Rao',
  customerEmail: 'meghana@example.com',
  customerPhone: '+971501234567',

  returnUrl:     'https://yourshop.example/order/confirmation',

  onSuccess: function (result) {
    // result.status_code === 1200
    console.log('Paid', result.order_id, result.transaction_id);
  },

  onFailure: function (result) {
    console.log('Not paid', result.message);
  },

  onClose: function () {
    // Payer closed the payment window without finishing
  }
});
```

A secure payment window opens. When the payer finishes, your `onSuccess` or `onFailure`
callback receives the [result](#the-payment-result).

That is the entire integration.

---

## Parameters

### Required

| Parameter | Type | Notes |
|---|---|---|
| `merchantId` | string | Issued to you by Shukria |
| `merchantKey` | string | Issued to you by Shukria |
| `amount` | number | e.g. `6297.90` |
| `orderId` | string | **Your** order reference. Must be unique per payment attempt |
| `customerName` | string | |
| `customerEmail` | string | |
| `customerPhone` | string | |

### Optional

| Parameter | Type | Notes |
|---|---|---|
| `currency` | string | ISO code. Defaults to `AED` |
| `returnUrl` | string | Where the payer lands after paying. Strongly recommended — see [Handling every outcome](#handling-every-outcome) |
| `callbackUrl` | string | Your page to return to if the payer cancels |
| `customerId` | string | Your own customer reference |
| `logoUrl` | string | Your logo, shown on the payment page |
| `locationId`, `transactionLocation` | string | Store or branch, for your own reporting |

> [!IMPORTANT]
> **`orderId` must be unique per attempt.** If a payer retries after a decline, generate a
> new one. Reusing an order reference will cause the retry to be rejected.

---

## The payment result

Every outcome — callback, redirect, or status query — carries the same fields.

```json
{
  "status_code": 1200,
  "status": "success",
  "order_id": "ORD_1755512400000",
  "transaction_id": "TXN-88213-1",
  "amount": "6297.90",
  "currency": "AED",
  "message": "Payment successful",
  "timestamp": "2026-08-18T12:01:14Z",
  "approval_code": "OK1234",
  "masked_card": "512345xxxxxx0008"
}
```

| Field | Notes |
|---|---|
| `status_code` | **The field to branch on.** See below |
| `status` | `success` · `failed` · `pending` |
| `order_id` | Your order reference, exactly as you sent it |
| `transaction_id` | Payment reference. **Quote this in any support request** |
| `amount` | String with 2 decimal places |
| `message` | Human-readable outcome |
| `approval_code` | Present on approved payments |
| `masked_card` | Last four digits only. A full card number is never sent to you |

### Status codes

| Code | Status | Meaning | What to do |
|---|---|---|---|
| `1200` | `success` | Payment approved and funds captured | Fulfil the order |
| `1400` | `failed` | Declined, cancelled, or could not be completed | Invite the payer to retry |
| `1100` | `pending` | Not yet resolved | **Do not fulfil.** See below |

> [!WARNING]
> **`1100` is not a failure.** It means the payment has not finished processing — most often
> because the payer's bank is still confirming. It may still succeed.
>
> Do not mark the order failed and do not fulfil it. [Check the status](#checking-payment-status)
> after a short delay, or wait for the result to settle.

`status_code` is a **number**. If you compare it, compare against `1200`, not `"1200"`.

---

## Checking payment status

```
GET https://shukriapg.ariticapp.com/pgpayments/pay/status/{orderId}
```

Query with **your own order reference** — the `orderId` you sent.

```bash
curl -s "https://shukriapg.ariticapp.com/pgpayments/pay/status/ORD_1755512400000"
```

```json
{
  "success": true,
  "payment": {
    "status_code": 1200,
    "status": "success",
    "order_id": "ORD_1755512400000",
    "transaction_id": "TXN-88213-1",
    "amount": "6297.90",
    "currency": "AED",
    "message": "Payment successful",
    "approval_code": "OK1234",
    "masked_card": "512345xxxxxx0008"
  }
}
```

An unknown reference returns `404` with `{"success": false, "error": "not_found"}`.

**When to use it**

- The payer closed the tab and you never received a callback
- You received `1100` (pending) and need to resolve it
- Reconciling your orders at end of day

---

## Handling every outcome

A payer can close the tab, lose connectivity, or be interrupted mid-payment. Relying only
on the browser callback will eventually lose you a payment that actually succeeded.

Use both:

```js
ShukriaPayment.process({
  // ...
  returnUrl: 'https://yourshop.example/order/confirmation',

  onSuccess: function (result) {
    markOrderPaid(result.order_id, result.transaction_id);
  },

  onFailure: function (result) {
    if (result.status_code === 1100) {
      // Not resolved — do not fail the order
      markOrderPending(result.order_id);
    } else {
      markOrderFailed(result.order_id, result.message);
    }
  },

  onClose: function () {
    // The payer may still have paid. Confirm before deciding.
    checkStatusOnServer(currentOrderId);
  }
});
```

Your `returnUrl` receives the same fields as query parameters:

```
https://yourshop.example/order/confirmation
    ?status_code=1200&status=success&order_id=ORD_1755512400000
    &transaction_id=TXN-88213-1&amount=6297.90&currency=AED
```

> [!CAUTION]
> **Confirm payments on your server, not only in the browser.** Query parameters and
> JavaScript callbacks reach you through the payer's browser and can be altered. Before
> fulfilling an order, verify it with the [status endpoint](#checking-payment-status) from
> your back-end.

### Recommended order lifecycle

```
Customer pays  →  status 1200  →  verify on your server  →  fulfil
                  status 1400  →  invite retry with a NEW orderId
                  status 1100  →  hold; re-check status shortly
                  no response  →  check status before deciding
```

---

## Going live

1. Test with the credentials issued for testing, using the test cards supplied with them.
2. Confirm all three outcomes behave correctly in your integration: success, decline, and
   an abandoned payment.
3. Confirm your server verifies status independently of the browser.
4. Request live credentials.
5. Swap `merchantId` and `merchantKey`. **No other change is required.**

---

## Postman collection

[`Shukria-Payments.postman_collection.json`](Shukria-Payments.postman_collection.json)

Import it into Postman to try the API before writing any code. Three steps, in order:

1. **Check the integration** — confirms you can reach Shukria and your URL is right
2. **Take a payment** — generates an `orderId` and opens a payment page
3. **Confirm the outcome** — queries the status, and tells you what to do with it

Set `merchantId` and `merchantKey` after importing. Keep `merchantKey` in a Postman
*environment* rather than the collection, so it is not saved into a shared file.

The status requests check the response against everything documented above — the fields
present, `status_code` being a number, and that no full card number is ever returned.

---

## Troubleshooting

**The payment window does not open**
A required parameter is missing. Open the browser console — the widget logs exactly which.

**`onFailure` fires with no obvious reason**
Check `result.status_code`. If it is `1100` the payment is pending, not failed.

**The payer paid but I received nothing**
They likely closed the window before it returned. Query the
[status endpoint](#checking-payment-status) with your `orderId`.

**A retry is rejected**
Reusing an `orderId` from a previous attempt. Generate a new one per attempt.

**Amounts are rejected**
Send a number, not a formatted string — `6297.90`, not `"AED 6,297.90"`.

---

## Support

Contact Shukria with:

- Your `merchantId`
- The `orderId`
- The `transaction_id`, if you received one
- Approximate date and time, with timezone

Those four identify any payment.

> [!NOTE]
> Never send a full card number, CVV, or your `merchantKey` in a support request. Shukria
> will never ask for them.
