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_* or pk_live_*) and secret (sk_test_* or sk_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 .env file 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.id is string, customer.email is string | null, and your editor will autocomplete every field.
  • The SDK attached a fresh Idempotency-Key header 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 openpendingcompleted 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.
Plugipay — Payments that don't tax your success