Configuration
Three ways to run it#
| Config | What happens | Money |
|---|---|---|
| nothing | The built-in test gateway, in memory. | None moves |
gateways and store | callCash runs in your server on your own Yoco and Netcash accounts. | Customer pays your gateway, your gateway pays your bank |
key: "cc_test_…" | A client for the hosted API. | Planned. The server does not exist yet |
Giving both key and gateways throws config_invalid.
Your own gateways#
TypeScriptlib/cash.ts
// lib/cash.ts (server only)
import { CallCash } from "callcash";
import { firestoreStore } from "callcash/firestore";
export const cash = new CallCash({
gateways: {
yoco: { secretKey: process.env.YOCO_SECRET_KEY!, webhookSecret: process.env.YOCO_WEBHOOK_SECRET },
netcash: { serviceKey: process.env.NETCASH_PAYNOW_KEY!, test: process.env.NETCASH_TEST === "1" },
},
routes: { card: ["yoco", "netcash"], default: ["netcash"] },
store: firestoreStore(db),
returnUrl: "https://example.co.za/paid",
});Options#
| Option | Type | What it does |
|---|---|---|
gateways.yoco.secretKey | string | Your Yoco secret key. sk_test_ runs in test mode, anything else in live mode. |
gateways.yoco.webhookSecret | string | The whsec_ secret from registering your Yoco webhook. Needed to accept Yoco events. |
gateways.netcash.serviceKey | string | Your Pay Now service key. |
gateways.netcash.test | boolean | true while "Make test mode active" is ticked in your Netcash dashboard. Marks payments as test. |
gateways.netcash.vendorKey | string | Your software vendor key if you are a Netcash ISV. Netcash's default is used otherwise. |
routes | object | Which gateways to try, in order, per way of paying. See Payments. |
store | Store | Where payments are kept. Required with real gateways. |
returnUrl | string | Where customers land after paying. Yoco needs it. |
key | string | A cc_test_ or cc_live_ key for the hosted API. Planned. |
baseUrl | string | The hosted API's address. Planned. |
fetch | function | Replace fetch, for tests. |
now | function | Replace the clock, for tests. |
A gateway named in routes but missing from gateways throws config_invalid when the client is created.
The store#
Real gateways need a store that outlives your process, or the constructor throws config_invalid. The store is what makes a payment count once when a gateway sends the same notification twice.
- Firestore:
firestoreStore(db, collection?)fromcallcash/firestore. One document per payment, incallcashPaymentsunless you name another collection. It works withfirebase-admin's Firestore without depending on it, and needs no composite index. - Your own: implement the
Storeinterface (create,get,find,update,list).updatemust read, change and write as one atomic step, for example in a database transaction. MemoryStore: for tests only. A restart forgets everything.
callCash() and configure()#
callCash(input) is a shortcut for client().payments.create(input). Set the client it uses once, where your server starts:
TypeScript
import { configure, callCash } from "callcash";
configure({ gateways: { yoco: { secretKey: process.env.YOCO_SECRET_KEY! } }, store, returnUrl });
const payment = await callCash({ amount: 250, reference: "order_1042" });Without configure(), callCash() uses CALLCASH_KEY (and CALLCASH_URL) from the environment when set, which means the planned hosted API. Otherwise it uses the test gateway.
Environment variables#
Keep keys in environment variables, never in code or in a client bundle. The names are yours; these docs use:
Terminal
YOCO_SECRET_KEY=sk_test_...
YOCO_WEBHOOK_SECRET=whsec_...
NETCASH_PAYNOW_KEY=...
NETCASH_TEST=1