Plaidly Docs

Node.js Integration

Accept crypto payments in Node.js and TypeScript apps

Node.js Integration

Install the official Plaidly Node SDK:

Not yet published to the package registry

@plaidly/node is not yet published to npm — install from source until registry publication ships.

git clone https://github.com/plaidly/plaidly-node.git
cd plaidly-node
npm install
npm run build

Once published, the intended install command will be:

npm install @plaidly/node

Initialize the client

import {
  PlaidlyClient,
  constructWebhookEvent,
  constructWebhookEventWithSecrets,
  onboardSandboxWithSimulation,
} from '@plaidly/node';

const plaidly = new PlaidlyClient({ apiKey: process.env.PLAIDLY_API_KEY! });

Create and poll a payment session

const session = await plaidly.paymentSessions.create({
  amount: 10,
  expires_in: '15m',
  paymentMethod: {
    methodID: 0,
    chain: 'solana',
    token: 'USDC',
    network: 'mainnet',
  },
  metadata: { order_id: 'ord_123' },
});

console.log(session.address);

const latest = await plaidly.paymentSessions.get(session.session_id);
console.log(latest.status);

Sandbox onboarding

const publicClient = new PlaidlyClient();
const merchant = await publicClient.merchants.register({
  name: 'Acme Demo Store',
  webhook_url: process.env.PLAIDLY_WEBHOOK_URL!,
});

const merchantClient = new PlaidlyClient({ apiKey: merchant.api_key });
const flow = await onboardSandboxWithSimulation(
  merchantClient,
  { chain: 'solana', token: 'USDC', network: 'testnet' },
  { simulate: true, includeReceipt: true },
);

console.log(flow.demoSession.session_id);
console.log(flow.terminalSession.status);
console.log(flow.receipt?.size ?? 0);

Verify webhooks

Express

import express from 'express';
import { constructWebhookEventWithSecrets } from '@plaidly/node';

const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-plaidly-signature'] as string;

  try {
    const event = constructWebhookEventWithSecrets(req.body, signature, [
      process.env.PLAIDLY_WEBHOOK_SECRET_NEW!,
      process.env.PLAIDLY_WEBHOOK_SECRET_OLD!,
    ]);

    if (event.event_type === 'payment_session.completed') {
      fulfillOrder(event.session_id);
    }
  } catch {
    return res.status(400).send('Invalid signature');
  }

  res.sendStatus(200);
});

Next.js App Router

import { constructWebhookEvent } from '@plaidly/node';
import { NextRequest } from 'next/server';

export async function POST(req: NextRequest) {
  const rawBody = await req.text();
  const signature = req.headers.get('x-plaidly-signature') ?? '';

  try {
    const event = constructWebhookEvent(
      rawBody,
      signature,
      process.env.PLAIDLY_WEBHOOK_SECRET!,
    );

    if (event.event_type === 'payment_session.completed') {
      await fulfillOrder(event.session_id);
    }
  } catch {
    return new Response('Invalid signature', { status: 400 });
  }

  return new Response('OK');
}

Error handling

The SDK throws typed errors:

import { PlaidlyError } from '@plaidly/node';

try {
  await plaidly.paymentSessions.create({
    amount: 10,
    expires_in: '15m',
    paymentMethod: { methodID: 0, chain: 'solana', token: 'USDC', network: 'mainnet' },
  });
} catch (err) {
  if (err instanceof PlaidlyError) {
    console.error(err.code, err.message, err.statusCode);
  }
}

Agent example flows

The TypeScript example index in plaidly-node/examples/ shows the same flows used by the agent docs:

  • sandbox merchant registration plus demo session simulation
  • webhook verification with a secret rotation window
  • x402 paid-resource retry using the built-in helpers

On this page