Escrow Safe Trade is live: protect your next high-value deal Learn more
ProductsPayment links & checkoutM-Pesa, cards, invoices, split payoutsEscrow Safe TradeMilestone and release-based escrowWallets & P2PPersonal and business walletsChama, Lengo & DeniGroup savings, goals and IOUsBusiness toolkitAccounting, payroll, POS, ticketingBulk payments & payrollPay many people in one uploadSubscriptions & billingRecurring plans and renewalsRent, loans & donationsCollections and campaignsAll products
SolutionsMerchantsBuyersChama groupsBusiness solutionsIndustries
Pricing
DevelopersDeveloper overviewQuickstart, auth and sandboxREST APIsCheckout, invoices and requestsWebhooksSigned, real-time eventsWallet-as-a-ServiceVirtual sub-accountsDocumentationGuides and API reference
Security
CompanyAbout usCareersPartnersBlogHelp centreContact us
Log in Get started Talk to sales
Events & guides

Integration Examples

Copy-paste starting points for a React button, plain HTML and the command line. All of them keep your API key on the server.

React — Checkout Button
"use client";
import { useState } from "react";

export function CheckoutButton({ amount, description }: { amount: number; description: string }) {
  const [loading, setLoading] = useState(false);

  async function startCheckout() {
    setLoading(true);
    try {
      // Call YOUR backend — never put API keys in the browser
      const res = await fetch("/api/create-checkout", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ amount, description }),
      });
      const { url } = await res.json();
      window.location.href = url; // redirect to hosted checkout page
    } finally {
      setLoading(false);
    }
  }

  return (
    <button onClick={startCheckout} disabled={loading}>{loading ? "Redirecting..." : `Pay KES ${(amount / 100).toFixed(2)}`}</button>
  );
}

// ── Your server-side route (/api/create-checkout) ──
// POST /api/create-checkout
export async function POST(req: Request) {
  const { amount, description } = await req.json();
  const res = await fetch("https://api.paysasa.com/api/v1/checkout/sessions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": process.env.PAYSASA_API_KEY!,
    },
    body: JSON.stringify({
      amount,
      currency: "KES",
      business_id: process.env.PAYSASA_BUSINESS_ID!,
      description,
      success_url: `${process.env.APP_URL}/order/success`,
      cancel_url: `${process.env.APP_URL}/cart`,
    }),
  });
  const { session } = await res.json();
  return Response.json({ url: session.hosted_url });
}
Plain HTML / Vanilla JS
<!DOCTYPE html>
<html>
  <body>
    <button id="pay-btn">Pay KES 150</button>
    <script>
      document.getElementById("pay-btn").addEventListener("click", async () => {
        // Proxy through YOUR backend to keep API key secret
        const res = await fetch("/create-checkout", { method: "POST" });
        const { url } = await res.json();
        window.location.href = url;
      });
    </script>
  </body>
</html>
cURL
curl -X POST https://api.paysasa.com/api/v1/checkout/sessions \
  -H "Content-Type: application/json" \
  -H "x-api-key: apk_live_a1b2c3d4.7f9e0a..." \
  -d '{
    "amount": 15000,
    "currency": "KES",
    "business_id": "biz_xxxxxxxxxxxxxxxx",
    "description": "Order #1042",
    "success_url": "https://yourstore.com/success",
    "cancel_url": "https://yourstore.com/cancel"
  }'