---
title: Pay by Points — Integration Steps
slug: pay-by-points/integration-steps
excerpt: >-
  Step-by-step guide to integrate Pay by Points via Seamless Checkout using Pine
  Labs Online APIs.
hidden: false
sidebar_order: 2
sidebar_label: Integration Steps
metadata:
  title: Pay by Points Integration Steps — Seamless Checkout API | Pine Labs
  description: >-
    Integrate Pay by Points into custom checkout with Pine Labs APIs. Check
    point balance, create orders, process payments using reward points, and
    capture transactions with step-by-step guide.
  keywords: >-
    pay by points integration, reward points API, loyalty redemption, seamless
    checkout, point balance check, Pine Labs integration
  robots: index
---
## Integration Steps — Custom Checkout

Integrate Pay by Points into your custom checkout using Pine Labs Online APIs.

Follow these steps to enable customers to redeem reward points during payment.

1. [Generate Token](#generate-token)
2. [Check Point Balance](#check-point-balance)
3. [Create Order](#create-order)
4. [Create Payment](#create-payment)
5. [Handle Payment](#handle-payment)
6. [Capture Order](#capture-order)
7. [Cancel Order](#cancel-order-optional)


> **Note:**
> - Store your Client ID and Secret in your backend securely.
> - Integrate APIs on your backend system — never call from the frontend.
> - Seamless checkout requires PCI compliance.

---

<h2 id="generate-token">1. [Prerequisite] Generate Token</h2>

Generate an access token to authenticate all subsequent API calls.

**Endpoint:** `POST /api/auth/v1/token`

```bash
curl --location 'https://pluraluat.v2.pinepg.in/api/auth/v1/token' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'Request-Timestamp: 2024-07-09T07:57:08.022Z' \
--header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \
--data '{
  "client_id": "<your_client_id>",
  "client_secret": "<your_client_secret>",
  "grant_type": "client_credentials"
}'
```

Refer to the [Generate Token API](/api/authentication/generate-token) documentation for full request and response details.

---

<h2 id="check-point-balance">2. Check Point Balance</h2>

Query the customer's reward points balance before creating a payment.

**Endpoint:** `POST /payment-option`

```bash
curl --location 'https://pluraluat.v2.pinepg.in/payment-option' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
  "points_card_details": {
    "card_last4": "1234",
    "card_number": "4111111111111234",
    "registered_mobile_number": "9876543210"
  },
  "order_details": {
    "order_amount": {
      "value": 5000,
      "currency": "INR"
    }
  }
}'
```

The response includes:

| Field | Description |
|---|---|
| `points_balance` | Number of reward points available |
| `inr_equivalent` | Converted INR amount |
| `conversion_rate` | Points-to-INR rate |

> **Customer consent:** You must obtain explicit customer consent before proceeding to redeem points. This is mandatory per partner bank requirements.

---

<h2 id="create-order">3. Create Order</h2>

Create an order with `POINTS` included in the allowed payment methods.

**Endpoint:** `POST /api/pay/v1/orders`

```bash
curl --location 'https://pluraluat.v2.pinepg.in/api/pay/v1/orders' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \
--header 'Request-Timestamp: 2024-07-09T07:57:08.022Z' \
--data '{
  "merchant_order_reference": "PBP-12345",
  "order_amount": {
    "value": 4573,
    "currency": "INR"
  },
  "pre_auth": false,
  "allowed_payment_methods": [
    "CARD",
    "POINTS"
  ],
  "notes": "Pay by Points order",
  "callback_url": "https://your-domain.com/callback",
  "failure_callback_url": "https://your-domain.com/failure",
  "purchase_details": {
    "customer": {
      "email_id": "customer@example.com",
      "first_name": "Kevin",
      "last_name": "Bob",
      "customer_id": "CUST-001",
      "mobile_number": "9876543210",
      "country_code": "91"
    }
  }
}'
```

> Include `"POINTS"` in the `allowed_payment_methods` array to enable Pay by Points for this order.

Refer to the [Create Order API](/api/orders/create-order) documentation for the full parameter list.

---

<h2 id="create-payment">4. Create Payment</h2>

Submit a split payment with both CARD and POINTS components. The amounts must total the order value.

**Endpoint:** `POST /api/pay/v1/orders/{order_id}/payments`

```bash
curl --location 'https://pluraluat.v2.pinepg.in/api/pay/v1/orders/{order_id}/payments' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \
--header 'Request-Timestamp: 2024-07-09T07:57:08.022Z' \
--data '{
  "payments": [
    {
      "merchant_payment_reference": "pay-card-ref-001",
      "payment_method": "CARD",
      "payment_amount": {
        "value": 1372,
        "currency": "INR"
      }
    },
    {
      "merchant_payment_reference": "pay-points-ref-001",
      "payment_method": "POINTS",
      "payment_amount": {
        "value": 3201,
        "currency": "INR"
      },
      "points_card_details": {
        "card_last4": "1234",
        "card_number": "4111111111111234",
        "registered_mobile_number": "9876543210"
      }
    }
  ]
}'
```

### Split payment example

| Component | Amount | Description |
|---|---|---|
| Card | ₹13.72 | Paid via credit/debit card |
| Points | ₹32.01 | Redeemed from reward points |
| **Total** | **₹45.73** | Must match order amount |

> **Important:** The sum of all payment amounts must exactly equal the order amount. Mismatched amounts will cause the payment to fail.

Refer to the [Create Payment API](/api/card-payments/create-payment) documentation for all parameters.

---

<h2 id="handle-payment">5. Handle Payment</h2>

The Create Payment response returns a `challenge_url`. Redirect the customer to this URL to complete authentication.

### Redirect flow

1. Redirect the customer to `challenge_url`
2. Customer completes authentication on the bank page
3. Bank redirects back to your `callback_url` with payment details

### Callback response

On successful payment:

```json
{
  "order_id": "v1-4405071524-aa-qlAtAf",
  "payment_status": "AUTHORIZED",
  "signature": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
}
```

### Verify signature (mandatory)

Generate a SHA256 HMAC signature on your server and compare it with the returned signature.

**Signature string format:**

```
order_id=<order_id>&status=AUTHORIZED
```

**Signature verification (Java):**

```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class SignatureVerifier {
    public static String generateHash(String input, String secretKey) {
        try {
            byte[] keyBytes = new byte[secretKey.length() / 2];
            for (int i = 0; i < secretKey.length() / 2; i++) {
                keyBytes[i] = (byte) Integer.parseInt(
                    secretKey.substring(i * 2, (i * 2) + 2), 16
                );
            }
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(keySpec);
            byte[] hashBytes = mac.doFinal(input.getBytes("UTF-8"));

            StringBuilder hash = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) hash.append('0');
                hash.append(hex);
            }
            return hash.toString().toUpperCase();
        } catch (Exception e) {
            return "";
        }
    }
}
```

> **Security:** Always verify the signature before processing the order. This confirms the payment response is authentic and has not been tampered with.

---

<h2 id="capture-order">6. Capture Order</h2>

After successful payment and signature verification, capture the order to complete the transaction.

**Endpoint:** `PUT /api/pay/v1/orders/{order_id}/capture`

```bash
curl --location --request PUT \
'https://pluraluat.v2.pinepg.in/api/pay/v1/orders/{order_id}/capture' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \
--header 'Request-Timestamp: 2024-07-09T07:57:08.022Z'
```

> Capture is only available when the order status is `AUTHORIZED`.

---

<h2 id="cancel-order-optional">7. Cancel Order (optional)</h2>

Cancel an authorized order if you do not wish to capture the payment.

**Endpoint:** `PUT /api/pay/v1/orders/{order_id}/cancel`

```bash
curl --location --request PUT \
'https://pluraluat.v2.pinepg.in/api/pay/v1/orders/{order_id}/cancel' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \
--header 'Request-Timestamp: 2024-07-09T07:57:08.022Z'
```

> Cancel is only available when the order status is `AUTHORIZED`.

---

<h2 id="best-practices">Best Practices</h2>

| Practice | Detail |
|---|---|
| **Verify signature** | Always verify the callback signature using SHA256 HMAC — this is mandatory |
| **Fetch order status** | Use [Get Order API](/api/orders/get-order-by-id) from your backend to confirm the order status |
| **Configure webhooks** | Set up webhooks for real-time payment notifications |
| **Flexible JSON parsing** | Do not fail on unknown fields — new fields may be added without notice |
| **Avoid hardcoding** | Do not hardcode field values, response structures, or error codes |
| **TLS 1.2+** | All API calls must use TLS 1.2 or higher |
| **Sanity testing** | Test the complete flow on UAT before going live |

