Dream Engines

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:

  1. api_key= argument to Client(...) / AsyncClient(...)
  2. DREAM_API_KEY environment variable
  3. DREAM_ENGINE_API_KEY (legacy alias, kept for compatibility)
BASH
export DREAM_API_KEY="dre_..."
PYTHON
import dream
client = dream.Client() # picks up DREAM_API_KEY
# or
client = 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:

  1. A dre_<43-char> token is generated and printed once.
  2. A Stripe customer is created.
  3. Its SHA-256 hash + customer_id are added to the dreamengine-api-keys Modal 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.

PYTHON
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 choice

Need higher limits? Email and we'll dial up your key.

Rotation

To rotate a key:

  1. Mint a new one for the same customer_id — the registry holds multiple keys per customer, all sharing the same credit balance.
  2. Update DREAM_API_KEY in your deployments to the new token.
  3. 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.