Introduction
Sell digital products in ETB with hosted checkout pages, benefits, webhooks and an API — settled through ArifPay.
Documentation Index
Fetch the complete documentation index at: https://dev.jami.bio/llms.txt
Use this file to discover all available pages before exploring further. For every page's raw
markdown source, append .md to its URL (e.g. https://dev.jami.bio/docs/quickstart.md), or
fetch the whole docs set in one call at https://dev.jami.bio/llms-full.txt.
JamiDev is Jami's product-and-payments layer for developers. You create products, share a checkout link (or embed checkout on your own site), and JamiDev handles the payment through local Ethiopian gateways, grants benefits like license keys, notifies your backend with signed webhooks, and emails receipts — all settled in ETB.
AI agent integration prompt
Paste the prompt below into Claude Code, Cursor, Windsurf, Codex or another coding agent to scaffold a full JamiDev integration — sandbox setup, checkout, webhook verification and going live.
# Goal — ship your first JamiDev checkout end-to-end
You are integrating JamiDev (https://dev.jami.bio/docs) into my project. Take me from zero
to a working checkout: product, checkout session, payment, webhook, fulfilled order.
## My application context
<my_stack>
Stack: [framework + language, e.g. Next.js 15 + TypeScript]
Surface: [web | backend-only | mobile webview]
Use case: [one-time digital product | subscription | donation]
Database: [Postgres | MySQL | Mongo]
</my_stack>
## Steps
1. **Enable Developer Mode & create a sandbox org** — requires a KYC-verified Jami account.
In the dashboard: Settings → Developer Mode, then switch to a sandbox organization
(simulated payments, nothing real moves).
2. **Create a product** — Store → Products → New product. Pick a pricing model (`fixed`,
`pwyw` or `free` — locked after creation). Publish it and copy the product id.
3. **Get an API token** — Developer → API Tokens. Save it as `JAMI_TOKEN`
(`jamidev_test_…` in sandbox, `jamidev_live_…` in production).
4. **Install the SDK and create a checkout**
```bash
npm install jami-sdk
```
```ts
import { Jami } from 'jami-sdk';
const jami = new Jami({ token: process.env.JAMI_TOKEN! });
const checkout = await jami.createCheckout({
productId: '<product id>',
customer: { email: 'buyer@example.com', phone: '251900000001' }, // magic sandbox success number
gateway: 'telebirr', // 'telebirr' | 'mpesa' | 'cbe'
});
```
Free products resolve instantly (`orderId` present). Paid products return `mode: 'redirect'`
(send the buyer to `checkoutUrl`) or `mode: 'direct'` (buyer confirms on their phone — poll next).
5. **Wait for payment**
```ts
if (!('orderId' in checkout)) {
const status = await jami.waitForCheckout(checkout.sessionId);
// status.status: 'completed' | 'expired', status.orderId
}
```
6. **Register a webhook and verify deliveries** — Automation → Webhooks → add your endpoint
URL, save the returned secret as `JAMI_WEBHOOK_SECRET`. Subscribe to `order.created`,
`order.completed`, `benefit.granted`, `checkout.session.expired`.
```ts
import { JamiSignatureError } from 'jami-sdk';
const event = await jami.webhooks.verify({
payload: rawBody, // exactly as received, do not JSON.parse first
signature: req.headers['x-jamidev-signature'],
secret: process.env.JAMI_WEBHOOK_SECRET!,
});
// event.type: 'order.created' | 'order.completed' | 'benefit.granted' | 'checkout.session.expired'
```
Respond `2xx` within 10 seconds. Handle idempotently — retries and manual resends can
redeliver the same `event.id`.
7. **List orders (fallback / reconciliation)**
```ts
const { items, total } = await jami.listOrders({ status: 'paid', page: 1, limit: 20 });
```
8. **Go live** — Settings → Environment → switch to production, register production
webhook endpoints (subscriptions are per-organization), and issue a fresh `jamidev_live_`
token.
## Failure modes
- Missing/invalid token → `401`, with `.hint` set when the token was minted for the org's
other environment (re-issue it).
- Validation error → `400`, message names the offending field.
- `POST /checkout` limited to 20 requests / 5 minutes / IP → `429`.
- Webhook signature mismatch, malformed header, or stale timestamp (>300s) → throws
`JamiSignatureError`; treat the delivery as untrusted.
## Sources of truth (cross-check before shipping)
- https://dev.jami.bio/llms-full.txt — full docs in one fetch
- https://dev.jami.bio/openapi.json — machine-readable REST spec
- /docs/api — raw REST reference (checkout, orders)
- /docs/sdk — typed SDK reference and error types
- /docs/webhooks — event payloads and signature verificationCore concepts
| Concept | What it is |
|---|---|
| Organization | An isolated workspace: its own products, customers, checkout links, API tokens, webhooks and balance. You can own several and switch between them from the dashboard header. |
| Environment | Every organization is either sandbox (simulated payments, nothing real moves) or production (live ArifPay charges). Switchable both ways in Settings. |
| Product | A sellable item with a pricing model — fixed, pwyw (pay-what-you-want) or free. The pricing model is locked after creation. |
| Checkout session | A short-lived (30 min) attempt to buy one product. Snapshots the price and metadata at creation, so later product edits never affect in-flight checkouts. |
| Order | A completed, paid checkout. Idempotent — a session can only ever produce one order, no matter how many times payment notifications replay. |
| Benefit | Something granted automatically on purchase, e.g. a generated license key. |
| Checkout link | A long-lived shareable URL (/jamidev/c/…) that can offer one or several products, carry metadata onto orders, and redirect buyers back to your site. |
Money
- All API amounts are integer ETB minor units (santim).
10000= 100.00 ETB. - Buyers pay exactly the listed price — nothing is added at checkout. A 100 ETB product charges the buyer 100 ETB.
- Taxes are deducted when the seller withdraws: 30% government tax + 5% Jami usage fee (a 100 ETB balance pays out 65 ETB). The dashboard's balance breakdown shows this estimate.
- Amounts are always computed server-side from the trusted price configuration. For
fixedproducts any client-supplied amount is ignored; forpwywthe amount must be an integer at or above the product's minimum.
Payment methods
Checkout supports Telebirr, M-Pesa and CBE Birr via ArifPay direct transfer — the buyer stays on the checkout page and confirms the payment on their phone. No card data ever touches Jami.
Sign in with Jami
Beyond payments, Jami is an OAuth 2.1 / OpenID Connect provider. You can put a
"Sign in with Jami" button in your own product and authenticate Jami users without
building an account system — v1 is identity only (sub, name, picture, email), with
resource scopes to follow. See Sign in with Jami.
What's coming
An official client SDK (@jami/jamidev) is planned — until then, the REST API
is small and stable enough to call directly.
