Node.js SDK @watenga/node

Node 18 or later; TypeScript types included.

Installation

bash
npm install @watenga/node

Before the first release

The package is release-ready; until it is published, install it from a checkout of the Watenga repository:
bash
pnpm --filter @watenga/node build && cd packages/watenga-node && npm pack
npm install /path/to/watenga-node-1.0.0.tgz

Take a test payment

Use a test secret key (sk_test_…) from the developer console. Test keys never move money: use the test cards and wallet numbers.

typescript
import Watenga from '@watenga/node';

const watenga = new Watenga(process.env.WATENGA_SECRET_KEY!); // sk_test_...

const checkout = await watenga.checkout.create({
  amount: '25.00',
  currency: 'USD',
  merchant_transaction_id: 'ORD-1001',
  return_url: 'https://shop.example/return',
});
// Send the buyer to checkout.payment_url

Receive the webhook

Verify the Watenga-Signature header against the raw request body before you trust an event. While you rotate the endpoint's signing secret, pass both secrets: either one verifies. On your machine, watenga listen --forward-to <your URL> (the CLI) forwards test events signed with a session secret.

typescript
import express from 'express';
import { Webhooks } from '@watenga/node';

app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  let event;
  try {
    event = Webhooks.constructEvent(req.body, req.headers['watenga-signature'] as string, process.env.WATENGA_WEBHOOK_SECRET!);
  } catch {
    return res.sendStatus(400);
  }
  if (event.type === 'payment.capture.completed') {
    // fulfil the order for event.data.object (a transaction)
  }
  res.sendStatus(200);
});

Errors

Every failed call raises one error type with the stable code, the HTTP status, the request_id to quote to support, the field at fault (param) and the code's page in the error reference.

typescript
import { WatengaApiError } from '@watenga/node';

try {
  await watenga.refunds.create('txn_...', { amount: '5.00', reason: 'customer_request' });
} catch (err) {
  if (err instanceof WatengaApiError) {
    console.error(err.code, err.statusCode, err.param, err.requestId, err.docUrl);
  }
}

Retries and idempotency

Network errors, 429 (after Retry-After) and 5xx answers are retried twice with backoff. Every write carries an Idempotency-Key, kept across those retries, so a retry is answered once and never applied twice; checkout.create uses checkout:<merchant_transaction_id>. See Idempotency.

typescript
// Every write gets an Idempotency-Key, kept across the SDK's own retries.
// When you retry a call yourself, pass the same key:
await watenga.refunds.create('txn_...', { reason: 'duplicate' }, { idempotencyKey: 'refund-ORD-1001' });

Pagination

Every list answers one page, { object: "list", data, has_more, next_cursor }; the auto-paginating form reads them all. See Pagination.

typescript
const page = await watenga.transactions.list({ status: 'completed', limit: 50 });
// { object: 'list', data: [...], has_more, next_cursor }

for await (const txn of watenga.transactions.listAll({ status: 'completed' })) {
  console.log(txn.id, txn.amount, txn.currency);
}

Resources

The SDK sends Watenga-Version: 2026-10-29; fields use the API's names (snake_case) and money is a decimal string. The same method names in every language.

ResourceMethods
checkoutcreate, getStatus
checkoutSessionscreate, retrieve, expire
transactionslist, listAll, retrieve, getMobileStatus
refundscreate
paymentLinkscreate, list, listAll, retrieve, update, deactivate, clone, versions, analytics
invoicescreate, list, listAll, retrieve, update, send, remind, void, templates
quotationscreate, list, listAll, retrieve, update, issue, revise, void, duplicate, convertToInvoice
planscreate, list, listAll, retrieve, update, del
subscriptionscreate, list, listAll, retrieve, cancel, pause, resume, change, upcomingInvoice, listInvoices, events
billingrecordUsage, reverseUsage, checkEntitlement
customerscreate, list, listAll, retrieve, update, timeline, setTag, paymentMethods
paymentMethodscreate, list, listAll, retrieve, del, charge
accountgetBalance, getProfile, getApiKey
automationslist, retrieve, listRuns, retrieveRun, registry, dryRun (read-only)
webhooksconstructEvent, generateTestSignature

Refunds and payouts

A secret key refunds when its app's Refunds switch is on and an Admin has set refund limits; a restricted key needs the refunds scope (Refunds). Payouts to your bank are dashboard-only, with two-step verification: they are not in the API or the SDKs.