Revenue & Earnings
How the tier-based revenue split works, how earnings are tracked, and where to see them
The revenue split
Every paid action call generates earnings split between you (the developer) and the Imperal platform:
total_cost = base_price + platform_fee (what user pays)
developer_share = floor(total_cost × revenue_split_dev / 100)
platform_share = total_cost - developer_shareThe split depends on your developer tier (see Developer Tiers for caps + break-even math):
| Tier | Split (dev / platform) | Annual cost |
|---|---|---|
| explorer (default, free) | 70 / 30 | 0 — automatic at signup |
| indie | 80 / 20 | 9,000 tokens / year |
| studio | 85 / 15 | 29,000 tokens / year |
| partner | 95 / 5 | 79,000 tokens / year (admin-promoted) |
Existing apps keep their currently-set revenue_split_dev even after tier upgrade — to bump an active app, Pause → Edit pricing → admin re-approval.
Example calculations
Non-BYOLLM user, paid extension at base_price=5, platform_fee=2. Numbers depend on your tier:
Explorer tier (70%):
total_cost = 5 + 2 = 7 tokens
developer_share = floor(7 × 70 / 100) = 4 tokens ← you earn this
platform_share = 7 - 4 = 3 tokens ← Imperal earns thisIndie tier (80%):
total_cost = 5 + 2 = 7 tokens
developer_share = floor(7 × 80 / 100) = 5 tokens ← 1 more per call vs explorer
platform_share = 7 - 5 = 2 tokensSame setup, BYOLLM user (platform_fee zeroed), explorer tier:
total_cost = 5 + 0 = 5 tokens
developer_share = floor(5 × 70 / 100) = 3 tokens
platform_share = 5 - 3 = 2 tokensSee BYOLLM Pricing for the full impact on your revenue mix.
What gets written when a user calls your extension
Each call generates four database/cache mutations atomically:
| Where | Row written | Meaning |
|---|---|---|
| Redis wallet (Lua) | DECRBY imperal:wallet:{user_id} | User pays tokens immediately |
| Stream event | XADD imperal:billing:events | Audit append; consumer-readable |
token_ledger | 2 rows per transaction | Double-entry: user side + platform side |
developer_earnings | 1 row | event_id, developer_id, app_id, user_id, tool_name, action_cost, developer_share, platform_share |
| Redis dev-cache | INCRBY imperal:developer:earnings:{dev_id} | Fast-read cache of running total |
All idempotent on event_id — replays / consumer restarts don't double-credit.
When you DON'T earn
| Scenario | Why |
|---|---|
Your pricing_model == 'free' | developer_share = 0 is recorded for usage analytics, but no tokens flow |
Your app status != 'active' (draft/suspended/pending_review) | _record_earnings skips entirely |
User invokes a @ext.skeleton handler | Skeletons are free, web-kernel-driven; not billed |
User invokes a @ext.panel handler | Same — panel renders are free |
The action is a read from __system__ (hub_chat) | Not your extension — web-kernel-internal |
| The action's wallet deduct returns -1 (insufficient balance) | Call rejected before reaching your handler |
| Saga compensation refunds the user (TopUpWorkflow failed mid-flight) | Reversed in token_ledger |
Viewing your earnings
Dev Portal → My App → Earnings tab
Shows:
- Total earned (all time) —
SUM(developer_share) FROM developer_earnings WHERE developer_id=:you - Total platform share — for transparency on Imperal's cut
- Pending payout —
earned − paid_or_approved - Paid out —
SUM(amount_tokens) FROM developer_payouts WHERE status IN ('approved','paid')
Dev Portal → My App → Analytics tab
Per-app, configurable time window (7d / 30d / all):
- Actions count
- Revenue (developer_share sum)
- Unique users (DISTINCT user_id)
API: GET /v1/developer/earnings
curl -H "Authorization: Bearer $YOUR_JWT" \
https://auth.imperal.io/v1/developer/earningsResponse:
{
"total_earnings": 12450,
"total_platform_share": 0,
"pending_payout": 9450,
"paid_out": 3000
}API: GET /v1/developer/apps/{app_id}/analytics?days=30
curl -H "Authorization: Bearer $YOUR_JWT" \
https://auth.imperal.io/v1/developer/apps/my_app/analytics?days=30Response:
{
"app_id": "my_app",
"period_days": 30,
"actions": 1234,
"revenue": 9450,
"unique_users": 87
}Currency conversion
Earnings are in tokens, not USD directly. Token-to-USD conversion happens at payout time, using the plan's topup_rate (default $0.001 per token = $1 per 1000 tokens). So:
9450 tokens × $0.001 = $9.45 USD payoutThe conversion rate is fixed at the moment you request the payout — fluctuations in pricing after that don't affect already-requested payouts.
What happens when a user refunds a top-up
Saga compensation flow (TopUpWorkflow): if Stripe captures funds but Imperal can't credit the wallet (e.g. Redis outage), the workflow auto-refunds Stripe. Your earnings rows that consumed those tokens are NOT clawed back — they were earned legitimately for actions actually performed; the user just lost the top-up that hadn't been spent yet.
For Stripe disputes / chargebacks (user disputes after spending), admin intervenes manually — developer_earnings may be adjusted with admin_note. Rare but documented.