API docs
Sandbox first. Live keys stay locked until ECCB authorization. Money-moving POSTs require an Idempotency-Key UUID.
Quickstart — payment link
curl -X POST "$RAILS/v1/payment-requests" \
-H "authorization: Bearer $JWT" \
-H "content-type: application/json" \
-d '{
"kind": "link",
"merchant_account_id": "<merchant-uuid>",
"amount": 25.00,
"reference": "Invoice 12"
}'The response includes fee, net, and link_path (/l/:slug). Hosted checkout is wallet-only in v1.
v1 map
POST /v1/accounts— customer, merchant, or agent walletGET /v1/accounts/me·GET /v1/accounts/:id/balancePOST /v1/payment-requests·POST /v1/payment-requests/:id/payGET /v1/fees/current— public schedulePOST /v1/redemptions—subtype=standard|instantGET /v1/webhook-endpoints·POST /v1/webhooks/deliver
Webhook signatures
Header format t=<unix>,v1=<hex>. Compute HMAC-SHA256 of timestamp + "." + raw body with the endpoint secret. Reject if the timestamp is older than 5 minutes.
const crypto = require("crypto");
function verify(secret, header, payload) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${payload}`)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(parts.v1),
Buffer.from(expected),
);
}