ChapaChapa Docs

HTML Checkout

Accept payments using a simple HTML form that redirects customers to Chapa's hosted checkout.

HTML Checkout lets you accept payments using a simple HTML form that redirects customers to Chapa's hosted checkout, without building a complex frontend integration.

It is best suited for:

  • Static websites
  • Simple e-commerce pages
  • Donation pages
  • Event ticket pages
  • Low-code / CMS platforms (WordPress, Webflow, etc.)
  • Quick prototypes

If you need full control over the payment flow, use the Hosted API directly: POST /v2/payments/hosted

How HTML Checkout Works

  1. Render a payment form in your website
  2. Customer submits the form
  3. Your backend initializes a payment with Chapa
  4. Chapa returns a checkout_url
  5. Customer is redirected to Chapa checkout
  6. Payment completes
  7. You verify the payment and/or receive a webhook

Important: The secret API key must always stay on the server.

Step 1: Create a Checkout Form (Frontend)

This form collects customer and payment information only. It does not talk to Chapa directly.

Example HTML:

<form id="pay-form">
  <input type="text" name="first_name" placeholder="First name" required />
  <input type="text" name="last_name" placeholder="Last name" required />
  <input type="email" name="email" placeholder="Email" required />
  <input type="tel" name="phone_number" placeholder="2517..." required />
  <input type="number" name="amount" placeholder="Amount" required />
  <select name="currency" required>
    <option value="ETB">ETB</option>
    <option value="USD">USD</option>
    <option value="UGX">UGX</option>
    <option value="DJF">DJF</option>
  </select>
  <button type="submit">Pay Now</button>
</form>

Step 2: Send Form Data to Your Backend

<script>
  document.getElementById("pay-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const form = e.target;
    const payload = {
      amount: Number(form.amount.value),
      currency: form.currency.value,
      merchant_reference: "ORDER_" + Date.now(),
      customer: {
        first_name: form.first_name.value,
        last_name: form.last_name.value,
        email: form.email.value,
        phone_number: form.phone_number.value
      },
      meta: {
        source: "html_checkout"
      }
    };
    const res = await fetch("/create-checkout", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload)
    });
    const data = await res.json();
    if (data?.data?.checkout_url) {
      window.location.href = data.data.checkout_url;
    } else {
      alert("Failed to initialize payment. Please try again.");
    }
  });
</script>

Step 3: Backend Endpoint (Required)

Your backend:

  • Receives the payload
  • Calls Chapa using your secret key
  • Returns checkout_url to the frontend

Backend Responsibilities:

  • Validate amount and currency
  • Validate customer fields
  • Call POST /v2/payments/hosted
  • Return only the checkout_url

Never expose CHAPA_TEST_ or CHAPA_LIVE_ keys in HTML or JavaScript.

Payment Initialization (Backend → Chapa)

POST https://api.chapa.co/v2/payments/hosted
Authorization: Bearer <SECRET_KEY>
Content-Type: application/json

Payload is forwarded from the frontend after validation.

After Redirect: Payment Verification

Once the customer completes payment:

  1. Chapa redirects the user (UX signal)
  2. A webhook is sent (recommended)
  3. Your backend must verify the payment

Verify Payment:

GET /v2/payments/{reference}/verify

Only after verification returns success should you:

  • Mark the order as paid
  • Deliver goods or services

Webhooks provide the most reliable confirmation.

Typical events:

  • payment.success
  • payment.failed
  • payment.cancelled
  • payment.incomplete
  • payment.auth_needed
  • payment.blocked

Best Practices:

  • Validate webhook authenticity
  • Handle duplicate events (idempotency)
  • Update internal transaction state
  • Optionally re-verify critical payments

Security Notes

Do

  • Always call Chapa from your backend
  • Use merchant_reference for tracing
  • Use idempotency keys for retries
  • Validate user input server-side
  • Rely on verification and webhooks

Don't

  • Put secret keys in HTML/JS
  • Trust redirect success alone
  • Assume payment is complete without verification

Common Use Cases

  • "Pay Now" button on landing pages
  • Donation pages
  • Simple event ticket checkout
  • Quick embedded payment flows
  • CMS-based websites

When NOT to Use HTML Checkout

Avoid HTML Checkout if you need:

  • One-click payments
  • Advanced UI control
  • Deep mobile integration
  • Direct charge flows

In those cases, use:

Next Steps

On this page