SDKs and plugins#
Every guide on this site shows plain HTTP — curl and Node's built-in fetch — because the API is small enough to call directly. The SDKs remove the boilerplate: idempotency keys, retries on 429 and 5xx, typed responses and webhook verification.
| Package | Platform | Status |
|---|---|---|
@povito/checkout-node |
Node.js 18+ | Phase 1 — in this repository, publishing with the first release |
@povito/checkout-js |
Browser drop-in | Phase 2 — see embedded checkout |
povito_checkout |
Flutter / Dart | Phase 2 |
povito-checkout-php and a WooCommerce plugin |
PHP | Phase 3, gated on licensing |
@povito/checkout-node#
No dependencies; uses the runtime's fetch.
npm install @povito/checkout-nodeCreate a session and send the shopper to it#
import { PovitoCheckout } from "@povito/checkout-node"
const povito = new PovitoCheckout({ secretKey: process.env.POVITO_CHECKOUT_SECRET_KEY })
const session = await povito.sessions.create({
reference_id: "POV-1041",
amount: 45000, // integer minor units — IQD has none, so this is 45,000 dinars
currency: "IQD",
line_items: [
{ label: "Basket", amount: 42000, type: "charge" },
{ label: "Delivery — Hi-Express", amount: 5000, type: "shipping" },
{ label: "Coupon RAMADAN", amount: 2000, type: "discount" },
],
payment_method_types: ["zaincash", "fib", "card"],
customer: { phone: "+9647800000000", name: "Ali M. Ismail" },
locale: "ar",
success_url: "https://your-store.example/checkout/return",
cancel_url: "https://your-store.example/cart",
metadata: { order_id: "POV-1041" },
})
// redirect the shopper
res.redirect(session.url)An Idempotency-Key is generated for every creating call; pass your own with { idempotencyKey } as the second argument to make retries across processes safe.
Verify by reference, never by the return URL#
const session = await povito.sessions.retrieve(id)
if (session.payment_status === "paid") fulfil(session.reference_id)Also available: sessions.list({ reference_id, status, created_after, limit, cursor }), sessions.expire(id) and paymentMethods.list().
Webhooks#
import { constructEvent, WebhookSignatureError } from "@povito/checkout-node"
app.post("/webhooks/povito", express.raw({ type: "application/json" }), async (req, res) => {
let event
try {
event = constructEvent(req.body, req.header("povito-signature"), process.env.POVITO_WEBHOOK_SECRET)
} catch (e) {
if (e instanceof WebhookSignatureError) return res.status(401).end()
throw e
}
if (event.type === "checkout.session.completed") {
// treat the webhook as a prompt: re-fetch, then act
const session = await povito.sessions.retrieve(event.data.object.id)
if (session.payment_status === "paid") await fulfil(session.reference_id)
}
res.status(200).end()
})constructEvent(rawBody, header, secret, toleranceSeconds = 300) verifies the raw bytes with a constant-time compare and parses the JSON; verifySignature does only the first half, and signPayload(rawBody, secret) produces a header the way Povito does so you can test your handler. Handle events idempotently by event.id; Povito retries on non-2xx at 1 m, 5 m, 30 m, 2 h, 6 h, 24 h, 24 h.
webhookEndpoints.create / list / retrieve / update / del and events.list / retrieve / redeliver cover the rest of the webhooks API.
Refunds#
await povito.refunds.create({ session_id: session.id, amount: 5000, reason: "Customer returned one item, ticket #4521" })Plus refunds.retrieve(id) and refunds.list({ session_id }).
Errors#
Every non-2xx response throws PovitoCheckoutError with status, code (for example amount_mismatch, idempotency_key_conflict, refund_exceeds_captured), details[] and requestId. GETs and keyed POSTs are retried on 429 and 5xx with backoff — safe because of the idempotency key.
Test mode#
Use a povito_ck_test_… key. Sessions created with it render the simulated test gateway; the test phone +9647500000000 accepts OTP 000000. See testing.