# Credyt Documentation for AI Tools > Documentation for Credyt, the real-time billing infrastructure for AI products. Explore guides, API references, and more to integrate Credyt into your AI applications. ## Ai Integration ### Credyt integration guide for AI assistants and tools This guide helps AI assistants (like ChatGPT, Claude, Lovable, and other AI and vibe coding tools) walk developers through integrating Credyt into their applications. Credyt is real-time billing infrastructure built for AI products. It handles usage-based billing, prepaid wallets, and revenue recognition, so you don't have to build it yourself. #### ⚠️ CRITICAL: READ THIS FIRST ⚠️[​](#️-critical-read-this-first-️ "Direct link to ⚠️ CRITICAL: READ THIS FIRST ⚠️") **STOP. Do not write any code yet.** When a user asks you to integrate Credyt, your response must follow this order: 1. ❌ DO NOT write code 2. ❌ DO NOT create files 3. ❌ DO NOT assume a billing model 4. ✅ DO ask discovery questions (one at a time) 5. ✅ DO explain billing models with examples from their domain 6. ✅ DO help them define products in Credyt 7. ✅ ONLY THEN write integration code **If you write code before understanding their business model, you are doing it wrong.** This is not optional. Discovery must come first. #### Required integration workflow[​](#required-integration-workflow "Direct link to Required integration workflow") Follow these steps in order. Do not skip ahead. **Phase 1: Discovery (REQUIRED FIRST)** Ask questions one at a time. Listen to answers. Explain concepts with concrete examples. Goals: * Understand their business model * Choose billing model (usage-based, subscription, or hybrid) * Decide fiat currency vs custom assets * Identify billable events * Define pricing dimensions Do not proceed until you understand their monetization strategy. **Phase 2: Product definition (REQUIRED SECOND)** Help them create product configuration in Credyt. This happens via API calls OR the Credyt dashboard. Either way, products must be defined before you write integration code. Goals: * Create custom assets (if needed) * Create products with pricing * Configure event types * Set up dimensional pricing (if needed) **Phase 3: Code integration (ONLY AFTER PHASES 1-2)** Now you can write code. Create backend integration, implement wallet checks, send usage events, handle top-ups. ##### Common mistakes to avoid[​](#common-mistakes-to-avoid "Direct link to Common mistakes to avoid") ❌ **WRONG**: ```text User: "Integrate Credyt into my image generation app" AI: *immediately writes code with $0.50 per image hardcoded* ``` ✅ **RIGHT**: ```text User: "Integrate Credyt into my image generation app" AI: "Before I write any code, I need to understand your business model. How do you want to charge for image generation?" ``` ❌ **WRONG**: Asking 10 questions at once in a massive list ✅ **RIGHT**: Ask questions sequentially, adapting based on previous answers ❌ **WRONG**: Assuming they want usage-based pricing ✅ **RIGHT**: Explaining all three models with examples from their domain #### Pre-code checklist[​](#pre-code-checklist "Direct link to Pre-code checklist") Complete ALL of these before writing any code: * Asked about billable activities (what costs them money) * Asked about pricing preferences (how they want to charge) * Asked about ability to front costs (can they absorb usage before payment) * Explained all three billing models with domain-specific examples * User has chosen a billing model * Decided fiat vs custom assets (with clear reasoning) * Identified all billable event types * Defined pricing dimensions (if applicable) * Helped create products in Credyt (API or dashboard) * Confirmed product configuration is complete **Only proceed to code when ALL boxes are checked.** #### Before you start[​](#before-you-start "Direct link to Before you start") When a user asks to integrate Credyt, you MUST start by understanding their business model. Do not proceed to code without completing discovery. This is not optional. Don't write code yet. Start with questions. Ask them sequentially, one at a time, adapting based on their answers. **Read these first**: * [Core concepts](https://docs.credyt.ai/concepts.md) * [Pricing models](https://docs.credyt.ai/pricing-guide.md) * [Full documentation](https://docs.credyt.ai/llms-full.txt) * [OpenAPI specification](https://docs.credyt.ai/assets/files/openapi.1.0-7a4de4c1a8ba674c4113b6d29f4a94db.yaml) > **Note**: If HTML docs don't load, append `.md` to the URL (e.g., `https://docs.dev.credyt.ai/advanced-topics/refunds.md`) to get the markdown version. #### Discovery: Understand their monetization[​](#discovery-understand-their-monetization "Direct link to Discovery: Understand their monetization") Before you write code, understand how they make money. ##### How to ask questions:[​](#how-to-ask-questions "Direct link to How to ask questions:") * Ask questions ONE AT A TIME * Listen to their answer before asking the next question * Adapt follow-up questions based on what they tell you * Never dump 5+ questions on them at once **Question order matters**: 1. Start with billing model (affects everything else) 2. Then fiat vs custom assets (if needed) 3. Then specific billable events 4. Then pricing dimensions 5. Finally account setup Each answer informs the next question. This is a conversation, not a form. ##### 1. Choose a billing model[​](#1-choose-a-billing-model "Direct link to 1. Choose a billing model") Help them pick between three models. Each solves different problems. Start by explaining what these models actually mean with concrete examples from their domain. ###### Real-time usage-based billing (prepaid)[​](#real-time-usage-based-billing-prepaid "Direct link to Real-time usage-based billing (prepaid)") Customers add funds upfront. Usage draws down the balance in real time. When the balance hits zero, service stops or triggers automatic refill. **What this means in practice**: * Charge users for activities they perform in your app * Examples: $0.03 per API call, $2.50 per video generated, $0.001 per token * Like a prepaid phone: add $20, make calls, balance decreases with each call **How others do it**: * OpenAI: charges per token consumed (e.g., $0.002 per 1K tokens for GPT-4) * Replicate: charges per second of model compute time * ElevenLabs: charges per character of audio generated This works when: * Infrastructure costs are variable and unpredictable * You can't afford to front costs for customers * Your customers expect pay-as-you-go pricing * You need cash flow protection **Example question for user**: "If you charge $0.10 per image your app generates, would customers prepay (like adding $10 for 100 images) or get billed monthly for what they used?" ###### Fixed recurring fees (aka traditional SaaS subscriptions)[​](#fixed-recurring-fees-aka-traditional-saas-subscriptions "Direct link to Fixed recurring fees (aka traditional SaaS subscriptions)") Customers pay a fixed amount per billing cycle. This provides baseline revenue while you figure out usage pricing. **What this means in practice**: * Charge a flat monthly or annual fee * Examples: $20/month for Pro access, $99/year for Premium features * Like Netflix: pay $15/month regardless of how much you watch **How others do it**: * Most traditional SaaS: Slack, Notion, Figma charge per seat per month * GitHub: $4/user/month for team features This works when: * You need revenue now but aren't ready to price usage * You want to understand cost structure before charging for usage * You're planning to transition to usage-based pricing later * Enterprise customers require predictable billing cycles Start here if you're still validating product-market fit. Track usage and costs without charging for them yet. Use profitability data to inform your eventual usage pricing. **Example question for user**: "Do you want to charge users a fixed monthly fee for access to your app, regardless of how much they use it?" ###### Hybrid (subscriptions + entitlements + top-ups)[​](#hybrid-subscriptions--entitlements--top-ups "Direct link to Hybrid (subscriptions + entitlements + top-ups)") Base subscription includes usage allowances. Additional usage is purchased through top-ups or charged as overages. **What this means in practice**: * Monthly subscription that includes a credit allowance * Examples: $20/month includes 1,000 credits, extra credits are $0.05 each * Like a phone plan: $30/month includes 5GB data, pay $10/GB for overages **How others do it**: * Clay: monthly subscription includes credit allocation for data enrichment * Cursor: different tiers include different amounts of AI completions * GitHub Copilot: subscription with usage caps, then throttling or upgrades This works when: * You need baseline recurring revenue plus usage-based growth * Some features are seat-based, others consumption-based * Customers want predictability with flexibility for overages * Different customer segments expect different billing approaches **Example question for user**: "Would you want to give users 1,000 free credits per month with their $20 subscription, then charge them $0.05 per credit when they run out?" **Start with this question**: "How do you want to charge for \[their specific activity]?" Then adapt based on their answer. If they say "per image" → usage-based. If they say "monthly fee" → subscription. If they say "both" → hybrid. **Follow-up questions (ask based on context)**: * "What activities in your app should be billable?" (be specific: API calls, images generated, minutes of video, tokens processed) * "How do you want to charge for those activities?" (give pricing examples: $0.10 per image, $2.50 per video, $0.001 per token) * "Can you afford to front infrastructure costs?" (explain: if a user generates a $5 video but hasn't paid yet, can you absorb that cost?) * "How predictable is customer usage?" (explain: some customers might use 10x more than others in the same month) * "What do similar products charge?" (help them research: look at OpenAI, Anthropic, Replicate, etc.) ##### 2. Fiat currency vs custom assets (critical decision)[​](#2-fiat-currency-vs-custom-assets-critical-decision "Direct link to 2. Fiat currency vs custom assets (critical decision)") One of the most important decisions: price in dollars or custom units? This choice affects how customers perceive value, how you handle pricing changes, and whether you can offer earning mechanisms. **Price in fiat currency (USD, EUR) when**: Your costs are deterministic per unit. Customers are technical users who understand infrastructure metrics. The unit-to-value relationship is already clear. **Examples**: * OpenAI and Anthropic price in tokens but show dollar balances. Technical users understand that 10M tokens through GPT-4 has a clear cost. * Replicate charges per second of compute time, billed in dollars. **Advantages**: * Transparent pricing (customers see exactly what they pay) * No conversion confusion * Simpler accounting * Enterprise-friendly (matches procurement expectations) **Price in custom units (credits, tokens, minutes) when**: Infrastructure costs vary but customer-facing pricing should stay predictable. Non-technical users need product-native units. You expect pricing to evolve as you learn unit economics. **What this means**: * Video platforms: Bill in "video minutes" not dollars * Translation apps: Bill in "words" or "document credits" not tokens * Voice platforms: Bill in "characters" or "conversation minutes" * Gaming: Bill in "coins" or "gems" that can be earned and spent **Why Midjourney uses GPU hours**: Midjourney allocates GPU time to subscribers (3.3 hours Basic, 15 hours Standard, 30 hours Pro). The actual GPU cost per image varies by model, resolution, and settings. Customers see consistent GPU time deductions. Infrastructure complexity is abstracted. Different models: Gen-4 costs more compute than Gen-4 Turbo. Customers pay in GPU time, not variable per-image costs. When infrastructure costs change, the GPU hour price can adjust without confusing customers. **Why Runway uses credits**: Runway bills video generation in credits. Gen-4 costs 12 credits/second, Gen-4 Turbo costs 5 credits/second. Different quality tiers have different computational requirements. Customers see predictable credit deductions. The relationship between credits and value stays stable even as underlying costs shift. ###### Three problems custom assets solve:[​](#three-problems-custom-assets-solve "Direct link to Three problems custom assets solve:") **1. Infrastructure costs vary, pricing shouldn't** AI platforms face unpredictable compute costs. Quality settings, duration, complexity all affect cost. If you bill directly for infrastructure, pricing becomes unpredictable. If you average costs, margins erode on expensive requests. Custom units decouple infrastructure variance from customer-facing pricing. A standard job costs 1 credit, high-quality costs 2 credits, priority costs 3 credits. Infrastructure scales invisibly. **2. Product-native units make sense** When you bill in dollars, customers see "$1.47" without understanding what they purchased. When you bill in video minutes, they see "Generated 4-second clip: -2 minutes." Usage history shows exactly what was consumed in units that map to behavior. Translation apps: A non-technical user being billed in LLM tokens has no reference. But "words" or document credits (small, medium, large) make immediate sense. **3. Value can be earned, not just purchased** Credits become powerful when customers can earn them outside purchases. Lovable lets users earn credits through referrals: 10 credits when someone signs up through your link, 10 more when they publish their first app. These credits work identically to purchased credits. Gaming platforms use gems, coins, tokens. Players purchase bundles but also earn currency through gameplay, achievements, daily bonuses. This enables hybrid monetization: some users pay, others earn, most do both. When credits can be earned through product engagement, they stop being purely transactional and become part of the product experience. **Start by asking**: "Do you want customers to see prices in dollars (like $2.50 per video) or in credits/tokens (like 10 credits per video)?" Listen to their answer. Then ask follow-up questions based on what they need help with: **If they're unsure, ask one of these**: * "Do your infrastructure costs vary significantly based on usage complexity?" * "Are your users technical (understand tokens/API calls) or non-technical (need simpler units)?" * "Do you want customers to earn credits through referrals or engagement?" * "Will your pricing likely change as you learn unit economics?" * "Would customers benefit from seeing 'video minutes' vs '$0.15 per generation'?" **If choosing custom assets**, they'll need to create these first (before products). See Step 2 in Implementation for the technical setup. ##### 3. Identify billable events[​](#3-identify-billable-events "Direct link to 3. Identify billable events") Help them identify what consumes resources or delivers value. **Start with**: "What activities in your app cost you money to provide?" Listen to their answer. Then dig deeper with specific follow-ups: **Follow-up questions (based on their answer)**: * "What actions cost you money?" * "What outcomes can you measure?" * "What events are expensive to process?" **Common event types**: * API calls * AI model completions (chat, images, video) * Processing time (minutes, seconds) * Volume consumed (tokens, data, storage) * Quality tiers (standard, premium) * Speed tiers (fast, regular) > **Best practice**: Send usage events for all meaningful activities initially. Review them in Credyt. Decide pricing later. ##### 4. Pricing dimensions[​](#4-pricing-dimensions "Direct link to 4. Pricing dimensions") Does pricing vary based on attributes? This is dimensional pricing. **Ask**: "Do you charge different amounts based on quality, speed, or model type?" If yes, ask for specifics: "What are the different tiers and how should they be priced?" **Common dimensions**: * "Do different AI models cost different amounts?" * "Do you charge more for faster processing?" * "Are there quality tiers with different prices?" These attributes become billable dimensions in Credyt. ##### 5. Account setup[​](#5-account-setup "Direct link to 5. Account setup") **Ask**: "Do you have a Credyt account set up already?" **If no**: * Sign up at * Accounts start in test mode (perfect for integration) * Get API keys from (Developers section) **If yes**: * Confirm they have their test API key * Remind them: server-side only, never in client code * Ask: "Do you have your API key handy?" *** #### Discovery checkpoint[​](#discovery-checkpoint "Direct link to Discovery checkpoint") Before moving to implementation, confirm you have: ✅ Clear billing model chosen (usage-based, subscription, or hybrid)
✅ Fiat or custom assets decision made
✅ All billable events identified
✅ Pricing structure defined (including dimensions if applicable)
✅ Credyt account set up with API keys If any of these are unclear, go back and ask more questions. **Only proceed to Implementation once discovery is complete.** *** #### Implementation[​](#implementation "Direct link to Implementation") Once you understand their model, walk them through these steps. > **Important**: If they want to use custom assets (tokens, credits, coins), create those FIRST before creating products or processing transactions. Custom assets must exist before they can be referenced in product pricing or wallet adjustments. ##### Step 1: Set up authentication[​](#step-1-set-up-authentication "Direct link to Step 1: Set up authentication") All API requests require the `X-CREDYT-API-KEY` header. **Security rules**: * Store API keys server-side only * Never expose keys in client code * Use environment variables ```javascript // .env file CREDYT_API_KEY = your_test_api_key_here; // API client const headers = { "Content-Type": "application/json", "X-CREDYT-API-KEY": process.env.CREDYT_API_KEY, }; ``` **Test your connection**: Verify your API key works by listing customers: ```javascript const response = await fetch("https://api.credyt.ai/customers", { headers }); if (response.ok) { console.log("✓ Connected to Credyt successfully"); } else { console.error("✗ Authentication failed - check your API key"); } ``` This endpoint always succeeds if you're authenticated correctly. ##### Step 2: Define products and pricing[​](#step-2-define-products-and-pricing "Direct link to Step 2: Define products and pricing") Products define what you bill for and how. You typically create these once during setup—not in your application code. **Workflow order** (important): 1. Create custom assets first (if using tokens, credits, etc.) 2. Then create products that reference those assets 3. Subscribe customers to products **Core concepts**: * **Product**: What the customer consumes (e.g., "Video Generation") * **Price**: One product can have multiple prices for different events * **Event type**: The billable action (e.g., `video_generated`, `message_completed`) * **Usage type**: * `unit` - charge per occurrence * `volume` - charge based on quantity in payload * `unit_and_volume` - both **Publishing products**: Products must be published before customers can subscribe to them. Set `publish: true` when creating the product, or publish it later using `PATCH /products/:productId/:version`. **If using custom assets (tokens, credits, coins)** Create these BEFORE creating products. Custom assets must exist before they can be referenced. ```javascript // Step 1: Create the custom asset const asset = { code: "CREDIT", name: "Credits", precision: 0, symbol: "⭐", label: "CR", rates: [ { source: "USD", rate: 0.05, // $0.05 per credit (or $1 = 20 credits) }, ], }; await fetch("https://api.credyt.ai/assets", { method: "POST", headers, body: JSON.stringify(asset), }); // Step 2: Now create products that use this asset const product = { name: "AI Image Generation", code: "image_gen_std", prices: [ { name: "Image Generation", type: "usage_based", billing_model: { type: "real_time" }, usage_calculation: { event_type: "image_generated", usage_type: "unit", }, pricing: [ { asset: "CREDIT", // References the asset we just created values: [{ unit_price: 10 }], // 10 credits per image }, ], }, ], publish: true, // Publish immediately so customers can subscribe }; await fetch("https://api.credyt.ai/products", { method: "POST", headers, body: JSON.stringify(product), }); ``` **If using fiat currency (USD, EUR)** You can skip asset creation and create products directly. **Unit-based pricing** Charge per occurrence. Here we charge $2.50 per video generation: ```javascript const product = { name: "AI Video Generation", code: "video_gen_std", prices: [ { name: "Video Generation", type: "usage_based", billing_model: { type: "real_time" }, usage_calculation: { event_type: "video_generated", usage_type: "unit", source_reference_field: "video_id", }, pricing: [ { asset: "USD", values: [{ unit_price: 2.5 }], }, ], }, ], publish: true, }; const response = await fetch("https://api.credyt.ai/products", { method: "POST", headers, body: JSON.stringify(product), }); ``` **Volume-based pricing** Charge based on quantity consumed. Here we charge $0.001 per token: ```javascript const product = { name: "AI Chat Service", code: "chat_service_std", prices: [ { name: "Token Usage", type: "usage_based", billing_model: { type: "real_time" }, usage_calculation: { event_type: "message_completed", usage_type: "volume", volume_field: "total_tokens", source_reference_field: "chat_id", }, pricing: [ { asset: "USD", values: [{ volume_rate: 0.001 }], }, ], }, ], publish: true, }; await fetch("https://api.credyt.ai/products", { method: "POST", headers, body: JSON.stringify(product), }); ``` **Dimensional pricing** Different rates based on attributes. Here we charge different rates per model: ```javascript const product = { name: "Multi-Model Chat", code: "chat_multimodel", prices: [ { name: "Token Usage", type: "usage_based", billing_model: { type: "real_time" }, usage_calculation: { event_type: "message_completed", usage_type: "volume", volume_field: "total_tokens", billable_dimensions: ["model"], // This is the key for dimensional pricing }, pricing: [ { asset: "USD", values: [ { name: "GPT-4 Tokens", dimensions: { model: "gpt-4" }, values: [{ volume_rate: 0.03 }], }, { name: "GPT-3.5 Tokens", dimensions: { model: "gpt-3.5" }, values: [{ volume_rate: 0.001 }], }, ], }, ], }, ], publish: true, }; ``` ##### Step 3: Create customers[​](#step-3-create-customers "Direct link to Step 3: Create customers") Register customers before billing them. Subscribe them to the products they use. **Key points**: * Use `external_id` to link the Credyt customer to your system's user ID or auth identity * Subscribe customers to products they'll use * Wallets are created automatically * Handle the case where customer already exists (422 error) ```javascript const customer = { name: "Jane Developer", external_id: "user_12345", // Your database user ID or auth provider ID (e.g., Auth0, Clerk) subscriptions: [ { products: [ { code: "video_gen_std", // Product code from Step 2 version: "default", // or specific version number }, ], }, ], }; const response = await fetch("https://api.credyt.ai/customers", { method: "POST", headers, body: JSON.stringify(customer), }); if (response.ok) { const { id: credytCustomerId } = await response.json(); // Store this ID in your database alongside your user record console.log("Customer created:", credytCustomerId); } else if (response.status === 422) { // Customer with this external_id already exists const error = await response.json(); if (error.errors?.external_id) { console.log("Customer already exists, looking up by external_id..."); // Look up existing customer const lookup = await fetch( `https://api.credyt.ai/customers?external_id=user_12345`, { headers }, ); const existingCustomer = await lookup.json(); console.log("Found existing customer:", existingCustomer.id); } } else { console.error("Failed to create customer:", await response.text()); } ``` **Using external IDs in API calls**: You can use your external ID directly when sending usage events, by specifying the `customer_external_id` instead: ```javascript const usageEvent = { customer_external_id: "user_12345", // Your ID for the customer events: [ /* ... */ ], }; await fetch("https://api.credyt.ai/events", { method: "POST", headers, body: JSON.stringify(usageEvent), }); ``` For other API calls, you need the Credyt customer ID. You can look it up by external ID: ```javascript // Look up Credyt ID from your external ID const response = await fetch( "https://api.credyt.ai/customers?external_id=user_12345", { headers }, ); const customer = await response.json(); const credytCustomerId = customer.id; // Now use Credyt ID for wallet operations, etc. await fetch(`https://api.credyt.ai/customers/${credytCustomerId}/wallet`, { headers, }); ``` **Best practice**: Store the Credyt customer ID in your database alongside your user record. This avoids the lookup call on every request. ##### Step 4: Fund customer wallets[​](#step-4-fund-customer-wallets "Direct link to Step 4: Fund customer wallets") Customers need balance before usage can be billed. You have four options. **Option A: Billing portal (self-service)** Easiest option. Customers manage their own top-ups through Credyt's hosted portal. What customers can do: * View balances and usage * Add funds via Stripe * Configure auto top-up * See transaction history No sign-up required. ```javascript // Generate a billing portal session const session = { customer_id: credytCustomerId, return_url: "https://yourapp.com/account", failure_url: "https://yourapp.com/billing-error", }; const response = await fetch(`https://api.credyt.ai/billing-portal/sessions`, { method: "POST", headers, body: JSON.stringify(session), }); const { redirect_url } = await response.json(); // Redirect customer to redirect_url // Link expires in 10 minutes ``` **Option B: Top-up API (your UI + Credyt payments)** Use when you want top-ups in your own UI but use Credyt's payment processing. ```javascript const topup = { customer_id: credytCustomerId, amount: 25.0, currency: "USD", description: "Account credit", return_url: "https://yourapp.com/account", failure_url: "https://yourapp.com/payment-failed", }; const response = await fetch(`https://api.credyt.ai/top-ups`, { method: "POST", headers, body: JSON.stringify(topup), }); const { redirect_url } = await response.json(); // Redirect to Stripe Checkout ``` **Option C: External PSP + Adjustments (your payment processing)** Use when you handle payments through your own payment provider. After successful payment in your PSP: ```javascript const adjustment = { transaction_id: "unique-uuid-or-payment-id", asset: "USD", amount: 25.0, reason: "external_topup", metadata: { psp: "stripe", payment_intent: "pi_abc123", }, }; await fetch( `https://api.credyt.ai/customers/${credytCustomerId}/wallet/adjustments`, { method: "POST", headers, body: JSON.stringify(adjustment), }, ); ``` **Option D: Pre-fund for testing (development only)** Quick way to add balance during development. No payment flows needed. ```javascript const adjustment = { transaction_id: crypto.randomUUID(), asset: "USD", amount: 100.0, reason: "external_topup", metadata: { note: "Test funding" }, }; await fetch( `https://api.credyt.ai/customers/${credytCustomerId}/wallet/adjustments`, { method: "POST", headers, body: JSON.stringify(adjustment), }, ); ``` ##### Step 5: Check balances[​](#step-5-check-balances "Direct link to Step 5: Check balances") Check wallet balances before allowing billable actions. This is the typical pattern. **Best practice**: Check balance first, then authorize the action, then send usage. **Get entire wallet**: ```javascript const response = await fetch( `https://api.credyt.ai/customers/${credytCustomerId}/wallet`, { headers }, ); const { accounts } = await response.json(); // accounts = [ // { id: "default:USD", asset: "USD", available: 14.56 }, // { id: "default:TOKENS", asset: "TOKENS", available: 5000 } // ] ``` **Get specific account**: ```javascript const response = await fetch( `https://api.credyt.ai/customers/${credytCustomerId}/wallet/default:USD`, { headers }, ); const account = await response.json(); // { // id: "default:USD", // asset: "USD", // available: 14.56, // pending_in: 0, // pending_out: 0.5 // } ``` **Implementation pattern**: ```javascript async function canPerformAction(customerId, estimatedCost) { const wallet = await fetch( `https://api.credyt.ai/customers/${customerId}/wallet`, { headers }, ); const { accounts } = await wallet.json(); const usdAccount = accounts.find((a) => a.asset === "USD"); if (!usdAccount || usdAccount.available < estimatedCost) { return { allowed: false, message: "Insufficient balance. Please top up your account.", currentBalance: usdAccount?.available || 0, }; } return { allowed: true }; } // Usage app.post("/api/generate-video", async (req, res) => { const customerId = req.user.credytCustomerId; const estimatedCost = 2.5; // $2.50 per video // 1. Check balance first const check = await canPerformAction(customerId, estimatedCost); if (!check.allowed) { return res.status(402).json({ error: check.message }); } // 2. Perform the action (generate video) const video = await generateVideo(req.body); // 3. Send usage event to bill await sendUsage(customerId, "video_generated", { video_id: video.id }); res.json({ videoId: video.id }); }); ``` ##### Step 6: Send usage events[​](#step-6-send-usage-events "Direct link to Step 6: Send usage events") After confirming balance, perform the action and send usage events. Billing happens in real time. **Requirements**: * Each event needs a unique `id` (idempotency key) * `event_type` must match a product's usage calculation * Include either the Credyt Customer ID (`customer_id`) or your external ID (`customer_external_id`) **Unit-based (charge per occurrence)** ```javascript const usageEvent = { customer_external_id: "user_12345", events: [ { id: crypto.randomUUID(), // Unique ID for idempotency event_type: "video_generated", occurred_at: new Date().toISOString(), subject: "video_abc123", // Reference to the generated video description: "AI video generation completed", data: { video_id: "video_abc123", // Matches source_reference_field }, }, ], }; await fetch("https://api.credyt.ai/events", { method: "POST", headers, body: JSON.stringify(usageEvent), }); ``` **Volume-based (charge based on quantity)** ```javascript const usageEvent = { customer_id: credytCustomerId, events: [ { id: crypto.randomUUID(), event_type: "message_completed", occurred_at: new Date().toISOString(), subject: "chat_session_456", description: "Chat completion", data: { chat_id: "chat_session_456", total_tokens: 1500, // Must match volume_field in product config input_tokens: 500, output_tokens: 1000, }, }, ], }; ``` **Dimensional (pricing varies by attribute)** ```javascript const usageEvent = { customer_id: credytCustomerId, events: [ { id: crypto.randomUUID(), event_type: "message_completed", occurred_at: new Date().toISOString(), subject: "chat_xyz", description: "GPT-4 chat", data: { chat_id: "chat_xyz", total_tokens: 2000, model: "gpt-4", // Billable dimension - matches product config }, }, ], }; ``` #### Advanced topics[​](#advanced-topics "Direct link to Advanced topics") ##### Custom assets implementation[​](#custom-assets-implementation "Direct link to Custom assets implementation") If you decided to use custom assets (see Discovery section 2), the implementation is covered in Step 2 of the Implementation guide above. Quick reminder of the workflow: 1. Create custom asset first (e.g., COINS, CREDITS, MINUTES) 2. Create products that price in that asset 3. Grant credits via Adjustments API or let customers purchase via top-ups ##### Auto top-up[​](#auto-top-up "Direct link to Auto top-up") Customers configure automatic refills via the Billing Portal. Set a threshold (e.g., when balance drops below $10) and a refill amount (e.g., add $50). Each asset can have its own configuration. Requires a saved payment card. ##### Testing payments[​](#testing-payments "Direct link to Testing payments") **Test mode**: * All new accounts start in test mode * Use Stripe test card: `4242 4242 4242 4242` * More test cards: **Going live**: * Switch account to live mode in Credyt Portal * Connect production Stripe account (if using Credyt payments) * Update API key to live key ##### Hybrid billing (subscriptions + entitlements)[​](#hybrid-billing-subscriptions--entitlements "Direct link to Hybrid billing (subscriptions + entitlements)") Credyt supports native hybrid billing that combines recurring subscriptions with bundled credit entitlements. **How it works**: Customers pay a monthly subscription fee and receive a credit allowance each billing cycle. When they exceed their included credits, they purchase additional credits or pay overage fees. Example: "$20/month includes 1,000 credits" **Create a custom asset for credits**: ```javascript const asset = { code: "CREDIT", name: "Credits", precision: 0, symbol: "⭐", label: "CR", rates: [ { source: "USD", rate: 0.05, // $0.05 per credit (or $1 = 20 credits) }, ], }; await fetch(`https://api.credyt.ai/assets`, { method: "POST", headers, body: JSON.stringify(asset), }); ``` **Create hybrid product with entitlements**: ```javascript const product = { name: "Premium Plan", code: "premium_monthly", entitlements: [ { name: "Monthly Credit Allowance", asset: "CREDIT", amount: 1000, // 1,000 credits included purpose: "bundled", refresh: { interval: "month", strategy: "expire_and_replace", // Unused credits don't roll over }, accounting: { revenue_basis: 0, // Revenue from subscription fee cost_basis: "auto", }, }, ], prices: [ { name: "Monthly Subscription Fee", type: "fixed", billing_model: { type: "recurring", recurring: { interval: "month" }, }, pricing: [ { asset: "USD", values: [{ unit_price: 20 }], }, ], }, { name: "Image Generation", type: "usage_based", billing_model: { type: "real_time" }, usage_calculation: { event_type: "image_generated", usage_type: "unit", }, pricing: [ { asset: "CREDIT", values: [{ unit_price: 10 }], // 10 credits per image }, ], }, ], publish: true, }; ``` **How consumption works**: 1. Customer pays $20/month 2. Receives 1,000 credits monthly 3. Each image costs 10 credits (can generate 100 images) 4. When credits run out, they purchase more at $0.05/credit 5. Credits expire each month (no rollover) **Subscribe customers**: ```javascript const customer = { name: "Jane Developer", external_id: "user_12345", email: "jane@example.com", subscriptions: [ { products: [{ code: "premium_monthly" }], }, ], }; const response = await fetch(`https://api.credyt.ai/customers`, { method: "POST", headers, body: JSON.stringify(customer), }); const data = await response.json(); // Check if payment is required if (data.subscriptions[0].status === "pending") { const redirectUrl = data.subscriptions[0].required_actions.find( (a) => a.type === "payment", ).redirect_url; // Redirect customer to complete payment } ``` Credyt handles billing cycles, credit grants, and consumption tracking automatically. **Using external PSP for subscriptions**: If you process subscriptions through your own payment provider, reflect payments in Credyt using Adjustments: ```javascript // When subscription payment succeeds in your PSP: const adjustment = { transaction_id: `sub_payment_${subscriptionId}`, asset: "USD", amount: 29.99, reason: "external_topup", description: "Monthly subscription", }; await fetch( `https://api.credyt.ai/customers/${customerId}/wallet/adjustments`, { method: "POST", headers, body: JSON.stringify(adjustment), }, ); ``` Then send usage events as normal. They deduct from the wallet balance. ##### Refunds[​](#refunds "Direct link to Refunds") Credyt doesn't handle refunds automatically. **Process**: 1. Process refund in your PSP (or Stripe if using Credyt payments) 2. Notify Credyt via Adjustments API ```javascript const refund = { transaction_id: `refund_${originalPaymentId}`, asset: "USD", amount: -20.0, // Negative amount reason: "external_refund", description: "Refund for technical issue", }; await fetch( `https://api.credyt.ai/customers/${customerId}/wallet/adjustments`, { method: "POST", headers, body: JSON.stringify(adjustment), }, ); ``` ##### Cost tracking (profitability)[​](#cost-tracking-profitability "Direct link to Cost tracking (profitability)") Track infrastructure costs alongside revenue. ```javascript const usageEvent = { customer_id: customerId, events: [ { id: crypto.randomUUID(), event_type: "video_generated", occurred_at: new Date().toISOString(), subject: "video_123", description: "Video generation", data: { minutes: 2, model: "sora-fast", }, costs: [ { // Optional cost tracking id: crypto.randomUUID(), vendor_external_id: "vnd_openai_123", description: "OpenAI Sora API", amount: 0.16, currency: "USD", metadata: { model: "sora-fast", resolution: "1080p", }, }, ], }, ], }; ``` Credyt will calculate profitability metrics (gross revenue, costs, net revenue, margin). [More information](https://docs.credyt.ai/features/profitability.md) ##### Standalone wallets (in-app economies)[​](#standalone-wallets-in-app-economies "Direct link to Standalone wallets (in-app economies)") Credyt's wallet API works for in-app economies where users earn and spend points without traditional payments. **Common use cases**: * Game currencies where players earn coins through gameplay * Reward programs where users accumulate points * Community platforms with reputation or karma systems * Referral programs that grant credits > **Critical**: Create your custom asset (COINS, POINTS, etc.) BEFORE granting credits or creating products. See Step 2 for how to create assets. **Setup** (do this once): ```javascript // 1. Create the custom asset first const asset = { code: "COINS", name: "Game Coins", precision: 0, symbol: "🪙", label: "COINS", rates: [ { source: "USD", rate: 0.01, // Not used if you never collect payments, but required }, ], }; await fetch("https://api.credyt.ai/assets", { method: "POST", headers, body: JSON.stringify(asset), }); // 2. Create a product that prices items in coins const product = { name: "In-Game Items", code: "game_items", prices: [ { name: "Power-Up Purchase", type: "usage_based", billing_model: { type: "real_time" }, usage_calculation: { event_type: "item_purchased", usage_type: "unit", }, pricing: [ { asset: "COINS", values: [{ unit_price: 100 }], // 100 coins per item }, ], }, ], publish: true, }; await fetch("https://api.credyt.ai/products", { method: "POST", headers, body: JSON.stringify(product), }); ``` **When users earn coins** (grant credits): ```javascript // User completes a quest - grant 500 coins const adjustment = { transaction_id: `quest_completed_${questId}_${userId}`, asset: "COINS", // Must match the asset code you created amount: 500, reason: "gift", description: "Quest completion reward", }; await fetch( `https://api.credyt.ai/customers/${customerId}/wallet/adjustments`, { method: "POST", headers, body: JSON.stringify(adjustment), }, ); ``` **When users spend coins**: Send usage events that deduct from their balance. ```javascript const usageEvent = { customer_id: customerId, events: [ { id: crypto.randomUUID(), event_type: "item_purchased", occurred_at: new Date().toISOString(), subject: `purchase_${itemId}`, description: "Power-up purchased", data: { item_id: itemId, item_name: "Speed Boost", }, }, ], }; await fetch("https://api.credyt.ai/events", { method: "POST", headers, body: JSON.stringify(usageEvent), }); ``` This gives you a reliable balance system without building wallet infrastructure yourself. #### Code Examples and Resources[​](#code-examples-and-resources "Direct link to Code Examples and Resources") ##### Bruno API Collection[​](#bruno-api-collection "Direct link to Bruno API Collection") Interactive API examples available at: * GitHub: * Download and import into Bruno () ##### Sample Integration Patterns[​](#sample-integration-patterns "Direct link to Sample Integration Patterns") **Express.js Middleware Example:** ```javascript const credytClient = { apiKey: process.env.CREDYT_API_KEY, baseUrl: "https://api.credyt.ai", async checkBalance(customerId) { const response = await fetch( `${this.baseUrl}/customers/${customerId}/wallet`, { headers: { "X-CREDYT-API-KEY": this.apiKey } }, ); return response.json(); }, async sendUsage(customerId, eventType, data) { const event = { customer_id: customerId, events: [ { id: crypto.randomUUID(), event_type: eventType, occurred_at: new Date().toISOString(), subject: data.subject, description: data.description, data: data.payload, }, ], }; return fetch(`${this.baseUrl}/events`, { method: "POST", headers: { "Content-Type": "application/json", "X-CREDYT-API-KEY": this.apiKey, }, body: JSON.stringify(event), }); }, }; // Middleware to check balance before expensive operations async function requireSufficientBalance(req, res, next) { const customerId = req.user.credytCustomerId; const { accounts } = await credytClient.checkBalance(customerId); const usdAccount = accounts.find((a) => a.asset === "USD"); if (!usdAccount || usdAccount.available < 1.0) { return res.status(402).json({ error: "Insufficient balance", balance: usdAccount?.available || 0, topUpUrl: `/billing/top-up`, }); } next(); } // Usage app.post("/api/generate-video", requireSufficientBalance, async (req, res) => { // Generate video... // Bill for usage await credytClient.sendUsage(req.user.credytCustomerId, "video_generated", { subject: `video_${videoId}`, description: "Video generation", payload: { minutes: 2, quality: "hd" }, }); res.json({ videoId, status: "processing" }); }); ``` #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ##### Customer not billed for usage[​](#customer-not-billed-for-usage "Direct link to Customer not billed for usage") **Check**: 1. Is customer subscribed to a product? (`GET /customers/:id`) 2. Does product have matching `event_type`? 3. For volume pricing: does `volume_field` match event data? 4. Is event ID unique? (Duplicates are ignored) 5. Does customer have wallet balance? **Test without affecting balances**: ```javascript const simulation = await fetch( `https://api.credyt.ai/products/:productId/simulate`, { method: "POST", headers, body: JSON.stringify({ events: [ /* your test event */ ], }), }, ); ``` ##### Negative balance[​](#negative-balance "Direct link to Negative balance") This is expected behavior. Credyt allows overdrafts by default so usage can complete without interruption. Check balance according to your business logic. The next top-up automatically corrects the negative balance. ##### No wallet or accounts[​](#no-wallet-or-accounts "Direct link to No wallet or accounts") Wallets are created automatically when: * Customer is subscribed to a product, OR * First top-up is initiated **Fix**: Ensure customer has at least one product subscription. ##### Billing portal link expired[​](#billing-portal-link-expired "Direct link to Billing portal link expired") Links expire after 10 minutes. When expired, the customer is redirected to your `return_url`. **Best practice**: Detect the redirect, generate a new session automatically, and redirect the customer back. #### Key reminders[​](#key-reminders "Direct link to Key reminders") ##### Security[​](#security "Direct link to Security") * API keys are server-side only * Never expose keys in client code * Use environment variables * Test mode and live mode use different keys ##### Testing[​](#testing "Direct link to Testing") * Start in test mode (default for new accounts) * Use Stripe test cards: * Pre-fund wallets with adjustments for quick testing * Test the full flow before going live ##### Product design[​](#product-design "Direct link to Product design") * Define products once as setup (not per-request) * Use `source_reference_field` for traceability * Include meaningful `subject` in usage events * Send usage for all activities initially, price later ##### Best practices[​](#best-practices "Direct link to Best practices") * Check balance before expensive operations * Use idempotent event IDs (UUIDs) * Store both Credyt customer ID and your external ID * Monitor wallet balances to prevent service interruption * Provide clear billing portal access for customers #### Next steps[​](#next-steps "Direct link to Next steps") **1. Connect Stripe** (if using Credyt payments) * Enables custom branding in checkout * Allows tax configuration * Required for production **2. Set up monitoring** * Track usage patterns * Monitor wallet balances * Review profitability metrics **3. Customize billing portal** * Add your branding * Configure return URLs * Test the customer experience **4. Plan for scale** * Consider auto top-up for power users * Design balance notification system * Plan for cost optimization #### Getting Help[​](#getting-help "Direct link to Getting Help") * **Documentation**: * **API Reference**: * **Support**: * **Examples**: #### Integration checklist[​](#integration-checklist "Direct link to Integration checklist") When guiding a user through Credyt integration: * Understand their monetization model (usage-based, subscription, hybrid) * Identify billable events and pricing dimensions * Confirm Credyt account setup and API key access * Define products and pricing configuration * Create customers and subscriptions * Implement wallet funding (portal, API, or external) * Send usage events from application * Check balances before billable actions * Test complete flow in test mode * Verify security (API keys server-side only) * Plan production deployment (Stripe connection, live mode) --- ## Attachments ### Search this site Source: llms-search.md #### Search this site You can search the Credyt documentation programmatically via the Algolia REST API without loading the full documentation file. ``` POST https://BEH9XOWQG9-dsn.algolia.net/1/indexes/Credyt%20Docs%20Prod/query X-Algolia-Application-Id: BEH9XOWQG9 X-Algolia-API-Key: 0ffd0ff4667fb75faf11e929bddf86a4 Content-Type: application/json {"query": "your search query"} ``` Returns ranked results with titles, URLs, and content snippets. Add `"hitsPerPage": 5` to limit results. --- ## Category ### Advanced Topics #### [📄️Refunds](https://docs.credyt.ai/advanced-topics/refunds.md) [Credyt does not process refunds directly. Initiate them through your PSP or Stripe Dashboard, then notify Credyt via the Wallet Adjustments API using a negative amount.](https://docs.credyt.ai/advanced-topics/refunds.md) --- ### Features #### [🗃Products and Pricing](https://docs.credyt.ai/features/product-catalog.md) [5 items](https://docs.credyt.ai/features/product-catalog.md) --- ### Partners #### [📄️Credyt for Platforms](https://docs.credyt.ai/partners/platforms-overview.md) [Credyt for Platforms lets you embed real-time billing inside your product via Connected Accounts. Isolated API access, webhooks, and quickstart guide included.](https://docs.credyt.ai/partners/platforms-overview.md) --- ### Quickstart #### [📄️Introduction](https://docs.credyt.ai/quickstart.md) [Get started with Credyt. This guide walks you from creating your first customer to sending real-time usage events and checking wallet balances, step by step in minutes.](https://docs.credyt.ai/quickstart.md) --- ### Tools #### [📄️MCP Server](https://docs.credyt.ai/tools/mcp-server.md) [Connect AI assistants like Claude, Cursor, Codex, and Gemini to Credyt via the Model Context Protocol (MCP) to manage products, pricing, customers, subscriptions, and billing with natural language.](https://docs.credyt.ai/tools/mcp-server.md) --- ### Use Cases #### [📄️Fiat vs Custom Units](https://docs.credyt.ai/use-cases/fiat-vs-custom-units.md) [Understand when to use fiat wallet accounts (USD/EUR) vs. custom unit accounts (tokens, minutes) and how a single customer wallet can hold and manage both simultaneously.](https://docs.credyt.ai/use-cases/fiat-vs-custom-units.md) --- ## Concepts ### Concepts & Terminology A guide to the core primitives, resources, and terminology used throughout the Credyt product. #### Customers[​](#customers "Direct link to Customers") Customers represent your end users in Credyt. Before billing can occur, you must register customers and subscribe them to products. When creating a customer, you can provide your own unique identifier (`external_id`) which can then be used when submitting usage events. **Key points:** * Customers are created via the Customers API * They must be subscribed to products to be billed * Can use either Credyt's customer ID or your own external ID * No extensive personal data required - only what's needed for identification and billing #### Products and Pricing[​](#products-and-pricing "Direct link to Products and Pricing") Products define what you're billing for and how customers are charged. Each product has a unique code and contains one or more prices that determine billing behavior. ##### Prices[​](#prices "Direct link to Prices") Prices are the building blocks of your billing configuration. Each price defines what event type triggers billing, how usage is measured, and the rates charged. **Price Types:** A price can be either: * **Usage-based**: Charges based on actual consumption or events. Usage-based prices track and bill for customer activity as it happens - such as API calls, tokens consumed, minutes processed, or tasks completed. * **Fixed**: Flat fees that don't vary with usage (e.g., monthly platform fee, seat license). These are billed as a set amount regardless of consumption. ##### Billing Models[​](#billing-models "Direct link to Billing Models") Each price has a billing model that determines *when* charges are applied: * **Real-time**: Usage is billed immediately as events occur, deducting from the customer's wallet balance in real-time. This ensures customers always know their current balance and can't consume more than their available funds (plus any configured overdraft). * **Recurring**: Usage accumulates over a billing period (typically monthly) and is billed at the end of that period. This is common for post-paid or invoice-based billing scenarios. ##### Usage Calculation[​](#usage-calculation "Direct link to Usage Calculation") For usage-based prices, the usage calculation configuration determines how usage is measured: * **Unit-based**: Charges per occurrence of an event (e.g., $0.50 per video promoted, $2 per API call) * **Volume-based**: Charges based on quantity consumed in the event payload (e.g., $0.001 per token, $0.10 per minute) * **Unit and Volume**: Combines both approaches (e.g., $0.05 per chat + $0.0001 per token used in that chat) ##### Dimensional Pricing[​](#dimensional-pricing "Direct link to Dimensional Pricing") Prices can optionally vary based on attributes of the usage event, such as: * Speed tier (fast vs regular) * Quality level (standard vs premium) * Model type (GPT-4 vs GPT-3.5) This allows a single price to handle multiple variations without creating separate price configurations. #### Subscriptions[​](#subscriptions "Direct link to Subscriptions") Subscriptions link customers to products, determining which pricing applies to their usage. When you subscribe a customer to a product, Credyt automatically provisions wallet accounts in the billing currencies defined by the product's pricing. **Important:** Subscriptions in Credyt are distinct from traditional recurring subscription payments. They represent which products a customer has access to, not necessarily a recurring payment commitment. #### Wallets and Accounts[​](#wallets-and-accounts "Direct link to Wallets and Accounts") Every customer has one wallet that can contain multiple accounts, each tracking a specific asset. ##### Wallets[​](#wallets "Direct link to Wallets") A wallet is the container for all of a customer's balance accounts. It's created automatically when a customer is subscribed to a product or initiates their first top-up. ##### Accounts[​](#accounts "Direct link to Accounts") Accounts hold balances in specific assets (currencies or custom units). They are provisioned automatically based on the products a customer subscribes to. Each account tracks: * Available balance * Pending incoming funds * Pending outgoing charges Accounts support overdrafts by default to ensure usage can be billed even when balances are low. #### Assets[​](#assets "Direct link to Assets") Assets are the units of value used for billing. They can be: * **Fiat currencies** (USD, EUR, etc.) * **Custom units** you define (tokens, minutes, credits, etc.) For custom assets, you define exchange rates from fiat currencies. These rates determine how much of your custom asset customers receive when topping up. Exchange rates can be updated and scheduled for future effective dates. #### Top-ups and Auto Top-up[​](#top-ups-and-auto-top-up "Direct link to Top-ups and Auto Top-up") ##### Top-ups[​](#top-ups "Direct link to Top-ups") Top-ups are how customers add funds to their wallet accounts. They can be initiated: * Through the Billing Portal (self-service) * Via the Top-up API (integrated into your product) * Externally through your own PSP (reflected via Adjustments) When using Credyt's payment processing, top-ups are handled through Stripe Checkout. ##### Auto Top-up[​](#auto-top-up "Direct link to Auto Top-up") Auto top-up keeps wallets funded automatically by defining balance thresholds and recharge amounts per asset. When a balance drops below the threshold, Credyt initiates an off-session payment and credits the wallet. **Configuration:** * Set per asset in the Billing Portal * Requires saved payment card authorization * Prevents service interruption during variable usage #### Credit Grants[​](#credit-grants "Direct link to Credit Grants") Credit grants are the fundamental units of a prepaid balance. Rather than treating a wallet as one undifferentiated pool, Credyt tracks each discrete allocation of value separately. **Each grant defines:** * Effective and expiry dates * Amount of value * Purpose (paid, promotional, included) * How it should be treated for revenue recognition **Key characteristics:** * Created from top-ups, adjustments, or entitlements * Consumed according to platform-defined rules * Enable proper revenue recognition at consumption * Support time-limited promotional credits * Remain auditable even after expiry #### Entitlements[​](#entitlements "Direct link to Entitlements") Entitlements are "right-to-use" grants that represent bundled allocations included with a product subscription. Unlike direct credit purchases, entitlements decouple service access from payment and enable hybrid billing models that combine recurring fees with usage-based pricing. **How entitlements work:** When a customer subscribes to a product with entitlements, Credyt automatically: * Grants the specified credit amount to the customer's wallet * Refreshes this allowance according to your defined schedule (daily, monthly, etc.) * Tracks consumption against the entitlement balance * Charges overage fees when credits are exhausted **Entitlement types:** * **Bundled entitlements**: Credits included as a feature of a fixed-fee plan (e.g., "$20/month includes 1,000 credits"). The subscription fee is recognized ratably while the credit value typically has a revenue basis of $0. * **Promotional entitlements**: Free credits granted to incentivize signups, login streaks, or referrals. No revenue is recognized. These track a cost basis to record marketing expense when consumed. **Key characteristics:** * Can grant credits in fiat currency or custom assets * Support flexible refresh strategies (expire-and-replace, rollover) * Enable priority-based consumption rules (e.g., use promotional credits before bundled credits) * Integrate with revenue recognition for proper accounting * Enable hybrid billing models combining subscriptions with usage overages #### Payments[​](#payments "Direct link to Payments") Payments in Credyt are processed through Stripe. When using Credyt's built-in payment processing: * Customers complete checkout via Stripe's hosted interface * Payment confirmation automatically updates wallet balances * All payment data and PCI compliance is handled by Stripe * Platforms can connect their own Stripe account or use Credyt's for testing For platforms using external PSPs, payments are reflected in Credyt via the Adjustments API. #### Adjustments[​](#adjustments "Direct link to Adjustments") Adjustments allow direct manipulation of account balances outside normal usage processing. They're used for: * External PSP payments (subscriptions, top-ups) * Refunds * Promotional credits and gifts * Manual corrections Each adjustment requires: * A unique transaction ID (idempotency key) * A reason code (external\_topup, external\_refund, gift, other) * The asset and amount * Optional expiry date and metadata #### Fees[​](#fees "Direct link to Fees") Fees are charges generated when usage events are processed. They represent the actual billable amount deducted from a customer's wallet. **Fees include:** * Product and price references * Calculated amounts based on usage * Dimensional attributes (if applicable) * Usage type (unit, volume, or both) * Description of what was billed Fees are created automatically when usage events match product pricing configurations. #### Billing Portal[​](#billing-portal "Direct link to Billing Portal") The Billing Portal is a hosted, self-service interface where customers can: * View wallet balances across all assets * See usage history and charges * Review transaction history * Initiate top-ups * Configure auto top-up settings * Manage saved payment cards **Access:** * No customer sign-up required * Accessed via pre-authenticated session links * Sessions expire after 10 minutes if unused * Fully customizable with your branding #### Vendors[​](#vendors "Direct link to Vendors") Vendors represent external services or infrastructure that power your product (AI model providers, compute platforms, third-party APIs). They're used in profitability tracking to correlate costs with revenue. #### Costs[​](#costs "Direct link to Costs") Costs represent expenses incurred from vendors when serving usage. They're attached to usage events to enable profitability analysis. **Costs can be attributed at:** * Customer level * Event level * Subject level (task or outcome) When combined with revenue from fees, costs enable calculation of gross revenue, net revenue, and margin per event, customer, or product. --- ## Faqs ### Frequently asked questions #### Architecture and fit[​](#architecture-and-fit "Direct link to Architecture and fit") **What is Credyt and who is it built for?** Credyt is real-time billing infrastructure for AI products. It's built for teams that charge for usage in real time — tokens, API calls, compute time, GPU hours — and need customers to prepay and manage their own balances. If you're building a usage-heavy product and don't want to front infrastructure costs or build wallet logic from scratch, Credyt is designed for you. **How is Credyt different from tools like Stripe Billing or Lago?** Most billing platforms are invoice-native. Usage accumulates throughout a billing period and payment is collected at cycle end. Credyt is wallet-native: customers prepay, and usage is authorized and debited in real time as it happens. There's no invoice cycle, no end-of-period reconciliation, and no risk of fronting costs you haven't collected yet. **Why does real-time billing matter for AI products specifically?** AI workloads incur real infrastructure costs with every API call, token, or model inference. Those costs happen continuously and can spike without warning. If you're billing in arrears, you're absorbing those costs before you've collected payment. Real-time billing flips that: usage is authorized before it runs, and funds are deducted immediately. You stay in control of margins at the point of consumption, not after the fact. **What does wallet-native architecture actually mean?** In most billing systems, wallets or credit accounts are a feature layered on top of invoices. In Credyt, the wallet is the billing system. Every customer gets a wallet from day one. Credits, balances, grants, and entitlements are first-class concepts with lifecycle management, expiry, and consumption ordering. There's no invoice generation step. The wallet is where authorization, deduction, and balance tracking all happen. **Is Credyt suitable for B2C products, or is it only for B2B?** Credyt works for both. It's particularly well suited to self-serve models where end users purchase and manage usage directly, without finance department involvement. The self-service portal is built for individual users and small teams, not for accounts payable workflows. If you're building a consumer-facing AI product with prepaid credits, the architecture fits naturally. *** #### Pricing and billing models[​](#pricing-and-billing-models "Direct link to Pricing and billing models") **Can I bill customers in tokens, GPU hours, or other custom units instead of dollars?** Yes. Credyt supports native custom assets. You define pricing in any unit that maps to your product: tokens, GPU hours, video minutes, API credits. Customers hold and spend balances in those units. You're not forced to convert everything to a generic credit type behind the scenes. Different asset types can have independent pricing rules and live side by side in one customer wallet. **How does Credyt pricing work?** Credyt charges per Monthly Active Wallet (MAW) with no upfront fees and no fixed platform costs. The first 10 MAWs per month are free. For built-in payment processing, PSP fees are passed through directly with no markup. What you pay the processor is what you pay. **Can I track which customers are actually profitable, not just how much they're spending?** Yes. Credyt ingests both usage events and their associated infrastructure costs, so you can see margin at the event level. You can track profitability per customer, per feature, or per workload in real time. This matters when infrastructure costs vary significantly by model, task type, or customer behavior, and you need to make pricing decisions based on actual margins rather than estimates. **Does Credyt support credit grants and free trial credits?** Yes. You can issue grants with defined purposes, expiry dates, and spending rules. Grants are first-class primitives in the wallet — not just invoice line items. You can use them for onboarding credits, referral rewards, retention campaigns, or limited-time promotions. Consumption ordering is explicit and deterministic: you define how grants are applied, and it works the same way every time. **Can I give customers a hybrid model with a monthly subscription plus usage on top?** Yes. Credyt supports hybrid billing: a flat-fee subscription combined with wallet top-ups and usage-based charges. Subscription entitlements can be bundled into the wallet at the start of each period, and overage is drawn from the customer's prepaid balance. You don't have to choose between recurring revenue and usage-based billing. **What pricing models does Credyt support?** Credyt supports event-based pricing (per occurrence), volume-based pricing, dimensional pricing (different rates based on usage attributes like model type or output format), and hybrid models that combine flat fees with usage charges. You define pricing rules via API. Rates apply automatically when usage events arrive. No hardcoded pricing logic in your application. *** #### Balance control and customer experience[​](#balance-control-and-customer-experience "Direct link to Balance control and customer experience") **How do I stop customers from going into debt or running up costs I can't collect?** Credyt authorizes every usage event before costs are incurred. When a customer attempts an action, your product checks their wallet balance in real time and approves or denies the request. If the balance is insufficient, the request is blocked. You prevent negative balances at the point of consumption rather than discovering exposure after the fact. **What happens when a customer's balance runs out mid-session?** Customers can set up automatic top-ups that trigger when their balance drops below a threshold they define. They control the threshold amount, top-up amount, and payment method through the self-service portal. Top-ups are processed immediately, so service continues without interruption. If auto top-up isn't configured, the balance hits zero and your product denies further usage until the customer adds funds. **Can my customers manage their own balance and top-ups?** Yes. Credyt includes a drop-in branded billing portal that customers access directly. They can view real-time balances, see live usage, add funds, configure automatic top-ups with threshold triggers, and manage payment methods. No custom frontend work required on your side, and no support tickets to manage routine billing tasks. **Do I need to build my own customer-facing billing UI?** No. The Credyt billing portal is a drop-in component you embed in your product. It shows real-time balances, live usage, transaction history, top-up flows, and payment method management out of the box. No custom frontend work required on your side. *** #### Integration and implementation[​](#integration-and-implementation "Direct link to Integration and implementation") **Does Credyt work alongside my existing billing setup, or do I have to replace it?** Credyt is designed to extend your existing stack, not replace it. If you use Stripe for subscriptions, you keep using it. Credyt adds the real-time authorization and wallet layer that invoice-based systems weren't built to provide. Both systems run alongside each other without conflict. **How long does it take to integrate Credyt?** Most teams ship in days. Credyt's API-first design means you're sending usage events, defining pricing rules, and embedding the billing portal rather than rebuilding billing infrastructure. You get wallet management, payment processing, and the customer portal out of the box. **Can I run prepaid wallets for some customers and invoice-based billing for others?** Yes. The two models can coexist. Use your existing subscription and invoicing tools for customers who prefer monthly billing. Use Credyt's wallet-based authorization for customers who want prepaid, real-time control. Each system handles its own customers without interfering with the other. **What if some enterprise customers need invoices?** Credyt can issue receipts through Stripe for completed transactions, but it doesn't provide full invoice management workflows — payment terms, dunning, collection processes. For customers who require invoices before payment, you'd use a dedicated invoicing tool alongside Credyt. Credyt handles the prepaid, real-time side. Your invoicing tool handles the accounts payable side. **Can I test my pricing configuration before going live?** Yes. Credyt has a test environment that's fully isolated from production, with a separate set of API credentials. You can create test customers, send simulated usage events, and validate pricing rules without affecting real customer data. Work in test mode until you're confident in the configuration, then switch to live. --- ## Partners ### Credyt for Platforms Preview Feature Credyt for Platforms is currently in preview. Please contact our [support team](mailto:support@credyt.ai) for access. #### Overview[​](#overview "Direct link to Overview") Credyt for Platforms (C4P) enables software platforms to embed Credyt's capabilities into their own products. Typical use-cases include: * Traditional invoice-native billing platforms looking to introduce real-time, usage-based billing and credit accounts * Commerce platforms wishing to introduce reward programs and store credit capabilities * Fintech platforms who need flexible wallet infrastructure to store and move value * Marketplaces with advanced money flows or a need to unify both open and closed-loop payments With C4P, each of your customers (or merchants) has a fully partitioned Credyt account with access to the capabilities you enable. Your customers can then create their own products, register their customers and bill them for usage, or interact with customer wallets directly. #### Integration[​](#integration "Direct link to Integration") ##### Account Structure[​](#account-structure "Direct link to Account Structure") Your customers exist in C4P as a *Connected Account* under your main platform account. Connected Accounts are unique per environment, so you may safely test in isolation. Connected Accounts can optionally be configured with their own wallets under your platform's management account. This if often desirable if you wish to implement usage-based billing for your own customers. ##### Security[​](#security "Direct link to Security") Integration between partners and Credyt is API-based. API access is secured using your platform's API key. The target connected account is specified via the `X-CREDYT-ACCOUNT` header. note At this stage we do not support API access directly from a connected account. Credyt API requests should always be initiated from your environment. Additionally you can access the Credyt Portal as the connected account for easy access to their account state and activity. ##### Actors and their interaction[​](#actors-and-their-interaction "Direct link to Actors and their interaction") Activities that use Credyt typically involve the following actors: 1. Your Customer's Customer (referred to as the *End User* in this context) 2. Your Customer 3. Your Platform 4. Credyt Interaction between these actors is typically sequential making Credyt invisible to your customers and the end user. ##### Example[​](#example "Direct link to Example") The following sequence of interactions would take place when the end-user performs a billable activity. 1. End user performs billable activity e.g. "Generate image" 2. Customer submits usage events to your platform 3. Your platform validates and identifies the customer 4. Your platform forwards usage events to Credyt 5. Credyt calculates any usage fees and debits the end user's wallet 6. Credyt may additionally send key events (such as low balance thresholds) to your platform via Webhook The complexity of your integration with Credyt will vary on how embedded our capabilities are into your existing products. In many cases it may be as simple as building a lightweight mapping and proxy layer between the two systems. ##### Webhooks[​](#webhooks "Direct link to Webhooks") To receive notifications of key events and activities within your connected accounts, you can register a webhook endpoint that specifically receives C4P activity. The webhook payload will include the Connected Account's ID so that you can correlate to your customer and take the necessary action. This is the pattern typically used by billing providers to trigger automatic wallet top-ups in response to low threshold events: Balance Threshold webhook ```json { "id": "whe_48b9cet5d6h6vf2rwg4w3ezkw2", "account": "acc_4y7dxxqt8dzzpf4w58te001zxb", "event_type": "balance_threshold_hit", "occurred_at": "2026-01-07T13:19:18.265Z", "data": { "customer_id": "cust_4tqzchnwchbwf87m7g86pw0xmm", "account_id": "default:USD", "available": 9.24, "threshold": 10.0 } } ``` #### Quickstart[​](#quickstart "Direct link to Quickstart") ##### Create a webhook for C4P[​](#create-a-webhook-for-c4p "Direct link to Create a webhook for C4P") Create a new webhook endpoint to receive events from your connected accounts: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/webhooks ```json { "url": "https://integrations.tradbill.com/credyt/c4p", "connect": true } ``` **Response** ```json { "id": "whd_01abc123", "secret": "whsec_••••••", "created_at": "2026-04-14T10:00:00Z" } ``` ```typescript await client.webhooks.createWebhookDestination({ url: "https://integrations.tradbill.com/credyt/c4p", connect: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/webhooksWebhooksCreateWebhookDestinationSample.ts#L11) **SDK response object** ```typescript const response = { id: "whd_01abc123", secret: "whsec_••••••", createdAt: "2026-04-14T10:00:00Z", }; ``` ```python response = client.webhooks.create_webhook_destination( body={ "url": "https://integrations.tradbill.com/credyt/c4p", "connect": True, }, ) ``` **SDK response object** ```python response = { "id": "whd_01abc123", "secret": "whsec_••••••", "created_at": "2026-04-14T10:00:00Z", } ``` ##### Create a connected account[​](#create-a-connected-account "Direct link to Create a connected account") Before you customer can begin using Credyt's capabilities they must be set up as a connected account: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/accounts ```json { "name": "BingoLingo", "external_id": "4bc6fbfc5493" } ``` **Response** ```json { "id": "acc_4tvras4k598tdb256atm8axemw" } ``` ```typescript await client.accounts.create({ name: "BingoLingo", externalId: "4bc6fbfc5493", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/accountsCreateSample.ts#L11) **SDK response object** ```typescript const response = { id: "acc_4tvras4k598tdb256atm8axemw", }; ``` ```python response = client.accounts.create( body={ "name": "BingoLingo", "external_id": "4bc6fbfc5493", }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/accounts_create_create_connected_account.py#L20) **SDK response object** ```python response = { "id": "acc_4tvras4k598tdb256atm8axemw", } ``` ##### Create a customer (the end user)[​](#create-a-customer-the-end-user "Direct link to Create a customer (the end user)") Each of your customer's customers (the end user) should be created as a `customer` object under the connected account, by specifying the `X-CREDYT-ACCOUNT` header: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers ```json { "name": "Francis Gutmann DDS", "external_id": "b7bac50a20bf44aa893bfd614d7631ae" } ``` **Response** ```json { "id": "cust_4s8epv6ej86aeep682pmcbhhm6", "subscriptions": [] } ``` ```typescript await client.customers.create({ name: "Francis Gutmann DDS", externalId: "b7bac50a20bf44aa893bfd614d7631ae", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersCreateSample.ts#L11) **SDK response object** ```typescript const response = { id: "cust_4s8epv6ej86aeep682pmcbhhm6", subscriptions: [], }; ``` ```python response = client.customers.create( body={ "name": "Francis Gutmann DDS", "external_id": "b7bac50a20bf44aa893bfd614d7631ae", }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_create_create_end_user.py#L20) **SDK response object** ```python response = { "id": "cust_4s8epv6ej86aeep682pmcbhhm6", "subscriptions": [], } ``` ##### Add credit to the end-user's wallet[​](#add-credit-to-the-end-users-wallet "Direct link to Add credit to the end-user's wallet") Suppose you're a billing platform and wish to credit the end-user's wallet each time a subscription payment is collected. This can be achieved by using the Wallet API: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_4s8epv6ej86aeep682pmcbhhm6/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "asset": "USD", "amount": 20, "reason": "external_topup", "metadata": { "payment_id": "4c81c0ff-d050-4e85-b111-13a7f3f251fa" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2026-04-14T10:00:00Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_4s8epv6ej86aeep682pmcbhhm6", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", asset: "USD", amount: 20, reason: "external_topup", metadata: { paymentId: "4c81c0ff-d050-4e85-b111-13a7f3f251fa", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L23) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2026-04-14T10:00:00Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_4s8epv6ej86aeep682pmcbhhm6", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "asset": "USD", "amount": 20, "reason": "external_topup", "metadata": { "payment_id": "4c81c0ff-d050-4e85-b111-13a7f3f251fa", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2026-04-14T10:00:00Z", } ``` #### Using other APIs[​](#using-other-apis "Direct link to Using other APIs") We invite you to explore the broader Credyt documentation for details on how to interact with Credyt on behalf of your customers. #### Restrictions[​](#restrictions "Direct link to Restrictions") The following capabilities are restricted or not yet supported. ##### Direct API Access[​](#direct-api-access "Direct link to Direct API Access") It is not possible to create API keys for connected accounts. API access is only granted via your platform's API Keys and the specified `X-CREDYT-ACCOUNT` header. ##### Webhooks[​](#webhooks-1 "Direct link to Webhooks") You can not create webhook endpoints for a specific connected account. You can however, create a webhook endpoint on your platform account that subscribes to connect account events, as described [here](#create-a-webhook-for-c4p). ##### Top-ups[​](#top-ups "Direct link to Top-ups") Currently top-ups via our built-in Stripe integration are not supported on connected accounts. Instead platforms using C4P must implement payment processing themselves. If you require this functionality please [contact support](mailto:support@credyt.ai). --- ## Pricing Guide ### Pricing Guide Real-time usage-based billing (UBB) works differently from traditional SaaS. While conventional billing meters usage and invoices monthly, AI-native products incur costs immediately - with every API call, token generated, or GPU second consumed. This fundamental difference shapes how you should approach pricing. Credyt supports three pricing models that align with how AI-native products actually deliver and consume value. Each model serves different product strategies and customer expectations. #### Supported Pricing Models[​](#supported-pricing-models "Direct link to Supported Pricing Models") ##### 1. Real-time usage-based billing from pre-paid balances[​](#1-real-time-usage-based-billing-from-pre-paid-balances "Direct link to 1. Real-time usage-based billing from pre-paid balances") Customers fund their wallet upfront with either fiat currency or custom assets (tokens, credits, minutes). Usage draws down from their balance in real time. When balance hits zero, service stops or triggers automatic top-up. **How it works in Credyt:** Customers top up their wallet through the [Billing Portal](https://docs.credyt.ai/features/billing-portal.md) or via the [Top-up API](https://docs.credyt.ai/features/wallets-and-topups.md). Balances can be held in standard currencies (USD, EUR) or [custom assets](https://docs.credyt.ai/features/assets.md) you define. As usage occurs, their balance is debited immediately. Customers can enable [auto top-up](https://docs.credyt.ai/features/auto-topup.md) to refill their balances automatically when they fall below a threshold. **Who uses this model:** OpenAI API, Anthropic Claude API, Replicate, ElevenLabs, and most LLM providers. Common with developer-focused products where customers understand marginal costs. **When to choose this:** * You sell tokens, API calls, or compute time * Infrastructure costs are variable and unpredictable * Cash flow protection is critical * You can't afford to front costs for customers * Your customer base includes developers who expect pay-as-you-go pricing **Implementation in Credyt:** Define products with `type: usage-based`and`billing_model.type: real_time` in your [product catalog](https://docs.credyt.ai/features/product-catalog.md). Usage events immediately debit the customer's wallet. For more complex scenarios where pricing varies based on characteristics of the usage (like AI model type, speed, or quality), use [dimensional pricing](https://docs.credyt.ai/features/product-catalog/dimensional-pricing.md) to define different rates for different usage attributes. See our [Topups Only Model guide](https://docs.credyt.ai/use-cases/top-ups-only-model.md) for further details. ##### 2. Recurring fixed fee (subscriptions)[​](#2-recurring-fixed-fee-subscriptions "Direct link to 2. Recurring fixed fee (subscriptions)") Customers pay a fixed amount on a recurring cycle. This provides predictable baseline revenue while you figure out usage-based pricing. **How it works in Credyt:** Credyt supports [fixed fee pricing](https://docs.credyt.ai/features/product-catalog/fixed-fee-pricing.md) natively, allowing you to charge recurring subscription fees directly. While Credyt was designed primarily for usage-based billing, recurring fees serve as an ideal starting point when you're still determining how to price usage. **Why start here:** Beginning with fixed subscriptions lets you generate immediate revenue while building understanding of your cost structure. You can send usage events and associated costs to Credyt without charging for them yet. Using [Profitability analysis](https://docs.credyt.ai/features/profitability.md), you track revenue against actual infrastructure costs per customer, giving you the data needed to confidently transition to usage-based pricing when ready. **Who uses this model:** Traditional SaaS companies, products prioritizing predictable revenue, or platforms in the early stages of introducing usage-based pricing. **When to choose this:** * You need baseline revenue but aren't ready to price usage yet * You want to understand cost structures before charging for usage * You're planning to transition to usage-based pricing gradually * Enterprise customers require predictable billing cycles * You're still validating product-market fit **Implementation in Credyt:** Configure products with fixed fee pricing following the [fixed fee pricing guide](https://docs.credyt.ai/features/product-catalog/fixed-fee-pricing.md). Send usage events to track consumption patterns and costs, then use profitability metrics to inform your eventual usage-based pricing model. ##### 3. Hybrid billing (subscriptions + entitlements + top-ups)[​](#3-hybrid-billing-subscriptions--entitlements--top-ups "Direct link to 3. Hybrid billing (subscriptions + entitlements + top-ups)") Base subscription provides predictable revenue and includes usage [entitlements](https://docs.credyt.ai/features/product-catalog/entitlements.md). Additional usage beyond the entitlement can be purchased through top-ups or charged additionally. **How it works in Credyt:** Combine [fixed fee pricing](https://docs.credyt.ai/features/product-catalog/fixed-fee-pricing.md) with usage-based charges. Subscriptions provide base access and bundled usage allowances through entitlements. When customers exceed their entitlement, they either top up for additional usage or are charged for overages. Both subscription entitlements and top-up credits can coexist in the same wallet. **Who uses this model:** Clay (seat-based access with credit allocations), Cursor (monthly credit pools per tier), GitHub Copilot (subscriptions with usage caps). Common when you want recurring revenue with usage-based expansion. **When to choose this:** * You need baseline recurring revenue plus usage-based growth * Some features are seat-based, others consumption-based * Customers want predictability with flexibility for overages * You're balancing stakeholder preferences for both models * Different customer segments expect different billing approaches **Implementation in Credyt:** Configure products with both fixed fees and usage-based pricing. Use [entitlements](https://docs.credyt.ai/features/product-catalog/entitlements.md) to define included usage allocations. Enable top-ups through [Credyt's Billing Portal](https://docs.credyt.ai/features/billing-portal.md) for additional usage. See our [Hybrid Pricing guide](https://docs.credyt.ai/features/product-catalog/entitlements.md). #### Choosing Your Pricing Model[​](#choosing-your-pricing-model "Direct link to Choosing Your Pricing Model") Start with three questions: **1. Can you afford to front infrastructure costs?** If no: Real-time prepaid credits eliminate cash flow risk. Customers pay before they consume. If yes: Subscription or hybrid models give customers payment flexibility that enterprise buyers often prefer. **2. How predictable is customer usage?** Highly unpredictable: Prepaid credits protect you from runaway costs. Real-time authorization prevents negative balances. Relatively stable: Subscriptions or hybrid models work well, providing baseline revenue while supporting usage spikes. **3. What billing model do your customers expect?** Developers and prosumers: Often prefer pay-as-you-go with real-time visibility into spend. Enterprise customers: Frequently require invoice cycles and payment terms that align with procurement processes. #### Pricing in Fiat vs Custom Units[​](#pricing-in-fiat-vs-custom-units "Direct link to Pricing in Fiat vs Custom Units") Credyt supports pricing in both standard currencies (USD, EUR) and [custom assets](https://docs.credyt.ai/features/assets.md) like tokens, minutes, or credits. **Fiat pricing:** Transparent and enterprise-friendly. Usage deducts directly in currency terms (e.g., $0.006 per API call). Straightforward for reconciliation and familiar to most customers. **Custom units:** Consumer-friendly for products where abstract units better represent value (e.g., 10 credits per video generation). You define [exchange rates](https://docs.credyt.ai/features/assets.md) between fiat and your custom units. The Billing Portal automatically handles conversions during top-up. Both approaches can coexist in a single customer wallet. See our [Fiat vs Custom Units guide](https://docs.credyt.ai/use-cases/fiat-vs-custom-units.md) for implementation details. #### Important Note: Invoice-based Usage Billing[​](#important-note-invoice-based-usage-billing "Direct link to Important Note: Invoice-based Usage Billing") Credyt does not currently support usage-based billing where usage is metered throughout a period and billed in arrears via invoices (similar to AWS Lambda or Twilio). All usage-based pricing in Credyt operates on a prepaid, real-time authorization model. If your business requires post-facto metering with invoicing after usage occurs, Credyt may not be the right fit for your billing infrastructure. #### Next Steps[​](#next-steps "Direct link to Next Steps") * Review [Products and Pricing](https://docs.credyt.ai/features/product-catalog.md) to understand how to configure create products and configure pricing * Read about [Dimensional Pricing](https://docs.credyt.ai/features/product-catalog/dimensional-pricing.md) if your pricing varies by attributes like speed, quality, or model type * Check our [Quickstart guide](https://docs.credyt.ai/quickstart.md) to start integrating --- ## Sdk ### SDKs #### TypeScript/JavaScript SDK[​](#typescriptjavascript-sdk "Direct link to TypeScript/JavaScript SDK") Install the SDK and initialize the client once for all the examples using the TypeScript SDK in this documentation: ```bash npm install @credyt/api-client ``` ```typescript import { CredytApiClient } from "@credyt/api-client"; const client = new CredytApiClient({ key: "YOUR_API_KEY" }); ``` Secret management Never hard-code your API key. Store it in an environment variable and read it at runtime: ```typescript const client = new CredytApiClient({ key: process.env.CREDYT_API_KEY! }); ``` Use a `.env` file locally (and add it to `.gitignore`), and inject the variable through your hosting platform's secrets manager in production. ##### More TypeScript Examples[​](#more-typescript-examples "Direct link to More TypeScript Examples") All of the examples in this documentation can also be found in our [GitHub repository](https://github.com/credyt/sdk-ts/tree/main/samples). #### Python SDK[​](#python-sdk "Direct link to Python SDK") Install the SDK and initialize the client once for all the examples using the Python SDK in this documentation: ```bash pip install credyt-api ``` ```python def main(): client = CredytApiClient( credential=ServiceKeyCredential(key=os.getenv("CREDYT_API_KEY")), ) response = client.customers.get( customer_id="cust_4qh0wajx2n9qtazh2tghzkyan2", ) print(response) if __name__ == "__main__": main() ``` Secret management Never hard-code your API key. Store it in an environment variable and read it at runtime: ```python client = CredytApiClient( credential=ServiceKeyCredential(key=os.getenv("CREDYT_API_KEY")), ) ``` Use a `.env` file locally (and add it to `.gitignore`), and inject the variable through your hosting platform's secrets manager in production. ##### More Python Examples[​](#more-python-examples "Direct link to More Python Examples") All of the examples in this documentation can also be found in our [GitHub repository](https://github.com/credyt/sdk-python/tree/main/samples). --- ## Security ### Security #### Infrastructure[​](#infrastructure "Direct link to Infrastructure") Credyt's infrastructure is hosted in Microsoft Azure. We use virtual networks to segregate and manage access between components and the public internet. Where managed infrastructure is used, we exclusively use private endpoints. Internal access control is governed entirely by Microsoft Entra. External access control for the Credyt dashboard is managed using Auth0. External access through the public internet is via a central reverse proxy, protected with HTTPS. Customer data is stored in a multi-tenant environment and encrypted in transit (TLS 1.2+) and at rest (AES-256). We use separate environments for development and production, each in their own private VNet. Internal private VNets are accessed via VPN when needed. VPN access control is also governed by Microsoft Entra. #### Authentication and access control[​](#authentication-and-access-control "Direct link to Authentication and access control") Credyt supports API key and OAuth authentication. API keys are scoped per environment with separate test and live keys. Role-based access control (RBAC) is available within customer accounts, allowing granular permissions across team members for dashboard and API access. All API requests are rate limited. #### Data retention[​](#data-retention "Direct link to Data retention") Usage events, billing records, and customer data are retained for the lifetime of the customer account. This supports historical reporting, auditability, and revenue recognition requirements. Where applicable, data may also be retained to meet legal or regulatory obligations. When a customer account is closed, all associated data is automatically deleted after a defined retention period. #### Payment processing[​](#payment-processing "Direct link to Payment processing") Credyt uses Stripe Connect (Standard Accounts model) for payment processing. Under this model, your customers own their Stripe account and relationship directly. Credyt acts as the platform but does not process, store, or have access to raw payment card data. No PCI data is held or processed by Credyt. Tokenised references such as Stripe customer IDs and masked card numbers are used within the platform for display and reconciliation purposes only. #### Personal identifiable information (PII)[​](#personal-identifiable-information-pii "Direct link to Personal identifiable information (PII)") Credyt processes PII of direct users of the platform (our customers) as part of account management and authentication. For end-user data (the customers of our customers), Credyt can optionally store name and email. This is not required. Customers can instead store only their own internal identifiers to link records to their systems. The choice of what PII to store in Credyt sits with the customer. Where end-user PII is stored, Credyt acts as a data processor on behalf of the customer. The customer retains responsibility as the data controller. #### API security[​](#api-security "Direct link to API security") * **Environment separation**: Test and live API keys are issued separately. Test environments are isolated from production. * **Rate limiting**: All API endpoints are rate limited to protect against abuse and ensure fair usage. * **Audit logging**: API activity is logged internally. Customer-facing audit logs are on the roadmap. * **Idempotency**: Usage event submission supports idempotency keys to prevent duplicate processing. #### GDPR and data protection[​](#gdpr-and-data-protection "Direct link to GDPR and data protection") Credyt is a US corporation. Where our customers or their end-users are in the EU, GDPR applies to Credyt as a data processor. Credyt supports customers in meeting their data protection obligations: * **Right to erasure**: End-user data can be deleted on request. * **Right to portability**: Customer data can be exported. * **Data Processing Agreement**: A DPA is available on request. Contact . * **Subprocessors**: A list of subprocessors is available on request. * **Data residency**: Customer data is currently stored in a single Azure region. Region selection is not currently available. #### Subprocessors[​](#subprocessors "Direct link to Subprocessors") Credyt uses a limited number of third-party services that process or store customer data. A full list of subprocessors is available on request by contacting . #### Incident response[​](#incident-response "Direct link to Incident response") In the event of a data breach, affected customers will be notified within 72 hours, in line with GDPR requirements. If you believe you have found a security vulnerability, please report it to . #### Certifications[​](#certifications "Direct link to Certifications") We are currently evaluating the SOC 2 certification process. If this is a requirement for your security team, contact or speak to your account executive. --- ## Quickstart ### Introduction The Quickstart Guide is the fastest way to get hands-on with Credyt and see how everything fits together. It walks you through the core concepts of the platform and gives you a clear, minimal path to start integrating; from creating your first customer to processing real-time usage and tracking wallet balances. We recommend working in test mode throughout this guide. The test environment is completely isolated from production and uses a separate set of API credentials, so you can safely experiment, send usage, and explore payment flows without impacting real customer data. Video Available Watch the video version of this quickstart guide on [YouTube](https://youtu.be/JFKvVFK_Wm4?si=OSG8-Dipl9M1Efqk). ##### Meet GlitchAI[​](#meet-glitchai "Direct link to Meet GlitchAI") Throughout our docs, we'll use examples from a fictitious AI media and content generation platform for marketers, GlitchAI. #### Prerequisites[​](#prerequisites "Direct link to Prerequisites") Sign up To complete this quickstart guide you'll need a Credyt account. You can sign up for free at To integrate with Credyt, you’ll need your API key, which must be included in the `X-CREDYT-API-KEY` header in all API requests. API keys are pre-generated for your account during sign-up and can be obtained from the [Credyt App](https://app.credyt.ai). If you’re part of an existing account, contact your account administrator to get access to the API key. When you’re ready to move beyond the basics, explore the [Features](https://docs.credyt.ai/category/features.md) and [Advanced Topics](https://docs.credyt.ai/category/advanced-topics.md) sections for a deeper dive into all of Credyt's capabilities. TypeScript SDK Install the SDK and initialize the client once for all the examples using the TypeScript SDK in this documentation: ```bash npm install @credyt/api-client ``` ```typescript import { CredytApiClient } from "@credyt/api-client"; const client = new CredytApiClient({ key: "YOUR_API_KEY" }); ``` #### Follow along with Bruno[​](#follow-along-with-bruno "Direct link to Follow along with Bruno") With our [Bruno request collections](https://github.com/credyt/learn/tree/main/bruno/credyt-api) you can follow along with the docs interactively and make API requests against your own account. You can view the setup instructions and download the collections from [GitHub](https://github.com/credyt/learn/archive/refs/heads/main.zip) or click the button below to open them directly in [Bruno](https://usebruno.com). [![Fetch in Bruno](https://fetch.usebruno.com/button.svg)](https://fetch.usebruno.com/?url=https%3A%2F%2Fgithub.com%2Fcredyt%2Flearn.git) After opening the collection in Bruno: 1. In the top right of the Bruno app select the environments dropdown and select "Configure" 2. Obtain your API keys from the [Credyt Portal](https://app.credyt.ai) and add them under the `credytApiKey` variable for your desired environment (test or live). Make sure to "Save" the changes. 3. Select the target environment in Bruno --- ### Billing Portal [API Reference](https://docs.credyt.ai/api/billing-portal-create-portal-session.md) The Billing Portal enables you to offer your customers a comprehensive billing experience, providing them with visibility into their balances, usage and top-up history. From here they can top up their accounts directly and manage their billing settings. More information on the billing portal can be found [here](https://docs.credyt.ai/features/billing-portal.md). #### Start a billing portal session[​](#start-a-billing-portal-session "Direct link to Start a billing portal session") Your customers do not need to register for Credyt in order to use the billing portal. Instead, you manage their access by generating a billing portal *session*, once you have authenticated and validated the user within your service. Let's open up the billing portal for the customer we've been working with: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/billing-portal/sessions ```json { "customer_id": "{{customerId}}", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure" } ``` ```typescript await client.billingPortal.createPortalSession({ customerId: "{{customerId}}", returnUrl: "https://glitch.ai/account", failureUrl: "https://glitch.ai/callbacks/credyt/failure", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/billingPortalCreatePortalSessionSample.ts#L11) ```python response = client.billing_portal.create_portal_session( body={ "customer_id": "{{customerId}}", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure", }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/billing_portal_create_portal_session_start_a_session.py#L20) The `redirect_url` is a pre-authenticated URL where you send your customer. This link is valid for 10 minutes. Return and Failure URLs When creating a billing portal session you specify both the URL the customer should return to when exiting the portal (`return_url`) and the failure URL (`failure_url`) we will redirect them to if their session expires or there are any issues. You can find more about failure handling [here](https://docs.credyt.ai/features/billing-portal.md). If you navigate to this URL you should see their recently updated balance and usage. ![Credyt\'s Billing Portal](/assets/images/billing-portal-11c343c1d1b18b46fa148cf70cea918f.png) --- ### Check Balance [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-customer-wallet.md) You can check a customer’s wallet balance at any time via the Customer Wallet API. A customer wallet may contain multiple accounts of different currencies or assets. In this guide we’ve placed this step last to show how the balance updates after usage events are sent. In practice, you'll typically want to check the balance before allowing the customer to perform the billable action. Overdrafts are enabled on wallet accounts by default, ensuring that usage can be billed in full. We recommend that you check balances according to your own business logic and overdraft tolerance. ##### Get Wallet Example[​](#get-wallet-example "Direct link to Get Wallet Example") After submitting a few `video_promoted` events in the [previous section](https://docs.credyt.ai/quickstart/send-usage.md) we can see our balance has been reduced accordingly. * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/customers/{customerId}/wallet ```http ``` **Response** ```json { "accounts": [ { "id": "default:USD", "name": "default", "asset": "USD", "available": 998.5 } ] } ``` ```typescript await client.customerWalletOps.getCustomerWallet(); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetCustomerWalletSample.ts#L11) **SDK response object** ```typescript const response = { accounts: [ { id: "default:USD", name: "default", asset: "USD", available: 998.5, }, ], }; ``` ```python response = client.customer_wallet_ops.get_customer_wallet() ``` **SDK response object** ```python response = { "accounts": [ { "id": "default:USD", "name": "default", "asset": "USD", "available": 998.5, }, ], } ``` ##### Get Account Example[​](#get-account-example "Direct link to Get Account Example") If you know the address of the account you wish to check, you can use the [Wallet Account API](https://docs.credyt.ai/api/customer-wallet-ops-get-account.md). Typically this will be in the format `default:{currency}`. * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/customers/{customerId}/wallet/{accountId} ```http ``` **Response** ```json { "id": "default:USD", "name": "default", "asset": "USD", "available": 998.5, "pending_in": 0, "pending_out": 0 } ``` ```typescript await client.customerWalletOps.getAccount(); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetAccountSample.ts#L27) **SDK response object** ```typescript const response = { id: "default:USD", name: "default", asset: "USD", available: 998.5, pendingIn: 0, pendingOut: 0, }; ``` ```python response = client.customer_wallet_ops.get_account() ``` **SDK response object** ```python response = { "id": "default:USD", "name": "default", "asset": "USD", "available": 998.5, "pending_in": 0, "pending_out": 0, } ``` --- ### Create a Customer [API Reference](https://docs.credyt.ai/api/customers-create.md) Before you can start billing your customers you need to register them in Credyt and create subscriptions to the products they use. #### Product Subscriptions[​](#product-subscriptions "Direct link to Product Subscriptions") When creating a customer you can subscribe them to products in your [Product Catalog](https://docs.credyt.ai/quickstart/create-a-product.md). The product code and version you specify determines the pricing that will be used to bill the customer. When you subscribe a customer to a product, Credyt automatically creates their wallet and provisions accounts in the billing currencies defined by the product’s pricing configuration. These accounts are used to track balances, top-ups, and usage from the start of the subscription. ##### Example[​](#example "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers ```json { "name": "John Doe", "external_id": "18991", "subscriptions": [ { "products": [ { "code": "glitch_video_std" } ] } ] } ``` **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: "John Doe", externalId: "18991", subscriptions: [ { products: [ { code: "glitch_video_std", }, ], }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersCreateSample.ts#L112) **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": "John Doe", "external_id": "18991", "subscriptions": [ { "products": [ { "code": "glitch_video_std", }, ], }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_create_subscribe_to_glitch_video.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", }, ], }, ], } ``` tip The `external_id` field allows you to use your own identifiers when sending usage data to Credyt Make a note of the customer `id`. We'll use it in the subsequent exercises. --- ### Create a Product [API Reference](https://docs.credyt.ai/api/products-create.md) The product catalogue is a core concept in Credyt. Before sending usage, you’ll need to add your products, which can be priced in multiple ways: * **Event Type** - what product event or outcome are you billing for? * **Currency or asset** - do you want to price in fiat or a custom asset such as tokens or minutes? * **Usage type** - are you charging per occurrence (unit) or volume (e.g. workload size)? * **Billing Dimensions** - do you price differently based on characteristics of the usage such as the AI model used? To get familiar with Credyt you can create products directly using our [Create Product API](https://docs.credyt.ai/api/products-create.md). This lets you validate your integration and usage flow before building out your full product catalogue. Start by defining a basic product with a default rate plan. This product will serve as the reference for sending usage events and testing wallet deductions. ##### Unit-based pricing[​](#unit-based-pricing "Direct link to Unit-based pricing") Use unit-based pricing to charge per occurrence of a particular event or outcome. In this example, we charge $0.50 per video that is promoted via the Glitch Marketplace: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/products ```json { "name": "Glitch Video", "code": "glitch_video_std", "prices": [ { "name": "Video Promotion", "type": "usage_based", "billing_model": { "type": "real_time" }, "usage_calculation": { "event_type": "video_promoted", "usage_type": "unit", "source_reference_field": "video_id" }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 0.5 } ] } ] } ], "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 Promotion", type: "usage_based", billingModel: { type: "real_time", }, usageCalculation: { eventType: "video_promoted", usageType: "unit", sourceReferenceField: "video_id", }, pricing: [ { asset: "USD", values: [ { unitPrice: 0.5, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L227) **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 Promotion", "type": "usage_based", "billing_model": { "type": "real_time", }, "usage_calculation": { "event_type": "video_promoted", "usage_type": "unit", "source_reference_field": "video_id", }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 0.5, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_usage_based_price.py#L20) **SDK response object** ```python response = { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": 1, "status": "published", "is_default": True, } ``` Versioning Products are automatically versioned so you can safely make changes to your pricing without impacting existing customers. --- ### Pre-fund Balance [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) To make testing easier, you can pre-fund your customer's balance without going through the full payment flow. This is the fastest way to see real-time billing in action! You can use the [Wallet Adjustment API](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) to pre-fund a customer’s wallet. For the full overview of how top-ups work in production, check out the [Top-ups and Wallets guide](https://docs.credyt.ai/features/wallets-and-topups.md). You can use this API for any kind of balance adjustment including external PSP payments, refunds, and promotional credits. A detailed explanation of this functionality is available in our [Adjustments guide](https://docs.credyt.ai/advanced-topics/adjustments-charges-gifts.md). ##### Example[​](#example "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/{customerId}/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "asset": "USD", "amount": 20, "reason": "external_topup", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0" } } ``` **Response** ```json { "id": "61e15192-a156-4af4-a3cc-ec6c937795fa", "created_at": "2025-10-17T21:00:56.743379Z" } ``` ```typescript await client.customerWalletOps.createAdjustment({ transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", asset: "USD", amount: 20, reason: "external_topup", metadata: { psp: "stripe", paymentIntent: "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L92) **SDK response object** ```typescript const response = { id: "61e15192-a156-4af4-a3cc-ec6c937795fa", createdAt: "2025-10-17T21:00:56.743379Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "asset": "USD", "amount": 20, "reason": "external_topup", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }, ) ``` **SDK response object** ```python response = { "id": "61e15192-a156-4af4-a3cc-ec6c937795fa", "created_at": "2025-10-17T21:00:56.743379Z", } ``` Wallet Idempotency Wallet adjustments can be safely retried by specifying the same unique transaction identifier (UUID) --- ### Send Usage Events [API Reference](https://docs.credyt.ai/api/events-send-usage.md) Submit actual usage events such as API calls, AI workloads, or product outcomes. Billable events are processed in real time and immediately debit the customer’s wallet. Each event must have a unique ID to ensure idempotency, preventing double billing if the same event is submitted multiple times. Customers are billed based on their [product subscriptions](https://docs.credyt.ai/quickstart/create-a-customer.md#product-subscriptions). Usage events are matched against the corresponding products' [usage calculation configuration](https://docs.credyt.ai/quickstart/create-a-product.md). For example, if a product has a `video_promoted` event type configured, sending a usage event of that type will calculate and debit a usage fee from the customer's wallet. note The response from the [Usage API](https://docs.credyt.ai/api/events-send-usage.md) does not include the updated wallet balance. To check the current balance after usage is processed, you can use the [Wallet API](https://docs.credyt.ai/api/customer-wallet-ops-get-customer-wallet.md). ##### Example[​](#example "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "video_promoted", "occurred_at": "2025-10-17T21:21:27.024729Z", "subject": "video_5f53d23a4958", "description": "Video Promoted", "data": { "promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm" } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", events: [ { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", eventType: "video_promoted", occurredAt: "2025-10-17T21:21:27.024729Z", subject: "video_5f53d23a4958", description: "Video Promoted", data: { promoId: "pro_4tbftjwzxja1h71nzas1g0g1xm", }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L93) ```python response = client.events.send_usage( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "video_promoted", "occurred_at": "2025-10-17T21:21:27.024729Z", "subject": "video_5f53d23a4958", "description": "Video Promoted", "data": { "promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm", }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_video_promoted.py#L20) #### Using external identifiers[​](#using-external-identifiers "Direct link to Using external identifiers") Alternatively you can specify the customer's external identifier in the `customer_external_id` field. This may be preferable if sending usage is in your application "hot path" and you want to avoid unnecessary lookups: ##### Example[​](#example-1 "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_external_id": "", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "video_promoted", "occurred_at": "2025-10-17T21:21:27.024729Z", "subject": "video_5f53d23a4958", "description": "Video Promoted", "data": { "promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm" } } ] } ``` ```typescript await client.events.sendUsage({ customerExternalId: "", events: [ { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", eventType: "video_promoted", occurredAt: "2025-10-17T21:21:27.024729Z", subject: "video_5f53d23a4958", description: "Video Promoted", data: { promoId: "pro_4tbftjwzxja1h71nzas1g0g1xm", }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L117) ```python response = client.events.send_usage( body={ "customer_external_id": "", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "video_promoted", "occurred_at": "2025-10-17T21:21:27.024729Z", "subject": "video_5f53d23a4958", "description": "Video Promoted", "data": { "promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm", }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_video_promoted_by_external_id.py#L20) --- ### Troubleshooting This guide covers some of the most common issues developers encounter when integrating with Credyt and how to troubleshoot them effectively. ##### The customer is not billed for usage events[​](#the-customer-is-not-billed-for-usage-events "Direct link to The customer is not billed for usage events") If your customer isn't being billed after sending usage events, you should check the following: **1. Ensure you have subscribed your customer to the product** Credyt will accept any usage event for a customer, even if they are not subscribed to a corresponding product. This is to ensure your Credyt integration doesn't break as you generate new events from your system. To validate that the customer is subscribed to a product, [retrieve the customers details](https://docs.credyt.ai/api/customers-create.md) and inspect their `subscriptions`, for example: * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/customers/cust\_4qh0wajx2n9qtazh2tghzkyan2 ```http ``` **Response** ```json { "id": "cust_4qh0wajx2n9qtazh2tghzkyan2", "external_id": "951832085fee4033a2878f841a24149a", "name": "Joan Parker", "active_subscription_count": 1, "created_at": "2025-11-14T03:25:02.885Z", "external_accounts": [], "subscriptions": [ { "id": "sub_4t2fz8a57hje7fjazkrc08jg5n", "started_at": "2025-10-23T11:11:40.100Z", "status": "active", "products": [ { "id": "prp_4t2fz8a57hje7fjazkrc08jg5n", "code": "glitch_video_std", "version": 1 } ] } ] } ``` ```typescript await client.customers.get("cust_4qh0wajx2n9qtazh2tghzkyan2"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersGetSample.ts#L11) **SDK response object** ```typescript const response = { id: "cust_4qh0wajx2n9qtazh2tghzkyan2", externalId: "951832085fee4033a2878f841a24149a", name: "Joan Parker", activeSubscriptionCount: 1, createdAt: "2025-11-14T03:25:02.885Z", externalAccounts: [], subscriptions: [ { id: "sub_4t2fz8a57hje7fjazkrc08jg5n", startedAt: "2025-10-23T11:11:40.100Z", status: "active", products: [ { id: "prp_4t2fz8a57hje7fjazkrc08jg5n", code: "glitch_video_std", version: 1, }, ], }, ], }; ``` ```python response = client.customers.get( customer_id="cust_4qh0wajx2n9qtazh2tghzkyan2", ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_get_get_a_customer.py#L20) **SDK response object** ```python response = { "id": "cust_4qh0wajx2n9qtazh2tghzkyan2", "external_id": "951832085fee4033a2878f841a24149a", "name": "Joan Parker", "active_subscription_count": 1, "created_at": "2025-11-14T03:25:02.885Z", "external_accounts": [], "subscriptions": [ { "id": "sub_4t2fz8a57hje7fjazkrc08jg5n", "started_at": "2025-10-23T11:11:40.100Z", "status": "active", "products": [ { "id": "prp_4t2fz8a57hje7fjazkrc08jg5n", "code": "glitch_video_std", "version": 1, }, ], }, ], } ``` If the customer is not subscribed to your desired product, a new subscription can be added via the Customers API. **2. Verify that the customer is subscribed to a product version that uses the same event\_type** Usage events don't directly reference a product or product version. Instead, billing is resolved based on the `event_type` field in the event payload. [Retrieve the customer's details](https://docs.credyt.ai/api/customers-create.md) to confirm the customer's active subscriptions and which product versions they are subscribed to. Then check the `event_type` configuration of the subscribed product versions. If no active subscription matches the event's `event_type`, the event won't be billed. **3. Check that the usage event matches the product configuration** Billing depends on event fields aligning with the product's usage configuration. To help troubleshoot, you can [retrieve a list of usage events](https://docs.credyt.ai/api/events-list.md) and provide the `customer_id` query parameter. For detailed information about each event, including the applicable fees and the product configuration it was matched against, [retrieve the specific event's details](https://docs.credyt.ai/api/events-get.md). Make sure: * The event's `event_type` matches what's defined in the product version. * The `customer_id` belongs to a customer with a valid subscription. * For volume-based pricing, confirm that your `usage_calculation` setup matches: * `usage_type` * `volume_field` * `billable_dimension` (if applicable) * Each event must include a unique `id` — duplicate event IDs are ignored to prevent double billing. tip Use the [Simulate Usage](https://docs.credyt.ai/api/products-simulate-usage.md) endpoint to test your pricing configuration in isolation. It accepts draft product versions and doesn't require a `customer_id`, making it ideal for testing your setup and troubleshooting configuration issues step by step. ##### The customer balance is negative[​](#the-customer-balance-is-negative "Direct link to The customer balance is negative") A negative balance is an expected condition in Credyt. Credyt allows balances to go negative to ensure that ongoing or multi-step tasks aren't interrupted when end customer's funds are depleted mid-process. This approach prevents failed operations due to minor balance delays and provides a smoother end-user experience. You can check customer's balance at any time with `GET /customers/:customerId/wallet` Based on the balance information, you can decide whether to pause access to your product or prompt the customer to top up their wallet. Once the customer tops up their account, Credyt will automatically correct the negative balance by deducting the owed amount from the next deposit. ##### The customer does not have any balances/accounts[​](#the-customer-does-not-have-any-balancesaccounts "Direct link to The customer does not have any balances/accounts") Customer wallets are created automatically when the customer is subscribed to a product or when a top-up is initiated. To ensure wallets are correctly set up, it's important that customers are subscribed to the relevant products when they are created - this helps avoid any misconfigurations. ##### Billing Portal link has expired[​](#billing-portal-link-has-expired "Direct link to Billing Portal link has expired") When a Billing Portal link expires, Credyt automatically redirects the customer to the `return_url` you provided when generating the link. To keep the experience seamless, you can: 1. Listen for this redirect event at your `return_url`. 2. Automatically request a new Billing Portal link from Credyt using your backend logic. 3. Redirect the customer back to the refreshed link without manual intervention. This ensures that customers always have uninterrupted access to their Billing Portal, even when older links expire. ##### Stripe Tax is not calculated at Checkout[​](#stripe-tax-is-not-calculated-at-checkout "Direct link to Stripe Tax is not calculated at Checkout") If you don't see Stripe Tax applied during checkout, it's usually because Stripe Tax needs to be explicitly activated on the connected Stripe account used for processing payments. Additionally, for tax calculation to work correctly, the customer's country of residence submitted during checkout must be configured for tax collection in Stripe Tax. When testing with Credyt's built-in Stripe account, setting the customer's country to the **United Kingdom (UK)** allows you to observe how tax behaves during checkout and in the top-up history. If you'd like to connect and test with your own Stripe test account, please reach out to us at for assistance. --- ## Features ### Assets AI platforms may price their services in different ways. Some charge directly in fiat currencies; others rely on pre-funded credits and many introduce custom usage units (what we refer to as "Assets") like tokens, GPU hours, or video minutes, to align usage with product outcomes. info This guide talks about configuration of custom assets such as tokens.
If your pricing model is entirely fiat based, you may skip this section. In Credyt, Assets are custom usage units such as tokens, minutes or requests. Think of them like bespoke currencies that are aligned with your product outcomes. They are distinct from fiat currencies and enable platforms bill for usage in a way that is clear, flexible, and transparent for customers. Customers purchase assets with fiat at an exchange rate defined by the platform, enabling straightforward pricing and reporting. #### Defining and managing Assets[​](#defining-and-managing-assets "Direct link to Defining and managing Assets") [API Reference](https://docs.credyt.ai/api/assets-create.md) Platforms can create and manage any custom asset they wish to offer. Each asset can have exchange rates defined for each fiat funding currency, giving platforms full control over how much a customer pays per unit of asset. * Platforms can update exchange rates at any time * Changes can be scheduled to take effect at a specific future time, ensuring predictable pricing * The exchange rate can optionally be overridden for [platform-initiated top-ups](https://docs.credyt.ai/features/wallets-and-topups.md) Assets help to promote a transparent and user-friendly experience. Each asset has a unique code, a customer-facing name, a label for UI display, and an optional symbol. These elements exist to: * Ensure customers can clearly identify the asset they are purchasing * Provide consistent representation across the platform and Billing Portal ##### Example[​](#example "Direct link to Example") Let's create a Glitch Video Credit for your AI platform. We'll price the Credit at $0.10 or inversely, $1.00 buys 10 Credits. When creating an asset, you can specify either the: * `rate` in the source currency - in this example `0.10 USD` * `inverse_rate` in your custom asset - in this case `10`, since each $1.00 buys 10 credits - 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", } ``` We can view the details of this asset at any time via the [Assets API](https://docs.credyt.ai/api/assets-get.md): * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/assets/VIDGENMIN ```http ``` **Response** ```json { "code": "VIDGENMIN", "name": "Video Generation Minutes", "precision": 2, "label": "MIN", "symbol": "⏰", "rates": [ { "source": "USD", "schedule": [ { "valid_from": "2026-02-06T10:01:29.686322Z", "rate": 0.1, "inverse_rate": 10 } ] } ], "created_at": "2026-02-06T10:01:29.686322Z" } ``` ```typescript await client.assets.get("VIDGENMIN"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/assetsGetSample.ts#L11) **SDK response object** ```typescript const response = { code: "VIDGENMIN", name: "Video Generation Minutes", precision: 2, label: "MIN", symbol: "⏰", rates: [ { source: "USD", schedule: [ { validFrom: "2026-02-06T10:01:29.686322Z", rate: 0.1, inverseRate: 10, }, ], }, ], createdAt: "2026-02-06T10:01:29.686322Z", }; ``` ```python response = client.assets.get( asset_code="VIDGENMIN", ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/assets_get_get_a_video_generation_minutes_asset.py#L20) **SDK response object** ```python response = { "code": "VIDGENMIN", "name": "Video Generation Minutes", "precision": 2, "label": "MIN", "symbol": "⏰", "rates": [ { "source": "USD", "schedule": [ { "valid_from": "2026-02-06T10:01:29.686322Z", "rate": 0.1, "inverse_rate": 10, }, ], }, ], "created_at": "2026-02-06T10:01:29.686322Z", } ``` #### Get a Quote[​](#get-a-quote "Direct link to Get a Quote") [API Reference](https://docs.credyt.ai/api/assets-quote.md) Once you've defined an asset you can use the quote capability to calculate and display how much of a custom asset a customer will receive when topping up (if they're topping up via the [Billing Portal](https://docs.credyt.ai/features/billing-portal.md), this will be done automatically). To obtain a quote specify the source fiat currency and the amount to convert, and optionally a point in time (`exchange_at`) to support historical or scheduled conversions. It returns the exchange rate applied and the resulting amount of the asset. ##### Example[​](#example-1 "Direct link to Example") This quote calculates how many Glitch Video Credits a customer would receive for 10 USD. The `destination_rate` of 10 means each $1.00 USD buys 10 credits, resulting in a total of 100 credits. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/assets/VIDGENMIN/quote ```json { "source": "USD", "amount": 10 } ``` **Response** ```json { "source": "USD", "source_amount": 10, "destination": "VIDGENMIN", "destination_amount": 100, "rate": 0.1, "inverse_rate": 10 } ``` ```typescript await client.assets.quote("VIDGENMIN", { source: "USD", amount: 10, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/assetsQuoteSample.ts#L11) **SDK response object** ```typescript const response = { source: "USD", sourceAmount: 10, destination: "VIDGENMIN", destinationAmount: 100, rate: 0.1, inverseRate: 10, }; ``` ```python response = client.assets.quote( asset_code="VIDGENMIN", body={ "source": "USD", "amount": 10, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/assets_quote_quote_video_generation_minutes.py#L20) **SDK response object** ```python response = { "source": "USD", "source_amount": 10, "destination": "VIDGENMIN", "destination_amount": 100, "rate": 0.1, "inverse_rate": 10, } ``` #### Changing asset rates[​](#changing-asset-rates "Direct link to Changing asset rates") If the platform updates the exchange rate and schedules it to take effect the next day, all new purchases will automatically use the new rate, ensuring that billing remains consistent and predictable. --- ### Auto Top-up Auto top-up is Credyt’s mechanism for keeping prepaid balances funded automatically, so usage-based products can run without interruption. It enables your customers to define simple rules that trigger a top-up whenever their balance drops below a certain threshold. Instead of relying on manual action at the exact moment a balance runs out, auto top-up ensures continuity for long-running or unpredictable workloads. This feature is essential for platforms that bill in real time, where usage can fluctuate rapidly, and a depleted balance could interrupt an in-progress task, degrade the user experience, or lead to unexpected churn. #### How auto top-up works in Credyt[​](#how-auto-top-up-works-in-credyt "Direct link to How auto top-up works in Credyt") Auto top-up is configured by your customers directly in the [Billing Portal](https://docs.credyt.ai/features/billing-portal.md) and applied **per asset** (e.g., USD, credits, tokens, or minutes). In its current form, auto top-up is available to platforms using Credyt’s built-in payment processing, powered by Stripe’s payments infrastructure. For each asset, a customer can: * Enable or disable auto top-up * Choose a saved payment card or add a new one * Define a balance threshold * Define a top-up amount When the balance for a given asset drops below the configured threshold, Credyt automatically initiates an off-session payment via Stripe and credits the wallet once the payment succeeds. This happens without interrupting the customer’s workflow and without requiring any manual action when the balance runs low. ![Alt text for accessibility](/assets/images/autotopup_modal-81f0955f54da2cf585c9dff9512d30d9.png "Account balance view") #### Per-asset configuration[​](#per-asset-configuration "Direct link to Per-asset configuration") Auto top-up is asset-specific by design. Each wallet asset has its own independent auto top-up configuration. This allows customers to treat different balances independently, which is especially useful for products that combine multiple billing models or usage units. All saved payment cards belong to the customer account and are available across all asset configurations. ![Alt text for accessibility](/assets/images/balances_autotopup-83c24b993d68bc2d46d3244dec42a34c.png "Account balance view") #### Card management and authorisation[​](#card-management-and-authorisation "Direct link to Card management and authorisation") Auto top-up relies on payment cards explicitly authorized by the end customer for future use. Card authorisation can happen in two ways: * When a customer adds a new card through the Billing Portal * When a customer completes a manual top-up and consents to saving the card for future use All card authorization flows, including any required authentication steps, are handled through Stripe’s secure payment infrastructure. The selection or change of the payment card used for auto top-up is performed exclusively by the end customer within the Billing Portal. Platforms redirect customers to the portal but do not directly control card selection. --- ### Billing Portal The Credyt Customer Billing Portal enables you to offer your customers a comprehensive billing experience with complete visibility into their balances, usage and top-up history. From here they can top up their accounts directly and manage their billing settings. ##### Key features[​](#key-features "Direct link to Key features") * Real-time balance updates in both fiat and custom assets (tokens, minutes, etc.) * Transparent reporting on usage and spend, helping customers plan ahead * Both manual and automated top-ups to prevent service interruptions * Self-service with no sign-up required for your customers * Fully hosted by Credyt — no need to build complex payment flows or dashboards yourself * Customizable with your own branding and product URLs #### Integration[​](#integration "Direct link to Integration") To open the billing portal for a particular customer you use the Credyt API to generate a pre-authenticated billing portal session link that you redirect the customer to. No additional UI or payment flow needs to be built on your side. See our [quickstart](https://docs.credyt.ai/quickstart/billing-portal.md) for how to generate a billing portal session. #### Billing Portal UX[​](#billing-portal-ux "Direct link to Billing Portal UX") Below we break down the different sections of the billing portal. ##### Wallet Balances[​](#wallet-balances "Direct link to Wallet Balances") * Shows the customer’s wallet account balances across both fiat and custom assets * Displays total amount spent this month for easy tracking * Always kept up to date with usage events and top-ups ![Alt text for accessibility](/assets/images/balance-5895db2e9be4ca5952db496a9776f0f4.png "Account balance view") ##### Topup and auto topup[​](#topup-and-auto-topup "Direct link to Topup and auto topup") * Manual top-up allows customers to add funds whenever they need. * Auto top-up automatically refills the wallet when balance falls below a set threshold, preventing service interruptions. * Applicable only if the platform uses Credyt’s payment rails via Stripe. * Ensures smooth operations and reduces friction in customer payments. ##### Spend history[​](#spend-history "Direct link to Spend history") * Charts show spend trends over time, in both fiat and custom units. * Helps customers understand spending patterns and plan for future usage. ![Alt text for accessibility](/assets/images/recent_spend-bc8a94dfd6a3de1ee41c02d868b3f9e6.png "Spend trend chart") ##### Usage history[​](#usage-history "Direct link to Usage history") * Each usage record shows the product name, the subject sent by the platform (e.g., the specific task or action performed), and a tooltip with the event description. * The fee description from the product configuration is also displayed, offering full transparency into how each event was billed. * This added context helps customers understand exactly what each usage item represents and how it relates to what they did in the AI product. ![Alt text for accessibility](/assets/images/recent_usage-462c5501530244081ed29cf4ee22e65d.png "Usage by product and event") ##### Transactions[​](#transactions "Direct link to Transactions") A complete, consolidated record of all credit and debit events affecting a customer’s balance, including top-ups, fees, refunds, gifts, and adjustments. * Displays all relevant balance movements in one place for easy tracking and auditing. * Covers a broad range of transaction types, including Stripe top-ups, external adjustments, refunds, usage and ad-hoc fees, and promotional credits. * Includes filtering options by month, asset, and transaction category for efficient navigation of transaction history. ![Alt text for accessibility](/assets/images/transactions-32b786c0dead855898c5f679a7aac071.png "Transactions table") --- ### Credit grants #### Introduction[​](#introduction "Direct link to Introduction") Prepaid balances are commonly used to track and bill usage. However, a single undifferentiated prepaid balance is often insufficient to support operational needs such as revenue recognition, expiry enforcement, tax calculation at redemption, promotional credits, and plan-specific incentives. These requirements call for more granular tracking and management of prepaid value. Credit grants provide this structure. A credit grant represents a discrete allocation of prepaid value with its own lifecycle, purpose, and financial attributes. Instead of treating a wallet account as one undifferentiated pool of funds, Credyt models it as a sequence of grants - each independently issued, consumed and monitored with its own distinct lifetime. This approach enables prepaid usage billing to operate correctly across billing, accounting, and compliance. #### A core primitive of real-time usage billing[​](#a-core-primitive-of-real-time-usage-billing "Direct link to A core primitive of real-time usage billing") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-credit-grants.md) Credit grants are the fundamental units of a prepaid balance and lie at the core of Credyt’s real-time, usage-based billing model. Each grant defines: * Its effective and expiry dates * The amount of value it holds * How it should be treated for billing, revenue, and compliance purposes ##### Issuing credit grants[​](#issuing-credit-grants "Direct link to Issuing credit grants") Credit grants enter a wallet through a small number of well-defined entry points. Each entry point determines the purpose of the grant and how its expiry is set - two attributes that are then exposed directly via the [Get credit grants](https://docs.credyt.ai/api/customer-wallet-ops-get-credit-grants.md) endpoint. When a customer initiates a top-up, and the payment is successfully processed, Credyt automatically creates a credit grant with the purpose set to `paid`. Paid credit grants have a default expiry of one year, ensuring that prepaid value is time-bound while remaining predictable for both the platform and the end user. Credit grants can also be created through wallet adjustments and may be used for promotional credits or for credits included in bundled packages or entitlements. In these cases, Credyt derives the purpose and expiry of the grant from the adjustment itself. The `reason` and `expires_at` parameters submitted via the [Wallet adjustments](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) API determine how the grant is classified and how long it remains valid. Credit grants do not have to become available immediately - the platform can define when they become effective using the `effective_from` parameter in the [Top-ups](https://docs.credyt.ai/api/top-ups-initiate.md) and [Wallet adjustments](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) APIs. Top-ups initiated directly from the Billing Portal become effective immediately by default. By standardizing how grants are issued, Credyt ensures that every credit grant has a clear origin, a defined purpose, and an explicit lifetime, all of which are visible and auditable at the grant level. ##### Consumption at grant level[​](#consumption-at-grant-level "Direct link to Consumption at grant level") An account’s balance is the sum of its active grants. Usage draws down from these grants following platform-defined rules, such as prioritizing included or promotional credits before paid ones, or consuming the earliest-expiring grants first. Because consumption deducts from grants as it occurs: * Revenue can be recognized at the time of consumption * Exchange rates/cost basis for custom units can be locked at purchase * Expiry and breakage are handled appropriately at the grant level * Taxes can be applied accurately using relevant jurisdiction and service metadata ##### Handling credit expiry[​](#handling-credit-expiry "Direct link to Handling credit expiry") When a credit grant expires, it is flagged as inactive and no longer available for usage. This triggers a set of processes to ensure accurate billing, accounting, and auditability: * Revenue recognition - any remaining deferred revenue linked to the expired credit grant is recognized as actual revenue. This moves the value from deferred revenue to recognized revenue in the underlying ledger. * Usage drawdown - expired credit grants are excluded from the available balances. Subsequent usage will draw from the next active credit grants according to platform-defined consumption rules. * Auditability - even after expiry, the credit grant record remains available for auditing purposes. These records can be retrieved through the [Get credit grants](https://docs.credyt.ai/api/customer-wallet-ops-get-credit-grants.md) endpoint, providing full visibility into grant history and status. * Grace Periods - Credyt implements a grace period for credit expiry, delaying the effective expiration by several hours. This delay accommodates late event submissions and synchronization issues, ensuring usage events are processed accurately without premature expiry. ##### Revenue recognition at consumption[​](#revenue-recognition-at-consumption "Direct link to Revenue recognition at consumption") Revenue in Credyt is recognized when credits are consumed or expire, not when they are purchased. When a customer tops up, the value is recorded as deferred revenue and only becomes recognized revenue as usage draws down from the associated credit grants. Each credit grant retains the transaction price and, where applicable, the exchange rate (cost basis) from the time of purchase. This ensures that, as usage is billed, whether in fiat or custom units, revenue can be calculated accurately in fiat and posted correctly to the general ledger, even if exchange rates change between top-up and consumption. By tying revenue recognition directly to grant-level consumption, Credyt avoids the accounting ambiguity that arises from flat prepaid balances and maintains precise, auditable revenue reporting. ##### Example[​](#example "Direct link to Example") * 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", ) ``` --- ### Customers [API Reference](https://docs.credyt.ai/api/customers-create.md) Before you can bill your customers, you need to register them in Credyt and subscribe them to the products they use. We require only the data necessary for you to identify your customers and perform core billing activities. Your own unique reference or ID (the customer `external_id`) can be provided and later used when submitting usage, avoiding the need to maintain ID mappings in your systems. If you use Credyt’s built-in payment processing, the external ID is included as metadata in Stripe, aiding payment operations. #### Subscribe a Customer to a Product[​](#subscribe-a-customer-to-a-product "Direct link to Subscribe a Customer to a Product") To streamline integration, subscriptions can be provided at the same as creating the customer. A customer can be subscribed to multiple products, which are identified by their respective product code and version. This determines the pricing that will be applied when usage is billed. For convenience, if you omit a product's version we'll use the current "default" version. You can also use the `default` identifier when working with the Product Catalog API. When a customer is subscribed to a product, Credyt automatically provisions wallet accounts in the currencies defined by the product’s pricing configuration. These accounts are used to track balances, top-ups, and usage from the start of the subscription. Unmatched Usage Make sure to subscribe a customer to all of the products they use. Unmatched usage events will be accepted but will not be billed. For more details on creating and managing products, see [Products and Pricing](https://docs.credyt.ai/features/product-catalog.md). ##### Example[​](#example "Direct link to Example") * 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", }, ], }, ], } ``` --- ### Products and Pricing The product catalog is a central concept in Credyt. It defines the products your platform offers and informs how the billing engine processes and charges for usage. Each product includes a pricing configuration, which determines how usage is measured and charged. A product has a unique code and an associated rate plan specifying pricing, metering, and billing units. Products are versioned automatically so you roll out changes to pricing safely without impacting existing customers. #### Create a Product[​](#create-a-product "Direct link to Create a Product") [API Reference](https://docs.credyt.ai/api/products-create.md) The Create a Product endpoint lets your platform define new products and their default pricing configuration (rate plan). A product represents what your customers consume, for example, a service, action, or unit of resource, and how they are billed for it. Each product requires a: * Customer-facing name * A unique code used to identifying it creating [Customer Subscriptions](https://docs.credyt.ai/features/customers.md) * One or more prices You can define multiple prices to cater for all the billable aspects of your products. Each price has a usage calculation that determined how matching usage events should be measured and processed. ##### Example[​](#example "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/products ```json { "name": "Glitch Video", "code": "glitch_video_std", "prices": [ { "name": "Video Promotion", "type": "usage_based", "billing_model": { "type": "real_time" }, "usage_calculation": { "event_type": "video_promoted", "usage_type": "unit", "source_reference_field": "video_id" }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 0.5 } ] } ] } ], "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 Promotion", type: "usage_based", billingModel: { type: "real_time", }, usageCalculation: { eventType: "video_promoted", usageType: "unit", sourceReferenceField: "video_id", }, pricing: [ { asset: "USD", values: [ { unitPrice: 0.5, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L227) **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 Promotion", "type": "usage_based", "billing_model": { "type": "real_time", }, "usage_calculation": { "event_type": "video_promoted", "usage_type": "unit", "source_reference_field": "video_id", }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 0.5, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_usage_based_price.py#L20) **SDK response object** ```python response = { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": 1, "status": "published", "is_default": True, } ``` #### Usage Calculation[​](#usage-calculation "Direct link to Usage Calculation") The usage calculation configuration determines how Credyt interprets incoming usage events. It supports several calculation modes providing flexibility for different pricing models: * **`unit`** – charges per occurrence of the event (e.g., per chat, per verification, per API call). * **`volume`** – charges based on the volume or quantity consumed, included in the event payload (e.g., tokens, minutes, megabytes). * **`unit_and_volume`** – combines both approaches In addition to a [usage event `subject`](https://docs.credyt.ai/api/events-send-usage.md), the usage calculation configuration can specify a `source_reference_field`, the name of a field in your event payload that helps correlate the generated usage fee with the customer activity, for example `video_generation_id`. ##### How usage events are billed[​](#how-usage-events-are-billed "Direct link to How usage events are billed") Product usage is billed by matching the `event_type` of incoming events to a price's `usage_calculation` configuration. If no matching configuration exists, the usage will be recorded, but not billed for. This ensures that each event is billed according to the correct pricing logic and allows multiple event types to coexist within a single product or across different products. ###### Pricing Example[​](#pricing-example "Direct link to Pricing Example") | Product | Event Type | Usage Mode | Source Reference Field | Description | | ------------ | ------------------ | ----------------- | ---------------------- | ---------------------------------------- | | Glitch Video | video\_promoted | unit | video\_id | Charges per promoted video | | Glitch Video | video\_minutes | volume | video\_id | Charges based on total minutes processed | | Glitch Text | message\_completed | unit\_and\_volume | chat\_id | Charges per chat + tokens used in chat | In this example: * A usage event with `event_type: video_promoted` will trigger the first unit-based price * A usage event with `event_type: video_minutes` will trigger the second price and bill based on the volume of minutes * A usage event with `event_type: message_completed` will trigger the third price, combining both approaches (unit + volume) #### Pricing[​](#pricing "Direct link to Pricing") The `pricing` configuration of a price defines the actual rates your customers pay for usage. Each product price can have pricing defined in multiple currencies or [custom assets](https://docs.credyt.ai/features/assets.md), for example, a fiat currency like `USD` or a custom asset like as `TOK` (tokens) or `MIN` (minutes). The asset value defines: * **unit price** — the base rate per unit of usage (for unit-based models). * **volume rate** — the rate per aggregated volume unit (for volume-based models). * **min\_amount / max\_amount** — optional limits that cap or floor how much can be charged per event. This flexible structure allows you to model a wide range of usage-based pricing approaches, from simple per-event fees to complex, volume-based charging logic. #### Publishing and Versioning[​](#publishing-and-versioning "Direct link to Publishing and Versioning") [API Reference](https://docs.credyt.ai/api/products-create-version.md) By default, products are created in draft mode, allowing you to review or update the configuration before publishing. You can also validate the configuration by [simulating usage](https://docs.credyt.ai/api/products-simulate-usage.md), which lets you run events through the billing engine and view the generated fees without registering them in the system. When you need to update the pricing of an existing product, use the Update Product endpoint. Credyt automatically creates a new draft version of the product with your updated pricing details. You can choose to publish the version immediately (note that published versions are non-editable) or keep it in draft, test it by sending usage events, and then publish it — and make it the default version — using the Update a Product Version endpoint. Once published, a product becomes version-locked, ensuring billing consistency for customers already subscribed to it. Any future pricing or logic changes are introduced as new product versions, preserving historical accuracy. You can also archive a product or a product version. Deleting a product makes it unavailable for new subscriptions. If the product has already been used, it will be archived to preserve history; however, any new usage events for this product will not be accepted. Archiving a product version makes it unavailable for new subscriptions, but it remains active for customers already subscribed to it, and usage events will continue to be accepted. --- ### Dimensional Pricing [API Reference](https://docs.credyt.ai/api/products-create.md) Dimensional Pricing allows pricing to adapt based on custom attributes (billable dimensions) of a usage event; such as speed, quality, or model type. Instead of creating separate prices for each dimension value, you define a single price and assign values for each variation of your billable dimensions. This reduces your setup and maintenance effort and ensures pricing consistency across dimensions. You can use `*` as the value to specify fallback pricing for your product. In the following example we charge a different price based on the `speed` of the video generation task. This field is included in the usage events sent to Credyt. Here we charge $1.00/minute for "fast" workloads and $0.40/minute for "regular" speed workloads. A fallback of $0.40/minute is specified if an unknown speed is sent through. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/products ```json { "name": "Glitch Video Advanced", "code": "glitch_video_adv", "prices": [ { "name": "Video Generation Compute", "type": "usage_based", "billing_model": { "type": "real_time" }, "usage_calculation": { "event_type": "video_generated", "usage_type": "unit_and_volume", "volume_field": "minutes", "source_reference_field": "video_id", "billable_dimensions": [ "speed" ] }, "pricing": [ { "asset": "USD", "values": [ { "name": "Video Generation Minutes (Fast)", "dimensions": { "speed": "fast" }, "values": [ { "volume_rate": 1 } ] }, { "name": "Video Generation Minutes (Regular)", "dimensions": { "speed": "regular" }, "values": [ { "volume_rate": 0.4 } ] }, { "name": "Video Generation Minutes (Default)", "dimensions": { "speed": "*" }, "values": [ { "volume_rate": 0.4 } ] } ] } ] } ], "publish": true } ``` **Response** ```json { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_adv", "version": 1, "status": "published", "is_default": true } ``` ```typescript await client.products.create({ name: "Glitch Video Advanced", code: "glitch_video_adv", prices: [ { name: "Video Generation Compute", type: "usage_based", billingModel: { type: "real_time", }, usageCalculation: { eventType: "video_generated", usageType: "unit_and_volume", volumeField: "minutes", sourceReferenceField: "video_id", billableDimensions: [ "speed", ], }, pricing: [ { asset: "USD", values: [ { name: "Video Generation Minutes (Fast)", dimensions: { speed: "fast", }, values: [ { volumeRate: 1, }, ], }, { name: "Video Generation Minutes (Regular)", dimensions: { speed: "regular", }, values: [ { volumeRate: 0.4, }, ], }, { name: "Video Generation Minutes (Default)", dimensions: { speed: "*", }, values: [ { volumeRate: 0.4, }, ], }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L11) **SDK response object** ```typescript const response = { id: "prp_4e28n8kk41931f5yt5em49ecw7", code: "glitch_video_adv", version: 1, status: "published", isDefault: true, }; ``` ```python response = client.products.create( body={ "name": "Glitch Video Advanced", "code": "glitch_video_adv", "prices": [ { "name": "Video Generation Compute", "type": "usage_based", "billing_model": { "type": "real_time", }, "usage_calculation": { "event_type": "video_generated", "usage_type": "unit_and_volume", "volume_field": "minutes", "source_reference_field": "video_id", "billable_dimensions": [ "speed", ], }, "pricing": [ { "asset": "USD", "values": [ { "name": "Video Generation Minutes (Fast)", "dimensions": { "speed": "fast", }, "values": [ { "volume_rate": 1, }, ], }, { "name": "Video Generation Minutes (Regular)", "dimensions": { "speed": "regular", }, "values": [ { "volume_rate": 0.4, }, ], }, { "name": "Video Generation Minutes (Default)", "dimensions": { "speed": "*", }, "values": [ { "volume_rate": 0.4, }, ], }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_dimensional_usage_based_price.py#L20) **SDK response object** ```python response = { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_adv", "version": 1, "status": "published", "is_default": True, } ``` When sending usage for a customer subscribed to the above product, the price will be matched based on the `event_type` and billing dimensions included in the `data` object of the incoming usage event. In the following example, the price for "Video Generation Minutes (Fast)" would be matched since `data.speed = "fast"`. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_4td6grpw680sgewcaz5p89pf40", "events": [ { "id": "ba15987a-7b68-4a9d-b2e6-eadeff29e657", "event_type": "video_generated", "occurred_at": "2025-11-04T21:53:21.392Z", "subject": "video_defc8524", "description": "Video Generated", "data": { "minutes": 10, "speed": "fast" } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_4td6grpw680sgewcaz5p89pf40", events: [ { id: "ba15987a-7b68-4a9d-b2e6-eadeff29e657", eventType: "video_generated", occurredAt: "2025-11-04T21:53:21.392Z", subject: "video_defc8524", description: "Video Generated", data: { minutes: 10, speed: "fast", }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L35) ```python response = client.events.send_usage( body={ "customer_id": "cust_4td6grpw680sgewcaz5p89pf40", "events": [ { "id": "ba15987a-7b68-4a9d-b2e6-eadeff29e657", "event_type": "video_generated", "occurred_at": "2025-11-04T21:53:21.392Z", "subject": "video_defc8524", "description": "Video Generated", "data": { "minutes": 10, "speed": "fast", }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_video_generated.py#L20) --- ### Hybrid Billing with Entitlements Combine traditional [fixed-fee pricing](https://docs.credyt.ai/features/product-catalog/fixed-fee-pricing.md) with bundled credit entitlements to mix recurring revenue with usage-based overages seamlessly. Hybrid billing lets you charge a monthly subscription fee while granting customers a fixed credit allowance each billing cycle. When customers exceed their included credits, they pay for additional usage at your defined overage rates. This model works for AI products where you want predictable recurring revenue while maintaining the flexibility of usage-based pricing. #### When hybrid billing fits[​](#when-hybrid-billing-fits "Direct link to When hybrid billing fits") Hybrid billing works when: * You want predictable monthly revenue from subscriptions * Customers need a base credit allowance included with their plan * You charge for usage beyond the included allowance * Different plan tiers provide different credit allocations Common examples include SaaS products with tiered plans ($20/month with 1,000 credits included), developer tools with base usage quotas, and AI platforms with plan-based credit allowances. #### How entitlements work[​](#how-entitlements-work "Direct link to How entitlements work") Entitlements are "right-to-use" grants that decouple service access from direct credit purchases. While a commitment represents pre-funded balance intended for consumption, an entitlement represents a bundled allocation granted at the product level. When you subscribe a customer to a product with entitlements, Credyt automatically: 1. Grants the specified credit amount to the customer's wallet 2. Refreshes this allowance according to your defined schedule (daily, monthly, etc.) 3. Tracks consumption against the entitlement balance 4. Charges overage fees when credits are exhausted #### Entitlement types[​](#entitlement-types "Direct link to Entitlement types") Entitlements are categorized by their accounting purpose, which dictates how Credyt handles revenue recognition and cost tracking. ##### Bundled entitlements[​](#bundled-entitlements "Direct link to Bundled entitlements") Credits included as a feature of a fixed-fee plan. The subscription fee is recognized ratably over the billing cycle, while the credit value is generally assigned a revenue basis of $0 (the value is captured by the recurring fee). Example: "$20/month includes 1,000 credits" ##### Promotional entitlements[​](#promotional-entitlements "Direct link to Promotional entitlements") Free credits granted to incentivize signups, login streaks, or referrals. No revenue is recognized. These track a cost basis to record marketing expense when consumed. Example: "$2 free daily credits for new users" #### Creating a hybrid billing product[​](#creating-a-hybrid-billing-product "Direct link to Creating a hybrid billing product") Entitlements can grant credits in either fiat currency or [custom assets](https://docs.credyt.ai/features/assets.md), for example credits, tokens or minutes. To use custom assets, first create the asset and define the buy rate, then create a product that uses the asset. ##### Step 1: Create a custom credit asset[​](#step-1-create-a-custom-credit-asset "Direct link to Step 1: Create a custom credit asset") Before creating your product, define a custom asset for your credits. This asset has a buy rate that determines how much customers pay when purchasing additional credits. In this example, we create a `CREDIT` asset where each credit costs $0.05 (or inversely, $1.00 buys 20 credits). * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/assets ```json { "code": "CREDIT", "name": "Credits", "precision": 0, "symbol": "⭐", "label": "CR", "rates": [ { "source": "USD", "rate": 0.05 } ] } ``` ```typescript await client.assets.create({ code: "CREDIT", name: "Credits", precision: 0, symbol: "⭐", label: "CR", rates: [ { source: "USD", rate: 0.05, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/assetsCreateSample.ts#L11) ```python response = client.assets.create( body={ "code": "CREDIT", "name": "Credits", "precision": 0, "symbol": "⭐", "label": "CR", "rates": [ { "source": "USD", "rate": 0.05, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/assets_create_credit_asset.py#L20) ##### Step 2: Create the product with entitlements[​](#step-2-create-the-product-with-entitlements "Direct link to Step 2: Create the product with entitlements") Now create a product that grants bundled credits and charges for actual usage, for example "AI Image Generations". ###### Example: monthly subscription with bundled credits[​](#example-monthly-subscription-with-bundled-credits "Direct link to Example: monthly subscription with bundled credits") This example creates a Premium Plan that costs $20/month and includes 1,000 credits that refresh monthly. The product charges 10 credits per image generation. When customers run out of bundled credits, they can purchase more at the $0.05 rate defined in the asset. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/products ```json { "name": "Premium Plan", "code": "premium_monthly_01", "entitlements": [ { "name": "Monthly Credit Allowance", "asset": "CREDIT", "amount": 1000, "purpose": "bundled", "lifecycle": { "duration": "month", "refresh": { "strategy": "expire_and_replace" } }, "accounting": { "revenue_basis": 0, "cost_basis": "auto" } } ], "prices": [ { "name": "Monthly Subscription Fee", "type": "fixed", "billing_model": { "type": "recurring", "recurring": { "interval": "month" } }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 20 } ] } ] }, { "name": "Image Generation", "type": "usage_based", "billing_model": { "type": "real_time" }, "usage_calculation": { "event_type": "image_generated", "usage_type": "unit" }, "pricing": [ { "asset": "CREDIT", "values": [ { "unit_price": 10 } ] } ] } ], "publish": true } ``` ```typescript await client.products.create({ name: "Premium Plan", code: "premium_monthly_01", entitlements: [ { name: "Monthly Credit Allowance", asset: "CREDIT", amount: 1000, purpose: "bundled", lifecycle: { duration: "month", refresh: { strategy: "expire_and_replace", }, }, accounting: { revenueBasis: 0, costBasis: "auto", }, }, ], prices: [ { name: "Monthly Subscription Fee", type: "fixed", billingModel: { type: "recurring", recurring: { interval: "month", }, }, pricing: [ { asset: "USD", values: [ { unitPrice: 20, }, ], }, ], }, { name: "Image Generation", type: "usage_based", billingModel: { type: "real_time", }, usageCalculation: { eventType: "image_generated", usageType: "unit", }, pricing: [ { asset: "CREDIT", values: [ { unitPrice: 10, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L186) ```python response = client.products.create( body={ "name": "Premium Plan", "code": "premium_monthly_01", "entitlements": [ { "name": "Monthly Credit Allowance", "asset": "CREDIT", "amount": 1000, "purpose": "bundled", "lifecycle": { "duration": "month", "refresh": { "strategy": "expire_and_replace", }, }, "accounting": { "revenue_basis": 0, "cost_basis": "auto", }, }, ], "prices": [ { "name": "Monthly Subscription Fee", "type": "fixed", "billing_model": { "type": "recurring", "recurring": { "interval": "month", }, }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 20, }, ], }, ], }, { "name": "Image Generation", "type": "usage_based", "billing_model": { "type": "real_time", }, "usage_calculation": { "event_type": "image_generated", "usage_type": "unit", }, "pricing": [ { "asset": "CREDIT", "values": [ { "unit_price": 10, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_premium_plan.py#L20) With this configuration: * Customer pays $20/month for the subscription * Receives 1,000 credits each month * Each image generation costs 10 credits * When credits are exhausted, customer can purchase more at $0.05/credit * Customer can generate 100 images with their included credits ###### Example: free tier with promotional credits[​](#example-free-tier-with-promotional-credits "Direct link to Example: free tier with promotional credits") This example models a Free Plan that costs $0 but includes a recurring daily entitlement of 50 credits. Each image generation costs 5 credits. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/products ```json { "name": "Free Tier Product", "code": "free_tier_01", "entitlements": [ { "name": "Daily Reward", "asset": "CREDIT", "amount": 50, "purpose": "promotion", "lifecycle": { "duration": "day", "refresh": { "strategy": "expire_and_replace" } }, "accounting": { "revenue_basis": 0, "cost_basis": "auto" } } ], "prices": [ { "name": "Image Generation", "type": "usage_based", "billing_model": { "type": "real_time" }, "usage_calculation": { "event_type": "image_generated", "usage_type": "unit" }, "pricing": [ { "asset": "CREDIT", "values": [ { "unit_price": 5 } ] } ] } ], "publish": true } ``` ```typescript await client.products.create({ name: "Free Tier Product", code: "free_tier_01", entitlements: [ { name: "Daily Reward", asset: "CREDIT", amount: 50, purpose: "promotion", lifecycle: { duration: "day", refresh: { strategy: "expire_and_replace", }, }, accounting: { revenueBasis: 0, costBasis: "auto", }, }, ], prices: [ { name: "Image Generation", type: "usage_based", billingModel: { type: "real_time", }, usageCalculation: { eventType: "image_generated", usageType: "unit", }, pricing: [ { asset: "CREDIT", values: [ { unitPrice: 5, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L64) ```python response = client.products.create( body={ "name": "Free Tier Product", "code": "free_tier_01", "entitlements": [ { "name": "Daily Reward", "asset": "CREDIT", "amount": 50, "purpose": "promotion", "lifecycle": { "duration": "day", "refresh": { "strategy": "expire_and_replace", }, }, "accounting": { "revenue_basis": 0, "cost_basis": "auto", }, }, ], "prices": [ { "name": "Image Generation", "type": "usage_based", "billing_model": { "type": "real_time", }, "usage_calculation": { "event_type": "image_generated", "usage_type": "unit", }, "pricing": [ { "asset": "CREDIT", "values": [ { "unit_price": 5, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_free_tier.py#L20) With this configuration: * No monthly fee * Customer receives 50 free credits daily * Each image generation costs 5 credits * Customer can generate 10 images per day with free credits * When credits are exhausted, customer can purchase more at $0.05/credit #### Entitlement configuration[​](#entitlement-configuration "Direct link to Entitlement configuration") | Field | Type | Description | | --------------- | ------- | ----------------------------------------------------------------------------------------- | | `purpose` | Enum | Defines the accounting track: `bundled` or `promotion` | | `revenue_basis` | Decimal | Amount of revenue earned per unit used. Defaults to `0.00` for bundled/promotional grants | | `cost_basis` | Decimal | Internal cost to expense per unit used. Defaults to `auto` to follow the usage price | | `lifecycle` | Object | Defines the refresh lifecycle (e.g. refresh daily and do not rollover unused credits) | | `priority` | Integer | Dictates consumption order. Lower scores are burned first | ##### Refresh strategies[​](#refresh-strategies "Direct link to Refresh strategies") The `lifecycle` object controls how entitlements replenish: * `duration`: How often credits refresh (`day`, `month`, etc.) * `duration_count`: The number of duration units. A value of 2 with a month duration means 2 months. Defaults to 1 if not specified. * `refresh`: Refresh object to define strategy. * `strategy`: What happens to unused credits * `expire_and_replace`: Unused credits expire, new allocation granted * `rollover`: Unused credits carry forward (up to defined limits) #### Consumption and priority rules[​](#consumption-and-priority-rules "Direct link to Consumption and priority rules") By default, Credyt consumes grants in the order they expire (FIFO). However, you can assign a higher `priority` to promotional grants to ensure free credits are exhausted before customers touch bundled or paid balances. ##### Example consumption order[​](#example-consumption-order "Direct link to Example consumption order") 1. Promotional credits (highest priority) 2. Bundled subscription credits 3. Purchased credits or pay-as-you-go This ensures customers use their free promotional credits first, then their included subscription credits, before incurring overage charges. #### Revenue recognition[​](#revenue-recognition "Direct link to Revenue recognition") When a bundled entitlement has a `revenue_basis > 0`, Credyt manages revenue recognition: * **Usage**: Revenue is recognized unit-by-unit as consumed * **Expiry**: Remaining balance at period end moves from contract liability to revenue as breakage For bundled entitlements with `revenue_basis: 0.00`, the subscription fee is recognized ratably over the billing cycle regardless of credit consumption. #### Subscribing customers[​](#subscribing-customers "Direct link to Subscribing customers") Once you've created your hybrid product, subscribe customers by referencing the product code when creating the customer: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers ```json { "name": "John Doe", "external_id": "18991", "email": "j.doe@gmail.com", "subscriptions": [ { "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure", "redirect_to": "portal", "products": [ { "code": "premium_monthly_01" } ] } ] } ``` ```typescript await client.customers.create({ name: "John Doe", externalId: "18991", email: "j.doe@gmail.com", subscriptions: [ { returnUrl: "https://glitch.ai/account", failureUrl: "https://glitch.ai/callbacks/credyt/failure", redirectTo: "portal", products: [ { code: "premium_monthly_01", }, ], }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersCreateSample.ts#L129) ```python response = client.customers.create( body={ "name": "John Doe", "external_id": "18991", "email": "j.doe@gmail.com", "subscriptions": [ { "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure", "redirect_to": "portal", "products": [ { "code": "premium_monthly_01", }, ], }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_create_subscribe_to_premium_plan.py#L20) Return and Failure URLs When adding a customer to a paid recurring subscription product, a link is provided for the customer to enter their card details. You specify both the URL the customer should return to when exiting the portal (`return_url`) and the failure URL (`failure_url`) we will redirect them to if their session expires or there are any issues. You can find more about failure handling [here](https://docs.credyt.ai/features/billing-portal.md). `redirect_to` can be set to `return_url` so the customer is returned to the `return_url` instead of the portal. When the subscription activates, Credyt automatically grants the entitlement credits to the customer's wallet and begins tracking consumption. --- ### Recurring Fixed Fee Pricing With Recurring Fixed Fee Pricing you can charge your customers a fixed rate for access to your products or services on a recurring basis. This is ideal for SaaS products with tiered plans, monthly memberships, or any service with predictable recurring charges. When you subscribe a customer to a product with fixed fee pricing, Credyt automatically handles the billing cycle, invoicing, and payment collection according to the configuration you specify. #### Creating a Monthly Fixed Fee Product[​](#creating-a-monthly-fixed-fee-product "Direct link to Creating a Monthly Fixed Fee Product") [API Reference](https://docs.credyt.ai/api/products-create.md) Before you can subscribe your customers, you need to create products with fixed fee prices. Products are created via the Products API. ##### Example[​](#example "Direct link to Example") In this example we create a new product `glitch_pro` that costs $20.00/month and requires payment upfront. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/products ```json { "name": "Glitch Pro Subscription", "code": "glitch_pro", "prices": [ { "id": "prc_4asvwjbgbypk6d9z3xp95ttrc8", "name": "Monthly Subscription", "type": "fixed", "billing_model": { "type": "recurring", "recurring": { "interval": "month" } }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 20 } ] } ] } ], "publish": true } ``` **Response** ```json { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_pro", "version": 1, "status": "published", "is_default": true } ``` ```typescript await client.products.create({ name: "Glitch Pro Subscription", code: "glitch_pro", prices: [ { id: "prc_4asvwjbgbypk6d9z3xp95ttrc8", name: "Monthly Subscription", type: "fixed", billingModel: { type: "recurring", recurring: { interval: "month", }, }, pricing: [ { asset: "USD", values: [ { unitPrice: 20, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L160) **SDK response object** ```typescript const response = { id: "prp_4e28n8kk41931f5yt5em49ecw7", code: "glitch_pro", version: 1, status: "published", isDefault: true, }; ``` ```python response = client.products.create( body={ "name": "Glitch Pro Subscription", "code": "glitch_pro", "prices": [ { "id": "prc_4asvwjbgbypk6d9z3xp95ttrc8", "name": "Monthly Subscription", "type": "fixed", "billing_model": { "type": "recurring", "recurring": { "interval": "month", }, }, "pricing": [ { "asset": "USD", "values": [ { "unit_price": 20, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_monthly_fixed_fee.py#L20) **SDK response object** ```python response = { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_pro", "version": 1, "status": "published", "is_default": True, } ``` #### Subscribing Customers[​](#subscribing-customers "Direct link to Subscribing Customers") [API Reference](https://docs.credyt.ai/api/customers-create.md) Once you've created your fixed fee product, you can subscribe customers by referencing this product code when creating the customer: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers ```json { "name": "John Doe", "external_id": "18991", "email": "j.doe@gmail.com", "subscriptions": [ { "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure", "products": [ { "code": "glitch_pro" } ] } ] } ``` **Response** ```json { "id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "subscriptions": [ { "id": "sub_411xhg4kqakf3d8ybezbzta558", "status": "action_required", "products": [ { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_pro", "version": "default", "status": "action_required" } ], "required_actions": [ { "type": "payment", "redirect_url": "https://billing.credyt.ai/api/sign-in?token=xyz" } ] } ] } ``` ```typescript await client.customers.create({ name: "John Doe", externalId: "18991", email: "j.doe@gmail.com", subscriptions: [ { returnUrl: "https://glitch.ai/account", failureUrl: "https://glitch.ai/callbacks/credyt/failure", products: [ { code: "glitch_pro", }, ], }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersCreateSample.ts#L88) **SDK response object** ```typescript const response = { id: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", subscriptions: [ { id: "sub_411xhg4kqakf3d8ybezbzta558", status: "action_required", products: [ { id: "prp_4e28n8kk41931f5yt5em49ecw7", code: "glitch_pro", version: "default", status: "action_required", }, ], requiredActions: [ { type: "payment", redirectUrl: "https://billing.credyt.ai/api/sign-in?token=xyz", }, ], }, ], }; ``` ```python response = client.customers.create( body={ "name": "John Doe", "external_id": "18991", "email": "j.doe@gmail.com", "subscriptions": [ { "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure", "products": [ { "code": "glitch_pro", }, ], }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_create_subscribe_to_glitch_pro.py#L20) **SDK response object** ```python response = { "id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "subscriptions": [ { "id": "sub_411xhg4kqakf3d8ybezbzta558", "status": "action_required", "products": [ { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_pro", "version": "default", "status": "action_required", }, ], "required_actions": [ { "type": "payment", "redirect_url": "https://billing.credyt.ai/api/sign-in?token=xyz", }, ], }, ], } ``` Return and Failure URLs When adding a customer to a paid recurring subscription product, a link is provided for the customer to enter their card details. You specify both the URL the customer should return to when exiting the portal (`return_url`) and the failure URL (`failure_url`) we will redirect them to if their session expires or there are any issues. You can find more about failure handling [here](https://docs.credyt.ai/features/billing-portal.md). When a subscription requires further action before it can be activated, such as collecting an initial payment, its status will be set to `action_required` and it will contain one or more actions in the `required_actions` array. When payment is required there will be a required action of `type: payment` with a corresponding `redirect_url` you should redirect your customer to. If the subscription starts in the future, then a required action of `type: payment_method` is returned with a `redirect_url` to collect the customer's card details. This will typically be a link to the [Billing Portal](https://docs.credyt.ai/features/billing-portal.md) where your customer will be prompted to complete payment. #### Webhook Notifications[​](#webhook-notifications "Direct link to Webhook Notifications") To receive a notification when the customer has completed the required actions, subscribe to the `subscription.activated` webhook. --- ### 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 --- ### Usage Based Billing Usage based billing in Credyt operates on a **real-time, prepaid model**. Customers maintain a wallet balance - funded through manual top-ups, automatic recharges, or credit entitlements bundled in a subscription - and each usage event immediately debits that balance as it occurs. Invoicing Credyt does not meter usage and bill in arrears (post-usage invoicing). All usage-based pricing operates on real-time wallet deductions. If your model requires post-period invoicing, see our [Pricing Guide](https://docs.credyt.ai/pricing-guide.md) to evaluate whether Credyt is the right fit. For payment collection, top-up flows, and managing customer wallet balances, see [Wallets and Topups](https://docs.credyt.ai/features/wallets-and-topups.md). #### How It Works[​](#how-it-works "Direct link to How It Works") Every customer in Credyt has a wallet. When a customer is subscribed to a usage-based product, Credyt automatically provisions the wallet accounts required by that product's pricing configuration. As your platform sends usage events, Credyt matches each event to the customer's active subscription, applies the correct pricing logic, and debits the balance in real time. Wallets can hold balances in standard currencies (USD, EUR) or in any custom asset you define — tokens, credits, compute minutes. Both approaches use the same product and event structure; the only difference is what asset the pricing is denominated in. For a detailed look at funding wallets, managing balances, and accepting payments, see [Wallets and Topups](https://docs.credyt.ai/features/wallets-and-topups.md). #### Billing in Fiat and Custom Units[​](#billing-in-fiat-and-custom-units "Direct link to Billing in Fiat and Custom Units") You can price usage in a standard currency or in a custom asset. The choice is made in the product's pricing configuration and determines which wallet account is debited when usage is reported. **Fiat pricing** — Usage is deducted directly in currency terms (e.g. $1.00 per video minute). Transparent and straightforward to reconcile. A good default for developer-facing products where customers expect to see dollar costs. **Custom units** — Usage is deducted in abstract units like tokens, credits, or minutes (e.g. 10 credits per video generated). You define the asset and its exchange rate against fiat; Credyt applies the rate automatically when customers top up. Custom units give you flexibility to abstract away infrastructure costs and create consumer-friendly pricing experiences. A single customer wallet can hold accounts in multiple assets simultaneously. See [Assets](https://docs.credyt.ai/features/assets.md) for more details on asset configuration. #### Usage Calculation Modes[​](#usage-calculation-modes "Direct link to Usage Calculation Modes") The `usage_calculation` configuration on a product price determines how Credyt interprets each incoming event. Three modes are supported: | Mode | How it bills | Typical use cases | | ----------------- | ----------------------------------------------------------------------- | ------------------------------------------------- | | `unit` | Charges a fixed amount per event occurrence | Video promotions, API calls, verifications | | `volume` | Charges based on a numeric quantity included in the event payload | Video minutes generated, tokens, storage | | `unit_and_volume` | Charges both a per-event fee and a quantity-based fee in the same event | Per-message fee + tokens consumed in that message | ##### Unit[​](#unit "Direct link to Unit") A flat fee is applied each time a matching event is received. No quantity field is required in the event payload. ```json "usage_calculation": { "event_type": "video_promoted", "usage_type": "unit", "source_reference_field": "video_id" } ``` ##### Volume[​](#volume "Direct link to Volume") The fee is calculated from a numeric field in the event's `data` object. You specify which field to read using `volume_field`. ```json "usage_calculation": { "event_type": "video_generated", "usage_type": "volume", "volume_field": "minutes", "source_reference_field": "video_id" } ``` The corresponding event payload must include the `volume_field` value in `data`. In this example Credyt reads `minutes` to calculate the fee: ```json { "event_type": "video_generated", "data": { "minutes": 4, "video_id": "vid_9a3c7f1b2e84" } } ``` ##### Unit and Volume[​](#unit-and-volume "Direct link to Unit and Volume") Combines both: a flat per-event fee plus a volume-based fee derived from the payload. Useful for pricing models that have both a call fee and a consumption fee. ```json "usage_calculation": { "event_type": "message_completed", "usage_type": "unit_and_volume", "volume_field": "tokens", "source_reference_field": "chat_id" } ``` The event payload must include the `volume_field` value in `data`. Credyt applies the per-event fee once and the volume fee against `tokens`: ```json { "event_type": "message_completed", "data": { "tokens": 1840, "chat_id": "chat_3e91b7f042ac" } } ``` ##### Dimensional pricing[​](#dimensional-pricing "Direct link to Dimensional pricing") If your rates vary based on attributes of the usage — such as processing speed or output quality — you can define `billable_dimensions` to apply different rates to different variants without creating separate products. For example, charging $1.00/minute for fast video generation and $0.40/minute for standard. See [Dimensional Pricing](https://docs.credyt.ai/features/product-catalog/dimensional-pricing.md) for details. #### Setup Flow[​](#setup-flow "Direct link to Setup Flow") ##### Step 1: Create a usage-based product[​](#step-1-create-a-usage-based-product "Direct link to Step 1: Create a usage-based product") [API Reference](https://docs.credyt.ai/api/products-create.md) Define your product and its pricing configuration. Set `type: usage_based` and `billing_model.type: real_time`. Products are created in draft mode by default. Set `publish: true` to make the product immediately available for subscriptions, or omit it to review and test first. The example below creates a Glitch Video product that charges $1.00 per minute of video generated: * 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", "source_reference_field": "video_id" }, "pricing": [ { "asset": "USD", "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", sourceReferenceField: "video_id", }, pricing: [ { asset: "USD", values: [ { volumeRate: 1, }, ], }, ], }, ], publish: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/productsCreateSample.ts#L99) **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", "source_reference_field": "video_id", }, "pricing": [ { "asset": "USD", "values": [ { "volume_rate": 1, }, ], }, ], }, ], "publish": True, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/products_create_glitch_video.py#L20) **SDK response object** ```python response = { "id": "prp_4e28n8kk41931f5yt5em49ecw7", "code": "glitch_video_std", "version": 1, "status": "published", "is_default": True, } ``` A product can contain multiple prices to cover different billable aspects. For example, Glitch Video could add a second price with `event_type: video_promoted` to charge separately for video promotions, within the same subscription and without requiring customers to subscribe to an additional product. Simulating usage You can validate your product configuration before going live by [simulating usage events](https://docs.credyt.ai/api/products-simulate-usage.md). Simulated events run through the full billing engine and return calculated fees without modifying any wallet balances. See [Simulating Usage](#simulating-usage) below. ##### Step 2: Subscribe your customers[​](#step-2-subscribe-your-customers "Direct link to Step 2: Subscribe your customers") [API Reference](https://docs.credyt.ai/api/customers-create.md) Register the customer in Credyt and subscribe them to your product. You can provide your own identifier using `external_id`, which can then be used in place of Credyt's customer ID when submitting usage events — avoiding the need to maintain ID mappings in your system. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers ```json { "name": "John Doe", "external_id": "18991", "subscriptions": [ { "products": [ { "code": "glitch_video_std" } ] } ] } ``` **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: "John Doe", externalId: "18991", subscriptions: [ { products: [ { code: "glitch_video_std", }, ], }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/customersCreateSample.ts#L112) **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": "John Doe", "external_id": "18991", "subscriptions": [ { "products": [ { "code": "glitch_video_std", }, ], }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/customers_create_subscribe_to_glitch_video.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", }, ], }, ], } ``` When the subscription is created, Credyt automatically provisions the wallet accounts required by the product's pricing — in this case a USD account. No additional setup is needed. Unmatched usage Make sure to subscribe a customer to all products they use. Usage events that arrive before a subscription is active, or that reference a product the customer is not subscribed to, will be accepted but will not be billed or deducted from the wallet. ##### Step 3: Fund the wallet[​](#step-3-fund-the-wallet "Direct link to Step 3: Fund the wallet") [API Reference TopUp](https://docs.credyt.ai/api/top-ups-initiate.md) [API Reference Adjustment](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) Before usage can be billed, the customer's wallet must hold a sufficient balance. Credyt provides a hosted [Billing Portal](https://docs.credyt.ai/features/billing-portal.md) and a Top-up API to accept customer payments via Stripe. You can also reuse your existing billing setup that leverages an external provider. See [Wallets and Topups](https://docs.credyt.ai/features/wallets-and-topups.md) for the full payment and top-up setup. ##### Step 4: Send usage events[​](#step-4-send-usage-events "Direct link to Step 4: Send usage events") [API Reference](https://docs.credyt.ai/api/events-send-usage.md) As your platform processes customer activity, send usage events to Credyt. Events are matched to the customer's subscription by `customer_id` (or `external_id`) and to the correct price by `event_type`. Matched events are processed and the customer's wallet is debited immediately. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_4td6grpw680sgewcaz5p89pf40", "events": [ { "id": "ba15987a-7b68-4a9d-b2e6-eadeff29e657", "event_type": "video_generated", "occurred_at": "2025-11-04T21:53:21.392Z", "subject": "video_defc8524", "description": "Video Generated", "data": { "minutes": 10, "speed": "fast" } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_4td6grpw680sgewcaz5p89pf40", events: [ { id: "ba15987a-7b68-4a9d-b2e6-eadeff29e657", eventType: "video_generated", occurredAt: "2025-11-04T21:53:21.392Z", subject: "video_defc8524", description: "Video Generated", data: { minutes: 10, speed: "fast", }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L35) ```python response = client.events.send_usage( body={ "customer_id": "cust_4td6grpw680sgewcaz5p89pf40", "events": [ { "id": "ba15987a-7b68-4a9d-b2e6-eadeff29e657", "event_type": "video_generated", "occurred_at": "2025-11-04T21:53:21.392Z", "subject": "video_defc8524", "description": "Video Generated", "data": { "minutes": 10, "speed": "fast", }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_video_generated.py#L20) Each event's `id` acts as an idempotency key. If the same event is submitted more than once — due to a retry or network error — Credyt will process it only once, preventing accidental double billing. You can submit multiple events in a single request by adding entries to the `events` array. #### Correlating Usage[​](#correlating-usage "Direct link to Correlating Usage") Including the `subject` field on every event is strongly recommended. It links each billable event to a specific activity in your system — a video, a chat session, a job — and is used by the Billing Portal to present customers with an itemised view of their usage. It also feeds into [Profitability](https://docs.credyt.ai/features/profitability.md) analysis, where you can track both revenue and infrastructure costs against the same activity. For finer-grained traceability at the product level, configure a `source_reference_field` in the product's `usage_calculation`. This maps a field from the event's `data` object (e.g. `video_id` or `chat_id`) to each generated fee, making it easier to reconcile billing records with your own logs. #### Simulating Usage[​](#simulating-usage "Direct link to Simulating Usage") [API Reference](https://docs.credyt.ai/api/products-simulate-usage.md) Before going live, you can simulate usage events against any product version to validate your pricing configuration. Simulated events run through the same billing logic and return the fees that would be generated, without debiting any wallet or registering the usage in the system. This is particularly useful when introducing a new product version or testing a pricing change before publishing it. #### See Also[​](#see-also "Direct link to See Also") * [Wallets and Topups](https://docs.credyt.ai/features/wallets-and-topups.md) — top-up options and wallet management * [Dimensional Pricing](https://docs.credyt.ai/features/product-catalog/dimensional-pricing.md) — variable rates based on usage attributes like processing speed or output quality * [Hybrid Billing with Entitlements](https://docs.credyt.ai/features/product-catalog/entitlements.md) — combining subscriptions with usage-based overages * [Pricing Guide](https://docs.credyt.ai/pricing-guide.md) — choosing the right billing model for your product --- ### Profitability tip Profitability data is available via the [Credyt MCP Server](https://docs.credyt.ai/tools/profitability-analysis-mcp.md) and can be queried directly through your AI assistant. Real-time, usage-based pricing works best if you understand your costs just as well as your revenue. For AI-driven products, costs are often variable, workload-dependent, and incurred at different points in time than revenue. Fixed pricing models break down quickly in this environment, making it difficult to answer a fundamental question: is this product, or this customer, actually profitable? Credyt’s Profitability feature is designed to close that gap. It gives platforms a way to correlate what they earn with what they spend, at the level where it matters most: individual products, workloads, and customers. #### From real-time billing to business insights[​](#from-real-time-billing-to-business-insights "Direct link to From real-time billing to business insights") Credyt’s core infrastructure orchestrates real-time billing. The Profitability layer builds on that foundation to help you answer *how much you should charge,* and whether your pricing truly works. The feature combines: * **Usage events** (already powering billing), and * **Cost data** from underlying vendors and infrastructure With both inputs in one place, platforms can monitor profitability in real time, validate pricing assumptions against actual costs, quickly surface unprofitable customers or workloads, and adjust pricing models before issues compound. #### How it works[​](#how-it-works "Direct link to How it works") The sections below outline the core building blocks of Credyt Profitability and explain how they work together to connect usage, costs, and revenue into a coherent profitability model. ##### Vendors[​](#vendors "Direct link to Vendors") [API Reference](https://docs.credyt.ai/api/vendors-ops-create-vendor.md) Vendors are the external services or infrastructure that power your product - for example, an AI model provider, a compute platform, or a third-party API. Each cost recorded in Credyt is linked to a vendor. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/vendors ```json { "name": "OpenAI", "external_id": "openai" } ``` **Response** ```json { "id": "vnd_4rjb887sb1h4j2m0hdjmh49gdg", "created_at": "2026-02-17T09:42:22.470555Z" } ``` ```typescript await client.vendorsOps.createVendor({ name: "OpenAI", externalId: "openai", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/vendorsVendorsOpsCreateVendorSample.ts#L11) **SDK response object** ```typescript const response = { id: "vnd_4rjb887sb1h4j2m0hdjmh49gdg", createdAt: "2026-02-17T09:42:22.470555Z", }; ``` ```python response = client.vendors_ops.create_vendor( body={ "name": "OpenAI", "external_id": "openai", }, ) ``` **SDK response object** ```python response = { "id": "vnd_4rjb887sb1h4j2m0hdjmh49gdg", "created_at": "2026-02-17T09:42:22.470555Z", } ``` tip You can use your external ID when submitting costs in your events by specifying the `vendor_external_id` field instead of `vendor_id`. ##### Costs[​](#costs "Direct link to Costs") [API Reference](https://docs.credyt.ai/api/events-send-usage.md) The `costs` object is intentionally structured to mirror usage-based fees. A `costs` item can include: * Unit or volume-based cost information * Rates (e.g. cost per token, per minute, per task) * Optional metadata for further analysis This symmetry between fees and costs makes profitability calculations consistent and predictable. ```json "costs": [ { "id": "68116730-e125-408b-8f75-90f1fb9aa7dd", "vendor_id": "vnd_4rcmsv3fagtvha1j05q4fymsmw", "description": "OpenAI Sora", "metadata": { "model": "sora-fast", "resolution": "1080p", "billing_type": "per_minute" }, "units": 0, "unit_price": 0, "input_volume": 0, "volume_rate": 0, "package_size": 0, "amount": 0.16, "currency": "USD" } ] ``` ##### Cost attribution[​](#cost-attribution "Direct link to Cost attribution") [API Reference](https://docs.credyt.ai/api/events-send-usage.md) The power of Credyt Profitability comes from how costs are attached to usage. Costs can be attributed at different levels of granularity: * **Customer-level** - when costs apply broadly to a customer * **Event-level** - when a specific usage event directly incurs cost * **Subject-level** - when costs relate to a task or outcome (e.g. a `ticket_id` or `generation_id`) Subject-level attribution is especially useful for multi-stage or deferred-cost workflows. For example, if costs begin accumulating before a final “charge” event is emitted, they can still be attached to the same subject and factored into the final profitability calculation. It is the platform’s responsibility to submit cost information along with usage data by including costs in the usage events sent to Credyt. This ensures that costs are properly linked to customers, events, or subjects for accurate profitability tracking. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_4zrjbt38gmpb55h95ygp38sp40", "events": [ { "id": "9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", "event_type": "video_generated", "occurred_at": "2026-01-05T14:32:18Z", "subject": "chat_videoId39854734", "description": "Video gen completed", "costs": [ { "id": "68116730-e125-408b-8f75-90f1fb9aa7dd", "vendor_id": "vnd_4rcmsv3fagtvha1j05q4fymsmw", "description": "OpenAI Sora", "metadata": { "model": "sora-fast", "resolution": "1080p", "billing_type": "per_minute" }, "amount": 0.16, "currency": "USD" } ], "data": { "model": "video fast", "speed": "fast", "minutes": 2 } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_4zrjbt38gmpb55h95ygp38sp40", events: [ { id: "9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", eventType: "video_generated", occurredAt: "2026-01-05T14:32:18Z", subject: "chat_videoId39854734", description: "Video gen completed", costs: [ { id: "68116730-e125-408b-8f75-90f1fb9aa7dd", vendorId: "vnd_4rcmsv3fagtvha1j05q4fymsmw", description: "OpenAI Sora", metadata: { model: "sora-fast", resolution: "1080p", billingType: "per_minute", }, amount: 0.16, currency: "USD", }, ], data: { model: "video fast", speed: "fast", minutes: 2, }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L59) ```python response = client.events.send_usage( body={ "customer_id": "cust_4zrjbt38gmpb55h95ygp38sp40", "events": [ { "id": "9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", "event_type": "video_generated", "occurred_at": "2026-01-05T14:32:18Z", "subject": "chat_videoId39854734", "description": "Video gen completed", "costs": [ { "id": "68116730-e125-408b-8f75-90f1fb9aa7dd", "vendor_id": "vnd_4rcmsv3fagtvha1j05q4fymsmw", "description": "OpenAI Sora", "metadata": { "model": "sora-fast", "resolution": "1080p", "billing_type": "per_minute", }, "amount": 0.16, "currency": "USD", }, ], "data": { "model": "video fast", "speed": "fast", "minutes": 2, }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_video_generated_with_costs.py#L20) ##### Profitability[​](#profitability-1 "Direct link to Profitability") [API Reference](https://docs.credyt.ai/api/events-get.md) Once revenue and costs are linked, Credyt can calculate profitability across multiple dimensions: * **Per event** - gross revenue, total cost, net revenue, and margin * **Per customer** - understanding which customers are sustainable * **Per product** - identifying profitable and loss-leading offerings These metrics are exposed through existing retrieval endpoints, starting from the most granular level and rolling up from there. Specifically, the profitability data for individual events is available in the `stats` object returned by both the [Get an event's details](https://docs.credyt.ai/api/events-get.md) and [List events](https://docs.credyt.ai/api/events-list.md) endpoints. * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/events/9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21 ```http ``` **Response** ```json { "id": "9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", "event_type": "video_generated", "occurred_at": "2026-01-05T14:32:18Z", "subject": "chat_videoId39854734", "description": "Video gen completed", "data": { "model": "video fast", "speed": "fast", "minutes": 2 }, "customer_id": "cust_4zrjbt38gmpb55h95ygp38sp40", "created_at": "2026-01-05T14:32:18Z", "fees": [ { "id": "fee_5a1s2xq3ky8z16b1enqybz1qdn", "product_id": "prp_42b28p940qcq31r7amf2729snb", "product_code": "glitch_video_adv_1", "product_version": 1, "price_id": "prc_475p31bj838yec0q2fy66snbcy", "price_name": "Video Generation Compute", "currency": "MIN", "usage_type": "volume", "volume_field": "minutes", "input_volume": 2, "volume_rate": 1, "description": "Video gen completed", "amount": 2 } ], "costs": [ { "id": "68116730-e125-408b-8f75-90f1fb9aa7dd", "vendor_id": "vnd_4rcmsv3fagtvha1j05q4fymsmw", "description": "OpenAI Sora", "metadata": {}, "amount": 0.16, "currency": "USD" } ], "stats": { "gross_revenue": 0.2, "total_costs": 0.16, "net_revenue": 0.04, "margin": 0.2, "currency": "USD" } } ``` ```typescript await client.events.get("9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsGetSample.ts#L11) **SDK response object** ```typescript const response = { id: "9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", eventType: "video_generated", occurredAt: "2026-01-05T14:32:18Z", subject: "chat_videoId39854734", description: "Video gen completed", data: { model: "video fast", speed: "fast", minutes: 2, }, customerId: "cust_4zrjbt38gmpb55h95ygp38sp40", createdAt: "2026-01-05T14:32:18Z", fees: [ { id: "fee_5a1s2xq3ky8z16b1enqybz1qdn", productId: "prp_42b28p940qcq31r7amf2729snb", productCode: "glitch_video_adv_1", productVersion: 1, priceId: "prc_475p31bj838yec0q2fy66snbcy", priceName: "Video Generation Compute", currency: "MIN", usageType: "volume", volumeField: "minutes", inputVolume: 2, volumeRate: 1, description: "Video gen completed", amount: 2, }, ], costs: [ { id: "68116730-e125-408b-8f75-90f1fb9aa7dd", vendorId: "vnd_4rcmsv3fagtvha1j05q4fymsmw", description: "OpenAI Sora", metadata: {}, amount: 0.16, currency: "USD", }, ], stats: { grossRevenue: 0.2, totalCosts: 0.16, netRevenue: 0.04, margin: 0.2, currency: "USD", }, }; ``` ```python response = client.events.get( event_id="9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_get_get_event_with_profitability.py#L20) **SDK response object** ```python response = { "id": "9c2c8e3a-7f6b-4f5e-9c1f-2e6b6a4a9f21", "event_type": "video_generated", "occurred_at": "2026-01-05T14:32:18Z", "subject": "chat_videoId39854734", "description": "Video gen completed", "data": { "model": "video fast", "speed": "fast", "minutes": 2, }, "customer_id": "cust_4zrjbt38gmpb55h95ygp38sp40", "created_at": "2026-01-05T14:32:18Z", "fees": [ { "id": "fee_5a1s2xq3ky8z16b1enqybz1qdn", "product_id": "prp_42b28p940qcq31r7amf2729snb", "product_code": "glitch_video_adv_1", "product_version": 1, "price_id": "prc_475p31bj838yec0q2fy66snbcy", "price_name": "Video Generation Compute", "currency": "MIN", "usage_type": "volume", "volume_field": "minutes", "input_volume": 2, "volume_rate": 1, "description": "Video gen completed", "amount": 2, }, ], "costs": [ { "id": "68116730-e125-408b-8f75-90f1fb9aa7dd", "vendor_id": "vnd_4rcmsv3fagtvha1j05q4fymsmw", "description": "OpenAI Sora", "metadata": {}, "amount": 0.16, "currency": "USD", }, ], "stats": { "gross_revenue": 0.2, "total_costs": 0.16, "net_revenue": 0.04, "margin": 0.2, "currency": "USD", }, } ``` The initial version of Credyt Profitability focuses on foundational primitives rather than complex dashboards. By starting with event-level revenue and cost correlation, platforms gain the raw insight needed to safely experiment with pricing and detect margin erosion early. As the feature evolves, this foundation enables richer analysis without changing how data is captured today. Future iterations will expand on this foundation with: * Broader cost distribution models * Deeper vendor analysis * Subject-level profitability views In its initial form, Credyt Profitability provides platforms with a useful, real-time view into how their product economics are performing. --- ### Tasks AI products rarely bill for a single, isolated action. In practice, a customer's work is a sequence of steps: a script gets drafted, a video gets rendered, subtitles get generated, translations get applied. Each step produces a usage event. Each event has its own cost. Taken individually, these events tell you what happened. Taken together, they tell you whether a deliverable was profitable. Tasks are Credyt's way of holding that whole picture in one place. A task is the collection of all usage events that share the same `subject` for a given customer - automatically assembled and continuously updated as new events arrive. There's no separate resource to create. If you're already including a `subject` field on your usage events, tasks are already forming in the background. #### How tasks work[​](#how-tasks-work "Direct link to How tasks work") [API Reference — List Tasks](https://docs.credyt.ai/api/tasks-list.md) · [API Reference — Get a Task](https://docs.credyt.ai/api/tasks-get.md) The `subject` field on a usage event is a string you define. It's intended to identify the activity your customer is performing - a video job, a chat session, a document workflow, an autonomous agent run. When multiple events share the same customer and subject, Credyt treats them as a single task. A task accumulates: * **All events** in the order they occurred, with their individual fees, costs, and stats * **Aggregated profitability stats** across the full set of events: gross revenue, total costs, net revenue, and margin * **A per-vendor cost breakdown**, showing how much each external service contributed to total costs Tasks are read-only views - they don't require you to open or close anything. As long as events continue arriving with the same `subject`, the task continues to grow. The task identifier is derived directly from the customer and subject: `{customer_id}:{subject}`. When querying the task detail endpoint, URL-encode the identifier before passing it as a path parameter — for example, `cust_47yxefzbfwkxragp01ccce965n%3Avideo_gen_a7c23f91`. #### Tasks and the subject field[​](#tasks-and-the-subject-field "Direct link to Tasks and the subject field") If you haven't used `subject` in your events yet, see the [Usage Events](https://docs.credyt.ai/features/usage.md#correlating-usage) guide. The recommendation is to include a subject for every event, and this matters primarily because of tasks. Subjects work best when they map to an outcome your customer cares about - not an internal process step. For a video generation platform, the subject might be `video_gen_a7c23f91`. For a customer support agent, it might be `ticket_89423`. For a podcast production tool, it might be `episode_s02e11`. The subject should be stable across all the events that together constitute the delivery of that outcome. tip A task spans as many events as it takes to complete the deliverable. If a workflow involves three LLM calls, a rendering job, and a post-processing step, all five events under the same subject form one task. Credyt doesn't impose any limit on the number of events per task. #### Example[​](#example "Direct link to Example") ##### GlitchAI: a video production job[​](#glitchai-a-video-production-job "Direct link to GlitchAI: a video production job") GlitchAI is a video generation platform. When a customer submits a video request, GlitchAI runs a pipeline: a language model generates a script, a video model renders the footage, a transcription model produces subtitles, and a translation service localises the output. Each of these steps produces a usage event. All of them carry the same `subject`, the ID of the video job. Not every event in a task needs to generate a billing fee. GlitchAI charges its customers for three specific outcomes - video generation, subtitle generation, and translation - and only those event types are configured with a matching price in the product catalog. The script generation step produces an event but no fee. GlitchAI treats it as a cost of producing the video, bundled into the overall economics of the job rather than passed through as a separate line item. However, GlitchAI still submits costs for the scripting step. Even when an event carries no fee, the cost data it contains flows into the task's profitability calculation. This is where tasks become particularly powerful for internal analysis: by tracking what each intermediate step actually costs to run - regardless of whether it's billed for - the platform gets a complete picture of its unit economics. If the scripting step starts consuming significantly more tokens than expected, it will appear in the task's cost breakdown, even though customers never see a charge for it. This makes cost-annotated intermediate events a useful signal for detecting loops, unexpected retries, or model behaviour that drifts outside normal parameters. Here's what those events look like as they are submitted: POST * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_47yxefzbfwkxragp01ccce965n", "events": [ { "id": "b1b2c3d4-0001-4000-8000-000000000001", "event_type": "script_generated", "occurred_at": "2026-05-28T11:50:00Z", "subject": "video_gen_a7c23f91", "description": "Script generation completed", "costs": [ { "id": "c1000000-0001-4000-8000-000000000001", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "GPT-4o script generation", "amount": 0.0043, "currency": "USD" } ], "data": { "model": "gpt-4o", "input_tokens": 512, "output_tokens": 1840 } }, { "id": "b1b2c3d4-0002-4000-8000-000000000002", "event_type": "video_generated", "occurred_at": "2026-05-28T11:51:48Z", "subject": "video_gen_a7c23f91", "description": "Video generation completed", "costs": [ { "id": "c1000000-0002-4000-8000-000000000002", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "Sora video generation (fast, 1080p)", "amount": 0.32, "currency": "USD" } ], "data": { "model": "sora-fast", "speed": "fast", "minutes": 2 } }, { "id": "b1b2c3d4-0003-4000-8000-000000000003", "event_type": "subtitles_generated", "occurred_at": "2026-05-28T11:53:12Z", "subject": "video_gen_a7c23f91", "description": "Subtitle generation completed", "costs": [ { "id": "c1000000-0003-4000-8000-000000000003", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "Whisper transcription", "amount": 0.0048, "currency": "USD" } ], "data": { "model": "whisper-1", "audio_minutes": 2 } }, { "id": "b1b2c3d4-0004-4000-8000-000000000004", "event_type": "translation_completed", "occurred_at": "2026-05-28T11:54:51Z", "subject": "video_gen_a7c23f91", "description": "Subtitle translation completed", "costs": [ { "id": "c1000000-0004-4000-8000-000000000004", "vendor_id": "vnd_4r349d2m72m7r2jx68z20tswx2", "description": "DeepL translation", "amount": 0.0052, "currency": "USD" } ], "data": { "characters": 2600 } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_47yxefzbfwkxragp01ccce965n", events: [ { id: "b1b2c3d4-0001-4000-8000-000000000001", eventType: "script_generated", occurredAt: "2026-05-28T11:50:00Z", subject: "video_gen_a7c23f91", description: "Script generation completed", costs: [ { id: "c1000000-0001-4000-8000-000000000001", vendorId: "vnd_4c22r59kkbz0z2cnntdksn7t45", description: "GPT-4o script generation", amount: 0.0043, currency: "USD", }, ], data: { model: "gpt-4o", inputTokens: 512, outputTokens: 1840, }, }, { id: "b1b2c3d4-0002-4000-8000-000000000002", eventType: "video_generated", occurredAt: "2026-05-28T11:51:48Z", subject: "video_gen_a7c23f91", description: "Video generation completed", costs: [ { id: "c1000000-0002-4000-8000-000000000002", vendorId: "vnd_4c22r59kkbz0z2cnntdksn7t45", description: "Sora video generation (fast, 1080p)", amount: 0.32, currency: "USD", }, ], data: { model: "sora-fast", speed: "fast", minutes: 2, }, }, { id: "b1b2c3d4-0003-4000-8000-000000000003", eventType: "subtitles_generated", occurredAt: "2026-05-28T11:53:12Z", subject: "video_gen_a7c23f91", description: "Subtitle generation completed", costs: [ { id: "c1000000-0003-4000-8000-000000000003", vendorId: "vnd_4c22r59kkbz0z2cnntdksn7t45", description: "Whisper transcription", amount: 0.0048, currency: "USD", }, ], data: { model: "whisper-1", audioMinutes: 2, }, }, { id: "b1b2c3d4-0004-4000-8000-000000000004", eventType: "translation_completed", occurredAt: "2026-05-28T11:54:51Z", subject: "video_gen_a7c23f91", description: "Subtitle translation completed", costs: [ { id: "c1000000-0004-4000-8000-000000000004", vendorId: "vnd_4r349d2m72m7r2jx68z20tswx2", description: "DeepL translation", amount: 0.0052, currency: "USD", }, ], data: { characters: 2600, }, }, ], }); ``` ```python response = client.events.send_usage( body={ "customer_id": "cust_47yxefzbfwkxragp01ccce965n", "events": [ { "id": "b1b2c3d4-0001-4000-8000-000000000001", "event_type": "script_generated", "occurred_at": "2026-05-28T11:50:00Z", "subject": "video_gen_a7c23f91", "description": "Script generation completed", "costs": [ { "id": "c1000000-0001-4000-8000-000000000001", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "GPT-4o script generation", "amount": 0.0043, "currency": "USD", }, ], "data": { "model": "gpt-4o", "input_tokens": 512, "output_tokens": 1840, }, }, { "id": "b1b2c3d4-0002-4000-8000-000000000002", "event_type": "video_generated", "occurred_at": "2026-05-28T11:51:48Z", "subject": "video_gen_a7c23f91", "description": "Video generation completed", "costs": [ { "id": "c1000000-0002-4000-8000-000000000002", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "Sora video generation (fast, 1080p)", "amount": 0.32, "currency": "USD", }, ], "data": { "model": "sora-fast", "speed": "fast", "minutes": 2, }, }, { "id": "b1b2c3d4-0003-4000-8000-000000000003", "event_type": "subtitles_generated", "occurred_at": "2026-05-28T11:53:12Z", "subject": "video_gen_a7c23f91", "description": "Subtitle generation completed", "costs": [ { "id": "c1000000-0003-4000-8000-000000000003", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "Whisper transcription", "amount": 0.0048, "currency": "USD", }, ], "data": { "model": "whisper-1", "audio_minutes": 2, }, }, { "id": "b1b2c3d4-0004-4000-8000-000000000004", "event_type": "translation_completed", "occurred_at": "2026-05-28T11:54:51Z", "subject": "video_gen_a7c23f91", "description": "Subtitle translation completed", "costs": [ { "id": "c1000000-0004-4000-8000-000000000004", "vendor_id": "vnd_4r349d2m72m7r2jx68z20tswx2", "description": "DeepL translation", "amount": 0.0052, "currency": "USD", }, ], "data": { "characters": 2600, }, }, ], }, ) ``` All four events carry the same `subject: "video_gen_a7c23f91"`. That's enough for Credyt to treat them as a single task, regardless of how far apart in time they arrive. #### Listing tasks[​](#listing-tasks "Direct link to Listing tasks") [API Reference](https://docs.credyt.ai/api/tasks-list.md) The List Tasks endpoint returns a paged list of tasks, each with its aggregated profitability stats. This is the right starting point when you want to scan across many customers and jobs - for example, identifying tasks with low margins, or reviewing all the video jobs a specific customer has run this month. GET * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/tasks ```http ``` ```typescript await client.tasks.list(); ``` ```python response = client.tasks.list() ``` The list can be sorted by `last_updated_at`, `created_at`, `total_costs`, `gross_revenue`, or `margin`, always in descending order. Sorting by `total_costs` or `margin` is particularly useful for cost audits - it surfaces your most expensive or least profitable jobs immediately. #### Getting a task's details[​](#getting-a-tasks-details "Direct link to Getting a task's details") [API Reference](https://docs.credyt.ai/api/tasks-get.md) The task detail endpoint returns the complete picture for a single task: every event in sequence, the aggregated stats, and a breakdown of costs by vendor. GET * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/tasks/cust\_47yxefzbfwkxragp01ccce965n:video\_gen\_a7c23f91 ```http ``` **Response** ```json { "id": "cust_47yxefzbfwkxragp01ccce965n:video_gen_a7c23f91", "created_at": "2026-05-28T11:50:00Z", "last_updated_at": "2026-05-28T11:54:51Z", "customer": { "id": "cust_47yxefzbfwkxragp01ccce965n", "name": "Alex Rivera", "external_id": "tasks_demo_001" }, "stats": { "gross_revenue": 0.56, "total_costs": 0.3343, "net_revenue": 0.2257, "margin": 0.403, "currency": "USD", "event_count": 4 }, "events": [ { "id": "b1b2c3d4-0001-4000-8000-000000000001", "event_type": "script_generated", "occurred_at": "2026-05-28T11:50:00Z", "subject": "video_gen_a7c23f91", "description": "Script generation completed", "data": { "model": "gpt-4o", "input_tokens": 512, "output_tokens": 1840 }, "customer_id": "cust_47yxefzbfwkxragp01ccce965n", "created_at": "2026-05-28T12:01:34.943077Z", "costs": [ { "id": "c1000000-0001-4000-8000-000000000001", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "GPT-4o script generation", "metadata": {}, "amount": 0.0043, "currency": "USD" } ], "fees": [], "stats": { "gross_revenue": 0, "total_costs": 0.0043, "net_revenue": -0.0043, "margin": -1, "currency": "USD" } } ], "vendors": [ { "id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "name": "OpenAI", "total_costs": 0.3291, "currency": "USD" }, { "id": "vnd_4r349d2m72m7r2jx68z20tswx2", "name": "DeepL", "external_id": "deepl", "total_costs": 0.0052, "currency": "USD" } ] } ``` ```typescript await client.tasks.get("cust_47yxefzbfwkxragp01ccce965n:video_gen_a7c23f91"); ``` **SDK response object** ```typescript const response = { id: "cust_47yxefzbfwkxragp01ccce965n:video_gen_a7c23f91", createdAt: "2026-05-28T11:50:00Z", lastUpdatedAt: "2026-05-28T11:54:51Z", customer: { id: "cust_47yxefzbfwkxragp01ccce965n", name: "Alex Rivera", externalId: "tasks_demo_001", }, stats: { grossRevenue: 0.56, totalCosts: 0.3343, netRevenue: 0.2257, margin: 0.403, currency: "USD", eventCount: 4, }, events: [ { id: "b1b2c3d4-0001-4000-8000-000000000001", eventType: "script_generated", occurredAt: "2026-05-28T11:50:00Z", subject: "video_gen_a7c23f91", description: "Script generation completed", data: { model: "gpt-4o", inputTokens: 512, outputTokens: 1840, }, customerId: "cust_47yxefzbfwkxragp01ccce965n", createdAt: "2026-05-28T12:01:34.943077Z", costs: [ { id: "c1000000-0001-4000-8000-000000000001", vendorId: "vnd_4c22r59kkbz0z2cnntdksn7t45", description: "GPT-4o script generation", metadata: {}, amount: 0.0043, currency: "USD", }, ], fees: [], stats: { grossRevenue: 0, totalCosts: 0.0043, netRevenue: -0.0043, margin: -1, currency: "USD", }, }, ], vendors: [ { id: "vnd_4c22r59kkbz0z2cnntdksn7t45", name: "OpenAI", totalCosts: 0.3291, currency: "USD", }, { id: "vnd_4r349d2m72m7r2jx68z20tswx2", name: "DeepL", externalId: "deepl", totalCosts: 0.0052, currency: "USD", }, ], }; ``` ```python response = client.tasks.get( task_id="cust_47yxefzbfwkxragp01ccce965n:video_gen_a7c23f91", ) ``` **SDK response object** ```python response = { "id": "cust_47yxefzbfwkxragp01ccce965n:video_gen_a7c23f91", "created_at": "2026-05-28T11:50:00Z", "last_updated_at": "2026-05-28T11:54:51Z", "customer": { "id": "cust_47yxefzbfwkxragp01ccce965n", "name": "Alex Rivera", "external_id": "tasks_demo_001", }, "stats": { "gross_revenue": 0.56, "total_costs": 0.3343, "net_revenue": 0.2257, "margin": 0.403, "currency": "USD", "event_count": 4, }, "events": [ { "id": "b1b2c3d4-0001-4000-8000-000000000001", "event_type": "script_generated", "occurred_at": "2026-05-28T11:50:00Z", "subject": "video_gen_a7c23f91", "description": "Script generation completed", "data": { "model": "gpt-4o", "input_tokens": 512, "output_tokens": 1840, }, "customer_id": "cust_47yxefzbfwkxragp01ccce965n", "created_at": "2026-05-28T12:01:34.943077Z", "costs": [ { "id": "c1000000-0001-4000-8000-000000000001", "vendor_id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "description": "GPT-4o script generation", "metadata": {}, "amount": 0.0043, "currency": "USD", }, ], "fees": [], "stats": { "gross_revenue": 0, "total_costs": 0.0043, "net_revenue": -0.0043, "margin": -1, "currency": "USD", }, }, ], "vendors": [ { "id": "vnd_4c22r59kkbz0z2cnntdksn7t45", "name": "OpenAI", "total_costs": 0.3291, "currency": "USD", }, { "id": "vnd_4r349d2m72m7r2jx68z20tswx2", "name": "DeepL", "external_id": "deepl", "total_costs": 0.0052, "currency": "USD", }, ], } ``` The response shows the task clearly for what it is: a 2-minute video job that passed through four steps and two vendors, earned $0.56 in gross revenue, cost $0.33 to produce, and landed at a 40.3% margin. The script generation step contributed nothing to gross revenue - its cost is absorbed into the job's overall economics - while video rendering, subtitles, and translation all generated fees. The vendor breakdown confirms that OpenAI accounted for virtually all of the cost, with DeepL responsible for a small fraction. #### What to look for[​](#what-to-look-for "Direct link to What to look for") Tasks become most useful once you have volume. The patterns that tend to surface first: **Margin erosion at the step level** - The per-event stats in the task detail show which steps consume the most cost relative to the revenue they earn. In the example above, the `video_generated` step runs at 20% margin, while `subtitles_generated` and `translation_completed` both run above 90%. The `script_generated` step returns `margin: -1`. If you're struggling with overall task profitability, the event breakdown tells you exactly where the pressure is. **Long-running or unexpectedly large tasks** - Sorting the task list by `total_costs` descending shows you the most expensive jobs on your platform. A task accumulating far more events than typical - or costs far above your average - may indicate a runaway process, an unusually complex job, or a customer finding an unintended usage pattern. **Vendor concentration and cost distribution** - The `vendors` array in the task detail shows which external services drive your cost structure. If a single vendor dominates costs across many tasks, that's both a business risk and a pricing signal. It may also point to optimisation opportunities - for example, routing simpler steps to a cheaper model. **Jobs that never resolve** - Because a task has no explicit end state, a task that stopped accumulating events long ago but still shows no billing resolution may indicate a pipeline failure or an abandoned job. The gap between `created_at` and `last_updated_at` in the task list is a useful proxy for job duration. #### Analysing tasks with the MCP server[​](#analysing-tasks-with-the-mcp-server "Direct link to Analysing tasks with the MCP server") Credyt's [MCP server](https://docs.credyt.ai/tools/mcp-server.md) includes support for tasks, which makes it a natural fit for conversational cost analysis. Rather than writing queries or building dashboards, you can ask an AI assistant connected to your Credyt account to surface the information directly. This is particularly useful when investigating a specific case. You can ask questions like "show me the most expensive video jobs this customer ran in May", "which tasks this week had a margin below 20%", or "pull up the full event breakdown for job video\_gen\_a7c23f91" and get a structured, readable answer in seconds. From there, you can drill in further - comparing that job to the customer's historical average, checking which vendor drove the cost spike, or looking at whether a similar pattern appears across other customers. Compared to scripting API calls or exporting data, the MCP approach is better suited to exploratory work: the kind of investigation where you're not sure what you're looking for yet, and where the next question depends on what the previous answer shows. #### Relationship to Profitability[​](#relationship-to-profitability "Direct link to Relationship to Profitability") Tasks are built on the same foundation as [Credyt Profitability](https://docs.credyt.ai/features/profitability.md). The `stats` at the event level and the cost attribution model are identical. What tasks add is the aggregation layer: instead of reviewing events one by one, you get a single view that rolls up across the full lifecycle of a deliverable. If you're already sending costs with your events and using the `subject` field consistently, Tasks require no additional integration. The data is already there. --- ### Usage Events [API Reference](https://docs.credyt.ai/api/events-send-usage.md) Usage events represent the activities in your system that you want to bill or (in the future) track costs for. Each event corresponds to a measurable outcome, such as an API call, a chat completion, or a video processed. Every usage event has a unique identifier that serves as an idempotency key. This ensures safe retries without accidental double billing, even if the same event is submitted multiple times due to network issues or other errors. When sending usage events you must provide a valid customer identifier. This allows Credyt to match the usage to the correct customer account and apply the appropriate pricing according to their [subscriptions](https://docs.credyt.ai/features/customers.md#subscribe-a-customer-to-a-product). Usage not linked to a valid subscription will be ignored. Usage events are billed in real time and the customer's balance will be debited as soon as an event is processed. Credyt supports a number of usage-based pricing models: * **`unit`** – charges per occurrence of the event (e.g., per chat, per verification, per API call). * **`volume`** – charges based on the volume or quantity consumed, included in the event payload (e.g., tokens, minutes, megabytes). * **`unit_and_volume`** – combines both approaches The `event_type` specified in the usage event must match the `event_type` configured in a product price’s usage calculation configuration for it to be charged for. View [Products and Pricing](https://docs.credyt.ai/features/product-catalog.md) guide for more details. By combining usage events with Credyt’s wallet and rate plan structure, you can build flexible, customer-friendly monetization models, whether you charge in fiat, tokens, or other custom units. ##### Example[​](#example "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "video_promoted", "occurred_at": "2025-10-17T21:21:27.024729Z", "subject": "video_5f53d23a4958", "description": "Video Promoted", "data": { "promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm" } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", events: [ { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", eventType: "video_promoted", occurredAt: "2025-10-17T21:21:27.024729Z", subject: "video_5f53d23a4958", description: "Video Promoted", data: { promoId: "pro_4tbftjwzxja1h71nzas1g0g1xm", }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L93) ```python response = client.events.send_usage( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "video_promoted", "occurred_at": "2025-10-17T21:21:27.024729Z", "subject": "video_5f53d23a4958", "description": "Video Promoted", "data": { "promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm", }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_video_promoted.py#L20) Note how `"promo_id": "pro_4tbftjwzxja1h71nzas1g0g1xm"` has been configured as `source_reference_field`. #### Correlating Usage[​](#correlating-usage "Direct link to Correlating Usage") We recommend you include the `subject` field in all usage events to correlate the usage to an activity in your system. This is displayed in the Usage history section of the [Billing portal](https://docs.credyt.ai/features/billing-portal.md), and feeds into [Profitability analysis](https://docs.credyt.ai/features/profitability.md) and [Tasks](https://docs.credyt.ai/features/tasks.md) - giving you a full view of both revenue and costs for any given activity. For finer grained traceability, you can include an additional reference that can be linked to a product price's `source_reference_field`. #### Simulating Usage[​](#simulating-usage "Direct link to Simulating Usage") Usage events can also be simulated before they affect actual balances. This is useful for validating new product configurations, experimenting with pricing models, or testing new features without impacting live customers. Simulated events calculate fees in the same way as live events but do not modify the wallet balance. --- ### Wallets and Topups Credyt's unique architecture unifies multiple billing models under a core primitive, the customer wallet. Every customer has one wallet, and that wallet can hold multiple accounts, each dedicated to a specific asset. Accounts are created automatically when a customer is subscribed to a product and can represent both fiat currencies or any [custom assets](https://docs.credyt.ai/features/assets.md) you define. Keeping wallets funded is critical for continuous product use. Credyt gives you two complementary ways to accept top-up payments, powered by Stripe. Hybrid Billing If you have a hybrid billing setup that leverages an external provider, be sure to read our [Adjustments](https://docs.credyt.ai/advanced-topics/adjustments-charges-gifts.md) guide. #### Option 1: Customer Billing Portal[​](#option-1-customer-billing-portal "Direct link to Option 1: Customer Billing Portal") The easiest way for your customers to add funds is through the hosted [Billing Portal](https://docs.credyt.ai/features/billing-portal.md), a self-service billing centre where they can check their balances, manage auto top-ups (recharge), and monitor their product usage: * Customers initiate top-ups directly in the portal * The only integration step is generating a session link and redirecting the customer * No sign-up is required on the customer side * The customer is responsible for defining the top-up amount * For custom assets, the default exchange rate is used Read more about the billing portal [here](https://docs.credyt.ai/features/billing-portal.md). ##### Create a Billing Portal Session[​](#create-a-billing-portal-session "Direct link to Create a Billing Portal Session") [API Reference](https://docs.credyt.ai/api/billing-portal-create-portal-session.md) * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/billing-portal/sessions ```json { "customer_id": "{{customerId}}", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure" } ``` ```typescript await client.billingPortal.createPortalSession({ customerId: "{{customerId}}", returnUrl: "https://glitch.ai/account", failureUrl: "https://glitch.ai/callbacks/credyt/failure", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/billingPortalCreatePortalSessionSample.ts#L11) ```python response = client.billing_portal.create_portal_session( body={ "customer_id": "{{customerId}}", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt/failure", }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/billing_portal_create_portal_session_start_a_session.py#L20) Redirect the customer to the `redirect_url`, where the customer can view their balance and initiate a top-up. #### Option 2: Top-up API[​](#option-2-top-up-api "Direct link to Option 2: Top-up API") Use the Top-up API when you want more control over the top-up flow, for example, if you choose to embed a top-up CTA directly within your product. * You collect or define the amount to top up in your own product * Your backend calls the Top-up API to create a checkout session * Credyt returns a `redirect_url` that navigates directly to the top-up payment page * After payment, the customer is returned to the customer billing portal * When topping up custom assets you have the option to override the default exchange rate * Use this to implement tiering or incentives ##### Initiate a top-up[​](#initiate-a-top-up "Direct link to Initiate a top-up") [API Reference](https://docs.credyt.ai/api/top-ups-initiate.md) * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/top-ups ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "amount": 25, "currency": "USD", "description": "Video Promotion Credits", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt-failure" } ``` **Response** ```json { "id": "top_473cr1y0ghbyc3m1yfbwvn3nxx", "status": "initiated", "redirect_url": "https://billing.credyt.ai/api/sign-in?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "created_at": "2024-07-29T15:51:28.071Z", "expires_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.topUps.initiate({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", amount: 25, currency: "USD", description: "Video Promotion Credits", returnUrl: "https://glitch.ai/account", failureUrl: "https://glitch.ai/callbacks/credyt-failure", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/topUpsInitiateSample.ts#L33) **SDK response object** ```typescript const response = { id: "top_473cr1y0ghbyc3m1yfbwvn3nxx", status: "initiated", redirectUrl: "https://billing.credyt.ai/api/sign-in?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", createdAt: "2024-07-29T15:51:28.071Z", expiresAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.top_ups.initiate( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "amount": 25, "currency": "USD", "description": "Video Promotion Credits", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt-failure", }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/top_ups_initiate_initiate_a_topup.py#L20) **SDK response object** ```python response = { "id": "top_473cr1y0ghbyc3m1yfbwvn3nxx", "status": "initiated", "redirect_url": "https://billing.credyt.ai/api/sign-in?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "created_at": "2024-07-29T15:51:28.071Z", "expires_at": "2024-07-29T15:51:28.071Z", } ``` Redirects the customer to the `redirect_url` to complete the top-up payment. #### Check the Wallet Balance[​](#check-the-wallet-balance "Direct link to Check the Wallet Balance") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-customer-wallet.md) After we receive confirmation that payment has succeeded the customer's wallet account balance will be updated. Typically this happens before the customer is redirected back to the billing portal. You can query a customer's wallet balances at any time, via the Customer Wallet API. * 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.566678 }, { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234 } ] } ``` ```typescript await client.customerWalletOps.getCustomerWallet("cust_473cr1y0ghbyc3m1yfbwvn3nxx"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetCustomerWalletSample.ts#L24) **SDK response object** ```typescript const response = { accounts: [ { id: "default:USD", name: "default", asset: "USD", available: 14.566678, }, { id: "default:TOK", name: "default", asset: "TOK", available: 993450234, }, ], }; ``` ```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.566678, }, { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234, }, ], } ``` #### Testing[​](#testing "Direct link to Testing") To make testing easier, all payments in test mode are processed through Credyt's default test Stripe account. We'll be adding the ability to use your own Stripe account for testing in the near future. When testing payments interactively with Stripe, you can use their standard test cards, for example: * Number: `4242 4242 4242 4242` * Expiry: Any future month/year (e.g. `12/34`) * CVC: any three‑digit CVC e.g. `123` * Any values for the other fields For the full list of test card numbers and scenarios, see [Stripe’s docs](https://docs.stripe.com/testing#cards). --- ### Webhooks Credyt can notify your platform in real time when billing events occur. You register one or more webhook destinations — HTTPS endpoints in your infrastructure — and Credyt delivers a signed HTTP `POST` request each time a matching event fires. #### Create a Webhook Destination[​](#create-a-webhook-destination "Direct link to Create a Webhook Destination") [API Reference](https://docs.credyt.ai/api/webhooks-create-webhook-destination.md) * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/webhooks ```json { "url": "https://yourplatform.com/webhooks/credyt", "topics": [ "*" ] } ``` **Response** ```json { "id": "whd_01abc123", "secret": "whsec_••••••", "created_at": "2026-04-14T10:00:00Z" } ``` ```typescript await client.webhooks.createWebhookDestination({ url: "https://yourplatform.com/webhooks/credyt", topics: [ "*", ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/webhooksWebhooksCreateWebhookDestinationSample.ts#L44) **SDK response object** ```typescript const response = { id: "whd_01abc123", secret: "whsec_••••••", createdAt: "2026-04-14T10:00:00Z", }; ``` ```python response = client.webhooks.create_webhook_destination( body={ "url": "https://yourplatform.com/webhooks/credyt", "topics": [ "*", ], }, ) ``` **SDK response object** ```python response = { "id": "whd_01abc123", "secret": "whsec_••••••", "created_at": "2026-04-14T10:00:00Z", } ``` Save your secret The `secret` is returned at creation time and can also be retrieved via `GET /webhooks/:webhookId`. Store it securely (e.g. as an environment variable) — it is required to verify webhook signatures. #### Available Webhook Events[​](#available-webhook-events "Direct link to Available Webhook Events") | Topic | Description | | ------------------------ | ---------------------------------------------------------------------------- | | `subscription.activated` | Fired when a subscription becomes active and includes the activated products | ##### Event envelope[​](#event-envelope "Direct link to Event envelope") All webhook payloads share a common envelope: ```json { "id": "evt_01abc123", "type": "subscription.activated", "created": "2026-04-14T10:00:00Z", "live_mode": true, "data": { ... } } ``` ##### `subscription.activated`[​](#subscriptionactivated "Direct link to subscriptionactivated") ```json { "id": "evt_01abc123", "type": "subscription.activated", "created": "2026-04-14T10:00:00Z", "live_mode": true, "data": { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "subscription_id": "sub_01abc123", "occurred_at": "2026-04-14T10:00:00Z", "products": [ { "product_rate_plan_id": "prp_4e28n8kk41931f5yt5em49ecw7", "product_code": "glitch_pro", "version": 1 }, { "product_rate_plan_id": "prp_4e28n8kk41931f5yt5em49ecw8", "product_code": "glitch_addon", "version": 2 } ] } } ``` #### Verifying Webhook Signatures[​](#verifying-webhook-signatures "Direct link to Verifying Webhook Signatures") Every webhook request includes a `Credyt-Signature` header you should use to confirm the request originated from Credyt and has not been tampered with. **Header format:** `t=,v0=` * `t` — Unix timestamp of when the event was dispatched * `v0` — HMAC-SHA256 hex signature of `${timestamp}.${rawBody}` using your destination secret The following Node.js helper verifies the signature: ```typescript import * as crypto from "crypto"; /** * Verify a Credyt webhook signature. * * @param secret - The webhook destination secret returned at creation * @param rawBody - The raw request body as a Uint8Array or Buffer * @param signatureHeader - The value of the `Credyt-Signature` header * @returns true if the signature is valid, false otherwise */ export function verifyWebhookSignature( secret: string, rawBody: Uint8Array, signatureHeader: string ): boolean { // Split on the first comma only: "t=,v0=" const [timestampPart, signaturesPart] = signatureHeader.split(",", 2); const timestamp = parseInt(timestampPart.replace("t=", ""), 10); if (isNaN(timestamp)) { return false; } const signatures = signaturesPart.replace("v0=", "").split(","); // Signed content is: "." const signedContent = `${timestamp}.${rawBody}`; const hmac = crypto.createHmac("sha256", secret); hmac.update(signedContent); const expectedSignature = hmac.digest("hex"); return signatures.some((sig) => sig === expectedSignature); } ``` **Express.js example** ```typescript import express from "express"; const app = express(); // Use raw body parser to preserve the exact bytes for signature verification app.post( "/webhooks/credyt", express.raw({ type: "application/json" }), (req, res) => { const signatureHeader = req.headers["credyt-signature"] as string; const isValid = verifyWebhookSignature( process.env.CREDYT_WEBHOOK_SECRET!, req.body, signatureHeader ); if (!isValid) { return res.status(401).send("Invalid signature"); } const event = JSON.parse(req.body.toString()); switch (event.topic) { case "subscription.activated": // Handle subscription activation break; } res.status(200).send(); } ); ``` Replay protection The `t` timestamp lets you reject replayed requests. Consider rejecting events where the timestamp is more than a few minutes old. #### Connect Webhooks[​](#connect-webhooks "Direct link to Connect Webhooks") If your platform uses Credyt's [C4P](https://docs.credyt.ai/partners/platforms-overview.md) functionality to manage sub-accounts, you can create dedicated webhook destinations for connected-account events by setting `connect: true` when creating the destination. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/webhooks ```json { "url": "https://yourplatform.com/webhooks/credyt/connect", "topics": [ "subscription.activated" ], "connect": true } ``` **Response** ```json { "id": "dst_4kf9v6xp00hzc99rdwr5m97wce", "secret": "whsec_abc123def456", "created_at": "2026-04-14T10:00:00Z" } ``` ```typescript await client.webhooks.createWebhookDestination({ url: "https://yourplatform.com/webhooks/credyt/connect", topics: [ "subscription.activated", ], connect: true, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/webhooksWebhooksCreateWebhookDestinationSample.ts#L27) **SDK response object** ```typescript const response = { id: "dst_4kf9v6xp00hzc99rdwr5m97wce", secret: "whsec_abc123def456", createdAt: "2026-04-14T10:00:00Z", }; ``` ```python response = client.webhooks.create_webhook_destination( body={ "url": "https://yourplatform.com/webhooks/credyt/connect", "topics": [ "subscription.activated", ], "connect": True, }, ) ``` **SDK response object** ```python response = { "id": "dst_4kf9v6xp00hzc99rdwr5m97wce", "secret": "whsec_abc123def456", "created_at": "2026-04-14T10:00:00Z", } ``` Connected-account events are routed **only** to destinations with `connect: true`. Standard destinations (with `connect: false`) receive platform-level events only. #### Testing Webhooks[​](#testing-webhooks "Direct link to Testing Webhooks") No endpoint yet? Tools like [webhook.site](https://webhook.site/) or [Hookdeck Console](https://console.hookdeck.com/) give you a temporary public URL that logs incoming requests — useful for inspecting the payload shape before you build your own endpoint. You can send a test event to an existing destination without triggering a real billing event. This is useful for verifying your endpoint handles the payload correctly. [API Reference](https://docs.credyt.ai/api/webhooks-test-webhook-destination.md) * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/webhooks/dst\_4kf9v6xp00hzc99rdwr5m97wce/test/subscription.activated ```http ``` **Response** ```json { "id": "evt_01abc123" } ``` ```typescript await client.webhooks.testWebhookDestination("dst_4kf9v6xp00hzc99rdwr5m97wce", "subscription.activated"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/webhooksWebhooksTestWebhookDestinationSample.ts#L11) **SDK response object** ```typescript const response = { id: "evt_01abc123", }; ``` ```python response = client.webhooks.test_webhook_destination( webhook_id="dst_4kf9v6xp00hzc99rdwr5m97wce", topic="subscription.activated", ) ``` **SDK response object** ```python response = { "id": "evt_01abc123", } ``` To test all destinations subscribed to a topic (without specifying a destination ID): [API Reference](https://docs.credyt.ai/api/webhooks-test-webhook-destinations.md) ```text POST https://api.credyt.ai/webhooks/test/:topic ``` Both endpoints return `202 Accepted` with the dispatched event ID: ```json { "id": "evt_01abc123" } ``` #### Managing Destinations[​](#managing-destinations "Direct link to Managing Destinations") | Operation | API Reference | | -------------------- | -------------------------------------------------------------------------------------------------------- | | List destinations | [GET /webhooks](https://docs.credyt.ai/api/webhooks-list-webhook-destinations.md) | | Get a destination | [GET /webhooks/:webhookId](https://docs.credyt.ai/api/webhooks-get-webhook-destination.md) | | Update a destination | [PATCH /webhooks/:webhookId](https://docs.credyt.ai/api/webhooks-update-webhook-destination.md) | | Delete a destination | [DELETE /webhooks/:webhookId](https://docs.credyt.ai/api/webhooks-delete-webhook-destination.md) | | List webhook events | [GET /webhooks/events](https://docs.credyt.ai/api/webhooks-list-events.md) | ##### Webhook Event Log[​](#webhook-event-log "Direct link to Webhook Event Log") The event log (`GET /webhooks/events`) lets you inspect every delivery attempt, including its status (`Success` or `Failed`) and timestamp. Results can be filtered by destination ID, status, and time range and support cursor-based pagination. --- ## Advanced Topics ### Adjustments, Gifts and Ad-hoc Charges The Adjustments API is the main way to keep customer balances in sync with events that happen outside of Credyt. Whenever a payment, refund, or credit is processed externally, the platform is responsible for notifying Credyt so that wallet balances stay accurate. #### Common use-cases[​](#common-use-cases "Direct link to Common use-cases") 1. **External PSP payments** - when subscription or top-up payments are processed through your own payment provider, you add the balance in Credyt via an adjustment. 2. **Refunds** - when funds are returned to a customer, you subtract the amount with a refund adjustment. 3. **Free credits / gifts** - when you want to reward users, run promotions, or compensate for issues, you credit the customer's balance directly. 4. **Ad-hoc charges** - when you may need to apply charges manually, outside of the normal usage processing flow. #### External PSP Payments[​](#external-psp-payments "Direct link to External PSP Payments") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) When subscriptions or top-ups are charged through your own PSP, the payment never reaches Credyt directly. To maintain accurate balances, send an adjustment with the same amount and asset. A detailed implementation guide is available in our [Hybrid model](https://docs.credyt.ai/use-cases/hybrid-model.md) article. ##### Example[​](#example "Direct link to Example") This adjustment adds $25 to the customer’s USD account. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Monthly Subscription", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: 25, description: "Monthly Subscription", reason: "external_topup", expiresAt: "2024-07-29T15:51:28.071Z", metadata: { psp: "stripe", paymentIntent: "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L56) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Monthly Subscription", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` #### Refunds[​](#refunds "Direct link to Refunds") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) Refunds are negative adjustments. You refund through your PSP (or Stripe Dashboard if using Credyt payments), then notify Credyt. For further details, refer to our [Refunds article](https://docs.credyt.ai/advanced-topics/refunds.md). ##### Example[​](#example-1 "Direct link to Example") This subtracts $20 from the customer’s fiat account balance (externally refunded). * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": -20, "description": "Technical failure", "reason": "external_refund", "expires_at": "2024-07-29T15:51:28.071Z" } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: -20, description: "Technical failure", reason: "external_refund", expiresAt: "2024-07-29T15:51:28.071Z", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L158) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": -20, "description": "Technical failure", "reason": "external_refund", "expires_at": "2024-07-29T15:51:28.071Z", }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` #### Free Credits / Gifts[​](#free-credits--gifts "Direct link to Free Credits / Gifts") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) Credyt allows you to grant gifts or free credits to customers through the Adjustments API. This lets you reward users, run promotions, or compensate for issues with a simple API call that updates their wallet balance in real-time. You can also define an expiry date for these credits when granting them, enabling time-limited promotions and helping drive engagement, and monetization. You can issue credits without a payment by applying a positive adjustment. ##### Example[​](#example-2 "Direct link to Example") Customer wallet is credited with 1,000 tokens. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "TOKENS", "amount": 1000, "description": "Signup bonus", "reason": "gift", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "signup_channel": "referral", "referral_id": "2c963f66afa6" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "TOKENS", amount: 1000, description: "Signup bonus", reason: "gift", expiresAt: "2024-07-29T15:51:28.071Z", metadata: { signupChannel: "referral", referralId: "2c963f66afa6", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L193) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "TOKENS", "amount": 1000, "description": "Signup bonus", "reason": "gift", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "signup_channel": "referral", "referral_id": "2c963f66afa6", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` #### Ad-hoc Charges[​](#ad-hoc-charges "Direct link to Ad-hoc Charges") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-charge.md) While usage-based billing is typically driven by real-time events, there are situations where you may need to apply charges manually, outside of the normal usage processing flow. Use **ad-hoc charge adjustments** to do exactly that. Ad-hoc charges are another form of balance adjustment, but unlike credits or gifts, they always deduct funds from a customer’s balance. This makes them particularly useful in scenarios where: * Usage data cannot be sent in real time due to technical issues or service interruptions * External data providers (for example, an AI API or third-party service) deliver usage information with delays * You need to apply one-off or corrective fees that aren’t tied to a usage event — such as overage adjustments, manual service fees, or administrative costs Each charge includes details such as the amount, currency, description, and subject (a contextual reference, such as a session or service ID). You can also include optional metadata and store calculation inputs (e.g., volume, rate, or unit price) for traceability and transparency to the customer. All ad-hoc charges appear in the customer’s Billing Portal usage history, displaying the information provided in the `Create a charge` request - including descriptions, amounts, and other contextual details you’ve shared. To ensure safe retries, each request must include a unique `transaction_id`, which acts as an idempotency key. If the same `transaction_id` is sent again, Credyt will recognize it as a duplicate and will not duplicate the charge. ##### Example[​](#example-3 "Direct link to Example") * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/charges ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "subject": "chat_5f53d23a4958", "description": "Overage costs for GPT-4 usage", "metadata": { "model": "gpt-4-1" }, "input_units": null, "input_volume": 2652000, "unit_price": null, "volume_rate": 0.5, "package_size": 1000000, "amount": 1.326 } ``` ```typescript await client.customerWalletOps.createCharge("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", subject: "chat_5f53d23a4958", description: "Overage costs for GPT-4 usage", metadata: { model: "gpt-4-1", }, inputUnits: null, inputVolume: 2652000, unitPrice: null, volumeRate: 0.5, packageSize: 1000000, amount: 1.326, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateChargeSample.ts#L15) ```python response = client.customer_wallet_ops.create_charge( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "subject": "chat_5f53d23a4958", "description": "Overage costs for GPT-4 usage", "metadata": { "model": "gpt-4-1", }, "input_units": None, "input_volume": 2652000, "unit_price": None, "volume_rate": 0.5, "package_size": 1000000, "amount": 1.326, }, ) ``` #### Key requirements and best practices[​](#key-requirements-and-best-practices "Direct link to Key requirements and best practices") * A unique `transaction_id` is required for each adjustment. * Amounts should be positive for crediting the account (top-ups, subscriptions, gifts) and negative for debiting the account (refunds, other adjustments). * The `reason` field indicates the type of adjustment (`external_topup`, `external_refund`, `gift`, `other`). * The `metadata` field can be used to attach PSP references, campaign IDs, or internal notes for reconciliation. --- ### Checkout Branding Stripe Checkout supports flexible branding options that help your topup flow feel native to your platform’s experience. When your customers add funds through the Billing Portal or via topup sessions, they will see your custom colours, logo, and other brand elements directly in Stripe’s hosted interface. You can configure these settings from your connected Stripe Dashboard under Settings → Business → Branding. Once saved, your branding automatically applies to all Checkout sessions initiated through Credyt. From your Stripe Dashboard, you can: * Upload your company logo. * Define primary and accent colours to match your platform’s theme. * Set your business name and statement descriptor for better payment recognition. * Adjust fonts and shapes of the checkout elements. These changes require no additional API configuration; updates made in your Stripe Dashboard take effect immediately. Branding settings can be tested in the test environment once you’ve connected a Stripe test account, or directly in the production account during pre-production testing, as changes are fast to execute and apply in real time. For detailed setup guidance, see [Stripe’s branding configuration documentation](https://docs.stripe.com/get-started/account/branding). --- ### Refunds [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) Refunds are not currently supported directly within Credyt. If you need to issue refunds, you must do so directly with your payment provider (your PSP or Stripe, if you use Credyt’s built-in payments). You can then use the Wallet Adjustments API to adjust the customer’s balance within Credyt. #### Refunds with an External PSP[​](#refunds-with-an-external-psp "Direct link to Refunds with an External PSP") If you use your own PSP for payment processing: 1. Initiate the refund through your PSP’s dashboard or API. 2. Notify Credyt of the refunded amount using the Adjustments API. Use a unique `transaction_id` and specify `reason: "external_refund"`. ##### Example[​](#example "Direct link to Example") This subtracts $20 from the customer’s fiat account balance. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": -20, "description": "Technical failure", "reason": "external_refund", "expires_at": "2024-07-29T15:51:28.071Z" } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: -20, description: "Technical failure", reason: "external_refund", expiresAt: "2024-07-29T15:51:28.071Z", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L158) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": -20, "description": "Technical failure", "reason": "external_refund", "expires_at": "2024-07-29T15:51:28.071Z", }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` #### Refunds with Credyt Payments[​](#refunds-with-credyt-payments "Direct link to Refunds with Credyt Payments") If you use Credyt’s built-in payments processing (via Stripe): 1. Initiate the refund in the Stripe Dashboard. Stripe handles payment reversal, receipts, and settlement. 2. Notify Credyt of the refund through the Adjustments API, so the customer’s balance is updated. ##### Example[​](#example-1 "Direct link to Example") This subtracts $20 from the customer’s fiat account balance. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": -20, "description": "Technical failure", "reason": "external_refund", "expires_at": "2024-07-29T15:51:28.071Z" } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: -20, description: "Technical failure", reason: "external_refund", expiresAt: "2024-07-29T15:51:28.071Z", }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L158) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": -20, "description": "Technical failure", "reason": "external_refund", "expires_at": "2024-07-29T15:51:28.071Z", }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` #### Best Practices[​](#best-practices "Direct link to Best Practices") * Always send refunds as a negative adjustment with `reason: "external_refund"`. * Use a unique identifier for `transaction_id` that ties the refund to the original payment. The Adjustments API supports metadata, which you can use to attach identifiers or other relevant information to make reconciliation and traceability easier. * Keep refund amounts and currencies consistent with the original payment to avoid reconciliation issues. --- ### Stripe Payments This article explains how to connect your own Stripe account to Credyt for testing and production payments, configure checkout branding, and (optionally) set up tax rules. #### Overview[​](#overview "Direct link to Overview") Credit partners with Stripe to process customer payments for wallet top-ups and automated balance refills. Using Stripe via Credyt allows your platform to manage payments securely, provide receipts, and ensure that wallet balances are updated accurately without additional development effort. During early testing, all payments are handled through Credyt’s shared test Stripe account, so you can start integrating without needing to set up your own account. As you approach go-live, we recommend connecting your own test Stripe account. This ensures that your integration behaves exactly as it will in production, allowing you to test branding, tax calculations, and refunds in a realistic environment. * Stripe is used to process all top-ups and auto-refills for your customers’ wallets. * Initial sandbox testing runs through Credyt’s shared test account, so no setup is required to start integration. * Connecting your own test Stripe account allows you to validate your integration before going live. * Both test and live Stripe environments are supported, and you can connect to each separately to maintain isolation between testing and production. #### Connect Your Own Stripe Account[​](#connect-your-own-stripe-account "Direct link to Connect Your Own Stripe Account") When you’re ready to move closer to production, connecting your own Stripe account allows you to test payments and branding under conditions that closely match your live environment. While initial sandbox testing uses Credyt’s shared test account, using your own account ensures your integration behaves exactly as it will in production. * Connecting your own Stripe account lets you test refunds, branding, and tax workflows in a realistic environment. Connecting your Stripe account is straightforward: Credyt generates an onboarding link from your Platform Dashboard. You click the link and complete Stripe’s connection flow. In test mode, no KYC or real bank account details are required; fast-click through the test onboarding flow to complete the set-up. Once connected, your Stripe account will handle all top-ups and auto-refills initiated through Credyt. This gives you full visibility into payment activity, including transaction metadata, while Credyt automatically synchronises wallet balances without additional engineering effort. * Click the onboarding link in your Platform Dashboard to connect your Stripe account. * In test mode, no KYC or payout setup is required, so you can quickly validate payments, branding, and tax configurations. * You’ll see all payments and related metadata (customer IDs, topup references, and amounts) directly in your Stripe Dashboard. * After a successful connection, your Stripe account will appear as “connected” in your Platform Dashboard. **Note**: > You can safely skip this step for early sandbox testing, but connecting your own account before production is strongly recommended. #### Handling Refunds and Disputes[​](#handling-refunds-and-disputes "Direct link to Handling Refunds and Disputes") All refund and dispute operations are managed directly in Stripe. When a customer requests a refund, you need to initiate it from your Stripe Dashboard. Keep in mind that refunded amounts are not automatically updated in the Credyt wallet balance. To ensure accuracy, your platform must also send Credyt an Adjustment request to deduct the amount refunded from the wallet. ##### Issue a refund[​](#issue-a-refund "Direct link to Issue a refund") 1. Log in to your Stripe Dashboard. 2. Use the global search bar to locate the customer or payment. You can search using: * Email address * Credyt customer ID * External (platform) customer ID, if implemented 3. Open the payment you want to refund. 4. Use the Actions menu to issue either a full or partial refund. After the refund is processed in Stripe, your platform must submit an Adjustment request to Credyt to deduct the refunded amount from the customer’s wallet. ##### Disputes[​](#disputes "Direct link to Disputes") Disputes (chargebacks) are also managed in Stripe. Credyt does not automatically reverse or resolve disputed payments. Your platform should monitor disputes directly in Stripe and follow their resolution workflow. Once the dispute outcome is known, you can adjust the corresponding wallet balance in Credyt if funds need to be credited or debited. [Learn more about handling disputes in Stripe](https://docs.stripe.com/disputes) #### Configure and Test Tax (Optional)[​](#configure-and-test-tax-optional "Direct link to Configure and Test Tax (Optional)") If your products require tax calculation, Stripe Tax can help you automatically determine and collect the right amount of tax for each top-up or payment. This configuration happens entirely in your connected Stripe account, and most of the required business information (such as company name, address, and registration details) is already available from the onboarding process. To enable and test tax handling: * Enable Stripe Tax from your connected Stripe Dashboard — setup is straightforward since most required data points are pre-filled from onboarding. * Make sure your business address and product codes are correct, as these determine the applicable tax regions and rates. * Trigger a test top-up session with tax enabled to verify that Stripe correctly calculates and displays tax amounts in both Checkout and the Tax module in your Stripe Dashboard. * Optionally, explore value-added services available through Stripe’s partner ecosystem, such as automated filing and tax reporting — these may require additional setup or subscription. At this stage, tax configuration and testing are handled directly in Stripe; no API changes are needed in Credyt. For detailed setup guidance, see [Stripe’s Tax documentation](https://docs.stripe.com/tax). #### Going Live with Stripe[​](#going-live-with-stripe "Direct link to Going Live with Stripe") Once you’re ready to move from testing to production, you’ll need to connect your live Stripe account. This ensures that top-ups and automated balance refills in your production environment are fully operational and compliant. To go live: * **Start from your production Credyt account.** Initiate the Stripe onboarding directly from your production Credyt Platform Dashboard, just as you did in test mode. During this step, you can either create a new Stripe account or link an existing one to Credyt. If you choose to link an existing Stripe account, your existing credentials and business profile information will remain intact (and can be edited during onboarding if needed). Payment activities and settings associated with Credyt will, however, remain segregated - managed under the Credyt connected account within your Stripe Dashboard, separate from your original Stripe setup. * **Complete Stripe’s onboarding and KYC process.** Stripe will guide you through its standard verification steps. Credyt pre-fills certain data points for convenience (such as business name, support email, and website), but you can edit these details in Stripe’s onboarding form if needed. If you connect an existing Stripe account that’s already verified, the KYC process is typically faster, as Stripe will reuse much of your existing information. * **Wait for Stripe’s review and approval.** After submitting all requested details, Stripe will review your account. In some cases, they may require additional verification (for example, a full SSN in the U.S. or proof of identity). This review can take a few days, and the account won’t be able to accept payments until it’s approved. We recommend starting this process at least two weeks before your anticipated launch date to avoid delays. * **Confirm the connection.** Once Stripe has approved the account and enabled payments, the Stripe section in your Credyt Platform Dashboard will display the status Connected — indicating that you’re ready to process live payments. #### Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") Even with a smooth setup, you may occasionally run into issues during onboarding or payments. Below are the most common cases and how to resolve them. ##### Onboarding link expired or invalid[​](#onboarding-link-expired-or-invalid "Direct link to Onboarding link expired or invalid") If your Stripe onboarding link no longer works (for example, if too much time has passed or you closed the tab before completing it): * Return to your Credyt Platform Dashboard and generate a new onboarding link. * Use the new link to pick up the process where you left off. ##### Stripe account shows as “Pending” in Credyt[​](#stripe-account-shows-as-pending-in-credyt "Direct link to Stripe account shows as “Pending” in Credyt") This means Stripe is still reviewing your details or awaiting verification documents. * Log in to your Stripe Dashboard and check for any required actions or document uploads. * Once you complete these steps, your status in Credyt will automatically update to Connected once Stripe approves the account. ##### Payments fail during testing or production[​](#payments-fail-during-testing-or-production "Direct link to Payments fail during testing or production") If a test or live payment fails: * Confirm that your Stripe account is fully connected in Credyt (status: *Connected*). * Check the Stripe Dashboard → Payments tab for error codes or messages. Stripe provides detailed failure reasons such as insufficient funds, card declines, or incomplete setup. * Ensure that webhooks are enabled in your connected account - Credyt uses them to update wallet balances after successful payments. ##### Refunds not reflected in Credyt balance[​](#refunds-not-reflected-in-credyt-balance "Direct link to Refunds not reflected in Credyt balance") Credyt does **not** automatically update wallet balances when a refund is processed in Stripe. * To adjust the wallet, your platform must send an Adjustment request to Credyt’s API after issuing the refund in Stripe. * This ensures the balance in Credyt accurately reflects the refunded amount. ##### Tax or branding changes not visible in Checkout[​](#tax-or-branding-changes-not-visible-in-checkout "Direct link to Tax or branding changes not visible in Checkout") If tax amounts or branding updates aren’t appearing as expected: * Confirm you’re editing settings in the same Stripe account connected to your current Credyt environment (test vs production). * For tax issues, verify that Stripe Tax is enabled and correctly configured (see Stripe Tax documentation). The most common issues revolve around the configuration of product tax codes and applicable jurisdictions (states or countries). * Branding changes under Settings → Business → Branding apply immediately in real time, but you may need to refresh or reopen your Checkout session to see updates. --- ## Use Cases ### Fiat vs Custom Units AI platforms bill in many ways - some charge directly in fiat currencies, others rely on product-native units like tokens, GPU hours, or video minutes. Each approach reflects a deliberate decision about what your customers should see and understand. Credyt supports all these cases with a single model: every customer has one wallet, and that wallet can hold multiple accounts, each tied to a specific asset. Accounts are created automatically and can represent fiat, credits, or any custom unit you define when configuring [products and pricing](https://docs.credyt.ai/features/product-catalog.md). #### What are custom assets?[​](#what-are-custom-assets "Direct link to What are custom assets?") Custom assets are product-native billing units. They let you charge customers in a way that matches how they use your product. Instead of showing customers a $0.50 charge for generating a video clip, you bill them 1 video minute. Instead of a $1.47 charge for image generation, they spend 14 images. The underlying infrastructure costs map to these units, but customers see balances and consumption in terms they immediately understand. Custom assets also decouple your customer-facing pricing from infrastructure cost volatility. When GPU costs shift or your model changes, you update a rate. Existing balances stay valid and customers keep the credits they purchased. #### Three problems custom assets solve[​](#three-problems-custom-assets-solve "Direct link to Three problems custom assets solve") **Infrastructure costs vary but customer-facing pricing shouldn't.** Not every request costs the same to run. Model quality, duration, and complexity all affect compute cost. Custom assets absorb that variance so customers always see predictable unit deductions, regardless of what's happening underneath. **Product-native units make consumption clear.** You generated a video: "1 video minute" is easier to understand than "$0.50 for generation". Customers know what they purchased and how fast they're using it. **Value can be earned, not just purchased.** Credits can be granted for referrals, onboarding bonuses, or loyalty programs. Many platforms use this model to drive acquisition and engagement - users earn credits through referrals and other activities, which work identically to purchased ones. This turns billing into part of the product experience. #### Account types[​](#account-types "Direct link to Account types") Credyt wallets support three account configurations. The one you choose depends on how you want customers to experience pricing and value. ##### Fiat Accounts[​](#fiat-accounts "Direct link to Fiat Accounts") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-account.md) A fiat account tracks balances in real currencies like USD or EUR. When a customer holds an account in fiat, usage is deducted in fiat terms (e.g. $0.006 per second). Fiat accounts are straightforward to reconcile and enterprise-friendly. **Example:** * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/customers/{customerId}/wallet/{accountId} ```http ``` **Response** ```json { "id": "default:USD", "name": "default", "asset": "USD", "available": 998.5, "pending_in": 0, "pending_out": 0 } ``` ```typescript await client.customerWalletOps.getAccount(); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetAccountSample.ts#L27) **SDK response object** ```typescript const response = { id: "default:USD", name: "default", asset: "USD", available: 998.5, pendingIn: 0, pendingOut: 0, }; ``` ```python response = client.customer_wallet_ops.get_account() ``` **SDK response object** ```python response = { "id": "default:USD", "name": "default", "asset": "USD", "available": 998.5, "pending_in": 0, "pending_out": 0, } ``` Credyt returns information about `default:USD` account in the customer’s wallet. ##### Custom Assets Accounts[​](#custom-assets-accounts "Direct link to Custom Assets Accounts") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-account.md) A custom asset account holds balances in a unit you define. Common examples include images, video minutes, translation words, and GPU hours. You create and manage any asset that fits your product. Each asset has an exchange rate that defines how fiat converts to custom assets on top-up. When infrastructure costs change, you update the rate. Existing balances aren't affected. Read more about [Asset management](https://docs.credyt.ai/features/assets.md). **Example:** * REST API * TypeScript SDK * Python SDK GET https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/default:TOK ```http ``` **Response** ```json { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234, "pending_in": 50000, "pending_out": 10000 } ``` ```typescript await client.customerWalletOps.getAccount("cust_473cr1y0ghbyc3m1yfbwvn3nxx", "default:TOK"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetAccountSample.ts#L40) **SDK response object** ```typescript const response = { id: "default:TOK", name: "default", asset: "TOK", available: 993450234, pendingIn: 50000, pendingOut: 10000, }; ``` ```python response = client.customer_wallet_ops.get_account( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", account_id="default:TOK", ) ``` **SDK response object** ```python response = { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234, "pending_in": 50000, "pending_out": 10000, } ``` Here, the customer has 245 images remaining. When they generate an image, Credyt deducts the appropriate amount and records the transaction automatically. ##### Mixed Accounts (Fiat + Custom Assets)[​](#mixed-accounts-fiat--custom-assets "Direct link to Mixed Accounts (Fiat + Custom Assets)") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-customer-wallet.md) A single wallet can hold both fiat and custom asset accounts at the same time. Top-ups are applied to the correct account depending on the asset type. Usage events deduct from the account linked to the billed product asset. **Example Wallet:** * 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.566678 }, { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234 } ] } ``` ```typescript await client.customerWalletOps.getCustomerWallet("cust_473cr1y0ghbyc3m1yfbwvn3nxx"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetCustomerWalletSample.ts#L24) **SDK response object** ```typescript const response = { accounts: [ { id: "default:USD", name: "default", asset: "USD", available: 14.566678, }, { id: "default:TOK", name: "default", asset: "TOK", available: 993450234, }, ], }; ``` ```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.566678, }, { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234, }, ], } ``` This customer has a USD balance for fiat-priced features and a custom asset balance (images) for custom-asset-priced features. Both live in the same wallet and are managed through the same billing portal. Not every product needs custom assets. If your costs are deterministic and your customers are technical users comfortable with infrastructure metrics, billing directly in fiat may be simpler. For a deeper look at when each approach fits, read [How to bill AI products in custom units instead of dollars](https://credyt.ai/blog/how-to-bill-ai-products-in-custom-units-instead-of-dollars). --- ### Hybrid Model **Subscriptions and Topups** Many AI platforms start with subscriptions and later add topups to handle usage spikes. Usage spikes can dramatically increase infrastructure spend, making subscription-only models insufficient for real-world profitability. That’s why a hybrid billing model, combining stable subscriptions with usage-based topups, is becoming prevalent in the AI economy. Credyt supports this hybrid approach even if your subscriptions are already managed externally. * **Subscriptions remain outside Credyt** - you keep using your existing PSP and billing system. * **Credyt is informed when a subscription payment succeeds** via the Adjustments API, which credits the customer’s wallet. * **Topups for additional usage** can be handled in two ways: * **Through Credyt** - using the Billing Portal or topup API (requires connecting a Stripe account). * **Outside Credyt** - process the payment with your PSP, then notify Credyt using the Adjustments API. This lets you add real-time usage billing without rebuilding your subscription flow or changing payment providers. #### Implementation guide[​](#implementation-guide "Direct link to Implementation guide") ##### Reflect Subscription Payments in Credyt[​](#reflect-subscription-payments-in-credyt "Direct link to Reflect Subscription Payments in Credyt") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) When a subscription renews in your PSP, call the Adjustments API to increase the wallet balance: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Monthly Subscription", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: 25, description: "Monthly Subscription", reason: "external_topup", expiresAt: "2024-07-29T15:51:28.071Z", metadata: { psp: "stripe", paymentIntent: "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L56) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Monthly Subscription", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` Wallet account balance increases by the subscription value. ##### Handle Topups for Additional Usage[​](#handle-topups-for-additional-usage "Direct link to Handle Topups for Additional Usage") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) **Option A: Use Credyt’s Payment Rails (Stripe Checkout)** * Customer tops up via **Billing Portal** (self-service) or **Topup API** (your UI). Read about [Topups](https://docs.credyt.ai/features/wallets-and-topups.md). * Credyt processes the payment through Stripe. * Requires either creating a new Stripe account or connecting your existing one via Credyt. **Option B: Keep Topups External** * Process the payment with your PSP. * Call the Adjustments API to reflect the new balance in Credyt. - REST API - TypeScript SDK - Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Ad-hoc usage", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: 25, description: "Ad-hoc usage", reason: "external_topup", expiresAt: "2024-07-29T15:51:28.071Z", metadata: { psp: "stripe", paymentIntent: "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L122) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Ad-hoc usage", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` ##### Send Usage Events[​](#send-usage-events "Direct link to Send Usage Events") [API Reference](https://docs.credyt.ai/api/events-send-usage.md) Once the wallet is funded (from subscription or topups), usage events will deduct balances in real time: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "message_completed", "occurred_at": "2024-07-29T15:51:28.071Z", "subject": "chat_5f53d23a4958", "description": "Chat message completed", "data": { "model": "gpt-4-1", "input_tokens": 2353, "output_tokens": 34697 } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", events: [ { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", eventType: "message_completed", occurredAt: "2024-07-29T15:51:28.071Z", subject: "chat_5f53d23a4958", description: "Chat message completed", data: { model: "gpt-4-1", inputTokens: 2353, outputTokens: 34697, }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L11) ```python response = client.events.send_usage( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "message_completed", "occurred_at": "2024-07-29T15:51:28.071Z", "subject": "chat_5f53d23a4958", "description": "Chat message completed", "data": { "model": "gpt-4-1", "input_tokens": 2353, "output_tokens": 34697, }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_message_completed.py#L20) --- ### Subscriptions Only Model Many AI platforms start with a subscription-only model, as it provides predictable recurring revenue and a straightforward customer experience. In some cases, companies rely on this approach due to limitations of their existing billing providers, which may not support real-time usage billing or flexible unit conversions. AI workloads, however, can fluctuate significantly, making it challenging to align subscription revenue with actual infrastructure costs. Credyt approaches this problem differently: instead of managing subscriptions directly, it uses pre-paid wallet balances that can be credited via the Adjustments API and billed in real time as usage occurs. This setup allows platforms to continue processing subscriptions through their existing PSP while gaining real-time usage tracking and flexible billing, and positions them to evolve toward a hybrid subscription and topups model as their needs grow. #### Implementation Guide[​](#implementation-guide "Direct link to Implementation Guide") ##### Reflect Subscription Payments in Credyt[​](#reflect-subscription-payments-in-credyt "Direct link to Reflect Subscription Payments in Credyt") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) When a subscription payment is received in your PSP, call the Adjustments API to credit the customer’s wallet according to the defined asset: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Monthly Subscription", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: 25, description: "Monthly Subscription", reason: "external_topup", expiresAt: "2024-07-29T15:51:28.071Z", metadata: { psp: "stripe", paymentIntent: "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L56) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Monthly Subscription", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` The wallet balance is updated as per the specified amount and asset. ##### Send Usage Events[​](#send-usage-events "Direct link to Send Usage Events") [API Reference](https://docs.credyt.ai/api/events-send-usage.md) As customers use your AI product, report usage events to Credyt. These events deduct from the wallet balance in real time: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "message_completed", "occurred_at": "2024-07-29T15:51:28.071Z", "subject": "chat_5f53d23a4958", "description": "Chat message completed", "data": { "model": "gpt-4-1", "input_tokens": 2353, "output_tokens": 34697 } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", events: [ { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", eventType: "message_completed", occurredAt: "2024-07-29T15:51:28.071Z", subject: "chat_5f53d23a4958", description: "Chat message completed", data: { model: "gpt-4-1", inputTokens: 2353, outputTokens: 34697, }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L11) ```python response = client.events.send_usage( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "message_completed", "occurred_at": "2024-07-29T15:51:28.071Z", "subject": "chat_5f53d23a4958", "description": "Chat message completed", "data": { "model": "gpt-4-1", "input_tokens": 2353, "output_tokens": 34697, }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_message_completed.py#L20) Wallet balances decrease in real time as usage is reported, giving you immediate visibility into consumption and remaining credits. ##### Final Notes[​](#final-notes "Direct link to Final Notes") * Platforms continue managing subscriptions with their existing PSP; Credyt does not replace subscription management. * Using pre-paid wallets allows for flexible unit conversions, real-time billing, and a smooth path toward hybrid subscription + topups models. * This approach is ideal for companies looking to add real-time usage tracking without overhauling their existing subscription flows. --- ### Topups Only Model Some AI platforms avoid subscriptions altogether and charge customers only when they add funds upfront. This model is straightforward, reduces credit risk, and works well for usage-heavy products where customers prefer a pay-as-you-go approach. This model is popular with consumer AI apps and prosumer tools (e.g., image, video, or avatar apps), as well as with infrastructure and API platforms that aim to limit credit risk and simplify billing with prepaid balances. With Credyt, you can implement top-ups in two ways: * **External top-ups** - process payments through your own PSP, then notify Credyt of the balance change via the Adjustments API. * **Credyt-powered top-ups** - use the Billing Portal (self-service UI) or Top-up API (platform UI + backend) to let customers add funds through Stripe Checkout. In both cases, usage events consume the wallet balance in real time. #### Implementation Guide[​](#implementation-guide "Direct link to Implementation Guide") #### Initialise Wallet Balance with a Top-up[​](#initialise-wallet-balance-with-a-top-up "Direct link to Initialise Wallet Balance with a Top-up") ##### Using Credyt's payment rails[​](#using-credyts-payment-rails "Direct link to Using Credyt's payment rails") * [API Reference Topups](https://docs.credyt.ai/api/top-ups-initiate.md). * [API Reference Billing Portal](https://docs.credyt.ai/api/top-ups-initiate.md) If you use Credyt’s payment rails, initiate the flow via [Billing Portal or the Top-up API](https://docs.credyt.ai/features/wallets-and-topups.md). For example, via Top-up API: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/top-ups ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "amount": 50, "currency": "USD", "description": "Image generation credits", "destination": { "account_name": "default", "asset": "USD", "exchange_rate": 1000000 }, "credit_expires_at": "2024-07-29T15:51:28.071Z", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt-failure", "metadata": { "order_id": "order_12345" } } ``` **Response** ```json { "id": "top_473cr1y0ghbyc3m1yfbwvn3nxx", "status": "initiated", "redirect_url": "https://billing.credyt.ai/api/sign-in?token=xyz", "created_at": "2024-07-29T15:51:28.071Z", "expires_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.topUps.initiate({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", amount: 50, currency: "USD", description: "Image generation credits", destination: { accountName: "default", asset: "USD", exchangeRate: 1000000, }, creditExpiresAt: "2024-07-29T15:51:28.071Z", returnUrl: "https://glitch.ai/account", failureUrl: "https://glitch.ai/callbacks/credyt-failure", metadata: { orderId: "order_12345", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/topUpsInitiateSample.ts#L11) **SDK response object** ```typescript const response = { id: "top_473cr1y0ghbyc3m1yfbwvn3nxx", status: "initiated", redirectUrl: "https://billing.credyt.ai/api/sign-in?token=xyz", createdAt: "2024-07-29T15:51:28.071Z", expiresAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.top_ups.initiate( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "amount": 50, "currency": "USD", "description": "Image generation credits", "destination": { "account_name": "default", "asset": "USD", "exchange_rate": 1000000, }, "credit_expires_at": "2024-07-29T15:51:28.071Z", "return_url": "https://glitch.ai/account", "failure_url": "https://glitch.ai/callbacks/credyt-failure", "metadata": { "order_id": "order_12345", }, }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/top_ups_initiate_initiate_topup_with_credits.py#L20) **SDK response object** ```python response = { "id": "top_473cr1y0ghbyc3m1yfbwvn3nxx", "status": "initiated", "redirect_url": "https://billing.credyt.ai/api/sign-in?token=xyz", "created_at": "2024-07-29T15:51:28.071Z", "expires_at": "2024-07-29T15:51:28.071Z", } ``` Response includes a `redirect_url` to Stripe Checkout. Redirect the customer to complete payment. ##### Using an external PSP[​](#using-an-external-psp "Direct link to Using an external PSP") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-create-adjustment.md) If you handle payments externally, reflect the top-up in Credyt via Adjustments API: * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/customers/cust\_473cr1y0ghbyc3m1yfbwvn3nxx/wallet/adjustments ```json { "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Ad-hoc usage", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0" } } ``` **Response** ```json { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z" } ``` ```typescript await client.customerWalletOps.createAdjustment("cust_473cr1y0ghbyc3m1yfbwvn3nxx", { transactionId: "3fa85f64-5717-4562-b3fc-2c963f66afa6", accountName: "default", asset: "USD", amount: 25, description: "Ad-hoc usage", reason: "external_topup", expiresAt: "2024-07-29T15:51:28.071Z", metadata: { psp: "stripe", paymentIntent: "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsCreateAdjustmentSample.ts#L122) **SDK response object** ```typescript const response = { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", createdAt: "2024-07-29T15:51:28.071Z", }; ``` ```python response = client.customer_wallet_ops.create_adjustment( customer_id="cust_473cr1y0ghbyc3m1yfbwvn3nxx", body={ "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "account_name": "default", "asset": "USD", "amount": 25, "description": "Ad-hoc usage", "reason": "external_topup", "expires_at": "2024-07-29T15:51:28.071Z", "metadata": { "psp": "stripe", "payment_intent": "pi_3RjbbNJNSIruR1rb0GwMGpH0", }, }, ) ``` **SDK response object** ```python response = { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2024-07-29T15:51:28.071Z", } ``` This adds $25 to the balance. #### Deduct Usage from the Wallet[​](#deduct-usage-from-the-wallet "Direct link to Deduct Usage from the Wallet") [API Reference](https://docs.credyt.ai/api/events-send-usage.md) Once a wallet has funds, usage is billed in real time. Each event reduces the available balance. * REST API * TypeScript SDK * Python SDK POST https://api.credyt.ai/events ```json { "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "message_completed", "occurred_at": "2024-07-29T15:51:28.071Z", "subject": "chat_5f53d23a4958", "description": "Chat message completed", "data": { "model": "gpt-4-1", "input_tokens": 2353, "output_tokens": 34697 } } ] } ``` ```typescript await client.events.sendUsage({ customerId: "cust_473cr1y0ghbyc3m1yfbwvn3nxx", events: [ { id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", eventType: "message_completed", occurredAt: "2024-07-29T15:51:28.071Z", subject: "chat_5f53d23a4958", description: "Chat message completed", data: { model: "gpt-4-1", inputTokens: 2353, outputTokens: 34697, }, }, ], }); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/eventsSendUsageSample.ts#L11) ```python response = client.events.send_usage( body={ "customer_id": "cust_473cr1y0ghbyc3m1yfbwvn3nxx", "events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "event_type": "message_completed", "occurred_at": "2024-07-29T15:51:28.071Z", "subject": "chat_5f53d23a4958", "description": "Chat message completed", "data": { "model": "gpt-4-1", "input_tokens": 2353, "output_tokens": 34697, }, }, ], }, ) ``` [View full sample on GitHub](https://github.com/credyt/sdk-python/blob/main/samples/events_send_usage_message_completed.py#L20) #### Check Wallet Balance[​](#check-wallet-balance "Direct link to Check Wallet Balance") [API Reference](https://docs.credyt.ai/api/customer-wallet-ops-get-customer-wallet.md) At any time, the platform can query balances: * 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.566678 }, { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234 } ] } ``` ```typescript await client.customerWalletOps.getCustomerWallet("cust_473cr1y0ghbyc3m1yfbwvn3nxx"); ``` [View full sample on GitHub](https://github.com/credyt/sdk-ts/blob/main/samples/walletsCustomerWalletOpsGetCustomerWalletSample.ts#L24) **SDK response object** ```typescript const response = { accounts: [ { id: "default:USD", name: "default", asset: "USD", available: 14.566678, }, { id: "default:TOK", name: "default", asset: "TOK", available: 993450234, }, ], }; ``` ```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.566678, }, { "id": "default:TOK", "name": "default", "asset": "TOK", "available": 993450234, }, ], } ``` --- ## Tools ### MCP Server The Credyt MCP Server connects AI assistants directly to your billing infrastructure. Once installed, you can create products, configure pricing, onboard customers, submit usage events, and inspect wallet balances. All through natural language, without leaving your editor. #### What is an MCP Server?[​](#what-is-an-mcp-server "Direct link to What is an MCP Server?") [MCP (Model Context Protocol)](https://modelcontextprotocol.io) is an open standard that lets AI assistants call external tools and APIs in a structured way. When an MCP server is connected to your AI client, the model can invoke those tools during a conversation, reading and writing real data on your behalf, rather than just generating code for you to run separately. Credyt's MCP Server exposes your billing operations as callable tools. Your AI assistant can manage pricing, customers, and analyze activity directly without switching context. #### What can Credyt's MCP Server do?[​](#what-can-credyts-mcp-server-do "Direct link to What can Credyt's MCP Server do?") * **Products & pricing**: create, version, and manage products with usage-based, fixed, or hybrid pricing. Simulate usage events to verify pricing before going live. * **Customers**: create and look up customers, update their details, and link them to your own external IDs. * **Subscriptions**: subscribe customers to products, activate or deactivate subscriptions, and upgrade or downgrade to different product versions. * **Wallets**: inspect wallet balances and drill into individual account details, including pending transactions. * **Usage events**: submit metered usage events, retrieve event details with generated fees and profitability stats, and review event history per customer. * **Charges & adjustments**: create ad-hoc charges or directly credit and debit wallet accounts for gifts, external top-ups, and refunds. * **Vendors**: set up vendors to track costs associated with usage events and measure profitability. * **Profitability**: query revenue, costs, and margin across products, customers, and vendors. * **Assets**: create and manage custom credit units (tokens, minutes, credits, etc.) with exchange rates. **Example prompts you can use once connected:** > "Create a $29/month Pro plan that includes 1,000 API credits, renewing monthly." > "Show me the wallet balance and recent usage for customer cust\_abc123." > "Simulate 500 `api_call` events against the Pro plan's default version." #### Prerequisites[​](#prerequisites "Direct link to Prerequisites") * A Credyt account — sign up at [app.credyt.ai](https://app.credyt.ai/api/sign-up) * A Credyt API key (found in the **Developers** section of the dashboard) * An MCP-compatible AI client (Claude Code, Claude Desktop, Cursor, Codex, Windsurf, Gemini CLI, or GitHub Copilot) * Node.js installed (required for the `npx`-based setup commands below) Live vs. test mode There is a single MCP endpoint: `https://mcp.credyt.ai`. Whether you're operating in live or test mode is determined by the API key you use — generate separate live and test keys from [app.credyt.ai](https://app.credyt.ai). #### How to use the MCP Server[​](#how-to-use-the-mcp-server "Direct link to How to use the MCP Server") * AI Coding Agents * Vibe Coding Tools The fastest setup path is `npx add-mcp`, which writes the MCP config for your client automatically. * Claude Code * Claude Desktop * Cursor * Codex * Gemini CLI * GitHub Copilot * Windsurf **Step 1 — Connect the MCP server:** ```bash npx add-mcp \ https://mcp.credyt.ai \ --header "Authorization: Bearer key_your_api_key_here" ``` **Step 2 — Install the Credyt plugin** (adds guided skills as slash commands): ```text /plugin marketplace add credyt/ai-tools /plugin install credyt@credyt/ai-tools ``` This gives you `/credyt:billing-setup`, `/credyt:billing-verification`, and `/credyt:billing-integration` as slash commands on top of the raw MCP tools. **Automatic setup via `add-mcp`:** ```bash npx add-mcp "npx mcp-remote https://mcp.credyt.ai --header Authorization:\${CREDYT_API_KEY}" \ --name credyt \ --env "CREDYT_API_KEY=Bearer key_your_api_key_here" \ -a claude-desktop -y ``` Replace `key_your_api_key_here` with your key, then restart Claude Desktop. **Manual setup:** open **Settings → Developer → Edit config** and add: ```json { "mcpServers": { "credyt": { "command": "npx", "args": [ "mcp-remote", "https://mcp.credyt.ai", "--header", "Authorization:${CREDYT_API_KEY}" ], "env": { "CREDYT_API_KEY": "Bearer key_your_api_key_here" } } } } ``` Restart Claude Desktop after saving. ```bash npx add-mcp \ https://mcp.credyt.ai \ --header "Authorization: Bearer key_your_api_key_here" ``` `add-mcp` will detect your Cursor installation and write the config automatically. ```bash npx add-mcp \ https://mcp.credyt.ai \ --header "Authorization: Bearer key_your_api_key_here" ``` ```bash npx add-mcp \ https://mcp.credyt.ai \ --header "Authorization: Bearer key_your_api_key_here" ``` ```bash npx add-mcp \ https://mcp.credyt.ai \ --header "Authorization: Bearer key_your_api_key_here" ``` `add-mcp` doesn't support Windsurf. Instead, add the Credyt server directly to `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "credyt": { "serverUrl": "https://mcp.credyt.ai", "headers": { "Authorization": "Bearer key_your_api_key_here" } } } } ``` Then install the Credyt skills from your terminal: ```bash npx skills add credyt/ai-tools ``` Vibe coding tools (Lovable, Bolt, Replit, V0) connect the MCP server through their settings UI rather than the command line. Once connected, you send a single prompt to install the Credyt skills and set up billing in one go — no terminal needed. * Lovable * Bolt * Replit * V0 **Step 1 — Add the MCP server:** Open **Settings → Integrations → MCP Servers** and add a new server: | Field | Value | | ------------- | ------------------------------ | | Name | `credyt` | | URL | `https://mcp.credyt.ai` | | Authorization | `Bearer key_your_api_key_here` | **Step 2 — Set up billing:** Start a new chat and send: ```text Run 'npx skills add credyt/ai-tools' — then set up my Credyt billing ``` **Step 1 — Add the MCP server:** Open the chat input, click **(+) → Connectors → Manage connectors → Custom MCP server** and add a new server: | Field | Value | | ------------- | ------------------------------ | | Name | `credyt` | | URL | `https://mcp.credyt.ai` | | Authorization | `Bearer key_your_api_key_here` | **Step 2 — Set up billing:** Start a new chat and send: ```text Run 'npx skills add credyt/ai-tools' — then set up my Credyt billing ``` **Step 1 — Add the MCP server:** Open **Integrations → MCP Servers for Replit Agent → Add MCP server**: | Field | Value | | ------------- | ------------------------------ | | Name | `credyt` | | URL | `https://mcp.credyt.ai` | | Authorization | `Bearer key_your_api_key_here` | **Step 2 — Set up billing:** Start a new chat and send: ```text Run 'npx skills add credyt/ai-tools' — then set up my Credyt billing ``` **Step 1 — Add the MCP server:** Open **Settings → MCP Connections → Add MCP**: | Field | Value | | ------------- | ------------------------------ | | Name | `credyt` | | URL | `https://mcp.credyt.ai` | | Authorization | `Bearer key_your_api_key_here` | **Step 2 — Set up billing:** Start a new chat and send: ```text Run 'npx skills add credyt/ai-tools' — then set up my Credyt billing ``` #### AI Skills[​](#ai-skills "Direct link to AI Skills") Credyt ships guided AI Skills that walk your assistant through complete billing workflows. Unlike the raw MCP tools, Skills provide step-by-step instructions that keep the AI on track for complex multi-step tasks. | Skill | What it does | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `pricing-strategy` | Guides you through defining your pricing strategy before configuring any billing tooling. | | `billing-setup` | Discovers your pricing model through a guided conversation, then configures products, assets, and pricing via MCP. Runs a full end-to-end billing cycle verification automatically. | | `billing-verification` | Tests the full billing cycle for a specific product — creates a test customer, funds their wallet, sends a usage event, and confirms the fee was charged correctly. | | `billing-integration` | Wires Credyt into your application code. Adds customer creation at signup, usage event tracking, balance checks, billing portal links, and balance display. | **Claude Code** — skills are available as slash commands via the plugin installed above: Pricing strategy ```text /credyt:pricing-strategy ``` Billing setup ```text /credyt:billing-setup ``` Billing verification ```text /credyt:billing-verification ``` Billing integration ```text /credyt:billing-integration ``` **AI coding agents** (Claude Desktop, Cursor, Codex, Windsurf, Gemini CLI, GitHub Copilot) — install skills first, then use the prompts below: ```bash npx skills add credyt/ai-tools ``` Pricing strategy ```text Help me define my pricing strategy with Credyt ``` Billing setup ```text Set up my billing with Credyt ``` Billing verification ```text Verify my Credyt billing is working correctly ``` Billing integration ```text Integrate Credyt billing into my app ``` **Vibe coding tools** (Lovable, Bolt, Replit, V0) — skills are installed and run in one prompt, no terminal step needed: Pricing strategy ```text Run 'npx skills add credyt/ai-tools --skill pricing-strategy' — then help me define my pricing strategy with Credyt ``` Billing setup ```text Run 'npx skills add credyt/ai-tools --skill billing-setup' — then set up my Credyt billing ``` Billing verification ```text Run 'npx skills add credyt/ai-tools --skill billing-verification' — then verify my Credyt billing is working correctly ``` Billing integration ```text Run 'npx skills add credyt/ai-tools --skill billing-integration' — then integrate Credyt billing into my app ``` #### Available tools[​](#available-tools "Direct link to Available tools") The Credyt MCP Server exposes 31 tools across 9 domains. Descriptions match the tool schemas returned to your AI client. ##### Customers[​](#customers "Direct link to Customers") | Tool | Description | | ----------------------------- | --------------------------------------------------------------------------------------- | | `create_customer` | Create a customer with optional product subscriptions and metadata. | | `get_customer` | Get a customer's full details including subscriptions, metadata, and external accounts. | | `list_customers` | List customers with optional filtering by external ID. | | `update_customer` | Update a customer's name, email, or external ID. | | `create_subscription` | Add a product subscription to an existing customer. | | `update_subscription` | Activate or deactivate a customer's subscription. | | `update_subscription_product` | Change the product version on a subscription to upgrade or downgrade the customer. | ##### Products[​](#products "Direct link to Products") | Tool | Description | | ---------------- | ---------------------------------------------------------------------------------------------- | | `create_product` | Create a new product with pricing. Products define what you bill for. | | `get_product` | Get a product's details including all versions and default version pricing. | | `list_products` | List products with optional filtering by code. | | `delete_product` | Delete or archive a product. Products with active subscribers are archived instead of deleted. | ##### Product versions[​](#product-versions "Direct link to Product versions") | Tool | Description | | ------------------------- | --------------------------------------------------------------------------------------------------------- | | `create_product_version` | Create a new version of an existing product with updated pricing, without affecting existing subscribers. | | `get_product_version` | Get details of a specific product version including its pricing configuration. | | `update_product_version` | Publish a draft version or make a published version the default. | | `archive_product_version` | Archive a product version. Archived versions cannot be modified or subscribed to. | ##### Wallets[​](#wallets "Direct link to Wallets") | Tool | Description | | -------------------- | ------------------------------------------------------------------------------------ | | `get_wallet` | Get a customer's wallet with account balances. | | `get_wallet_account` | Get detailed balances for a specific wallet account, including pending transactions. | ##### Usage events[​](#usage-events "Direct link to Usage events") | Tool | Description | | ---------------- | --------------------------------------------------------------------------------------------- | | `submit_events` | Submit usage events for a customer, identified by `customer_id` or `customer_external_id`. | | `get_event` | Get an event's details including generated usage fees and profitability stats. | | `list_events` | List usage events with optional filtering by customer, ordered by submission date descending. | | `simulate_usage` | Simulate usage events against a product version to test pricing before going live. | ##### Charges & adjustments[​](#charges--adjustments "Direct link to Charges & adjustments") | Tool | Description | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `create_charge` | Create an ad-hoc charge against a wallet account outside normal usage processing. | | `create_adjustment` | Directly credit or debit a wallet account. Use positive amounts to credit (gifts, top-ups, refunds) and negative amounts to debit. | ##### Vendors[​](#vendors "Direct link to Vendors") | Tool | Description | | --------------- | ------------------------------------------------------------ | | `create_vendor` | Create a vendor to track costs associated with usage events. | | `get_vendor` | Get a vendor's details. | | `list_vendors` | List vendors with optional filtering by external ID. | ##### Profitability[​](#profitability "Direct link to Profitability") | Tool | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `get_analysis` | Get profitability analysis for an account, including overview metrics, performance over time, breakdowns, and grouped stats. | | `list_customer_stats` | List profitability stats for all customers, sorted by gross revenue descending. Includes a summary aggregating stats across all customers. | | `get_customer_stats` | Get lifetime profitability stats for a customer: gross revenue, total costs, net revenue, and margin. | | `get_vendor_stats` | Get aggregated cost stats for a vendor, broken down by category. | ##### Assets[​](#assets "Direct link to Assets") | Tool | Description | | ---------------- | ------------------------------------------------------------------------------------------- | | `create_asset` | Create a custom asset (credits, tokens, coins, minutes, etc.) with optional exchange rates. | | `get_asset` | Get an asset's details including exchange rate history. | | `list_assets` | List all custom assets, sorted alphabetically by code. | | `add_asset_rate` | Add a new exchange rate for an asset. Closes the previous rate automatically. | | `quote_asset` | Get an exchange quote — how many asset units a given source amount buys. | *** For a deeper guide to integrating Credyt into your application using an AI coding assistant, see the [AI Integration Guide](https://docs.credyt.ai/ai-integration.md). --- ### Profitability via MCP Credyt's Profitability feature connects what you earn to what you spend, at the level where it matters most: individual products, customers, and vendor relationships. The MCP server makes that data directly accessible through your AI assistant, so you can query revenue, costs, and margin without building dashboards or writing queries. This page covers the profitability tools available through the MCP. For a conceptual overview of how Credyt models costs and calculates margin at the event level, see [Profitability](https://docs.credyt.ai/features/profitability.md). #### Available tools[​](#available-tools "Direct link to Available tools") | Tool | What it answers | | --------------------- | ------------------------------------------------------------------------------------------------------ | | `get_analysis` | Account-wide profitability broken down by product, event type, or cost category over a selected period | | `list_customer_stats` | All customers ranked by profitability — gross revenue, costs, net revenue, and margin | | `get_customer_stats` | Lifetime profitability for a single customer | | `get_vendor_stats` | Aggregated cost breakdown for a vendor, by category | #### Analysis[​](#analysis "Direct link to Analysis") `get_analysis` is the primary tool for understanding profitability across your business. It serves two related purposes: general business insight - understanding revenue mix, cost distribution, and performance trends - and pricing validation, surfacing whether your pricing structures are well-calibrated and where margin is being created or eroded. **Example prompts:** > "What was our net margin last month, broken down by product?" > "Show me which event types are losing money this quarter." > "Compare gross revenue and costs by cost category for the last 30 days, scoped to our LLM API product." > "Which product version has the worst margin this month?" ##### Primary and secondary category[​](#primary-and-secondary-category "Direct link to Primary and secondary category") The primary category sets the lens for the analysis - whether you want to understand performance across products, costs by event type, spend by model tier, or just see aggregate numbers for the period. This first answer often raises a second question. If a product is underperforming, what's driving it - a specific version, an event type with an unexpectedly high cost, a model tier that's consuming margin? If overall costs are up, which cost category is responsible, and which products is it concentrated in? The secondary category is how you drill into that: within each primary group, results are further broken down by a second dimension, letting you trace an outlier or an unexpected pattern to its source rather than stopping at the top level. Valid combinations: | Primary | Valid secondary options | | --------------- | ---------------------------------------- | | `product` | `version`, `event_type`, `cost_category` | | `event_type` | `product`, `cost_category` | | `cost_category` | `product`, `event_type` | For example, if the top-level view by product shows that your AI Agents product has a low margin, adding a secondary breakdown by `event_type` will surface which operation types within that product are driving the cost. If costs by `cost_category` show an expensive model tier, breaking down by `product` will tell you which products are routing to it and at what volume. You do not need to specify a secondary category upfront. Starting with the primary view and then drilling down with a follow-up prompt is a natural way to work through the analysis. ##### Filtering[​](#filtering "Direct link to Filtering") Two filters let you narrow the scope of the analysis before choosing a primary category. Product filter - scopes the entire analysis to a single product version. Useful when you want to focus on one product in isolation: understanding its cost structure, comparing its versions, or investigating a margin issue without noise from the rest of the catalogue. Events filter - controls which events are included: | Value | What's included | | ---------- | --------------------------------------------------- | | `all` | Every event, regardless of billing status (default) | | `billed` | Only events that generated a fee | | `unbilled` | Only events with no associated fee | Filtering to `unbilled` isolates events that generated costs but no revenue - test traffic, zero-price subscription events, or misconfigured products. ##### Sorting[​](#sorting "Direct link to Sorting") You can ask the assistant to sort results by net revenue, gross revenue, costs, net margin, or trend, in either direction. Sorting by net margin ascending, for example, immediately surfaces the least profitable products, event types, or cost categories for the selected period. #### Customer profitability[​](#customer-profitability "Direct link to Customer profitability") ##### List customer stats[​](#list-customer-stats "Direct link to List customer stats") list\_customer\_stats returns profitability stats for all customers over a selected period, defaulting to the last 30 days. Results include gross revenue, costs, net revenue, and margin per customer, with an aggregate summary across all customers. **Example prompts:** > "Which customers are unprofitable this month?" > "Show me the top 10 customers by net revenue for Q1." > "What's our overall margin across all customers this quarter?" > "List customers sorted by margin ascending - I want to see who we're losing money on." ##### Get customer stats[​](#get-customer-stats "Direct link to Get customer stats") get\_customer\_stats returns lifetime profitability for a single customer: gross revenue, costs, net revenue, and margin in USD. **Example prompt:** > "What's the lifetime margin for customer cust\_abc123?" #### Vendor costs[​](#vendor-costs "Direct link to Vendor costs") `get_vendor_stats` returns aggregated cost data for a specific vendor, broken down by cost category - typically the model or infrastructure tier your platform routes to. Cost categories are only as granular as the metadata your platform submits with usage events. If you include `model` in event cost metadata, the breakdown will reflect individual model tiers. See [Profitability](https://docs.credyt.ai/features/profitability.md#costs) for details on how to structure cost metadata. **Example prompts:** > "What did we spend with OpenAI last month, broken down by model?" > "How much did we spend on gpt-4o vs gpt-4o-mini this quarter?" > "Show me the cost breakdown for our Anthropic vendor over the last 90 days." > "Which model tier is driving the most cost from our primary vendor?" #### See also[​](#see-also "Direct link to See also") * [Profitability](https://docs.credyt.ai/features/profitability.md) - how Credyt models costs, cost attribution, and event-level margin calculation * [MCP Server](https://docs.credyt.ai/tools/mcp-server.md) - full tool list and setup instructions --- ## API Reference ### API #### [📄️Introduction](https://docs.credyt.ai/api/credyt-api.md) --- ### Create account Create a new connected account #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Get an account's details Returns a connected account's details #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### Get current account context Returns context about the current account based on the provided API key #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List accounts Returns a paged list of connected accounts #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Get analysis overview Get analysis overview #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 400 * 401 * 422 The request has succeeded. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Add a new asset buy rate Adds a new buy rate for an asset #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Create an asset Create a new custom asset #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Get an asset's details Returns an existing asset #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List assets Returns a paged list of assets sorted by code alphabetically #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Get a quote Helper to get a quote for an asset #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 400 * 401 * 422 The request has succeeded. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Create a portal session Creates a new session for the customer billing portal. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 400 * 401 * 422 The request has succeeded. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Credyt API Version: 1.0 Export * [OpenAPI Spec](https://docs.credyt.ai/openapi/openapi.1.0.yaml) #### Authentication[​](#authentication "Direct link to Authentication") * API Key: ApiKeyAuth | Security Scheme Type: | apiKey | | ---------------------- | ---------------- | | Header parameter name: | X-CREDYT-API-KEY | --- ### Create adjustment Adjustments allow you to directly impact the balance of an account outside of normal usage processing. This might be necessary to reflect out-of-bound operations such as refunds, or if you operate a hybrid setup and collect funds outside of Credyt. Every adjustment must have a corresponding `reason` that influences how revenue is ultimately recognized. The adjustment `transaction_id` is used as an idempotency key to ensure safe retries. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Create a charge Charges allow you to charge ad-hoc fees to an account outside of normal usage processing. The charge `transaction_id` is used as an idempotency key to ensure safe retries. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Get a customer's wallet account Returns the detailed balances of a specific account in a customer's wallet #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### Get credit grants for a wallet account Returns credit grants associated with the customer's account. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 The request has succeeded. The server could not understand the request due to invalid syntax. 404 Not Found --- ### Get a customer's wallet Returns the available balances of the accounts in a customer's wallet #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### Get a wallet transaction Returns the details of a wallet transaction #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List wallet transactions Returns a customer's wallet transactions. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Create a customer Create a new customer #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Add a subscription to a customer Adds a new subscription to a customer #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Add a subscription product Adds a product to a customer's existing subscription #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 404 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized 404 Not Found Client error --- ### Remove a subscription product Removes a product from a customer's existing subscription #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 404 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized 404 Not Found Client error --- ### Get a customer's details Returns a customer's details #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### Get a customer's stats Returns a customer's stats #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List customers Returns a paged list of customers. When `external_id` is provided, the response will be a 303 See Other redirect to the specific customer resource if a match is found, or a 404 Not Found if no match exists. When `email` is provided, the response will be a filtered list of customers with that email address (which may be empty if no match is found). #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### All customer stats Returns a paged list of customers with their profitability stats and an aggregate summary. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Update a customer Update a customer #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 404 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized 404 Not Found Client error --- ### Update a subscription Updates a customer's subscription #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 404 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized 404 Not Found Client error --- ### Update a subscription product Updates a customer's subscription product #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 404 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized 404 Not Found Client error --- ### Get an event's details Returns an event's details and any generated usage fees #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List events Returns a paged list of events ordered by submission date in descending order. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Submit events Submit usage events for a customer. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Archive a product version Archives an existing product version making it unavailable for subscription #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Create a product Creates a new product #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Update product Updates an existing product creating a new version #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Delete or archive a product Deletes an existing product. If the product has been used it will be archived. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Get a product's details Gets the details of an existing product and its versions #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List product subscribers Returns a paginated list of customers subscribed to this product. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Get a product version's details Get a version of a product. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List products Get all products #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### List product versions Get all product versions #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Simulate usage Simulate usage calculation for a product by sending test usage events #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 400 * 401 * 422 The request has succeeded. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Update a product version Update an existing version of a product. Only unpublished versions can be modified. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 409 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized 409 Conflict Client error --- ### Get a task's details Returns a task's events, stats, and per-vendor cost breakdown. The `taskId` is `{customer_id}:{subject}` — URL-encode the value before passing it (e.g. `cust_473cr1y0ghbyc3m1yfbwvn3nxx%3Apod_episode_5f53d23a`). #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List tasks Returns a paged list of tasks ordered by the specified sort field in descending order. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Get a top-up's details Returns an existing top-ups #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### Initiate top-up Initiates a top-up to a customer's wallet. #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Create a vendor Create a new vendor #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Get a vendor's details Returns a vendor's details #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### Get a vendor's stats Returns a vendor's stats #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List vendors Returns a paged list of vendors #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 The request has succeeded. --- ### Create a webhook destination Create a new webhook destination #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 422 The request has succeeded and a new resource has been created as a result. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Delete a webhook destination Delete a webhook destination #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 204 * 400 * 401 * 422 There is no content to send for this request, but the headers may be useful. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error --- ### Get a webhook destination's details Returns a webhook destination's details #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 The request has succeeded. 401 Unauthorized 404 Not Found --- ### List webhook events List webhook events with filtering and cursor-based pagination #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 The request has succeeded. 401 Unauthorized --- ### List webhook destinations Returns a paged list of webhook destinations #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 401 The request has succeeded. 401 Unauthorized --- ### Test a connected account webhook destination Test a webhook destination for a connected account #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 202 * 401 * 404 The request has been accepted for processing, but processing has not yet completed. 401 Unauthorized 404 Not Found --- ### Test connected account webhook destinations Test webhook destinations for a connected account #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 202 * 401 * 404 The request has been accepted for processing, but processing has not yet completed. 401 Unauthorized 404 Not Found --- ### Test a webhook destination Test a webhook destination #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 202 * 401 * 404 The request has been accepted for processing, but processing has not yet completed. 401 Unauthorized 404 Not Found --- ### Test webhook destinations Test webhook destinations #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 202 * 401 * 404 The request has been accepted for processing, but processing has not yet completed. 401 Unauthorized 404 Not Found --- ### Update a webhook destination Update a webhook destination #### Request[​](#request "Direct link to request") #### Responses[​](#responses "Direct link to Responses") * 200 * 400 * 401 * 422 The request has succeeded. The server could not understand the request due to invalid syntax. 401 Unauthorized Client error ---