Skip to main content
Driftstack DRIFTSTACK

SDK — crypto orders

The client.cryptoOrders resource wraps every customer-facing endpoint on the surface with full type safety. Admin endpoints are not exposed; integrators that need them call the REST surface directly.

Quote

Preview a tier's fiat-cents price (and the crypto pay range, once NowPayments is wired up) without minting an order:

const quote = await client.cryptoOrders.quote({ product: 'solo_manual' });
console.log(quote.price_cents, quote.price_currency);

Mint a checkout

Always pair the call with an idempotencyKey so accidental double-submits don't mint duplicate orders:

const key = crypto.randomUUID();
const order = await client.cryptoOrders.createCheckout(
  { product: 'team_manual', price_cents: 4900, price_currency: 'USD' },
  { idempotencyKey: key },
);
console.log(order.order_id, order.payment_address);

On a duplicate key within the 24h window, the SDK returns the original order — same order_id, same created_at. See /docs/idempotency-keys.

List + drill down

const { orders } = await client.cryptoOrders.list();
for (const o of orders) {
  console.log(o.order_id, o.status, o.expires_at);
}

// V-666.BR — narrow to a single status server-side.
const { orders: paid } = await client.cryptoOrders.list({
  status: 'paid',
  limit: 25,
});

const single = await client.cryptoOrders.get('ord_abc123def456');
console.log(single.events); // V-666.AU timeline

status accepts pending, confirming, paid, failed, partial, or cancelled. Unknown values return a 400 from the server. limit is clamped to 1..=100; the default is 50.

Pagination

// V-666.BU — explicit cursor paging.
let cursor: string | undefined;
while (true) {
  const page = await client.cryptoOrders.list({ status: 'paid', cursor });
  for (const o of page.orders) console.log(o.order_id);
  if (!page.next_cursor) break;
  cursor = page.next_cursor;
}

// Or use the async iterator helper:
for await (const o of client.cryptoOrders.listAll({ status: 'paid' })) {
  console.log(o.order_id);
}

Update the customer note

await client.cryptoOrders.updateNote('ord_abc', {
  customer_note: 'PO-9921',
});

Cancel a pending order

try {
  await client.cryptoOrders.cancel('ord_abc');
} catch (err) {
  // 409: order has moved past pending; cancellation is no longer self-service.
  // 404: order doesn't exist or belongs to another account.
}

Crypto payments are non-refundable. Cancelling a pending order halts its pay window; cancelling a paid order is not supported — past billing periods stay billed. See /legal/refunds.

Fetch the receipt

The JSON receipt is the canonical machine-readable artefact. For PDF / text variants, hit the corresponding REST endpoint directly:

const receipt = await client.cryptoOrders.receipt('ord_abc');
console.log(receipt.paid_at, receipt.price_cents);

Listening for settlement

crypto.order.paid / crypto.order.failed events are emitted server-side and are now subscribable — see /docs/webhooks-crypto-events for the payload contract. For integrations without an inbound HTTPS endpoint, poll client.cryptoOrders.get(order_id) until status transitions to paid or failed. The SDK ships verifyWebhookSignature for every live event type, including the now-live crypto.order.* events alongside the session + quota + api-key + egress-capability event domains.

End-to-end example

A runnable end-to-end walkthrough — quote, idempotent checkout, update note, fetch receipt, cursor-iterate paid orders — ships with the SDK as packages/sdk-typescript/examples/crypto-checkout.ts. Run with DRIFTSTACK_API_KEY=... npx tsx examples/crypto-checkout.ts.

Related