Developers · REST API

One API.
We find the route.

Quote, then send. Payve picks the best rail, signs every webhook and keeps a balanced ledger. You get four statuses and a spec that matches the server.

1 · Quote
1curl https://api…/v1/quotes \
2 -H "Authorization: Bearer $KEY" \
3 -d sourceCurrency=NGN \
4 -d destinationCurrency=KES \
5 -d amount=5000000 \
6 -d transactionType=payout
7
8{ "id": "qte_8xk2…",
9 "rate": "0.0836",
10 "destinationAmount": "418000",
11 "feeAmount": "5000",
12 "expiresAt": "…T14:36:12Z" }
2 · Send
1curl https://api…/v1/payouts \
2 -H "Authorization: Bearer $KEY" \
3 -H "Idempotency-Key: pay-0142" \
4 -d quoteId=qte_8xk2… \
5 -d method=mobile_money \
6 -d country=KE \
7 -d "beneficiary[mobileNumber]=…" \
8 -d "beneficiary[holderName]=Amina" \
9 -d merchantReference=PAY-0142
10
11{ "id": "pyt_2m9q…",
12 "status": "pending" }

Host and values illustrative. Amounts in minor units.

The whole API on one screen

Six resources. One header for auth, one for idempotency. Nothing you have to install.

  • QuotesPOST /v1/quotes — rate, margin, fee and the amount the recipient gets, held for five minutes by default.
  • PayoutsPOST /v1/payouts and /v1/payouts/bulk — bank or mobile money in five currencies. GET …/banks, …/operators and the two name-check validators.
  • CollectionsPOST /v1/payins — bank transfer, virtual account or card in NGN, GHS and KES; mobile money rolling out. Or create a payment link and share a URL.
  • ConversionsPOST /v1/conversions with a quoteId — a quote converts once; the second attempt is refused.
  • WalletsPOST /v1/wallets per currency; GET /v1/wallets for available and on-hold balances backed by ledger entries.
  • WebhooksSeven events, one signature scheme, redelivered with backoff. Redeliver any event from the dashboard or POST /v1/webhooks/events/{id}/retry.

Auth: x-api-key: sk_test_… (or x-api-key). Sandbox keys start with sk_test_. No SDK yet — the OpenAPI spec is the contract, and it's generated from the running server.

Webhooks

You learn a payment arrived from us, not from polling.

  • payout.successful
  • payout.failed
  • payin.successful
  • payin.failed
  • payin.expired
  • conversion.successful
  • conversion.failed

Deliveries that don’t get a 2xx are redelivered with backoff. Every attempt is visible in the dashboard with the response you returned, and any event can be resent.

Delivery
1POST https://you.example/payve/webhooks
2X-Payve-Event: payout.successful
3X-Payve-Timestamp: 1789994172
4X-Payve-Signature: t=1789994172,v1=3f9a…c2
5
6{ "event": "payout.successful",
7 "data": { "id": "pyt_2m9q…", "status": "successful",
8 "merchantReference": "PAYROLL-SEP-0142",
9 "destinationAmount": "418000" } }
Verify (Node)
1const [t, v1] = sig.split(",").map((p) => p.slice(p.indexOf("=") + 1));
2const expected = createHmac("sha256", secret)
3 .update(`${t}.${rawBody}`)
4 .digest("hex");
5ok = timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
6 && Math.abs(Date.now() / 1000 - Number(t)) < 300;

Why builders trust it

Three properties you can build on. All three are enforced server-side.

Idempotent

Same Idempotency-Key, same result. Never a second debit.

Send the header on anything that moves money. A retry inside 24 hours returns the original response — the money-path is safe to retry by construction, not by luck.

Signed

Every webhook carries an HMAC you can verify in six lines.

X-Payve-Signature is t=<unix>,v1=<hmac-sha256 of "t.body">. Reject anything older than five minutes or with a bad digest. The secret is yours to rotate.

Plain

Four statuses. The same four everywhere.

pending · processing · successful · failed — in the API, the dashboard, the webhooks and the app. Internally the engine tracks much more; you never have to.

A sandbox you control

Same endpoints, same statuses, same webhooks. The only difference is that the money isn’t real — and the rails do what you tell them.

  • Same contractsk_test_ keys hit the same paths and get the same shapes back. Move to live by swapping the key.
  • Rails you controlTell the sandbox rail to answer late or decline a share of payouts, and watch the reroute and the webhooks you’ll see in production.
  • Real ledgerSandbox wallets keep a balanced ledger too. Reconcile against it before you go live.

Quote. Send. Get the webhook.

Sandbox keys on signup. No SDK to install. No setup fee.