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
- Render a payment form in your website
- Customer submits the form
- Your backend initializes a payment with Chapa
- Chapa returns a
checkout_url - Customer is redirected to Chapa checkout
- Payment completes
- You verify the payment and/or receive a webhook
Important: The secret API key must always stay on the server.
Recommended Implementation (Secure)
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_urlto 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/jsonPayload is forwarded from the frontend after validation.
After Redirect: Payment Verification
Once the customer completes payment:
- Chapa redirects the user (UX signal)
- A webhook is sent (recommended)
- Your backend must verify the payment
Verify Payment:
GET /v2/payments/{reference}/verifyOnly after verification returns success should you:
- Mark the order as paid
- Deliver goods or services
Webhooks (Strongly Recommended)
Webhooks provide the most reliable confirmation.
Typical events:
payment.successpayment.failedpayment.cancelledpayment.incompletepayment.auth_neededpayment.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_referencefor 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:
- Hosted API
- Inline.js
- Direct Charge
Next Steps
- Accept Payments - Full hosted payment integration
- Quick Start - Simple end-to-end payment flow
- Dashboard Overview - Manage payments from the dashboard