Node.js
Official TypeScript / Node.js SDK for the Pine Labs Online Payment Gateway — published on npm as pinelabs-node.
pinelabs-node is the official TypeScript / Node.js SDK for the Pine Labs Online Payment Gateway (Plural). It is generated from the same OpenAPI spec that powers this documentation, so every operation, request, and response model is fully typed.
- Package:
pinelabs-nodeon npm - Runtime: Node.js ≥ 18
- Module format: ESM-only
This package ships as ES modules. Use import from a project with "type": "module", or use dynamic import(). Calling require("pinelabs-node") in CommonJS will fail with ERR_PACKAGE_PATH_NOT_EXPORTED.
Install
npm install pinelabs-node
Quickstart
The Pine Labs API uses OAuth2 with the client_credentials grant. Exchange your client_id / client_secret for an access token, then pass it to PinelabsApiClient.
import { PinelabsApiClient } from "pinelabs-node";
const baseUrl = "https://pluraluat.v2.pinepg.in"; // UAT
// const baseUrl = "https://api.pluralpay.in"; // Production
// 1. Get a token (the auth call itself does not need a bearer token)
const auth = new PinelabsApiClient({ baseUrl, token: "" });
const tokenResponse = await auth.authentication.generateToken({
grant_type: "client_credentials",
client_id: process.env.PINELABS_CLIENT_ID!,
client_secret: process.env.PINELABS_CLIENT_SECRET!,
});
// 2. Build an authenticated client
const client = new PinelabsApiClient({
baseUrl,
token: tokenResponse.access_token,
});
// 3. Call any operation
const order = await client.orders.createOrder({
merchant_order_reference: "order-001",
order_amount: { value: 50000, currency: "INR" }, // ₹500.00
// ...see the API reference for the full schema
});
console.log(order);
Environments
| Environment | Base URL |
|---|---|
| UAT | https://pluraluat.v2.pinepg.in |
| Production | https://api.pluralpay.in |
Pass the URL via baseUrl. The exported PinelabsApiEnvironment enum currently only contains Production; for UAT, set baseUrl explicitly.
Auto-refreshing token
For long-running services, cache the token and refresh it before it expires. Pass a function instead of a string to token — it will be invoked on every request, including the auth call itself, so guard against re-entrancy:
import { PinelabsApiClient } from "pinelabs-node";
const baseUrl = "https://pluraluat.v2.pinepg.in";
const auth = new PinelabsApiClient({ baseUrl, token: "" });
let cached: { value: string; expiresAt: number } | undefined;
let fetching = false;
async function getToken(): Promise<string | undefined> {
// Re-entrancy guard: the auth endpoint itself doesn't need a token.
if (fetching) return undefined;
// Refresh ~30s before expiry
if (cached && Date.now() < cached.expiresAt - 30_000) {
return cached.value;
}
fetching = true;
try {
const r = await auth.authentication.generateToken({
grant_type: "client_credentials",
client_id: process.env.PINELABS_CLIENT_ID!,
client_secret: process.env.PINELABS_CLIENT_SECRET!,
});
cached = {
value: r.access_token,
expiresAt: Date.now() + r.expires_in * 1000,
};
return cached.value;
} finally {
fetching = false;
}
}
const client = new PinelabsApiClient({ baseUrl, token: getToken });
// Every call now picks up a fresh token automatically.
await client.orders.getOrderById({ order_id: "ord-123" });
Without the fetching flag the token supplier will recurse into itself when the auth call fires — your process will hang silently with no output and no error.
Sub-clients
PinelabsApiClient exposes one sub-client per API tag. All are lazy-loaded.
| Sub-client | Purpose |
|---|---|
client.authentication | OAuth token generation |
client.orders | Create, capture, cancel, and fetch orders |
client.refunds | Create and look up refunds |
client.settlements | Settlement reports + UTR lookup |
client.checkout | Hosted-checkout related operations |
client.paymentLinks | Single + bulk payment links |
client.cardPayments | Direct card payment + OTP flow |
client.bnpl | Buy-Now-Pay-Later eligibility and flows |
client.convenienceFee | Convenience-fee config and computation |
client.eChallans | Government e-challan integration |
client.applePay | Apple Pay session + decryption |
client.internationalPayments | Cross-border (DCC / MCC) payments |
client.customers | Customer profile management |
client.tokenization | Card / network tokenization |
client.payouts | Payouts: balance, create, cancel, list |
client.subscriptionsPlans | Recurring-billing plans |
client.subscriptionsSubscriptions | Subscription lifecycle |
client.subscriptionsPresentations | Subscription debit presentations |
client.payByPoints | Loyalty / points-based payments |
client.affordabilitySuite | EMI / offer eligibility |
client.splitSettlements | Split settlements between sub-merchants |
For the full operation list and request/response schemas, see the API reference.
Error handling
The SDK exports two typed error classes. Catch them to distinguish HTTP failures from network timeouts:
import {
PinelabsApiClient,
PinelabsApiError,
PinelabsApiTimeoutError,
} from "pinelabs-node";
try {
await client.orders.getOrderById({ order_id: "missing" });
} catch (err) {
if (err instanceof PinelabsApiError) {
console.error("HTTP", err.statusCode, err.body);
} else if (err instanceof PinelabsApiTimeoutError) {
console.error("Request timed out");
} else {
throw err;
}
}
PinelabsApiError exposes statusCode, body (parsed JSON when the server returns JSON), and headers.
Per-request options
Every operation accepts an optional second argument for ad-hoc overrides:
await client.orders.createOrder(
{ merchant_order_reference: "order-002", order_amount: { value: 1000, currency: "INR" } },
{
timeoutInSeconds: 10,
maxRetries: 0,
abortSignal: AbortSignal.timeout(8000),
headers: { "x-correlation-id": "req-abc" },
},
);
Useful for per-call timeouts, propagating trace IDs, or disabling retries on idempotency-sensitive flows.
TypeScript usage
The package ships full .d.ts declarations. Recommended tsconfig.json settings for consumers:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"strict": true
}
}
The DOM / DOM.Iterable libs are required because the SDK's fetch shims reference Headers.entries() and HeadersIterator.
Source & support
- npm: pinelabs-node
- Issues: github.com/plural-pinelabs/Pinelabs-Agentic-SDK/issues
- API reference: /docs/api-reference
For the agent-toolkit (LangChain, Vercel AI SDK, OpenAI Agents, Anthropic, Claude Agent SDK), see pinelabs-agent-toolkit. For the command-line interface, see pinelabs-cli.
