Dream Engines

Billing

The client.billing resource exposes the prepaid credits surface:

  • client.billing.balance() — current balance, in cents and dollars.
  • client.billing.topup(amount_usd=...) — create a Stripe Checkout session URL for a one-time top-up.
  • client.billing.transactions(limit=...) — recent ledger events (debits, credits, refunds), newest first.

All three also work on dream.AsyncClient.

balance()

Returns a dream.BillingBalance:

PYTHON
import dream
client = dream.Client() # reads DREAM_API_KEY
b = client.billing.balance()
print(b.customer_id) # 'cus_xxx'
print(b.balance_mils) # 49755 — integer mils, exact
print(b.balance_cents) # 498 — integer cents, half-up display
print(b.balance_usd) # 4.9755 — float dollars (exact)

The storage unit is mils (1 mil = $0.0001 = 1/100 of a cent). At the v0.2 list price of $0.0005/frame, every frame is exactly 5 mils, so a canonical 49-frame DreamDojo rollout debits exactly 245 mils ($0.0245) — no rounding loss. balance_cents is a half-up display helper; balance_usd is also derived from balance_mils and carries sub-cent precision.

topup(amount_usd=...)

Creates a Stripe Checkout session. Open the returned url in a browser to complete payment; once Stripe confirms, the engine's webhook credits your balance.

PYTHON
session = client.billing.topup(amount_usd=25.00)
print("Open this in a browser to pay:", session.url)

The returned dream.TopupSession carries:

  • session_id — Stripe Checkout session id (cs_...).
  • url — hosted Checkout URL.
  • amount_cents / amount_usd — what you asked for.
  • customer_id — your Stripe customer id.

Bounds

The SDK validates amount_usd client-side before any HTTP call:

LimitUSD
Minimum top-up$5
Maximum top-up$10,000

ValueError is raised on out-of-range. The engine enforces the same bounds server-side.

transactions(limit=...)

Returns recent ledger events as list[dream.BillingTransaction], newest first. Each event carries a signed amount_cents (negative for debits, positive for credits and refunds) and a running balance_after_cents snapshot — no need to replay the sequence to know the running balance.

PYTHON
for txn in client.billing.transactions(limit=20):
sign = "+" if txn.amount_cents > 0 else ""
print(f"{txn.kind:>7} {sign}${txn.amount_usd:.4f} {txn.detail}")
AttributeTypeNotes
idstrrequest_id for predicts (joins your own logs); Stripe event.id for top-ups
tsfloatPOSIX seconds
kindstr"debit", "credit", or "refund"
amount_milsintSigned, exact (storage unit; 1 mil = $0.0001)
amount_cents / amount_usdint / floatSigned display values
balance_after_milsintRunning balance after this event, exact
balance_after_cents / balance_after_usdint / floatDisplay
detailstrHuman-readable label

For exact ledger math, use amount_mils and balance_after_mils. The _cents and _usd derivations are for display ergonomics only — half-up cents lose sub-cent precision (e.g. 245 mils → 2¢) but amount_usd (mils-derived) shows the exact $0.0245.

Limits: 1 ≤ limit ≤ 200. Higher values silently clamp to 200.

Engine errors that triggered a refund show as a "refund" row alongside the original "debit" row — the audit trail is self-balancing, so the sum of amount_cents matches the current balance modulo any newer events.

Insufficient credits

When your balance can't cover the predicted cost of a predict / predict_batch, the engine returns 402 before the model fires. The SDK raises dream.InsufficientCreditsError:

PYTHON
try:
rollout = model.predict(start_frame=img, actions=acts)
except dream.InsufficientCreditsError as e:
print(f"balance: ${e.balance_usd:.4f}")
print(f"needed: ${e.requested_usd:.4f}")
session = client.billing.topup(amount_usd=25.00)
# Customer pays via session.url, then retry the predict.

InsufficientCreditsError is a subclass of dream.DreamError, so a single except dream.DreamError: catches it alongside the rest of the typed-error taxonomy.

Async parity

PYTHON
import dream
async def topup_if_low() -> None:
async with dream.AsyncClient() as client:
b = await client.billing.balance()
if b.balance_cents < 1000:
session = await client.billing.topup(amount_usd=25.00)
print("Top up here:", session.url)

Server endpoints

For users wiring the wire protocol directly:

  • GET /v1/billing/balance — authenticated; returns {customer_id, balance_cents, balance_usd}.
  • GET /v1/billing/transactions?limit=N — authenticated; returns {customer_id, transactions: [...]} (newest first, clamped to 200).
  • POST /v1/billing/topup — authenticated; body {"amount_cents": int}; returns {session_id, url, amount_cents, customer_id}.
  • POST /v1/billing/webhookunauthenticated by design. Stripe signs the payload with the webhook secret; the engine verifies. Idempotent on event.id. Configured by Stripe dashboard, not callable by SDK clients.

See Pricing & limits for the full billing model.