JamiDev
API Reference

Checkout

Create checkout sessions and poll their status.

Create a checkout session

POST /api/jamidev/checkout

Public (used by hosted checkout pages) or authenticated with a bearer token.

With the SDK:

const checkout = await jami.createCheckout({
	productId: '665f1c2ab8d3a2f4e1a9c222',
	customer: { email: 'buyer@example.com', phone: '0912345678' },
	gateway: 'telebirr',
});

Request body

{
	"productId": "665f1c2ab8d3a2f4e1a9c222",
	"amount": 15000,
	"customer": {
		"email": "buyer@example.com",
		"phone": "0912345678",
		"name": "Abebe B.",
		"externalId": "user_42"
	},
	"collectedFields": { "<checkoutFieldId>": "value" },
	"gateway": "telebirr",
	"checkoutLink": "cl_Q4sp2Xr5ybOi",
	"successUrl": "https://yoursite.com/thanks?c={CHECKOUT_ID}"
}
FieldNotes
productIdRequired. Must be a published product. Accepts either the public p_… product id (shown in your dashboard) or the raw ObjectId.
amountOnly for pwyw products — integer minor units, ≥ the product minimum. Ignored for fixed (server uses the configured price) and free.
customer.emailRequired. Upserts the customer per organization.
customer.phoneRequired for paid products — the payment push goes to this number. Ethiopian formats accepted (09…, 2519…, 9…).
collectedFieldsValues keyed by checkout-field id; required fields are enforced.
gatewaytelebirr | mpesa | cbe (default telebirr). Anything else is rejected.
checkoutLinkOptional cl_… token — merges the link's metadata into the order and applies its success URL. Stale tokens are ignored, never an error.
successUrlOptional. Honored for token callers; anonymous calls only when the URL's host matches one of the org's registered redirect URLs.

Responses

Free product — the order is created immediately:

{ "sessionId": "665f…", "orderId": "665f…" }

Paid, production — direct (phone-push) payment; keep the buyer on your page and poll:

{ "sessionId": "665f…", "checkoutUrl": null, "mode": "direct" }

Paid, sandbox — redirect the buyer to the simulator:

{ "sessionId": "665f…", "checkoutUrl": "https://jami.bio/jamidev/simulate/665f…", "mode": "redirect" }

Sessions expire after 30 minutes if unpaid.

Poll session status

GET /api/jamidev/checkout/{sessionId}

Public. Safe to poll every ~3 seconds — or let the SDK poll for you:

const status = await jami.waitForCheckout(sessionId); // resolves on completed/expired
{
	"sessionId": "665f…",
	"status": "open",
	"expiresAt": "2026-07-11T10:00:00.000Z",
	"amount": 10000,
	"currency": "ETB",
	"orderId": null,
	"orderStatus": null
}
  • status: opencompleted or expired.
  • When orderId is non-null, the payment succeeded and benefits are granted.
  • The endpoint actively reconciles: while a session is open it checks the payment provider directly (throttled), so polling resolves even if a provider webhook is delayed. Expired sessions are finalized automatically.

List orders

See Orders.

On this page