Start
Getting started
Create a payment session, embed checkout, and receive webhooks.
Prerequisites
- Portal access with KYB approved, business status ACTIVE, and a receive payment ID configured.
- Production checkout domains registered under Integrations → Allowed browser origins.
- An HTTPS endpoint that can accept Zippy webhook POSTs.
- Backend ability to store secrets securely (API key + webhook signing secret).
- A page or route on a registered origin where you can embed
@zippypay/checkout.
Configure Zippy Pay
- Complete KYB and confirm business is active in the portal. Payment session creation requires KYB approval,
status = ACTIVE, and a configured receive payment ID. - Register allowed browser origins under Integrations → Allowed browser origins for every domain where checkout runs (HTTPS in production;
localhostfor local dev only). - Create an API key under Developer → API Keys. Plaintext is shown once as
zp_live_.... - Register an HTTPS webhook endpoint under Developer → Webhooks. Store the one-time
whsec_...signing secret.
Create a payment session
From your trusted backend, call POST /api/v1/payment-sessions with your business API key. Send Idempotency-Key and X-Correlation-Id on every create request.
/api/v1/payment-sessionscurl -X POST "https://api.zippypay.io/api/v1/payment-sessions" \
-H "Content-Type: application/json" \
-H "X-Api-Key: zp_live_REDACTED" \
-H "Idempotency-Key: 83596f5e-2134-4e66-8304-20d61f290cf0" \
-H "X-Correlation-Id: merchant-request-123" \
-d '{
"amount": "25.00",
"currency": "USD",
"merchantReference": "order-12345",
"successUrl": "https://yourstore.com/checkout/success",
"failureUrl": "https://yourstore.com/checkout/failure",
"metadata": {
"orderId": "12345"
}
}'Response excerpt
json{
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"clientToken": "zps_REDACTED",
"expiresAt": "2026-08-31T12:30:00.000Z"
}Store sessionId with your order or cart. Pass sessionId and clientToken to the Checkout SDK — never expose your zp_live_ API key in the browser.
Embed checkout
Install and initialize @zippypay/checkout with the values returned from session creation:
Checkout SDK quick embed
javascriptimport { ZippyPay } from "@zippypay/checkout";
const checkout = ZippyPay.create({
sessionId: "550e8400-e29b-41d4-a716-446655440000",
clientToken: "zps_REDACTED",
container: "#zippy-checkout",
onComplete: (result) => {
console.log("Payment complete", result);
},
onError: (error) => {
console.error("Checkout error", error);
},
});The customer completes payment in the embedded checkout UI. Your backend does not accept card or wallet details directly — the SDK and Zippy mobile app handle payer authentication.
Receive events
Prefer webhooks for fulfillment. When a payment succeeds, Zippy sends payment_session.completed with the session status, amount, and transaction details:
payment_session.completed
json{
"id": "11111111-1111-4111-8111-111111111111",
"type": "payment_session.completed",
"createdAt": "2026-08-31T12:00:00.000Z",
"data": {
"paymentSessionId": "550e8400-e29b-41d4-a716-446655440000",
"status": "COMPLETED",
"merchantReference": "order-12345",
"amount": "25.00",
"currency": "USD",
"transactionId": "880e8400-e29b-41d4-a716-446655440003",
"transactionStatus": "COMPLETED",
"payer": {
"paymentId": "john.doe12",
"displayName": "John S."
}
}
}As a fallback, poll merchant GET endpoints from your backend by sessionId or merchantReference until status is terminal. See Get a payment session and Get by merchantReference.
Verify every delivery with your whsec_... secret before updating order state. Read Webhooks overview and signature verification for the full receiver checklist.
Common failures
- Sending the API key under a header other than
X-Api-Key. - Embedding checkout before prerequisites are met (KYB, active business, payment ID, or registered origin) → session create or checkout init fails.
- Checkout hosted on an unregistered domain →
payment-session.origin-not-allowed. - Passing the API key to the browser instead of the
zps_client token. - Webhook URL not HTTPS, or verifying a re-serialized JSON body instead of the exact raw bytes.
- Fulfilling on redirect alone without verifying
payment_session.completed.