Skip to content

@gj-kit/toss-payments

A confirm that skipped verification does not compile — flow.confirm takes only VerifiedCheckout.

  • npm 0.6.2
  • 0 runtime dependencies
  • 550+ unit tests
  • 144 @ts-expect-error compile guards
  • 42 Toss error codes classified

Toss integrations break in ways that only surface in production: confirming without comparing the amount you stored, a cron re-running billing approve without an idempotency key and charging twice, trusting an unsigned PAYMENT_STATUS_CHANGED payload, or forgetting to save the virtual-account secret so every deposit webhook is rejected as unknown-order. And a confirm that fails on transport is not a failed payment — batch-failing it tells the customer their payment failed after the money already moved.

  • Unwired flows have no property — createTossPayments returns a type where billing does not exist unless you pass a BillingKeyStore, and confirm does not exist unless you pass an OrderStore.
  • Secret keys cannot reach the browser — Toss’s four key kinds are four separate brands; the secret parsers live only on the node-resolved /server entry, and loadWidgets accepts WidgetClientKey alone.
  • confirm() rejects unverified callbacks — flow.confirm takes only VerifiedCheckout — the brand flow.verify mints after the callback amount matches the amount createOrder stored and the 10-minute approval window still holds.
  • Cancel has no shortcut path — Nothing cancels by paymentKey: you go getPayment to asCancelable to kind narrowing, where a deposited virtual account requires refundAccount and every non-virtual-account payment declares it refundAccount?: never.
  • Webhook trust is graded, not assumed — verify() takes raw body only, events split into signature / secret / unverified, and there is no onBillingApproved key because Toss sends no such webhook.

Outcome: A server-only payment kit whose available flows match the stores you pass in.

Terminal window
pnpm add @gj-kit/toss-payments

Parse the API secret at boot and provide your server-owned order store before enabling confirmation.

Copy this first, then replace only the app-owned values named above.

import { orThrow } from '@gj-kit/toss-payments';
import { createTossPayments, parseApiSecretKey } from '@gj-kit/toss-payments/server';
declare const apiSecretFromEnv: string; // Read this once from your server environment.
export const toss = createTossPayments({
secretKey: orThrow(parseApiSecretKey(apiSecretFromEnv)),
});
// Add your OrderStore to enable toss.confirm; the type exposes only wired flows.

Two mistakes that normally pass review and detonate in production — a half-wired kit and a billing approve with no idempotency key — are both compile errors here.

import { idempotencyKey, orThrow } from '@gj-kit/toss-payments';
import type { BillingKeyStore, BillingOrder, BillingProfile, OrderStore } from '@gj-kit/toss-payments/server';
import { createTossPayments, parseApiSecretKey } from '@gj-kit/toss-payments/server';
declare const apiSecret: string; // app owns
declare const orderStore: OrderStore; // app owns
declare const billingKeyStore: BillingKeyStore; // app owns
declare const profile: BillingProfile; // app owns
declare const order: BillingOrder; // app owns
export const toss = createTossPayments({
secretKey: orThrow(parseApiSecretKey(apiSecret)),
orders: orderStore, // omit and `toss.confirm` is not on the type
billingKeys: billingKeyStore, // omit and `toss.billing` is not on the type
});
// toss.billing.approve(profile, order); -> error TS2554: Expected 3 arguments, but got 2.
export const charged = toss.billing.approve(profile, order, {
idempotencyKey: orThrow(idempotencyKey(`sub:2026-09:${profile.customerKey}`)),
});

Use it when payment key boundaries, order-amount verification, webhook trust, and idempotent billing flows must be encoded in types.

Do not treat it as a complete order system or store raw secrets, audit payloads, and refund policy in its generic layer.

Engines: node >=20

Peer Supported range Required for
@tosspayments/tosspayments-sdk ^2 documented optional subpaths only
Entry Exported symbols
Root entry 155
./browser 14
./server 257
./testing 9
./webhook 40

Never import server key parsers into browser code or trust a redirect/webhook without the documented verification path. Keep secrets and exact audit bodies encrypted at rest.

complete API reference contains every public function, class, type, constant, and error contract generated from release declarations. Each item shows its import path, release signature, and package version.

Relationship Package Why combine them
Standalone — This package can be adopted without another GJ Kit package.
Optional companion @gj-kit/toss-payments-nestjs Register the typed core kit through Nest dependency injection.
Optional companion @gj-kit/toss-payments-postgresql Use PostgreSQL implementations for application-owned payment stores.

npm · GitHub