Imperal Docs
Billing & Earnings

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_share

The split depends on your developer tier (see Developer Tiers for caps + break-even math):

TierSplit (dev / platform)Annual cost
explorer (default, free)70 / 300 — automatic at signup
indie80 / 209,000 tokens / year
studio85 / 1529,000 tokens / year
partner95 / 579,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 this

Indie 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 tokens

Same 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 tokens

See 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:

WhereRow writtenMeaning
Redis wallet (Lua)DECRBY imperal:wallet:{user_id}User pays tokens immediately
Stream eventXADD imperal:billing:eventsAudit append; consumer-readable
token_ledger2 rows per transactionDouble-entry: user side + platform side
developer_earnings1 rowevent_id, developer_id, app_id, user_id, tool_name, action_cost, developer_share, platform_share
Redis dev-cacheINCRBY 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

ScenarioWhy
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 handlerSkeletons are free, web-kernel-driven; not billed
User invokes a @ext.panel handlerSame — 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/earnings

Response:

{
  "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=30

Response:

{
  "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 payout

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

On this page