PayDirect

SDKs & CLI

Official client libraries and CLI tool for PayDirect settlement — crypto on Base mainnet and USD card payments via Stripe Checkout. See Merchant Integration for the full dual-rail guide.

Method Reference
Quick comparison of available methods across SDKs
OperationTypeScriptPythonCLI
Create paymentcreatePayment()create_payment()payments create
Get paymentgetPayment(id)get_payment(id)payments get
List paymentslistPayments()list_payments()payments list
Cancel paymentcancelPayment(id)cancel_payment(id)payments cancel
Verify paymentverifyPayment(id)verify_payment(id)payments verify
Create webhookcreateWebhook()create_webhook()webhooks create
List webhookslistWebhooks()list_webhooks()webhooks list
Delete webhookdeleteWebhook(id)delete_webhook(id)webhooks delete
List keyslistKeys()list_keys()keys list
Create keycreateKey()create_key()-
Revoke keyrevokeKey(id)revoke_key(id)-
Verify webhook sigverifyWebhookSignature()verify_signature()-
v0.3.0 — Payouts, Balance, Withdraw, Workspaces, Smart Wallets
Send payoutsendPayout()-
List payoutslistPayouts()-
Get balancegetBalance()-
Get wallet statsgetWalletStats()-
Withdrawwithdraw()-
Create workspacecreateWorkspace()-
List workspaceslistWorkspaces()-
Get workspacegetWorkspace()-
Create smart walletcreateSmartWallet()-
v0.4.0 — DEX Swaps
Get swap quotegetSwapQuote()-
Execute swapexecuteSwap()-
Get smart walletgetSmartWallet()-
Set default walletsetDefaultWallet()-
Merchant Checkout (Crypto + Stripe)
Dual-rail checkout pattern — SDK for crypto; REST for Stripe until SDK types add paymentMethod

Register outbound webhooks with createWebhook(), then branch at checkout. Use separate idempotency keys per rail (order-123-crypto vs order-123-stripe).

TypeScript — dual-rail checkout helper

import { PayDirectClient } from "@paydirect/sdk";

const client = new PayDirectClient({ apiKey: process.env.PAYDIRECT_API_KEY! });

type CheckoutMethod = "crypto" | "stripe";

async function startCheckout(order: {
  id: string;
  amount: string;
  method: CheckoutMethod;
  listingId: string;
}) {
  // 1. Register webhook once at app startup (not per checkout):
  // await client.createWebhook("https://yourapp.com/hooks", ["payment.forwarded"]);

  if (order.method === "crypto") {
    const { payment, paymentUrl, receivingAddress } = await client.createPayment({
      tokenSymbol: "USDC",
      amount: order.amount,
      merchantWallet: process.env.MERCHANT_WALLET!,
      description: `Listing ${order.listingId}`,
      metadata: { orderId: order.id, listingId: order.listingId },
      idempotencyKey: `${order.id}-crypto`,
    });
    return { payment, redirect: paymentUrl, receivingAddress };
  }

  // Stripe: REST until SDK adds paymentMethod / USD (same auth as SDK)
  const res = await fetch("https://www.paydirect.com/api/v1/payments", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.PAYDIRECT_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `${order.id}-stripe`,
    },
    body: JSON.stringify({
      paymentMethod: "stripe",
      tokenSymbol: "USD",
      amount: order.amount,
      description: `Listing ${order.listingId}`,
      metadata: { orderId: order.id, listingId: order.listingId },
    }),
  });
  const data = await res.json();
  // Live: data.checkoutUrl. Sandbox: payment already forwarded.
  return {
    payment: data.payment,
    redirect: data.checkoutUrl ?? data.paymentUrl,
  };
}

// 2. Fulfill when settled
async function onPaymentForwarded(paymentId: string) {
  const { verified, payment } = await client.verifyPayment(paymentId);
  if (verified) await activateListing(payment.metadata.listingId);
}

Python — dual-rail checkout helper

import os
import requests
from paydirect import PayDirectClient

client = PayDirectClient(api_key=os.environ["PAYDIRECT_API_KEY"])

def start_checkout(order_id: str, amount: str, method: str, listing_id: str):
    metadata = {"orderId": order_id, "listingId": listing_id}

    if method == "crypto":
        result = client.create_payment(
            token_symbol="USDC",
            amount=amount,
            merchant_wallet=os.environ["MERCHANT_WALLET"],
            description=f"Listing {listing_id}",
            metadata=metadata,
            idempotency_key=f"{order_id}-crypto",
        )
        return {"payment": result["payment"], "redirect": result.get("paymentUrl")}

    # Stripe via REST
    res = requests.post(
        "https://www.paydirect.com/api/v1/payments",
        headers={
            "Authorization": f"Bearer {os.environ['PAYDIRECT_API_KEY']}",
            "Idempotency-Key": f"{order_id}-stripe",
        },
        json={
            "paymentMethod": "stripe",
            "tokenSymbol": "USD",
            "amount": amount,
            "description": f"Listing {listing_id}",
            "metadata": metadata,
        },
    )
    res.raise_for_status()
    data = res.json()
    return {
        "payment": data["payment"],
        "redirect": data.get("checkoutUrl") or data.get("paymentUrl"),
    }

def fulfill(payment_id: str):
    result = client.verify_payment(payment_id)
    if result["verified"]:
        activate_listing(result["payment"]["metadata"]["listingId"])

Webhook handler (Express)

import { PayDirectClient } from "@paydirect/sdk";

app.post("/webhooks/paydirect", express.raw({ type: "application/json" }), (req, res) => {
  const valid = PayDirectClient.verifyWebhookSignature(
    process.env.PAYDIRECT_WEBHOOK_SECRET!,
    req.body.toString(),
    req.headers["x-paydirect-signature"] as string,
  );
  if (!valid) return res.status(401).send("Invalid signature");

  const event = JSON.parse(req.body.toString());
  if (event.event === "payment.forwarded") {
    const payment = event.data;
    // payment.paymentProvider === "onchain" | "stripe"
    fulfillOrder(payment.metadata.orderId);
  }
  res.sendStatus(200);
});

API reference: Stripe setup, inbound Stripe webhooks (ops).

TypeScript
TypeScript SDK
@paydirect/sdk v0.3.0 — Official TypeScript/JavaScript client

Installation

npm install @paydirect/sdk
# or
pnpm add @paydirect/sdk

Initialization

import { PayDirectClient } from "@paydirect/sdk";

const client = new PayDirectClient({
  apiKey: "pd_test_abc123...",
  baseUrl: "https://www.paydirect.com/api/v1",  // optional, this is the default
  timeoutMs: 30000,                              // optional, default 30s
});

Create a Payment (crypto)

const { payment, receivingAddress, paymentUrl } = await client.createPayment({
  tokenSymbol: "USDC",             // "USDC" | "ETH" | "ADAO"
  amount: "100.00",
  merchantWallet: "0xYourBase...",
  description: "Invoice #1234",    // optional
  metadata: { orderId: "ORD_1" },  // optional
  idempotencyKey: "order-1-crypto", // optional — use per-rail keys for dual checkout
  expiresInMinutes: 60,            // optional, default 60
});
// Share paymentUrl with payer — no API key required on hosted /pay/:id page

Create a Payment (Stripe — REST)

Pass paymentMethod: "stripe" via REST until the SDK adds USD / card support.

const res = await fetch("https://www.paydirect.com/api/v1/payments", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAYDIRECT_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "order-1-stripe",
  },
  body: JSON.stringify({
    paymentMethod: "stripe",
    tokenSymbol: "USD",
    amount: "49.00",
    description: "Pro subscription",
    metadata: { orderId: "ORD_1" },
  }),
});
const { payment, checkoutUrl, paymentUrl, paymentProvider } = await res.json();
// Live: redirect to checkoutUrl. Sandbox: payment.status === "forwarded"

List and Get Payments

// List with filters
const { payments, total } = await client.listPayments({
  status: "forwarded",
  environment: "sandbox",
  limit: 20,
  offset: 0,
});

// Get by ID
const { payment } = await client.getPayment("a1b2c3d4-...");

// Cancel
const { payment: cancelled } = await client.cancelPayment("a1b2c3d4-...");

// Verify settlement
const { verified, payment: p } = await client.verifyPayment("a1b2c3d4-...");

Webhooks

// Create
const { webhook } = await client.createWebhook(
  "https://yourapp.com/webhooks",
  ["payment.forwarded", "payment.failed"]
);
console.log(webhook.signingSecret); // "whsec_..." — store this!

// List
const { webhooks } = await client.listWebhooks();

// Delete
await client.deleteWebhook("7");

Webhook Signature Verification

// Static method — no client instance needed
const isValid = PayDirectClient.verifyWebhookSignature(
  "whsec_...",        // signing secret
  rawRequestBody,     // string
  signatureHeader     // X-PayDirect-Signature value
);

Error Handling

import { PayDirectError } from "@paydirect/sdk";

try {
  await client.createPayment({ ... });
} catch (err) {
  if (err instanceof PayDirectError) {
    console.log(err.message);  // human-readable error
    console.log(err.status);   // HTTP status code (408 = timeout)
    console.log(err.data);     // raw response body
  }
}
v0.3.0

Payouts

// Send a payout to any address
const { payout } = await client.sendPayout({
  tokenSymbol: "ADAO",
  amount: "500",
  destinationAddress: "0xRecipient...",
  walletType: "smart_wallet",  // optional: "eoa" | "smart_wallet"
  description: "Agent payment",
});

console.log(payout.txHash);

// List payout history
const { payouts, total } = await client.listPayouts({ limit: 50 });
v0.3.0

Wallet Balance

const balance = await client.getBalance();

console.log(balance.eth, balance.usdc, balance.adao);
console.log(balance.defaultWalletType);

// Smart wallet balance (if provisioned)
if (balance.smartWallet) {
  console.log(balance.smartWallet.adao);
}
v0.4.0

Wallet Stats (Treasury / Agents)

const stats = await client.getWalletStats();

// Cumulative workspace activity (EOA + smart wallet)
console.log(stats.stats.totalActivity);
console.log(stats.stats.tokenVolumes.ADAO?.volume);

// Combined balances including settlement address
console.log(stats.balances.total.adao);

// Per-wallet breakdown
console.log(stats.wallets.smartWallet?.address);
console.log(stats.wallets.smartWallet?.transactions.total);
v0.3.0

Withdraw

const result = await client.withdraw({
  tokenSymbol: "USDC",
  amount: "50",             // omit for full balance
  walletType: "smart_wallet",
});

console.log(result.explorerUrl);
v0.3.0

Workspaces (Admin)

// Requires admin secret as apiKey
const admin = new PayDirectClient({
  apiKey: process.env.PAYDIRECT_ADMIN_SECRET!,
});

// Create workspace for a platform user
const ws = await admin.createWorkspace({
  name: "alice-workspace",
  ownerEmail: "[email protected]",
  platform: "myplatform",
  settlementWallet: "0xSettlement...",
});

console.log(ws.workspaceId, ws.apiKeys.live);

// List workspaces
const { workspaces } = await admin.listWorkspaces({ platform: "myplatform" });

// Get workspace details
const info = await admin.getWorkspace(ws.workspaceId);
v0.3.0

Smart Wallets

// Create smart wallet (ERC-4337, gasless)
const result = await client.createSmartWallet(workspaceId, {
  setDefault: true,
});

console.log(result.smartWallet.address);

// Get wallet info
const info = await client.getSmartWallet(workspaceId);
console.log(info.eoa, info.smartWallet, info.defaultWalletType);

// Switch default wallet type
await client.setDefaultWallet(workspaceId, "smart_wallet");
Python
Python SDK
paydirect - Official Python client

Installation

pip install paydirect

Initialization

from paydirect import PayDirectClient

client = PayDirectClient(
    api_key="pd_test_abc123...",
    base_url="https://www.paydirect.com/api/v1",  # optional default
)

Create a Payment (crypto)

result = client.create_payment(
    token_symbol="USDC",
    amount="100.00",
    merchant_wallet="0xYourBase...",
    description="Invoice #1234",       # optional
    metadata={"orderId": "ORD_1"},     # optional
    idempotency_key="order-1-crypto",  # optional
    expires_in_minutes=60,             # optional
)

payment = result["payment"]
receiving_address = result["receivingAddress"]
payment_url = result.get("paymentUrl")

Create a Payment (Stripe — REST)

import requests

res = requests.post(
    "https://www.paydirect.com/api/v1/payments",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": "order-1-stripe",
    },
    json={
        "paymentMethod": "stripe",
        "tokenSymbol": "USD",
        "amount": "49.00",
        "description": "Pro subscription",
        "metadata": {"orderId": "ORD_1"},
    },
)
data = res.json()
checkout_url = data.get("checkoutUrl")  # live Stripe Checkout
payment_url = data.get("paymentUrl")    # hosted PayDirect page

List, Get, Cancel, Verify

# List
result = client.list_payments(status="forwarded", limit=20)

# Get
result = client.get_payment("a1b2c3d4-...")

# Cancel
result = client.cancel_payment("a1b2c3d4-...")

# Verify
result = client.verify_payment("a1b2c3d4-...")
print(result["verified"])  # True

Webhooks

# Create
result = client.create_webhook(
    url="https://yourapp.com/webhooks",
    events=["payment.forwarded", "payment.failed"]
)

# List
result = client.list_webhooks()

# Delete
result = client.delete_webhook("7")

Webhook Signature Verification

from paydirect.webhooks import verify_signature

is_valid = verify_signature(
    secret="whsec_...",
    payload=raw_request_body,
    signature=request.headers["X-PayDirect-Signature"]
)

Error Handling

from paydirect import PayDirectError

try:
    client.create_payment(...)
except PayDirectError as e:
    print(e)          # error message
    print(e.status)   # HTTP status code
    print(e.data)     # raw response body
CLI
Command Line Tool
paydirect CLI for terminal-based API interaction

Installation

npm install -g @paydirect/cli
# or use npx
npx @paydirect/cli <command>

Configuration

# Option 1: Initialize config file
paydirect init pd_test_abc123...

# Option 2: Environment variable
export PAYDIRECT_API_KEY=pd_test_abc123...
export PAYDIRECT_BASE_URL=https://www.paydirect.com/api/v1  # optional

The init command creates a .paydirect.json file in the current directory.

Commands

CommandDescription
init <key>Save API key to .paydirect.json
payments create --token=USDC --amount=100 --wallet=0x...Create a payment
payments list [--status=pending]List payments with optional filter
payments get <id>Get payment details
payments cancel <id>Cancel a pending payment
payments verify <id>Verify payment settlement
webhooks listList webhooks
webhooks create <url> [events]Register a webhook
webhooks delete <id>Remove a webhook
keys listList API keys
statusShow recent payments

Examples

# Create a 50 USDC payment (crypto)
paydirect payments create --token=USDC --amount=50 --wallet=0xABC...

# Stripe payments: use curl/REST (CLI stripe flag coming soon)
curl -X POST https://www.paydirect.com/api/v1/payments \
  -H "Authorization: Bearer $PAYDIRECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"paymentMethod":"stripe","tokenSymbol":"USD","amount":"25.00"}'

# List pending payments
paydirect payments list --status=pending

# Verify a payment (crypto or Stripe)
paydirect payments verify a1b2c3d4-...

# Register a webhook for forwarded events
paydirect webhooks create https://myapp.com/hooks payment.forwarded,payment.failed
AI Framework Packages
NEW
Pre-built tools for AI agents to make payments, swap tokens, and manage wallets.

@paydirect/ai-sdk
Vercel AI SDK

npm install @paydirect/ai-sdk ai @ai-sdk/openai zod
import { createPayDirectTools } from "@paydirect/ai-sdk";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

const tools = createPayDirectTools({
  apiKey: process.env.PAYDIRECT_API_KEY!,
});

const { text } = await generateText({
  model: openai("gpt-4o"),
  tools,
  maxSteps: 5,
  prompt: "Check my balance then swap 10 USDC for ETH",
});

@paydirect/langchain
LangChain

npm install @paydirect/langchain @langchain/core
import { createLangChainTools } from "@paydirect/langchain";

const tools = await createLangChainTools({
  apiKey: process.env.PAYDIRECT_API_KEY!,
});
// Pass tools to your LangChain agent

Available tools: getBalance, getWalletStats, sendPayout, createPayment, getPayment, listPayments, getSwapQuote, executeSwap, withdraw

x402 Protocol (by Coinbase)
Optional
HTTP-native payments for AI agents. Install these alongside the PayDirect SDK if you want to add x402 pay-per-request to your API endpoints.

Server Side (Protect API Routes)

npm install x402-next @x402/core @x402/evm

Client Side (Agent Auto-Pay)

npm install @x402/fetch @x402/core @x402/evm

Quick Example

// Protect a route with x402
import { withX402 } from "x402-next"

export const GET = withX402(
  handler,
  "0xYourWallet",
  { price: "$0.01", network: "base-sepolia" },
  { url: "https://x402.org/facilitator" }
)

See the x402 Payments Guide for full setup instructions.