Quickstart

A test payment and its webhook, end to end: your server creates a checkout session, the customer pays it, and your server fulfils the order from the signed webhook.

1. Get test keys

In the developer console, create an API app in test mode. Copy its publishable key (pk_test_…) and secret key (sk_test_…, shown once) into your server's environment. A test key never moves money.

2. Install an SDK

bash
npm install @watenga/node

Until the packages are on their registries, each SDK page shows how to install it from the Watenga repository. Raw HTTP works too: send Authorization: Bearer sk_test_… and Watenga-Version: 2026-10-29.

3. Create a checkout session on your server

The amount is decided by your server; the browser or app only pays the session.

typescript
import express from 'express';
import Watenga from '@watenga/node';

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

app.post('/checkout-session', async (_req, res) => {
  const session = await watenga.checkoutSessions.create({
    amount: '25.00',           // your server decides the amount
    currency: 'USD',
    reference: 'ORD-1001',
    return_url: 'http://localhost:3000/thank-you',
  });
  res.json({ client_secret: session.client_secret, url: session.url });
});

4. Let the customer pay

Redirect to the session's url (a Watenga-hosted page), or show the checkout in your page with Watenga.js and the session's client_secret:

markup
<script src="https://js.watenga.africa/v1/watenga.js"></script>
<div id="payment-form"></div>
<script>
  // Your server created the checkout session (step 1) and returned its client_secret.
  fetch('/checkout-session', { method: 'POST' })
    .then((r) => r.json())
    .then((session) => {
      Watenga('pk_test_your_publishable_key').mount('#payment-form', {
        clientSecret: session.client_secret,
        amount: 25.00,
        currency: 'USD',
        reference: 'ORD-1001',
        onSuccess: function (txn) { window.location.href = '/thank-you?payment=' + txn.id; },
        onError: function (err) { console.error(err.code, err.message); }
      });
    });
</script>

Pay with a test card (any future expiry, any CVC):

Card numberBrandWhat happens
4111 1111 1111 1111VisaApproved: payment.capture.completed
4000 0000 0000 0002VisaDeclined by the issuer (do not retry): payment.capture.declined
4000 0000 0000 9995VisaDeclined, insufficient funds (the buyer may retry)
4000 0000 0000 0119VisaProvider timeout: stays pending, then fails

Expiry: any future month, e.g. 12/34. CVC: any 3 digits. Any name and address. Test keys only: these numbers never reach a card network.

5. Receive the webhook

Fulfil the order when payment.capture.completed arrives, never from onSuccess or the return address alone. Verify the Watenga-Signature header against the raw body:

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);
});

On your machine, forward your test app's events with the CLI and use the secret it prints:

bash
watenga listen --forward-to http://localhost:3000/webhooks

In production, add your HTTPS endpoint under the app's webhook endpoints in the developer console and use its signing secret.

6. Go live

When the test payment and webhook work, follow the go-live checklist: a live app and keys, the live signing secret, and your business verified.