Skip to content

@usestack/node

Terminal window
npm install @usestack/node

Node 18+, no dependencies, ESM and CommonJS.

import Stack from '@usestack/node'; // or: import { Stack } from '@usestack/node'
const stack = new Stack(process.env.STACK_SECRET_KEY!, { timeoutMs: 30_000, maxRetries: 2 });
Option Default
baseUrl https://api.usestack.cc The Stack API.
timeoutMs 30000 Per attempt.
maxRetries 2 For network errors, 429 and 5xx, with exponential backoff. Retries reuse the idempotency key.
fetch global fetch For tests or a custom transport.

Throws if secretKey isn’t a secret key (sk_test_… / sk_live_…).

stack.testMode is true for sk_test_ keys.

const intent = await stack.paymentIntents.create(
{ amount: 570_000, currency: 'NGN', description: 'Order 123', metadata: { orderId: '123' }, customer: { email } },
{ idempotencyKey: 'order_123' },
);
intent.client_secret; // send to your app

params: amount (kobo, integer), currency ('NGN'), and optionally description, metadata and customer: { email?, phone? }.

options.idempotencyKey: generated per call if you leave it out.

Returns a CreatedPaymentIntent: a payment intent plus client_secret.

Returns the PaymentIntent.

Cancels an unpaid payment. Returns the PaymentIntent. Safe to repeat.

const refund = await stack.refunds.create({ paymentIntent: 'pi_...', amount: 100_000 }, { idempotencyKey: 'refund_123' });

params: paymentIntent, and amount in kobo (leave it out for a full refund).

Returns a Refund: { id, payment_intent, amount, status, created_at }.

verify(rawBody, signatureHeader, secret, toleranceSeconds = 300)

Section titled “verify(rawBody, signatureHeader, secret, toleranceSeconds = 300)”
const event = stack.webhooks.verify(req.body, req.headers['stack-signature'], process.env.STACK_WEBHOOK_SECRET!);

Checks the signature and the timestamp, and returns the parsed WebhookEvent. Throws StackSignatureError if either is wrong: answer 400 and drop the event. rawBody must be the exact bytes received (string, Buffer or Uint8Array).

Also exported on its own as verifyWebhook.

generateTestHeader(payload, secret, timestamp?)

Section titled “generateTestHeader(payload, secret, timestamp?)”

Builds a valid Stack-Signature header for your own tests:

import { generateTestHeader } from '@usestack/node';
const body = JSON.stringify({ id: 'evt_test', type: 'payment_intent.succeeded', data: { /* … */ } });
await request(app).post('/stack/webhook').set('stack-signature', generateTestHeader(body, SECRET)).send(body);

Works out fees locally, with no network call. Amounts are in kobo.

stack.fees.of(1_000_000, 'card');
// { amount: 1000000, stackFee: 5000, paystackFee: 25000, totalFees: 30000, youReceive: 970000 }
stack.fees.grossUp(1_000_000, 'card');
// { amount: 1030613, stackFee: 5153, paystackFee: 25460, totalFees: 30613, youReceive: 1000000 }
  • of(amount, method, { international? }): what a payment of amount costs you, and what you receive.
  • grossUp(target, method = 'card', { international? }): the smallest amount to charge so you receive at least target. For passing the fees on.

method is 'balance', 'card', 'debit' or 'transfer'. Stack’s fee is exactly what the API charges. Paystack’s is estimated from its published rates (1.5% + ₦100 from ₦2,500, capped at ₦2,000; 3.9% + ₦100 for a foreign card with international: true).

The same functions are exported on their own (fees, grossUp, stackFee, paystackFee), with DEFAULT_FEE_SCHEDULE. Pass feeSchedule to new Stack() only if Stack has agreed different fees with you.

StackError: type, status, message, details, requestId. See Errors.

StackSignatureError: a webhook that didn’t verify.

PaymentIntent, CreatedPaymentIntent, PaymentIntentStatus, PaymentIntentCreateParams, Refund, RefundCreateParams, RequestOptions, WebhookEvent, WebhookEventType, PaymentSucceededData, PaymentFailedData, FeeBreakdown, FeeMethod, FeeOptions, FeeSchedule.