Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

payzum — official TypeScript / Node.js SDK

Accept crypto and stablecoin payments (USDC/USDT, multi-chain) with Payzum. Non-custodial — funds settle to your own wallet. Zero runtime dependencies, strict TypeScript, ESM. Node 18+.

npm install payzum

You need two values from your Payzum dashboard: an API key and a webhook secret.

Charge a customer

import { Payzum } from "payzum"

const payzum = new Payzum("your-api-key")   // Payzum.sandbox(...) for staging

const invoice = await payzum.payments.create({
  priceAmount: "49.99",                     // a string — never a number
  priceCurrency: "usd",
  payCurrency: "all",                       // the buyer picks the coin on the checkout page
  orderId: "ORDER-12345",
  ipnCallbackUrl: "https://your-shop.example/payzum/ipn",
  idempotencyKey: "ORDER-12345",            // lets the SDK retry safely on network hiccups
})
redirect(String(invoice["invoice_url"]))

That's the whole flow: create, redirect, and wait for the webhook. Which coins the buyer can pick is configured in your dashboard, not in code.

Get notified when it's paid

Payzum POSTs a signed webhook (IPN) to your ipnCallbackUrl. Hand the SDK the raw request body and the headers — it finds the right header, checks the signature and rejects replays, all by itself:

import { SignatureError, Verifier, isPaidStatus, paymentStatusFromMerchant } from "payzum"

const verifier = new Verifier(webhookSecret)

try {
  // rawBody: the bytes exactly as received, before any JSON parsing
  const data = verifier.verifyPaymentIpn(rawBody, req.headers)

  const status = paymentStatusFromMerchant(String(data["payment_status"]))
  if (isPaidStatus(status)) {
    await fulfilOrder(String(data["order_id"]))   // only fulfil on isPaidStatus()
  }
} catch (e) {
  if (e instanceof SignatureError) {
    res.status(401).send("bad signature")
    return
  }
  throw e
}

Deliveries can arrive more than once — deduplicate on verifier.eventId(req.headers) if a repeat must be a no-op on your side.

Statuses

A payment is always in one of five states: waiting, partially_paid, finished, expired, failed.

  • isPaidStatus(status) — safe to fulfil (covers overpayment too).
  • isTerminalStatus(status) — nothing further will happen.
  • paymentStatusFromMerchant(...) throws on anything unexpected, so a surprise value can never be mistaken for "paid".

Errors

Everything throws a typed error: ApiError (with .errorCode, e.g. AMOUNT_BELOW_MINIMUM, to branch on — never branch on messages), SignatureError for webhooks, TransportError for network failures, PayzumError for local validation.

Transient failures are retried for you, honouring the server's back-off hints. A create is only retried when you pass an idempotencyKey, and then in a way that cannot double-charge.

Amounts are exact

Amounts go in as strings and come back as exact decimal strings — the SDK never converts money through a JavaScript number in either direction.

Testing your integration

new Payzum(apiKey, { transport }) accepts any Transport implementation, so you can test without touching the network. The SDK's own suite runs with npm test.

Docs: https://merchant.payzum.com/docs · llms: https://merchant.payzum.com/llms.txt

About

Official Node.js/TypeScript SDK for the Payzum crypto payment API

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages