PayBeta API v1
Merchant Checkout Integration
Offer PayBeta Buy Now Pay Later at your checkout in three steps: create an API key, open a hosted checkout session from your backend, and receive a signed webhook when the customer's plan is approved.
1. Getting started
Sign in as a PayBeta merchant, open Merchant → Developers, and create your first API key. Save your Live and Sandbox keys somewhere safe — they are only shown once.
Base URL for every API request:
https://pay-grow-easy.lovable.app/api/public/v12. Authentication
All requests are authenticated with a Bearer API key in theAuthorization header. Keys look likepk_live_… (production) orpk_sandbox_… (test).
Authorization: Bearer pk_live_<your-secret>3. Create a checkout session
Call this from your server when a customer chooses PayBeta at checkout. You get back a checkout_url to redirect the customer to.
Request body
{
"amount": 2499.00,
"currency": "ZAR",
"reference": "order_10231",
"description": "Order #10231 — 2x Sneakers",
"customer_email": "buyer@example.com",
"customer_phone": "+27821234567",
"success_url": "https://yourstore.com/thank-you?ref=10231",
"cancel_url": "https://yourstore.com/cart",
"metadata": { "order_id": "10231", "sku": "SN-42" },
"expires_in_minutes": 60
}cURL
curl -X POST https://pay-grow-easy.lovable.app/api/public/v1/checkout/sessions \
-H "Authorization: Bearer pk_live_..." \
-H "Content-Type: application/json" \
-d '{"amount":2499,"currency":"ZAR","reference":"order_10231","success_url":"https://yourstore.com/thanks","cancel_url":"https://yourstore.com/cart"}'Node.js
const res = await fetch("https://pay-grow-easy.lovable.app/api/public/v1/checkout/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAYBETA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 2499,
currency: "ZAR",
reference: order.id,
success_url: `${site}/thanks?o=${order.id}`,
cancel_url: `${site}/cart`,
metadata: { order_id: order.id },
}),
});
const session = await res.json();
return Response.redirect(session.checkout_url, 303);Response (201)
{
"id": "b3f1…-uuid",
"object": "checkout.session",
"status": "open",
"amount": 2499,
"currency": "ZAR",
"reference": "order_10231",
"checkout_url": "https://pay-grow-easy.lovable.app/checkout/b3f1…-uuid",
"expires_at": "2026-07-23T13:00:00Z"
}4. Redirect the customer
Send the customer to session.checkout_url. PayBeta signs them in, runs credit checks, presents plan options (3 / 6 / 12 installments, weekly/bi-weekly/monthly), and captures the NCA pre-agreement acceptance. On success we forward them to your success_url.
5. Retrieve a session or plan
curl https://pay-grow-easy.lovable.app/api/public/v1/plans/PLAN_ID \
-H "Authorization: Bearer pk_live_..."Plan response
{
"id": "…",
"object": "plan",
"plan_number": "KP12345678",
"status": "active",
"total_amount": 2499,
"outstanding_balance": 1666,
"collection_frequency": "monthly",
"total_instalments": 3,
"instalments": [
{ "number": 1, "amount": 833, "due_date": "2026-07-23", "status": "paid" },
{ "number": 2, "amount": 833, "due_date": "2026-08-23", "status": "pending" },
{ "number": 3, "amount": 833, "due_date": "2026-09-23", "status": "pending" }
]
}6. Webhooks
Configure your webhook URL and signing secret under Merchant → Developers. Every event POSTs JSON with a PayBeta-Signature header.
Event types
checkout.session.completed— customer finished the hosted checkout and a plan was created.plan.approved— the plan is active and first collection scheduled.plan.paid— the final instalment has been collected.instalment.paid— a scheduled instalment was collected.instalment.failed— a scheduled instalment failed (retry in progress).
Signature header
PayBeta-Signature: t=1700000000,v1=<hex sha256 of raw body using your webhook secret>Verifying in Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody, header, secret) {
const [, , sig] = /t=(\d+),v1=([a-f0-9]+)/.exec(header ?? "") ?? [];
if (!sig) return false;
const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(sig, "hex");
const b = Buffer.from(expected, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}Example payload
{
"id": "evt_…",
"type": "checkout.session.completed",
"created": 1700000000,
"livemode": true,
"data": {
"session": { "id": "…", "reference": "order_10231", "amount": 2499, "metadata": {} },
"plan": { "id": "…", "total_amount": 2499 }
}
}7. Testing (sandbox)
Use a pk_sandbox_… key to create sessions in the sandbox environment. Sandbox sessions use PayBeta's mock PSP so no real money moves, and webhooks are dispatched to your test webhook URL if you set one (otherwise the live URL). Sandbox events include "livemode": false.
8. Errors
Errors return a JSON body and a non-2xx status:
{ "error": { "code": "invalid_request", "message": "amount must be positive" } }| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Payload validation failed. |
| 401 | unauthorized | Missing/invalid API key. |
| 404 | not_found | Session or plan does not belong to your merchant. |
| 409 | duplicate_reference | reference already exists for this merchant. |
| 500 | server_error | Retry with exponential back-off. |