PayBeta

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/v1

2. 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.

POST/api/public/v1/checkout/sessions

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

GET/api/public/v1/checkout/sessions/{id}
GET/api/public/v1/plans/{id}
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" } }
StatusCodeMeaning
400invalid_requestPayload validation failed.
401unauthorizedMissing/invalid API key.
404not_foundSession or plan does not belong to your merchant.
409duplicate_referencereference already exists for this merchant.
500server_errorRetry with exponential back-off.