> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payglocal.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment Response Handling

> Understanding how PayGlocal sends payment responses to your system.

## Payment Callback Flow

After a user completes a payment, PayGlocal sends the transaction response to the callback URL provided by the merchant during payment creation. This allows the merchant system to receive the payment result, process the transaction status, and redirect or display the appropriate success or failure page to the user.

The response is sent as an **HTTP POST request** containing the payment details in encoded format.

***

## Overview

<CardGroup cols={3}>
  <Card title="HTTP POST Request" icon="arrow-up-from-bracket" color="#1A6FE8">
    PayGlocal sends payment results via HTTP POST to your configured `merchantCallbackURL`.
  </Card>

  <Card title="Encoded Token" icon="lock" color="#10B981">
    Payment data is sent as `x-gl-token` — a base64url encoded JWT containing the full transaction result.
  </Card>

  <Card title="Decode & Process" icon="code" color="#F59E0B">
    Extract, decode, and parse the token to access payment details and redirect the user accordingly.
  </Card>
</CardGroup>

***

## What Happens Internally — Step by Step

<Steps>
  <Step title="Payment Request Created">
    You send a payment initiation request to PayGlocal along with the `merchantCallbackURL` — a POST endpoint on your backend that you create yourself.
  </Step>

  <Step title="Customer Completes Payment">
    The customer completes (or abandons) the payment on the PayGlocal payment page.
  </Step>

  <Step title="PayGlocal Processes the Transaction">
    Once the transaction is processed, PayGlocal prepares the payment response containing the transaction status, amount, currency, transaction ID, payment method, and card or network details.
  </Step>

  <Step title="PayGlocal Sends Callback">
    PayGlocal fetches the `merchantCallbackURL` from the original request and sends an HTTP POST to that endpoint. The callback contains the encoded transaction response in the `x-gl-token` field.
  </Step>

  <Step title="Your Backend Receives and Processes">
    Your backend receives the callback at the configured endpoint. You decode the token, read the payment status, and decide what to show the user — a success page, failure page, or any other experience you choose.
  </Step>
</Steps>

***

## Implementation

### 1. Include `merchantCallbackURL` in Your Payment Request

Add `merchantCallbackURL` to your payment payload — this is where PayGlocal will POST the result after the transaction completes.

```json theme={null}
{
  "merchantTxnId": "23AEE8CB6B62EE2AF07",
  "paymentData": {
    "totalAmount": "15",
    "txnCurrency": "USD"
  },
  "merchantCallbackURL": "https://your-website-domain.com/payments/merchantCallback"
}
```

<Note>
  Must be a publicly accessible **HTTPS POST endpoint**. PayGlocal cannot reach localhost or private IPs.
</Note>

***

### 2. Receive, Decode, and Handle the Callback

Once the payment completes, PayGlocal POSTs to your callback URL with a single field in the body — `x-gl-token`. This token is a **JWT** (three dot-separated parts: Header · Payload · Signature). The payment data lives in the **Payload** section, encoded in base64url.

Here is what the raw token looks like when it arrives. It has **three dot-separated parts**, each shown in a different color:

<div style={{fontFamily: 'monospace', wordBreak: 'break-all', fontSize: '0.82em', lineHeight: '2', padding: '20px', background: '#0d1117', borderRadius: '8px', border: '1px solid #30363d'}}>
  <span style={{color: '#f7615f'}}>eyJpc3N1ZWQtYnkiOiJHbG9jYWwiLCJpcy1kaWdlc3RlZCI6ImZhbHNlIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJrSWQtRU5oN3Y1bDdTNE56YjhScCJ9</span><span style={{color: '#8b949e'}}>.</span><span style={{color: '#79c0ff'}}>eyJ4LWdsLW9yZGVySWQiOiJnbF9vLTlmY2QzYTY3YTUwNDUxODczdzNyMFBwWDIiLCJhbXBsaWZpZXItbWlkIjpudWxsLCJpYXQiOiIxNzc4OTY0MzQ4MzQ5IiwieC1nbC1lbmMiOiJ0cnVlIiwieC1nbC1naWQiOiJnbF85ZmNkM2E2N2E1MDQ1MTg3NzE2dzNyMFBwWDIiLCJ4LWdsLW1lcmNoYW50SWQiOiJ0ZXN0bmV3Z2NjMjYifQ</span><span style={{color: '#8b949e'}}>.</span><span style={{color: '#d2a8ff'}}>K6Xiu7zld57xkYZ1JkfvyzQouiWW1shKjftVbDbGBp5h-E-1YazfZqBM7wk3ubH3HxtpMUa4FClconTQCvlhSkNmWmU\_D8IU8tMpToUU8nHs7ZEOa\_GXT5GBvvkC\_\_ixg\_a6MQHbSu4CWPXZsZWUXnJHNj1IcS06gxGdvj8-84F-Rj8WiMkSgCI23Ac\_N4bqywzebbm3bSjY-aPzVa9s79y\_XbKbguxIaHAZdoRSE2rQp4i4J9JQedXjYtaCP\_Bqv5W9fHP42rytBTsX7ZnTxW9oUYU999VP6rYc2wMfTVWzpa2rm40Ps53Z9PvDCQmzcJsQdm6HWw894pUuCF1xCQ</span>
</div>

**What each part means:**

| Part       | Color     | Name          | What it contains                                                                                                                     |
| ---------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Part 1** | 🔴 Red    | **Header**    | Token metadata — signing algorithm (`RS256`) and the Key ID (`kid`) used to sign                                                     |
| **Part 2** | 🔵 Blue   | **Payload**   | **Your payment data** — transaction status, amount, `gid`, `merchantId`, and all other response fields. This is the part you decode. |
| **Part 3** | 🟣 Purple | **Signature** | Cryptographic signature — proves the token was issued by PayGlocal and has not been tampered with                                    |

<Note>
  The **middle part (Payload)** is where all the transaction data lives. Split the token on `.` and take index `[1]` to get this section, then base64url-decode it to read the payment result.
</Note>

Your callback endpoint decodes it in the following sequence:

**Extract the token** from the incoming request body:

```javascript theme={null}
const glToken = req.body['x-gl-token'];
```

**Split on `.`** — take the middle section (index 1), which is the Payload:

```javascript theme={null}
const base64UrlPayload = glToken.split('.')[1];
```

**Convert base64url → base64** by swapping `-` with `+` and `_` with `/`:

```javascript theme={null}
const base64Payload = base64UrlPayload.replace(/-/g, '+').replace(/_/g, '/');
```

**Decode to a UTF-8 string:**

```javascript theme={null}
const decodedString = Buffer.from(base64Payload, 'base64').toString('utf-8');
```

**Parse into a usable object:**

```javascript theme={null}
const paymentData = JSON.parse(decodedString);
```

After parsing, `paymentData` looks like this:

```json theme={null}
{
  "country": "UNITED KINGDOM",
  "amount": "48",
  "gid": "PGL_7F8A9B3C2D1E4F5A",
  "merchantId": "MERCH_9X8Y7Z6W5V4U3T",
  "cardType": "PREPAID",
  "merchantTxnId": "TXN_4K5L6M7N8O9P0Q",
  "paymentMethod": "CARD",
  "currency": "USD",
  "cardBrand": "VISA",
  "status": "SENT_FOR_CAPTURE"
}
```

***

### 3. Act on the Status

There is exactly **one success status**: `SENT_FOR_CAPTURE`. Every other status means the transaction did not complete.

Once decoded, PayGlocal hands control entirely back to you — you decide what the customer sees next. There is no fixed redirect or page; you build and control the experience.

**If `status === "SENT_FOR_CAPTURE"` → Payment successful:**
Mark the order as paid in your database, send a confirmation email, and redirect the customer to your success page.

**If `status` is anything else → Payment failed:**
Mark the order as failed and redirect the customer to your failure or retry page.

***

## Payment Status Reference

| Status               | Meaning                                   | Result    |
| -------------------- | ----------------------------------------- | --------- |
| `SENT_FOR_CAPTURE`   | Payment successful — funds captured       | ✅ Success |
| `AUTHORIZED`         | Funds held, capture pending               | ⏳ Pending |
| `ISSUER_DECLINE`     | Card declined by the issuing bank         | ❌ Failure |
| `GENERAL_DECLINE`    | Declined by PayGlocal risk engine         | ❌ Failure |
| `CUSTOMER_CANCELLED` | Customer cancelled on the payment page    | ❌ Failure |
| `ABANDONED`          | Customer left without completing payment  | ❌ Failure |
| `REQUEST_ERROR`      | Field-level error in the original request | ❌ Failure |

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Decode Before Trusting" icon="shield-check" color="#1A6FE8">
    Never act on the raw POST body. Always decode `x-gl-token` and read `status` before updating your database or redirecting the user.
  </Card>

  <Card title="Use gid as Source of Truth" icon="magnifying-glass" color="#10B981">
    If the callback is delayed or missed, use the [Status Check](/merchant/regular-payment/transaction-management) API with `gid` to fetch the current status.
  </Card>

  <Card title="Prevent Duplicate Processing" icon="clone" color="#F59E0B">
    Check `merchantTxnId` before updating order status — callbacks can occasionally arrive more than once.
  </Card>

  <Card title="Log Every Callback" icon="file-lines" color="#8B5CF6">
    Store the raw token and decoded payload for debugging, auditing, and reconciliation.
  </Card>
</CardGroup>

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bell" href="/merchant/webhooks">
    Server-to-server notifications that arrive independently of the browser callback.
  </Card>

  <Card title="Status Check" icon="magnifying-glass" href="/merchant/regular-payment/transaction-management">
    Verify any payment status server-side at any time using the gid.
  </Card>

  <Card title="Node.js Implementation" icon="node-js" href="/api-reference/callback-handling">
    Complete Node.js code for your `merchantCallbackURL` endpoint — ready to adapt and use.
  </Card>
</CardGroup>
