TypeScript
The official PayNow TypeScript SDK wraps the Management API and Storefront API with fully typed clients, so you get autocomplete for every endpoint, request body and response. It works from plain JavaScript as well. The types are there when you want them.
The source is on GitHub and the package is published to npm as @paynow-gg/typescript-sdk. Every endpoint page in these docs also has a TypeScript tab showing the SDK call for that endpoint.
Installation
NPM
npm install @paynow-gg/typescript-sdkPNPM
pnpm add @paynow-gg/typescript-sdkYarn
yarn add @paynow-gg/typescript-sdkThe SDK requires Node.js 20.3 or newer, or any runtime with a global fetch. You can also pass your own fetch implementation through the client options.
Management API
The Management client authenticates with an API key and is scoped to a single store. Keep it on your server - never ship an API key to a browser.
import { createManagementClient, type Management } from "@paynow-gg/typescript-sdk";
const management = createManagementClient({
apiKey: process.env.PAYNOW_API_KEY!,
storeId: "411486491630370816",
});
const bans: Management.BanDto[] = await management.bans.getBans({ limit: 50, ban_type: "steam" });
const ban = await management.bans.getBan("411486491630370816");
await management.bans.updateBan(ban.id, { reason: "chargeback" });
await management.bans.deleteBan(ban.id);Endpoints are grouped by tag, so the Bans endpoints live under management.bans, Products under management.products, and so on. Arguments follow the endpoint: path parameters first, then the request body, then query parameters.
Storefront API
The Storefront client only needs a store ID. Pass a customer token to act on behalf of a signed-in customer, for example to read or modify their cart.
import { createStorefrontClient } from "@paynow-gg/typescript-sdk";
const storefront = createStorefrontClient({
storeId: "411486491630370816",
customerToken: process.env.PAYNOW_CUSTOMER_TOKEN,
});
const store = await storefront.store.getStorefrontStore();
const cart = await storefront.cart.getCart();
await storefront.cart.addLine(
{ product_id: "411486491630370816", quantity: 1 },
{ headers: { "x-paynow-customer-ip": "127.0.0.1" } },
);Every method accepts an optional final options argument with per-request headers, an AbortSignal and a timeoutMs. That is how you forward the customer's IP address on storefront calls.
Error handling
Failed requests throw a PayNowApiError carrying the HTTP status, the error code, the message, the trace ID and any field-level validation failures.
import { isPayNowApiError } from "@paynow-gg/typescript-sdk";
try {
await management.bans.getBan("nope");
} catch (error) {
if (isPayNowApiError(error)) {
console.error(error.status, error.code, error.message, error.traceId);
console.error(error.errors);
console.error(error.response.headers.get("retry-after"));
}
}Webhook types
The SDK ships the payload type for every webhook event under the Webhooks namespace, so a handler can be fully typed without any runtime dependency. Every payload has the same envelope: event_type, event_id and a body that differs per event.
Verify the signature first, as described in Validating Incoming Webhooks, then narrow on event_type and cast to the matching payload type.
import type { Webhooks } from "@paynow-gg/typescript-sdk";
const payload = JSON.parse(rawBody) as { event_type: Webhooks.WebhookEventType };
switch (payload.event_type) {
case "ON_ORDER_COMPLETED": {
const { body } = payload as Webhooks.OnOrderCompletedPayload;
console.log(`Order ${body.id} completed`);
break;
}
case "ON_SUBSCRIPTION_CANCELED": {
const { body } = payload as Webhooks.OnSubscriptionCanceledPayload;
console.log(`Subscription ${body.id} canceled`);
break;
}
}Payload types are named after the event, so ON_PAYMENT_FAILED is Webhooks.OnPaymentFailedPayload. Webhooks.WebhookEventType is the union of every event name PayNow can send. The models shared between events, such as OrderDTO and CustomerDTO, are exported from the same namespace.
Other languages
TypeScript is the only SDK we publish today. Every other language can call the REST API directly - each endpoint page includes a curl example you can translate into your HTTP client of choice.