# Prepaid Credits AI products incur costs immediately — with every token generated, every video rendered, every API call processed. Unlike traditional SaaS where you can bill at the end of a period and absorb the cost in the meantime, AI infrastructure costs are real-time and often unpredictable. A single customer running a large batch job can cost you significantly before you've collected a cent. Prepaid credits address this. Customers fund a wallet before they consume, and usage draws down that balance in real time. You never front costs, cash flow is protected, and customers always have visibility into what they're spending. Beyond the financial mechanics, prepaid credits also let you abstract away the complexity of variable infrastructure costs into product-native units — tokens, video minutes, generation credits — that make intuitive sense to your customers rather than exposing raw dollar fractions per API call. This article covers wallets, credit grants, custom assets, and how to accept and manage customer payments. For the product configuration and usage event side of things, see [Usage Based Billing](https://docs.credyt.ai/features/product-catalog/usage-based-pricing.md). ## Wallets and Accounts[​](#wallets-and-accounts "Direct link to Wallets and Accounts") Every customer in Credyt has one wallet. That wallet can hold multiple accounts, one per asset. Accounts are created automatically when a customer is subscribed to a product — no separate setup required. A wallet can hold: * **Fiat accounts** — balances in standard currencies like USD or EUR, debited directly in currency terms (e.g. $1.00 per video minute) * **Custom asset accounts** — balances in units you define, like `VIDGENMIN` (video generation minutes) or `CREDIT`, debited in those units as usage occurs Both account types can coexist in the same wallet. A customer can hold a USD balance and a token balance simultaneously, with usage events drawing from the correct account based on what asset the product price is denominated in. **Example wallet response:** * REST API * TypeScript SDK * Python SDK GET https\://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet ```http ``` **Response** ```json { "accounts": [ { "id": "default:USD", "name": "default", "asset": "USD", "available": 14.57 }, { "id": "default:VIDGENMIN", "name": "default", "asset": "VIDGENMIN", "available": 320 } ] } ``` ```typescript await client.customerWalletOps.getCustomerWallet("cust_473cr1y0ghbyc3m1yfbwvn3nxx"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetCustomerWalletSample.ts#L39) **SDK response object** ```typescript const response = { accounts: [ { id: "default:USD", name: "default", asset: "USD", available: 14.57, }, { id: "default:VIDGENMIN", name: "default", asset: "VIDGENMIN", available: 320, }, ], }; ``` ```python response = client.customer_wallet_ops.get_customer_wallet( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", ) ``` **SDK response object** ```python response = { "accounts": [ { "id": "default:USD", "name": "default", "asset": "USD", "available": 14.57, }, { "id": "default:VIDGENMIN", "name": "default", "asset": "VIDGENMIN", "available": 320, }, ], } ``` Here the customer has a USD balance for fiat-priced products and a Video Generation Minutes balance for usage priced in that custom asset. ## Fiat vs Custom Assets[​](#fiat-vs-custom-assets "Direct link to Fiat vs Custom Assets") Each product price is tied to a specific asset — USD, tokens, minutes — and that's the account Credyt debits when a usage event arrives. Choosing between fiat and custom assets is one of the most consequential decisions in your billing setup. **Price in fiat (USD, EUR) when:** * Your costs are predictable per unit and straightforward to express in dollar terms * Your customers are developers or technical users who expect to see dollar costs * You want simple reconciliation with no conversion layer **Price in custom assets when:** * Infrastructure costs vary by workload and you want to abstract that variance behind stable unit pricing * You want product-native units that map to what customers actually do (minutes generated, not dollars spent) * You expect your pricing to evolve as you learn your unit economics, and want to adjust rates without changing the customer-facing unit * You want customers to be able to earn credits through referrals, daily bonuses, or promotions — not just purchase them Both approaches are fully supported and can coexist within the same wallet. ### Creating a custom asset[​](#creating-a-custom-asset "Direct link to Creating a custom asset") [API Reference](https://docs.credyt.ai/api/assets-create.md) Assets must be created before any product that references them. Define the asset code, name, display label, precision, and exchange rate against fiat. In this example we create a `VIDGENMIN` asset — Video Generation Minutes — priced at $0.10 per minute (or 10 minutes per $1.00): * REST API * TypeScript SDK * Python SDK POST https\://api.credyt.ai/assets ```json { "code": "VIDGENMIN", "name": "Video Generation Minutes", "precision": 2, "symbol": "⏰", "label": "MIN", "rates": [ { "source": "USD", "rate": 0.1 } ] } ``` **Response** ```json { "code": "VIDGENMIN", "created_at": "2026-02-06T10:01:29.686322Z" } ``` ```typescript await client.assets.create({ code: "VIDGENMIN", name: "Video Generation Minutes", precision: 2, symbol: "⏰", label: "MIN", rates: [ { source: "USD", rate: 0.1, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/assetsCreateSample.ts#L31) **SDK response object** ```typescript const response = { code: "VIDGENMIN", createdAt: "2026-02-06T10:01:29.686322Z", }; ``` ```python response = client.assets.create( body={ "code": "VIDGENMIN", "name": "Video Generation Minutes", "precision": 2, "symbol": "⏰", "label": "MIN", "rates": [ { "source": "USD", "rate": 0.1, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/assets_create_video_generation_minutes.py#L20) **SDK response object** ```python response = { "code": "VIDGENMIN", "created_at": "2026-02-06T10:01:29.686322Z", } ``` Once the asset exists, you can reference it in your product pricing configuration and Credyt will use the exchange rate to convert fiat payments into asset units when customers top up. Exchange rates can be updated at any time and changes can be scheduled to take effect at a future date, so you can adjust pricing without surprising customers mid-session. See [Assets](https://docs.credyt.ai/features/assets.md) for full asset management details. ## Credit Grants[​](#credit-grants "Direct link to Credit Grants") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-credit-grants.md) A wallet balance isn't a single undifferentiated pool of funds. Under the hood, Credyt models it as a sequence of **credit grants** — discrete allocations of prepaid value, each with its own lifecycle, purpose, and financial attributes. This matters for several practical reasons: * **Expiry and breakage** — grants have explicit expiry dates. When a grant expires, unused value is recognized as breakage revenue and the grant is excluded from available balance. * **Exchange rate locking** — for custom assets, the exchange rate at the time of purchase is locked to each grant. This ensures accurate fiat revenue reporting even if rates change between top-up and consumption. * **Auditability** — every grant has a clear origin, purpose, and lifetime, all visible and queryable via the API. * **Revenue recognition** — revenue is recognized when credits are consumed or expire, not when they are purchased. At the point of top-up, the value is recorded as deferred revenue and moves to recognized revenue as usage draws it down. ### How grants are issued[​](#how-grants-are-issued "Direct link to How grants are issued") Credit grants enter a wallet through a few well-defined paths: * **Top-up** — when a customer completes a payment, Credyt automatically creates a `paid` grant. Paid grants expire after one year by default. * **Wallet adjustment** — your platform can issue grants directly, for example as promotional credits or manual top-ups. The `reason` and `expires_at` parameters control how the grant is classified. * **Entitlements** — when a customer is subscribed to a hybrid product with bundled credits, Credyt automatically issues grants according to the entitlement configuration. See [Hybrid Billing with Entitlements](https://docs.credyt.ai/features/product-catalog/entitlements.md). ### Consumption order[​](#consumption-order "Direct link to Consumption order") Credyt consumes grants in the order they expire — the earliest-expiring grants are drawn down first. This ensures customers use credits before they expire. **Example**: querying active grants for a customer * REST API * TypeScript SDK * Python SDK GET https\://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/default:USD/grants ```http ``` ```typescript await client.customerWalletOps.getCreditGrants("cust_473cr1y0ghbyc3m1yfbwvn3nxx", "default:USD"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetCreditGrantsSample.ts#L11) ```python response = client.customer_wallet_ops.get_credit_grants( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", account_id="default:USD", ) ``` The promotional grant expires sooner, so Credyt will consume it first unless priority rules dictate otherwise. For more details on credit grants, see our [Credit Grants](https://docs.credyt.ai/features/credit-grants.md) article. ## Funding the Wallet[​](#funding-the-wallet "Direct link to Funding the Wallet") Credyt gives you three ways to accept customer payments and fund wallet balances. Choose based on how much control you want over the payment flow. When a payment is designated for a custom asset account, Credyt automatically converts the fiat amount to the corresponding asset units using the predefined exchange rate. ### Option 1: Billing Portal[​](#option-1-billing-portal "Direct link to Option 1: Billing Portal") [API Reference](https://docs.credyt.ai/api/billing-portal-create-portal-session.md) The simplest option. Credyt hosts a self-service billing centre where customers can manage their own balance — view transactions, add funds, configure auto top-up, and see usage history. You generate a session link and redirect the customer; Credyt handles everything else. * No payment UI to build * No sign-up required for the customer * Supports both fiat and custom asset top-ups with automatic conversion For more details on UX, see [Billing Portal](https://docs.credyt.ai/features/billing-portal.md). Setup and session management details are available in [Quickstart](https://docs.credyt.ai/quickstart/billing-portal.md). ### Option 2: Top-up API[​](#option-2-top-up-api "Direct link to Option 2: Top-up API") [API Reference](https://docs.credyt.ai/api/top-ups-initiate.md) Use this when you want to embed a top-up flow directly in your product UI but still use Credyt's payment processing. You define the amount, Credyt creates a Stripe checkout session and returns a redirect URL. * You control when and how customers are prompted to top up * Credyt handles the Stripe integration and payment confirmation * Supports exchange rate overrides for custom assets, useful for volume incentives or tiered pricing See [Wallets and Top-ups](https://docs.credyt.ai/features/wallets-and-topups.md) for further details. ### Option 3: Wallet Adjustments[​](#option-3-wallet-adjustments "Direct link to Option 3: Wallet Adjustments") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) Use this when you process payments through your own payment provider, or when you need to add balance manually — for example, to issue promotional credits or to pre-fund a wallet during development and testing. * Your PSP handles payment collection * You call the Adjustments API after a successful payment to credit the wallet * The `reason` field controls how the resulting credit grant is classified (`external_topup`, `promotional`, etc.) For more on adjustments, including charges and gifting credits, see [Adjustments](https://docs.credyt.ai/advanced-topics/adjustments-charges-gifts.md). ## Checking the Balance[​](#checking-the-balance "Direct link to Checking the Balance") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-customer-wallet.md) You can query a customer's wallet balance at any time. A common pattern is to check the balance before allowing a billable action, and gate access if the balance is insufficient. You can get the full wallet or a specific account: * REST API * TypeScript SDK * Python SDK GET https\://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/default:VIDGENMIN ```http ``` **Response** ```json { "id": "default:VIDGENMIN", "name": "default", "asset": "VIDGENMIN", "available": 320, "pending_in": 100, "pending_out": 0 } ``` ```typescript await client.customerWalletOps.getAccount("cust_473cr1y0ghbyc3m1yfbwvn3nxx", "default:VIDGENMIN"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetAccountSample.ts#L11) **SDK response object** ```typescript const response = { id: "default:VIDGENMIN", name: "default", asset: "VIDGENMIN", available: 320, pendingIn: 100, pendingOut: 0, }; ``` ```python response = client.customer_wallet_ops.get_account( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", account_id="default:VIDGENMIN", ) ``` **SDK response object** ```python response = { "id": "default:VIDGENMIN", "name": "default", "asset": "VIDGENMIN", "available": 320, "pending_in": 100, "pending_out": 0, } ``` `available` reflects the balance that can be spent right now. `pending_in` represents top-ups that have been initiated but not yet confirmed. ## Auto Top-up[​](#auto-top-up "Direct link to Auto Top-up") [API Reference](https://docs.credyt.ai/api/billing-portal-create-portal-session.md) Auto top-up lets customers keep their wallet funded automatically without manual intervention. This is a self-serve functionality where customers configure a threshold and a recharge amount per asset in the [Billing Portal](https://docs.credyt.ai/features/billing-portal.md). When the balance for a given asset drops below the threshold, Credyt initiates an off-session Stripe payment and credits the wallet automatically. This is particularly important for: * Long-running or background workloads where a depleted balance mid-task would cause a failure * Products where usage is unpredictable and customers can't easily anticipate when to top up * Consumer products where you want a seamless experience and minimal billing friction Auto top-up is configured per asset, so a customer can set independent rules for their USD account and their `VIDGENMIN` account. All card management is handled through the Billing Portal. See [Auto Top-up](https://docs.credyt.ai/features/auto-topup.md) for details. ## Setup Flow[​](#setup-flow "Direct link to Setup Flow") ### Step 1: Create a custom asset[​](#step-1-create-a-custom-asset "Direct link to Step 1: Create a custom asset") Define the asset code, name, and exchange rate against fiat. Skip this step if you are billing directly in USD or EUR. * REST API * TypeScript SDK * Python SDK POST https\://api.credyt.ai/assets ```json { "code": "VIDGENMIN", "name": "Video Generation Minutes", "precision": 2, "symbol": "⏰", "label": "MIN", "rates": [ { "source": "USD", "rate": 0.1 } ] } ``` **Response** ```json { "code": "VIDGENMIN", "created_at": "2026-02-06T10:01:29.686322Z" } ``` ```typescript await client.assets.create({ code: "VIDGENMIN", name: "Video Generation Minutes", precision: 2, symbol: "⏰", label: "MIN", rates: [ { source: "USD", rate: 0.1, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/assetsCreateSample.ts#L31) **SDK response object** ```typescript const response = { code: "VIDGENMIN", createdAt: "2026-02-06T10:01:29.686322Z", }; ``` ```python response = client.assets.create( body={ "code": "VIDGENMIN", "name": "Video Generation Minutes", "precision": 2, "symbol": "⏰", "label": "MIN", "rates": [ { "source": "USD", "rate": 0.1, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/assets_create_video_generation_minutes.py#L20) **SDK response object** ```python response = { "code": "VIDGENMIN", "created_at": "2026-02-06T10:01:29.686322Z", } ``` ### Step 2: Create a product[​](#step-2-create-a-product "Direct link to Step 2: Create a product") Define a usage-based product that references your asset in its pricing configuration. See [Usage Based Billing](https://docs.credyt.ai/features/product-catalog/usage-based-pricing.md) for the full product setup guide. * REST API * TypeScript SDK * Python SDK POST https\://api.credyt.ai/products ```json { "name": "Glitch Video", "code": "glitch_video_std", "prices": [ { "name": "Video Generation", "type": "usage_based", "billing_model": { "type": "real_time" }, "usage_calculation": { "event_type": "video_generated", "usage_type": "volume", "volume_field": "minutes" }, "pricing": [ { "asset": "VIDGENMIN", "values": [ { "volume_rate": 1 } ] } ] } ], "publish": true } ``` **Response** ```json { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": 1, "status": "published", "is_default": true } ``` ```typescript await client.products.create({ name: "Glitch Video", code: "glitch_video_std", prices: [ { name: "Video Generation", type: "usage_based", billingModel: { type: "real_time", }, usageCalculation: { eventType: "video_generated", usageType: "volume", volumeField: "minutes", }, pricing: [ { asset: "VIDGENMIN", values: [ { volumeRate: 1, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L130) **SDK response object** ```typescript const response = { id: "prp_4e28n8kk41931f5yt5em49ecw7", code: "glitch_video_std", version: 1, status: "published", isDefault: true, }; ``` ```python response = client.products.create( body={ "name": "Glitch Video", "code": "glitch_video_std", "prices": [ { "name": "Video Generation", "type": "usage_based", "billing_model": { "type": "real_time", }, "usage_calculation": { "event_type": "video_generated", "usage_type": "volume", "volume_field": "minutes", }, "pricing": [ { "asset": "VIDGENMIN", "values": [ { "volume_rate": 1, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_glitch_video_vidgenmin.py#L20) **SDK response object** ```python response = { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": 1, "status": "published", "is_default": True, } ``` ### Step 3: Subscribe your customer[​](#step-3-subscribe-your-customer "Direct link to Step 3: Subscribe your customer") When the subscription is created, Credyt automatically provisions the wallet accounts required by the product's pricing — no additional setup needed. * REST API * TypeScript SDK * Python SDK POST https\://api.credyt.ai/customers ```json { "name": "Walter Kreiger", "external_id": "18991", "subscriptions": [ { "products": [ { "code": "glitch_video_std", "version": "default" } ] } ] } ``` **Response** ```json { "id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "subscriptions": [ { "id": "sub_411xhg4kqakf3d8ybezbzta558", "started_at": "2025-08-24T14:15:22Z", "status": "active", "products": [ { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": "default" } ] } ] } ``` ```typescript await client.customers.create({ name: "Walter Kreiger", externalId: "18991", subscriptions: [ { products: [ { code: "glitch_video_std", version: "default", }, ], }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersCreateSample.ts#L27) **SDK response object** ```typescript const response = { id: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", subscriptions: [ { id: "sub_411xhg4kqakf3d8ybezbzta558", startedAt: "2025-08-24T14:15:22Z", status: "active", products: [ { id: "prp_4e28n8kk41931f5yt5em49ecw7", code: "glitch_video_std", version: "default", }, ], }, ], }; ``` ```python response = client.customers.create( body={ "name": "Walter Kreiger", "external_id": "18991", "subscriptions": [ { "products": [ { "code": "glitch_video_std", "version": "default", }, ], }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_create_create_a_customer.py#L20) **SDK response object** ```python response = { "id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "subscriptions": [ { "id": "sub_411xhg4kqakf3d8ybezbzta558", "started_at": "2025-08-24T14:15:22Z", "status": "active", "products": [ { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": "default", }, ], }, ], } ``` ### Step 4: Fund the wallet[​](#step-4-fund-the-wallet "Direct link to Step 4: Fund the wallet") Redirect the customer to the Billing Portal, initiate a top-up via the API, or credit the wallet directly via a wallet adjustment. See [Funding the Wallet](#funding-the-wallet) above. ### Step 5: Check the balance before billing[​](#step-5-check-the-balance-before-billing "Direct link to Step 5: Check the balance before billing") Query the wallet before allowing a billable action to confirm the customer has sufficient balance. * REST API * TypeScript SDK * Python SDK GET https\://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/default:VIDGENMIN ```http ``` **Response** ```json { "id": "default:VIDGENMIN", "name": "default", "asset": "VIDGENMIN", "available": 320, "pending_in": 100, "pending_out": 0 } ``` ```typescript await client.customerWalletOps.getAccount("cust_473cr1y0ghbyc3m1yfbwvn3nxx", "default:VIDGENMIN"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetAccountSample.ts#L11) **SDK response object** ```typescript const response = { id: "default:VIDGENMIN", name: "default", asset: "VIDGENMIN", available: 320, pendingIn: 100, pendingOut: 0, }; ``` ```python response = client.customer_wallet_ops.get_account( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", account_id="default:VIDGENMIN", ) ``` **SDK response object** ```python response = { "id": "default:VIDGENMIN", "name": "default", "asset": "VIDGENMIN", "available": 320, "pending_in": 100, "pending_out": 0, } ``` ## See Also[​](#see-also "Direct link to See Also") * [Usage-Based Billing](https://docs.credyt.ai/features/product-catalog/usage-based-pricing.md) — defining products, usage calculation modes, and sending usage events * [Credit Grants](https://docs.credyt.ai/features/credit-grants.md) — full grant lifecycle, consumption rules, and API reference * [Assets](https://docs.credyt.ai/features/assets.md) — custom asset management, exchange rates, and quoting * [Hybrid Billing with Entitlements](https://docs.credyt.ai/features/product-catalog/entitlements.md) — bundled credit allowances combined with subscriptions