The official Pandascrow Node.js SDK is out. It's on npm as pandascrow, and it wraps the whole v3 API: escrow, wallets, payouts, bank transfers, virtual accounts, invoices, payment links, KYC and webhook verification.
If you've built on our REST API before, you know the routine. Set the Token header, pick the right base URL, check status on every response, and verify webhook signatures by hand. The SDK does that part, so your code reads like your business logic: create an escrow, release it, pay out.
Install the Node.js SDK
npm install pandascrow
It's written in TypeScript and ships its own types. It works with both import and require, and it has no runtime dependencies. It uses the built-in fetch, so it runs on Node.js 18+, Bun, Deno, Cloudflare Workers and Vercel Edge.
WarningUse the SDK on your server only. Your API key gives full access to your Pandascrow account, so never ship it to a browser or a mobile app.
Create your first escrow
Grab your API key from Dashboard → Developers. The client starts in sandbox, so you can test without moving real money.
import Pandascrow from "pandascrow";
const ps = new Pandascrow(process.env.PANDASCROW_API_KEY!); // sandbox by default
const escrow = await ps.escrow.createOnetime({
uuid, // the Pandascrow user you're acting for
initiator_id: uuid,
initiator_role: "seller", // "buyer" | "seller" | "broker"
title: "Apartment 4B rent",
description: "12-month rent, 12 Admiralty Way",
currency: "NGN",
amount: 350000,
buyer_details: { name: "Tenant", email: "tenant@example.com" },
});
console.log(escrow.payment_url); // send the buyer here to fund it
That's a complete one-time escrow. The buyer pays through payment_url, we hold the money, and it's released to the seller once the buyer confirms delivery. Every method returns a promise of the data object from the API, typed, so your editor shows you the fields as you type.
Going live is one option:
const ps = new Pandascrow(process.env.PANDASCROW_API_KEY!, { sandbox: false });
What the SDK covers
Each part of the API has its own property on the client:
| Property | What it does |
|---|---|
escrow | One-time, milestone and recurring escrows, releases, disputes |
wallet and payouts | Balances, transactions, settlement accounts, payouts |
bank | Bank list, account validation, NGN transfers |
virtualAccounts | Dynamic and static accounts to collect transfers |
invoices | Create, send, pay and cancel invoices |
paymentLinks | Shareable links with custom slugs |
kyc | BVN, NIN, CAC, TIN, NUBAN, phone and driver's licence lookups |
For an endpoint we haven't wrapped yet, ps.request() sends any call with your key and base URL already set:
await ps.request("GET", "/clients", { uuid });
Milestone projects work the same way. Pass the stages and the buyer funds them one at a time:
await ps.escrow.createMilestone({
uuid, initiator_id: uuid, initiator_role: "buyer",
title: "Website build", description: "Company website", currency: "NGN",
seller_details: { name: "Dev Studio", email: "studio@example.com" },
deposit_option: "milestone",
milestones: [
{ title: "Design", amount: 150000 },
{ title: "Build", amount: 350000 },
],
});
Verify webhooks in one call
We sign every webhook with HMAC-SHA256 of the raw request body, using your secret key, and send the signature in the X-Pandascrow-Signature header. verifyWebhook checks it, rejects events older than five minutes to stop replays, and returns the parsed event.
Here it is in a Next.js App Router route:
// app/api/webhooks/pandascrow/route.ts
import { verifyWebhook } from "pandascrow";
export async function POST(req: Request) {
const raw = await req.text();
try {
const event = await verifyWebhook(
process.env.PANDASCROW_SECRET_KEY!,
raw,
req.headers.get("x-pandascrow-signature"),
);
if (event.event === "escrow.paid") {
// mark the order as funded
}
return new Response("ok");
} catch {
return new Response("invalid signature", { status: 400 });
}
}
TipAlways pass the raw body, not a parsed object. In Express, use
express.raw({ type: "application/json" })on the webhook route.
You'll receive events such as escrow.created, escrow.paid, escrow.completed, escrow.milestone.completed, escrow.dispute.opened, invoice.paid and wallet.deposit.success. The full list is in the webhooks reference.
Keep your own IDs on every record
Escrows, invoices and virtual accounts accept a metadata object. We store it as you sent it, return it when you fetch the record, and include it in every webhook for that record. So you don't need a lookup table to match a Pandascrow escrow to your order.
await ps.escrow.createOnetime({ ...details, metadata: { order_id: "A-1001" } });
// later, in your webhook handler
event.data.metadata?.order_id; // "A-1001"
Errors you can act on
Every failure rejects with a PandascrowError, whether it's a network error, a timeout, an HTTP error or a response with status: false. You get the message, the HTTP status, the full response and, where we have one, a link to the right page in the docs.
import { PandascrowError } from "pandascrow";
try {
await ps.escrow.complete(uuid, escrowId, otp);
} catch (err) {
if (err instanceof PandascrowError) {
console.log(err.message); // "Invalid OTP"
console.log(err.status); // 400, or 0 for network errors
console.log(err.docUrl); // link to the API reference
}
}
Bank transfers also take an idempotency key, so a retry after a timeout can't send the money twice:
await ps.bank.transfer(uuid, 25000,
{ account_number: "0123456789", account_name: "Ada Obi", bank_code: "058" },
{ idempotencyKey: "payout-7781" },
);
Prefer the terminal or PHP?
The Node.js SDK isn't the only new way in. The Pandascrow CLI (npm install -g pandascrow-cli) lets you create escrows, check balances and test webhooks from your terminal. PHP teams can use our PHP SDK on Packagist. SDKs for Python, Java, Ruby and Rust are in progress. Until they ship, every endpoint works over plain HTTPS from any language.
Start building
- Create a free account and get your sandbox key from the dashboard.
- Run
npm install pandascrow. - Follow the quick start on our developer page, or read the API reference.
The source is on GitHub under the MIT licence. If something's missing or broken, open an issue there or email us at hi@pandascrow.io. We read every one.
New to escrow? See how Pandascrow escrow protects both sides of a deal.
