Chipi runs on a prepaid credit balance that lives at the org level. You top up by sending USDC to a payment address; service calls (bill payments, gift cards, AI API) deduct credits as they happen. Everything is visible from the Billing tab in the dashboard.
Billing is managed entirely from the dashboard at /configure/billing — there is no SDK surface to call /treasury/* from your app. Credit consumption is automatic: when your code calls purchaseSku, redeems a gift card, or hits the AI API, the matching debit lands in your ledger server-side. This page explains the model so you know what you’re being charged for and how to keep the balance topped up.
The credit model
- 1 credit = 1 USD. Internally tracked as USDC on Starknet at $1 parity.
- Each org has one OrgBalance with two numbers:
totalUsd (gross deposits) and availableUsd (deposits − pending holds − consumed).
Each Chipi service that draws on prepaid credits writes one or more LedgerEntryType rows so you can audit exactly what was consumed when. Gift cards span three entries (the hold / redeem / release lifecycle); other services map to a single dedicated entry.
Service (ServiceType) | LedgerEntryType | Triggered by |
|---|
SKU_PURCHASE | SKU_MARGIN | purchaseSku() settles successfully |
GIFT_CARD | GIFT_HOLD → GIFT_REDEEM (or GIFT_HOLD_RELEASE on cancel) | Gift creation reserves credits; redeem / cancel finalises |
AI_API | AI_API_CALL | Each /v1/ai/chat, /think, /execute call |
GAS_SUBSIDY | GAS_SUBSIDY | Paymaster covers a tx your wallet didn’t pay for |
Services with a different billing model
Two shipped services don’t draw down availableUsd from your prepaid credits — they settle differently:
- x402 protocol payments (
@chipi-stack/x402, facilitator at x402.chipipay.com) — settles per call via the x402 protocol on Starknet. The end user pays the merchant directly through the facilitator; nothing flows through OrgBalance. See the x402 Payments dropdown for the full integration guide. The ServiceType.X402 enum value is reserved for any future flows that do route through credits (e.g., facilitator fees), but no runtime code uses it today.
- Pay-with-crypto button (
@chipi-stack/backend + a UI component shipped in the dashboard) — a checkout primitive that sends USDC straight to the merchant wallet. Same model: direct on-chain settlement, no credit debit. The ServiceType.PAY_BUTTON enum value is reserved.
ServiceType.KYC_VERIFICATION and ServiceType.ADDRESS_SCREENING are reserved for compliance services not yet shipped. When they go live, the service entry above will be updated.
Top-ups land as DEPOSIT. Adjustments (manual reconciliation), REFUND, REV_SHARE_CREDIT/PAYOUT, SETTLEMENT (catch-all), and WITHDRAWAL round out the LedgerEntryType vocabulary.
Credit packs
There are five purchasable packs. Each ships with a number of free gift-card credits as a bundled bonus.
| Pack | Amount | Free gift cards | Tagline |
|---|
| Tester | $2 | 1 | Learn first |
| Starter | $5 | 2 | Try it out |
| Growth | $25 | 10 | Most popular |
| Scale | $50 | 25 | |
| Pro | $100 | 50 | |
The packs are returned by GET /treasury/packs and rendered in the dashboard’s Billing tab.
How top-up works
┌──────────────┐ 1. register address ┌────────────────────┐
│ Your wallet │ ─────────────────────▶│ POST /treasury/ │
│ (Starknet) │ │ register-sender │
└──────────────┘ └────────────────────┘
│
│ 2. send USDC
▼
┌────────────────────────────────────┐
│ Chipi credits address │
│ (CHIPI_CREDITS_ADDRESS env var) │
└────────────────────────────────────┘
│
│ 3. background detector matches deposit
│ to a registered sender → org
▼
┌────────────────────────────────────┐
│ OrgBalance += deposit │
│ LedgerEntry { type: DEPOSIT } │
└────────────────────────────────────┘
- Register your sender wallet so the deposit detector knows which org gets credit. The dashboard’s Billing tab does this when you select a credit pack — it
POSTs to /treasury/register-sender with your Starknet address.
- Send USDC from that address to the Chipi credits address (revealed in the dashboard after registration).
- Wait ~2 minutes. The detector runs every 2 min on Trigger.dev. The dashboard polls for up to 3 min after a purchase before timing out the optimistic UI; the actual credit lands as soon as the next detector cycle catches it.
You can re-register the same address (it’s an upsert), and one org can have multiple registered senders.
Holds — the gift card pattern
Some services use a hold-then-consume pattern instead of a flat debit. It protects against partial failures and over-consumption when an action takes time to settle:
- Hold — when the action starts, Chipi reserves an estimated max cost (
POST /treasury/hold). The held amount drops availableUsd immediately so concurrent calls see the correct headroom. Lands in the ledger as GIFT_HOLD.
- Consume — when the action finishes, the actual cost gets
consume-hold’d. Only the actual amount is debited; any unused reservation is freed. Lands as GIFT_REDEEM.
- Release — if the action errors out before completing, the entire hold is
release-hold’d (full refund, no debit). Lands as GIFT_HOLD_RELEASE.
Currently only Gifts use this pattern. Bill payments use a flat SKU_MARGIN debit at settlement; AI API uses an up-front checkBalance + a final AI_API_CALL debit (no hold lifecycle, no separate ledger lines for in-flight calls). The hold / consume / release primitives are general-purpose and would suit any future long-running flow (e.g., streaming AI calls), but no other service uses them today.
You don’t call /treasury/hold directly — the service that needs it does so server-side.
Monitoring
In the dashboard at /configure/billing you get:
- Balance card —
totalUsd deposited, availableUsd after holds/debits, status (OK / LOW / CRITICAL / SUSPENDED).
- Ledger table — paginated
GET /treasury/ledger, filterable by type (any LedgerEntryType) and date range.
- Wallet address — your treasury wallet, one per org. Created on demand by
POST /treasury/create-wallet.
- Credit packs — the catalog above plus a purchase modal that handles registration + payment-address reveal.
You can configure two thresholds via PATCH /treasury/settings:
lowBalanceThresholdUsd — when availableUsd drops below this, the balance card shows LOW. Wire to a webhook for alerting (coming soon).
criticalThresholdUsd — same but at CRITICAL. When you hit zero, the org is SUSPENDED and service calls reject with a credit-insufficient error until you top up.
What this means for your code
Devs writing app code don’t call /treasury/*. Instead:
- Sufficient credits → service calls succeed and the debit lands silently in the ledger.
- Insufficient credits → calls reject with a credit-insufficient error (you’ll see it as a
ChipiApiError from the SDK; check .code for the specific reason).
So the right pattern in your backend is to catch the error, surface it to the user, and prompt them (or you) to top up — not to pre-check /treasury/balance before every call. See Error Handling for the catch patterns.
Where each thing lives
| Capability | Dashboard URL | Endpoint |
|---|
| Balance + status | /configure/billing | GET /treasury/balance |
| Ledger / activity | /configure/billing | GET /treasury/ledger |
| Buy credit pack | /configure/billing (Buy modal) | GET /treasury/packs + POST /treasury/register-sender |
| Treasury wallet | /configure/billing | GET /treasury/wallet-info, POST /treasury/create-wallet |
| Threshold settings | /configure/billing | PATCH /treasury/settings |
✅ Endpoint contracts, credit pack catalog, and LedgerEntryType / ServiceType enums verified against the live /treasury/* API on 2026-05-10.