Pine Labs Payment Protocol - Quickstart
Create agent-native payment experiences where AI agents securely discover, authorize, and complete paid API requests through a standardized machine payment protocol.
Build one paid endpoint first. The Server SDK protects the route and returns 402 until the Client retries with a payment credential. The Client SDK handles challenge parsing, token creation, retry, and receipt parsing.
Supported Payment Methods
1. UPI ReservePay (Available now) - Customer approves a mandate and every paid request debits the approved reserve.
2. Cards (Future scope) - P3P challenge and receipt stay the same; funding and capture become card-specific.
3. Crypto (Future scope) - P3P challenge and receipt stay the same; wallet, signature, and settlement behavior become rail-specific.
Payment Lifecycle
Setup Guide
Follow the below steps to integrate with Pine Labs payment protocol
- Configure Credentials
- Setup Customer Mandate
- Create a Paid Server Endpoint
- Call The Paid Resource
- Verify The Result
- Go Live
Prerequisites — Get Your API Credentials
Before you begin integrating, create your free Pine Labs Online developer account to get access to UAT credentials, API keys, and the merchant dashboard.
- Sign Up — Visit the Pine Labs Online Dashboard and register with your business email.
Create Account - Verify Your Email — Confirm your email address through the verification link sent to your inbox.
- Find Your Credentials — Once logged in, navigate to Settings → API Keys to generate your test-mode API key and secret.
- Copy both credentials — These are your PINELABS_CLIENT_ID and PINELABS_CLIENT_SECRET values. Store them securely — you will need them in the next step.

Do not expose PINELABS_CLIENT_SECRET in browser code. Use them only in backend services, agents, or server-side runtimes.
1. Configure Credentials
Set these environment variables in the backend runtime that owns the SDK calls:
PINELABS_CLIENT_ID="<<PINELABS_CLIENT_ID>>"
PINELABS_CLIENT_SECRET="<<PINELABS_CLIENT_SECRET>>"
PINELABS_CLIENT_ID and PINELABS_CLIENT_SECRET come from Pine Labs after merchant onboarding. Use sandbox credentials with P3PEnvironment.SANDBOX and production credentials with P3PEnvironment.PRODUCTION.
The server SDK derives the local P3P challenge HMAC key from PINELABS_CLIENT_SECRET internally. There is no separate challenge-signing value to configure or share.
2. Setup Customer Mandate
For the current UPI ReservePay rail, the customer must have an active mandate before paid requests can complete. Create that mandate with the server SDK before the client starts calling paid routes.
import {
Amount,
PaymentMethod,
PineLabsOnlineP3P
} from "@pine-labs-online/p3p-server-sdk";
const p3p = PineLabsOnlineP3P.create(config);
const mandate = await p3p.createMandate({
customerReference: "customer-ref-123",
mobileNumber: "9876543210",
amount: new Amount(100000, "INR"),
validityInDays: 20,
paymentMethod: PaymentMethod.UPI_RESERVE_PAY
});
The amount uses paise. 100000 means Rs 1,000.
The createMandate response includes a deep_link field — a UPI intent URL that the customer must approve in their UPI app. Follow these steps:
- Extract deep_link— Read deep_link from the create mandate response.
- Generate a QR code — Use any QR library (e.g. qrcode in Python, qrcode.react in JS) to encode the deep_link into a scannable QR.
- Display to customer — Show the QR code on your UI. The customer scans it with their UPI app to approve the mandate.
- Poll for activation — After the customer scans, poll the mandate status until it becomes ACTIVE.
3. Create a Paid Server Endpoint
import {
Amount,
ChargeOptions,
P3PEnvironment,
PaymentGateway,
PaymentMethod,
decidePayment
} from "@pine-labs-online/p3p-server-sdk";
const config = {
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
paymentGateway: PaymentGateway.PineLabsOnline,
availablePaymentMethods: [PaymentMethod.UPI_RESERVE_PAY],
env: P3PEnvironment.SANDBOX,
realm: P3PEnvironment.SANDBOX
};
export async function GET(request: Request) {
const decision = await decidePayment({
credentialHeader: request.headers.get("P3P-Credential") ?? undefined,
config,
chargeOptions: new ChargeOptions(
new Amount(10000, "INR"),
"/api/weather"
)
});
if (decision.action !== "proceed") {
return Response.json(decision.problemDetails, {
status: decision.status,
headers: decision.headers
});
}
return Response.json(
{ forecast: "Clear", paid: true },
{ headers: decision.headers }
);
}
decidePayment() wraps any route with the full challenge → verify → capture cycle. Define the price and resource path — the SDK handles the rest.
- config — Merchant credentials + environment
- chargeOptions — Price and resource path
- credentialHeader — Reads the P3P-Credential header (undefined on first call)
- decision.action !== "proceed" — Returns 402 challenge if credential missing/invalid
- action === "proceed" — Payment captured, return resource + receipt headers
4. Call The Paid Resource
import {
P3PCustomerAuthMode,
P3PEnvironment,
PaymentMethod,
PineLabsOnlineClient
} from "@pine-labs-online/p3p-client-sdk";
const client = PineLabsOnlineClient.create({
selectedPaymentMethod: PaymentMethod.UPI_RESERVE_PAY,
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
env: P3PEnvironment.SANDBOX
});
const response = await client.get(
"https://server.example.com/api/weather",
{},
{
customerReference: "customer-ref-123",
mobileNumber: "9876543210"
}
);
const receipt = response.headers.get("Payment-Receipt");
If the first request receives 402, the client SDK decodes the challenge, creates a one-time token, retries with P3P-Credential: Payment, and returns the final server response. Use client credentials in trusted backends or agents, and switch to customer-key mode when your integration is built around customer API tokens.
5. Verify The Result
An unpaid request must return:
HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment <challenge>
Content-Type: application/problem+json
Cache-Control: no-store
A paid request must return the protected response and Payment-Receipt. Store the receipt with your application-level order, usage, or audit record.
6. Go Live
Before production:
- Complete Pine Labs merchant onboarding.
- Move from sandbox credentials to production credentials.
- Confirm
PINELABS_CLIENT_SECRETis stored securely because it also derives the local challenge HMAC key. - Confirm mandate limits, refund behavior, and receipt storage with your Pine Labs integration owner.
