Authentication
Every request to the Dream Engine HTTP gateway carries a Bearer token
in the Authorization header. The SDK handles this — you only manage
the token itself.
Env vars
The SDK resolves api_key in this order:
api_key=argument toClient(...)/AsyncClient(...)DREAM_API_KEYenvironment variableDREAM_ENGINE_API_KEY(legacy alias, kept for compatibility)
export DREAM_API_KEY="dre_..."import dreamclient = dream.Client() # picks up DREAM_API_KEY# orclient = dream.Client(api_key="dre_...")If none of those are set, the client constructs without auth — useful for hitting a no-auth dev deployment locally.
Token format
Tokens look like dre_<43-char-base32>. The engine's auth layer hashes
them with SHA-256 and looks the hash up in a registry stored as a Modal
Secret. The raw token is never persisted on the server — if you lose
it, mint a new one.
Minting a key
Self-service signup at https://dreamengines.run/dashboard is the goal —
during the v0.2 beta, the engine team mints keys directly via the
internal scripts/create_api_key.py flow. Email
hello@dreamengines.run with your account info to get one.
Three things happen on mint:
- A
dre_<43-char>token is generated and printed once. - A Stripe customer is created.
- Its SHA-256 hash + customer_id are added to the
dreamengine-api-keysModal Secret. Optionally, the operator seeds an initial credit balance with--initial-credits 25.00(useful for compensated trials or partner onboardings).
There's no Stripe subscription on mint — the v0.2 billing model is prepaid credits topped up via Stripe Checkout. See Pricing & limits for the top-up flow.
Rate limits
A per-key in-memory token bucket runs as a sanity floor — catches pathological clients (infinite-loop bugs, runaway scripts) so they don't saturate a single container. It's deliberately loose; actual per-customer abuse is closed by the credits ledger (a 402 fires the moment the balance can't cover the next predict, before any GPU work).
Defaults on a fresh key: 50 qps refill, 200 burst. That's invisible for normal eval, MPC, and dataset-gen workloads. If you're a real-time MPC consumer hitting >50 req/sec sustained from a single key, email hello@dreamengines.run and we'll dial up your bucket.
When the bucket is empty, the engine returns 429 Too Many Requests
with a Retry-After header. The SDK retries automatically on 429,
honoring Retry-After. If retries exhaust (default: 3 attempts), the
SDK raises dream.RateLimitError — which carries the retry_after
attribute so you can sleep + retry yourself.
import dream, time try: rollout = client.models.get("dreamdojo-2b-gr1").predict(...)except dream.RateLimitError as e: time.sleep(e.retry_after or 1.0) # ... retry once, or backoff strategy of your choiceNeed higher limits? Email and we'll dial up your key.
Rotation
To rotate a key:
- Mint a new one for the same
customer_id— the registry holds multiple keys per customer, all sharing the same credit balance. - Update
DREAM_API_KEYin your deployments to the new token. - Revoke the old key (rare; for v0.2 we don't have a self-service revoke endpoint — contact the engine team).
Next
- Pricing & limits — flat per-frame pricing, prepaid credits, top-up flow, refunds.
- Errors & retries — full taxonomy:
AuthError,RateLimitError,InsufficientCreditsError,ModelNotFoundError,ValidationError,ServerError.