npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@paytrigo-net/sdk

v0.1.4

Published

payTrigo SDK client and OpenAPI types

Readme

@paytrigo-net/sdk

Official PayTrigo SDK (runtime client + TypeScript types). PayTrigo is non-custodial: funds go directly to the merchant wallet. The SDK helps you create invoices, fetch status/intent, and submit payment intents with full type safety.

Install

npm install @paytrigo-net/sdk
# or
pnpm add @paytrigo-net/sdk
# or
yarn add @paytrigo-net/sdk

Requirements

  • A runtime with fetch (Node 18+ or a polyfill)
  • TypeScript recommended (types are included)

Quickstart (Merchant)

import { createPaytrigoMerchantClient } from "@paytrigo-net/sdk";

const client = createPaytrigoMerchantClient({
  auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
});

const invoice = await client.invoices.create({
  amount: "29.00",
  // options omitted -> all enabled Address Book entries are exposed
  metadata: { orderId: "order_123" },
});

console.log(invoice.invoiceId, invoice.payUrl);

Configuration

Environment Variables

PAYTRIGO_API_KEY=sk_live_your_api_key_here
PAYTRIGO_PLATFORM_KEY=sk_live_your_platform_key_here
PAYTRIGO_API_URL=https://api.paytrigo.net
PAYTRIGO_WEBHOOK_SECRET=whsec_...

Base URL

The SDK defaults to https://api.paytrigo.net and automatically calls /v1/*. Do not include /v1 in baseUrl.

const client = createPaytrigoMerchantClient({
  baseUrl: process.env.PAYTRIGO_API_URL,
  auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
});

Timeouts, User-Agent, Retry

const client = createPaytrigoMerchantClient({
  auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
  timeoutMs: 10000,
  userAgent: "my-app/1.2.3",
  retry: { max: 2, backoffMs: 500 },
});

Hosted Checkout (Recommended)

Create the invoice on your server, then redirect the user to payUrl.

Server: Create Invoice

import { createPaytrigoMerchantClient } from "@paytrigo-net/sdk";

const client = createPaytrigoMerchantClient({
  auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
});

export async function createPayment(orderId: string, amount: string) {
  const invoice = await client.invoices.create({
    amount,
    metadata: { orderId },
  });

  return {
    invoiceId: invoice.invoiceId,
    payUrl: invoice.payUrl,
    checkoutToken: invoice.checkoutToken,
  };
}

Client: Redirect

const response = await fetch("/api/create-payment", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ amount: "29.00" }),
});

const { payUrl } = await response.json();
window.location.href = payUrl;

Merchant vs Platform Keys

Merchant keys are for checkout integrations. They cannot set recipientAddress and rely on Address Book entries configured in the dashboard.

Platform keys are for server-side marketplace flows. They must set recipientAddress for each invoice (or per option).

Security note: never expose API keys in the browser. Only use checkoutToken client-side.

Merchant: Multi-option (Multi-token)

await client.invoices.create({
  amount: "100.00",
  options: [
    { chain: "base", token: "usdc", isDefault: true },
    { chain: "base", token: "usdt" },
  ],
});

Platform: Single Option (Server-side only)

import { createPaytrigoPlatformClient } from "@paytrigo-net/sdk";

const platformClient = createPaytrigoPlatformClient({
  auth: { type: "apiKey", token: process.env.PAYTRIGO_PLATFORM_KEY! },
});

await platformClient.invoices.create({
  amount: "49.99",
  chain: "base",
  token: "usdc",
  recipientAddress: "0xSellerWallet...",
});

Platform: Multi-option (Each option needs recipientAddress)

await platformClient.invoices.create({
  amount: "49.99",
  options: [
    { chain: "base", token: "usdc", recipientAddress: "0xSellerWallet..." },
    { chain: "base", token: "usdt", recipientAddress: "0xSellerWallet..." },
  ],
});

Checkout Token Flow (Pay Page)

Use the checkout token to build a pay page that only has access to the specific invoice.

const invoice = await client.invoices.create({ amount: "29.00" });

const payClient = createPaytrigoMerchantClient({
  auth: { type: "checkoutToken", token: invoice.checkoutToken },
});

const intent = await payClient.invoices.getIntent(invoice.invoiceId);
const options = await payClient.invoices.getOptions(invoice.invoiceId);

Render Options (Chain/Token Selector)

const options = await payClient.invoices.getOptions(invoice.invoiceId);

const labels = options.options.map((option) => ({
  id: `${option.chain}-${option.token}`,
  label: `${option.chainName} ${option.tokenMeta.symbol}`,
  routerAddress: option.routerAddress,
  isDefault: option.isDefault,
}));

API-Only Flow (Intent + Submit)

Use this when you build your own wallet UI instead of Hosted Checkout.

import { createPaytrigoMerchantClient } from "@paytrigo-net/sdk";

const client = createPaytrigoMerchantClient({
  auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
});

// 1) Create invoice
const invoice = await client.invoices.create({
  amount: "50.00",
  chain: "base",
  token: "usdc",
});

// 2) Get intent (router, amountAtomic, steps, etc.)
const intent = await client.invoices.getIntent(invoice.invoiceId, {
  chain: "base",
  token: "usdc",
});

// 3) Build and send transaction with your wallet UI...
// 4) Submit txHash for verification
await client.invoices.submitPaymentIntent(invoice.invoiceId, {
  txHash: "0x...",
  chain: "base",
  token: "usdc",
});

Check Invoice Status

const invoice = await client.invoices.get("inv_123");
console.log(invoice.status, invoice.amount, invoice.chain);

Webhooks (Signature Verification)

Webhooks are the recommended way to confirm payments in production. Always verify the signature and dedupe on event.id or X-Paytrigo-Event-Id.

import crypto from "crypto";

type WebhookEvent = {
  id: string;
  type:
    | "invoice.created"
    | "invoice.confirmed"
    | "invoice.expired"
    | "invoice.invalid"
    | "invoice.updated";
  createdAt: string;
  data: {
    invoiceId: string;
    status: string;
    [key: string]: unknown;
  };
};

export async function handleWebhook(request: Request) {
  const rawBody = await request.text();
  const timestamp = request.headers.get("X-Paytrigo-Timestamp") ?? "";
  const signature = request.headers.get("X-Paytrigo-Signature") ?? "";
  const eventId = request.headers.get("X-Paytrigo-Event-Id") ?? "";

  const expected =
    "v1=" +
    crypto
      .createHmac("sha256", process.env.PAYTRIGO_WEBHOOK_SECRET!)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex");

  if (!timingSafeEquals(signature, expected)) {
    return new Response("Invalid signature", { status: 401 });
  }

  const event = JSON.parse(rawBody) as WebhookEvent;

  // Deduplicate by eventId (store in DB)
  if (await alreadyProcessed(eventId)) {
    return new Response("ok");
  }

  await markProcessed(eventId);
  await processEvent(event);
  return new Response("ok");
}

function timingSafeEquals(a: string, b: string) {
  try {
    return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
  } catch {
    return false;
  }
}

async function alreadyProcessed(_eventId: string) {
  return false;
}

async function markProcessed(_eventId: string) {}

async function processEvent(event: WebhookEvent) {
  if (event.type === "invoice.confirmed") {
    // fulfill order
  }
}

Next.js Webhook Route (App Router)

// app/api/webhooks/paytrigo/route.ts
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";

export async function POST(request: NextRequest) {
  const rawBody = await request.text();
  const timestamp = request.headers.get("X-Paytrigo-Timestamp") ?? "";
  const signature = request.headers.get("X-Paytrigo-Signature") ?? "";

  const expected =
    "v1=" +
    crypto
      .createHmac("sha256", process.env.PAYTRIGO_WEBHOOK_SECRET!)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex");

  if (!timingSafeEquals(signature, expected)) {
    return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
  }

  // Parse and process event
  return NextResponse.json({ received: true });
}

function timingSafeEquals(a: string, b: string) {
  try {
    return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
  } catch {
    return false;
  }
}

Polling (Not Recommended)

Polling is acceptable for testing or UI fallback, but webhooks are strongly recommended in production.

const terminalStates = new Set(["confirmed", "expired", "invalid"]);

async function pollInvoice(invoiceId: string) {
  while (true) {
    const invoice = await client.invoices.get(invoiceId);
    if (terminalStates.has(invoice.status)) return invoice;
    await new Promise((resolve) => setTimeout(resolve, 5000));
  }
}

Idempotency

For create and submit APIs, you can pass an idempotencyKey. If retry is enabled, the SDK will automatically set an idempotency key for POST requests.

await client.invoices.create({
  amount: "29.00",
  idempotencyKey: `pay_attempt_${crypto.randomUUID()}`,
});

Errors

import { PaytrigoError, PaytrigoValidationError } from "@paytrigo-net/sdk";

try {
  await client.invoices.create({ amount: "29.00" });
} catch (error) {
  if (error instanceof PaytrigoValidationError) {
    console.error(error.issues);
  } else if (error instanceof PaytrigoError) {
    console.error(error.status, error.code, error.message);
  }
}

Types

import type { components } from "@paytrigo-net/sdk";

type InvoiceDetail = components["schemas"]["InvoiceDetailResponseDto"];
type CreateInvoiceRequest = components["schemas"]["CreateInvoiceDto"];

Note: webhook payload types are not part of the OpenAPI spec yet. You can define your own type based on the docs:

type WebhookEvent = {
  id: string;
  type:
    | "invoice.created"
    | "invoice.confirmed"
    | "invoice.expired"
    | "invoice.invalid"
    | "invoice.updated";
  data: Partial<components["schemas"]["InvoiceDetailResponseDto"]> & {
    invoiceId: string;
    status: string;
  };
};

Note: CreateInvoiceDto.token is a string token ID (e.g. "usdc"), while invoice responses and webhooks return a token descriptor object.

Utility Type Patterns

type InvoiceSummary = Pick<
  components["schemas"]["InvoiceDetailResponseDto"],
  "invoiceId" | "status" | "amount" | "chain"
>;

type ClientSafeInvoice = Omit<
  components["schemas"]["InvoiceDetailResponseDto"],
  "metadata"
>;

OpenAPI JSON

// Requires resolveJsonModule in tsconfig
import openapi from "@paytrigo-net/sdk/openapi.json";

Platform Fee Helpers

import { getPlatformFeeSummary, expectPlatformFee } from "@paytrigo-net/sdk";

const summary = getPlatformFeeSummary(invoice);
expectPlatformFee(invoice, { bps: 50 });

You can also assert platform fees at creation time:

await client.invoices.create({
  amount: "29.00",
  expectPlatformFee: { bps: 50, recipient: "0xPlatformFeeWallet..." },
});

Escape Hatch (Raw Request)

const data = await client.request("get", "/v1/invoices/{invoiceId}", {
  params: { path: { invoiceId: "inv_..." } },
});

Next.js API Route Example

// app/api/create-payment/route.ts
import { NextRequest, NextResponse } from "next/server";
import { createPaytrigoMerchantClient } from "@paytrigo-net/sdk";

export async function POST(request: NextRequest) {
  const { amount } = await request.json();
  const client = createPaytrigoMerchantClient({
    auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
  });

  const invoice = await client.invoices.create({ amount });
  return NextResponse.json({
    invoiceId: invoice.invoiceId,
    payUrl: invoice.payUrl,
  });
}

Next.js Pages Router (API Route)

// pages/api/create-payment.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { createPaytrigoMerchantClient } from "@paytrigo-net/sdk";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") return res.status(405).end();

  const { amount } = req.body as { amount: string };
  const client = createPaytrigoMerchantClient({
    auth: { type: "apiKey", token: process.env.PAYTRIGO_API_KEY! },
  });

  const invoice = await client.invoices.create({ amount });
  res
    .status(200)
    .json({ invoiceId: invoice.invoiceId, payUrl: invoice.payUrl });
}

Development (Repo Maintainers)

  • OpenAPI JSON and schema types are generated. Do not edit openapi.json or src/schema.d.ts manually.
  • To regenerate from the API codebase:
pnpm sdk:sync

Repository

Source: https://github.com/paytrigo/paytrigo-sdk

License

MIT. See LICENSE.