Billing (Sumit)
LeonAI billing runs on Sumit (OfficeGuy) in US dollars (USD). Sumit adds 18% Israeli VAT to the ex-VAT list prices and issues a tax invoice/receipt (חשבונית מס/קבלה). All billing endpoints require a JWT (they are account operations — API keys are intentionally not accepted).
The legacy Stripe integration has been removed. All checkout, invoicing, and renewals now go through Sumit.
Pricing
List prices are ex-VAT, in US dollars. Annual billing saves 20%: a yearly plan is charged once a year at the annual per-month price × 12.
| Tier | Monthly (ex-VAT) | Yearly (ex-VAT) |
|---|---|---|
| Pro | $19 | $180 ($15/mo) |
| Business | $79 | $756 ($63/mo) |
| Enterprise | $299 | $2,868 ($239/mo) |
Plans (public)
curl https://api.short.leonai.io/api/v1/billing/plans
REST: GET /api/v1/billing/plans (no auth). Returns the public config the browser needs
to tokenize a card — the Sumit companyId and public API key — plus the USD
catalogue. Every amount carries its currency; priceMinor is in cents and price
in dollars:
{
"success": true,
"data": {
"provider": "sumit",
"configured": true,
"companyId": 123456,
"apiPublicKey": "...",
"currency": "USD",
"vatNote": "Prices are ex-VAT; 18% Israeli VAT is added at checkout.",
"plans": [
{
"tier": "pro",
"interval": "monthly",
"priceMinor": 1900,
"price": 19,
"currency": "USD",
"itemName": "LeonAI Pro (Monthly)"
}
]
}
}
Subscribe: the three-step flow
Card data is tokenized directly in the browser against Sumit and never touches the LeonAI backend (PCI scope stays with Sumit).
1. Checkout — reserve a session
curl -X POST https://api.short.leonai.io/api/v1/billing/checkout \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "tier": "pro", "interval": "monthly" }'
REST: POST /api/v1/billing/checkout. Body:
| Field | Required | Notes |
|---|---|---|
tier | yes | pro | business | enterprise |
interval | no | monthly (default) | yearly |
legalName | no | Company legal name for the invoice |
companyNumber | no | Company registration number |
Returns a short-lived identifier (a server-side session, TTL 1 hour) plus the
amount it will charge (priceMinor, in cents, ex-VAT) and its currency:
{
"success": true,
"data": {
"identifier": "…",
"priceMinor": 1900,
"currency": "USD",
"tier": "pro",
"interval": "monthly"
}
}
2. Tokenize the card in the browser
Using the companyId and apiPublicKey from /billing/plans, POST the raw card
directly to Sumit's vault (never to LeonAI):
POST https://api.sumit.co.il/creditguy/vault/tokenizesingleusejson/
{
"Credentials": { "CompanyID": <companyId>, "APIPublicKey": "<apiPublicKey>" },
"CardNumber": "…", "ExpirationMonth": "…", "ExpirationYear": "…",
"CVV": "…", "CitizenID": "<israeli-id>"
}
A success (Status === 0) returns a single-use token at Data.SingleUseToken. Only
this token — never the PAN or CVV — is sent to LeonAI.
3. Confirm — charge and activate
curl -X POST https://api.short.leonai.io/api/v1/billing/confirm \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "identifier": "…", "singleUseToken": "…", "cardLast4": "4242", "cardExpMonth": 12, "cardExpYear": 2028 }'
REST: POST /api/v1/billing/confirm. identifier and singleUseToken are required;
cardLast4 / cardExpMonth / cardExpYear are optional and used only for display.
LeonAI creates the Sumit recurring standing order (Sumit drives renewals itself via
Duration_Months), upgrades your tier, and issues the first tax invoice:
{
"success": true,
"data": { "tier": "pro", "status": "active", "documentUrl": "https://…/invoice.pdf" },
"message": "Subscription activated. Your invoice is ready."
}
Read the current subscription
curl https://api.short.leonai.io/api/v1/billing/subscription \
-H "Authorization: Bearer <jwt>"
REST: GET /api/v1/billing/subscription returns your billing state — tier, status,
interval, priceMinor + currency, currentPeriodStart / currentPeriodEnd,
cancelAtPeriodEnd, and the display card (last4, expMonth, expYear).
Cancel & resume
# Cancel at period end (keep access until currentPeriodEnd)
curl -X POST https://api.short.leonai.io/api/v1/billing/cancel -H "Authorization: Bearer <jwt>"
REST: POST /api/v1/billing/cancel sets cancelAtPeriodEnd: true and cancels the Sumit
standing order.
POST /api/v1/billing/resume always returns 409 — because the standing order is
already cancelled at Sumit, resuming billing means starting a fresh checkout. Re-run the
subscribe flow.
Invoices
curl https://api.short.leonai.io/api/v1/billing/invoices \
-H "Authorization: Bearer <jwt>"
REST: GET /api/v1/billing/invoices lists your Sumit tax invoices:
{
"success": true,
"data": [
{
"id": "…",
"documentNumber": "…",
"date": "2026-07-10",
"amount": 22.42,
"currency": "USD",
"downloadUrl": "https://…"
}
]
}
amount is VAT-inclusive (the total the customer paid), in the invoice's own
currency.
Billing responses used to carry ILS amounts as priceAgorot / priceIls / amountIls.
They now carry priceMinor (cents) or price / amount (dollars), always next to a
currency field. Read the amount together with its currency.
Webhook (server-to-server)
POST /api/v1/billing/sumit-webhook?secret=<SUMIT_WEBHOOK_SECRET> is a reconciliation
poke from Sumit. The secret is verified with a timing-safe comparison; the payload is
never trusted for state — LeonAI re-fetches the truth from Sumit (active standing order
- a settled payment) and grants or downgrades the tier accordingly. Subscription changes
also emit
subscription.upgraded/subscription.cancelledwebhooks to your own endpoints.