Quickstart
This page walks you from npm install to a hosted checkout URL in your browser. By the end you'll have created a Plugipay customer, opened a checkout session against them, and inspected the response shape.
It takes about five minutes.
Prerequisites
- Node 20 or later.
- A Plugipay workspace with at least one API key. Mint one under Settings → API keys in the dashboard; see Portal → API keys if you haven't done this yet.
- The key's access key ID (
pk_test_*orpk_live_*) and secret (sk_test_*orsk_live_*).
The secret appears once. Plugipay shows the secret in a dialog when you create a key. If you close it without copying, you have to mint a new key. Stash it in a
.envfile or your secret manager before you do anything else.
1. Install
npm install @forjio/plugipay-node
2. Set up environment variables
The SDK doesn't read environment variables on its own — you pass the credentials explicitly — but the standard convention across the Plugipay docs and the CLI is:
# .env
PLUGIPAY_KEY_ID=pk_test_AKIAxxxxxxxxxxxx
PLUGIPAY_SECRET=sk_test_xxxxxxxxxxxxxxxxxxxxxxxx
PLUGIPAY_BASE_URL=https://plugipay.com # optional; this is the default
Then load them however your project already loads env vars — dotenv, process.env direct, your platform's secret manager, etc.
For this walkthrough, we'll assume they're available as process.env.PLUGIPAY_KEY_ID and process.env.PLUGIPAY_SECRET.
3. Construct the client
Create a file called quickstart.ts (or .js):
import { PlugipayClient } from '@forjio/plugipay-node';
const plugipay = new PlugipayClient({
keyId: process.env.PLUGIPAY_KEY_ID!,
secret: process.env.PLUGIPAY_SECRET!,
});
That's it — the client is now ready. No network call happens at construction time; HMAC signing kicks in only when you make a request.
If keyId or secret is missing, the constructor throws synchronously:
Error: PlugipayClient: keyId and secret are required
Catch that early in your bootstrapping code so you don't ship a deploy that silently uses undefined credentials.
4. Create a customer
A customer is a persistent record of someone who can pay you. Charging the same person more than once, sending receipts, or starting a subscription — all of these want a customer record.
const customer = await plugipay.customers.create({
email: 'dewi@example.com',
name: 'Dewi Lestari',
phone: '+62-812-3456-7890',
metadata: { crmId: 'contact_19823' },
});
console.log(customer.id); // → cus_01HXxxxxxxxxxxxxxxxxxxxxxx
console.log(customer.email); // → dewi@example.com
console.log(customer.createdAt); // → 2026-05-12T10:42:00.123Z
A few things to notice:
- The SDK returned the customer object directly — not the API's
{ data, error, meta }envelope. The envelope is unwrapped for you. - The result is fully typed.
customer.idisstring,customer.emailisstring | null, and your editor will autocomplete every field. - The SDK attached a fresh
Idempotency-Keyheader automatically. If the network glitches and you retry, you'll get the same customer back, not a duplicate.
5. Create a checkout session
A checkout session is a one-time hosted payment page. Plugipay generates a URL, the customer pays at it, and you get a webhook (or the success/cancel redirect) when they're done.
const session = await plugipay.checkoutSessions.create({
amount: 199000, // 199,000 IDR (amount is in the currency's minor unit; IDR has no minor unit so 199000 = Rp 199.000)
currency: 'IDR',
methods: ['qris', 'va', 'ewallet'],
successUrl: 'https://myshop.com/order/thanks',
cancelUrl: 'https://myshop.com/cart',
customerId: customer.id,
lineItems: [
{ name: 'Premium Plan (monthly)', quantity: 1, unitAmount: 199000 },
],
metadata: { orderId: 'order_2026_001' },
});
console.log(session.id); // → cs_01HXxxxxxxxxxxxxxxxxxxxxxx
console.log(session.hostedUrl); // → https://plugipay.com/c/cs_01H...
console.log(session.status); // → "open"
console.log(session.expiresAt); // → 2026-05-12T11:42:00.000Z
session.hostedUrl is what you redirect the customer to. Open it in a browser to see the checkout page.
6. Inspect the response
Every checkout session has the shape declared by the CheckoutSession type:
{
id: 'cs_01H...',
accountId: 'acc_01H...',
customerId: 'cus_01H...',
amount: 199000,
currency: 'IDR',
status: 'open',
methods: ['qris', 'va', 'ewallet'],
adapter: null,
lineItems: [/* ... */],
successUrl: 'https://myshop.com/order/thanks',
cancelUrl: 'https://myshop.com/cart',
hostedUrl: 'https://plugipay.com/c/cs_01H...',
expiresAt: '2026-05-12T11:42:00.000Z',
completedAt: null,
metadata: { orderId: 'order_2026_001' },
createdAt: '2026-05-12T10:42:00.000Z',
updatedAt: '2026-05-12T10:42:00.000Z',
}
status will progress through open → pending → completed as the customer pays. To learn when it changes, subscribe to the plugipay.checkout_session.completed.v1 webhook — see Webhooks.
7. Polling vs webhooks
For a quick test, you can poll the session:
const updated = await plugipay.checkoutSessions.get(session.id);
console.log(updated.status); // → "completed" once the customer has paid
In production, don't poll — use a webhook handler. The full pattern is in the Webhooks page.
8. Handle errors
Wrap your calls in a try/catch and switch on the typed error code:
import { PlugipayClient, PlugipayError } from '@forjio/plugipay-node';
try {
const customer = await plugipay.customers.create({ email: 'dewi@example.com' });
} catch (err) {
if (err instanceof PlugipayError) {
console.error(`Plugipay error: ${err.code} (${err.status}) — ${err.message}`);
console.error(`requestId: ${err.requestId}`);
} else {
throw err;
}
}
The full error handling guide is at Errors.
9. Putting it together
The whole script:
import { PlugipayClient, PlugipayError } from '@forjio/plugipay-node';
const plugipay = new PlugipayClient({
keyId: process.env.PLUGIPAY_KEY_ID!,
secret: process.env.PLUGIPAY_SECRET!,
});
async function main() {
const customer = await plugipay.customers.create({
email: 'dewi@example.com',
name: 'Dewi Lestari',
});
const session = await plugipay.checkoutSessions.create({
amount: 199000,
currency: 'IDR',
methods: ['qris', 'va'],
successUrl: 'https://myshop.com/thanks',
cancelUrl: 'https://myshop.com/cart',
customerId: customer.id,
});
console.log('Pay at:', session.hostedUrl);
}
main().catch((err) => {
if (err instanceof PlugipayError) {
console.error(`[${err.code}] ${err.message} (requestId=${err.requestId})`);
} else {
console.error(err);
}
process.exit(1);
});
Run it with:
node --env-file=.env --experimental-strip-types quickstart.ts
(Or compile with tsc first if you prefer.)
What's next
You've got a working end-to-end call. From here:
- Wire up webhooks so you learn when the customer pays. See Webhooks.
- Add subscriptions to charge them on a schedule. See reference: subscriptions.
- Add refunds, invoices, payouts — everything else hangs off the same
PlugipayClient. See Reference. - Read about platform-partner mode if you're integrating Plugipay into a multi-tenant product. See Authentication.
Next
- Authentication — deeper on credentials, env vars, and on-behalf-of.
- Webhooks — learn about payments asynchronously.
- Reference — every method on
PlugipayClient.