# Billing (Sumit)

Source: https://developers.leonai.io/docs/guides/billing/

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).

:::note[Stripe removed]
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)

```bash
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:

```json
{
  "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

```bash
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`:

```json
{
  "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

```bash
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:

```json
{
  "success": true,
  "data": { "tier": "pro", "status": "active", "documentUrl": "https://…/invoice.pdf" },
  "message": "Subscription activated. Your invoice is ready."
}
```

## Read the current subscription

```bash
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

```bash
# 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.

:::note[Resuming]
`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](#subscribe-the-three-step-flow).
:::

## Invoices

```bash
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:

```json
{
  "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`.

:::note[Field names changed on 2026-10-29]
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.cancelled`
  [webhooks](https://developers.leonai.io/docs/guides/webhooks/) to your own endpoints.
