Use this for fal-studio-class apps: Vite + React frontend, Express backend, user-supplied model/provider keys, generated image/video outputs, persisted galleries, and a fast-moving model catalog.
This umbrella replaces narrower one-session skills. The right abstraction is not "auth migration" or "dynamic uploads" alone, but the broader app class: a multi-user media-generation studio whose UI and storage model must stay resilient as providers, models, and asset flows change.
When converting a single-user prototype into a real app: - add signup/login - store per-user fal keys - persist gallery rows in SQLite - upload final outputs immediately to durable storage - prefer saved asset URLs over provider preview URLs everywhere user-visible
Recommended tables:
- users(id, email, password_hash, fal_key, created_at)
- assets(id, user_id, model, prompt, result_kind, storage_key, storage_url, params_json, created_at)
Safe user shape:
{ id, email, hasFalKey: !!fal_key }
Do not hardcode model assumptions from memory.
For each endpoint: 1. inspect the real OpenAPI schema 2. derive required fields, enums, defaults, upload requirements, and output kind from that schema 3. use human docs only as a supplement for descriptions/pricing/prompt hints
Represent uploads by semantic section keys, not one generic image input:
- generalReferences
- firstFrame
- lastFrame
- storyboardReference
Backend should use multer.any() and group files by field name before mapping them to API params.
A single global generating boolean is too weak for model-comparison workflows.
Use a lightweight frontend job queue:
- queued
- running
- completed
- failed
Preserve only compatible upload buckets across model switches. Users should not lose valid references just because they compare two nearby models.
Provider errors often arrive as nested objects, arrays, moderation payloads, or opaque strings.
Normalize in shared helpers on both backend and frontend:
- unwrap error, detail, message, msg, reason
- join validation arrays clearly
- map status classes to user-facing categories:
- 401 invalid/missing key
- 403 safety/policy or restricted capability
- 422 invalid params or blocked request
- 429 rate limit
- 5xx provider-side failure
Treat persisted assets as the source of truth.
Rules: 1. save metadata at write time 2. return stable asset URLs from the backend 3. derive absolute share URLs server-side 4. gallery and result viewers should prefer persisted URLs over preview URLs 5. never rely on temporary provider URLs for long-lived gallery/share behavior
Useful metadata to persist:
- result_kind
- storage_mode
- inference_time
- output_duration
- request params/model name/prompt
GET https://api.fal.ai/v1/account/billing?expand=credits; it returns the account username and current credit balance.403 on billing can therefore mean "valid generation key, insufficient admin scope," not a bad key.fal_admin (account broker only) and fal_runtime_api (generation adapter only) credentials. From the ADMIN key, POST /v1/keys can mint the dedicated runtime key and returns its secret once.generation_only mode when the customer supplies only an API key.401 across many endpoints usually means a bad user key, not a model activation issue.Generation failed.A provider product page can advertise a workflow that its generic public wrapper schema does not expose. Do not force the advertised semantics through superficially similar fields.
Seedream 5.0 Pro native layers are the concrete warning case (last verified 2026-07-23):
- fal's num_images requests independent completed generations; it is not a semantic layer count.
- Prompting fal's ordinary edit endpoint for layers while sending num_images: 1 returned one flattened image in two observed completed requests, even though the prompt asked for transparent layers.
- Do not substitute the public BytePlus ModelArk image endpoint. Its current capability table explicitly documents seedream-5-0-pro as single-image generation, says sequential generation is unsupported, and says passing sequential_image_generation causes an error.
- The often-quoted 15-image combined input/output ceiling belongs to Seedream 5.0 Lite / 4.5 / 4.0 sequential generation, not Pro. It cannot be used as a Pro billing cap.
- A top-level BytePlus data[] response shape does not prove that Pro can return multiple semantic layers; the documented Pro contract can return a one-item array.
- Until an exact public layer endpoint, request field, provider-enforced output ceiling, and observed transparent-layer response are established, fail closed before upload or paid provider activity. Preserve the local compositor/demo separately.
General rule: establish the exact endpoint, request switch, response fixture, billing ceiling, and output semantics from official docs or an observed provider response before implementing a marketing claim. A provider page or demo can advertise a private/orchestrated workflow that neither its wrapper nor upstream public API exposes.
Keep fal out of zero-field product signup and request it just in time when paid media work needs it. Use one Connect fal entry for both new and existing users because fal itself combines login and signup through Google, GitHub, or SSO. The fastest supported direct flow is human OAuth/terms → select account context → paste one ADMIN setup key → broker verifies username/balance → broker creates an API-only runtime key.
Agentcard Companies (agentcard.sh, not agentcard.ai) can provide embedded per-user connection, KYC, user-funded wallet, multi-use cards, and approvals. For browser-assisted fal funding, keep Hermes as planner/proposer while a restricted deterministic payment runner injects card details outside model context. Human turns remain OAuth identity, terms, CAPTCHA, KYC, 3DS, OTP, and exact spend approval. Obtain fal written authorization or a first-party partner provisioning path before production dashboard automation.
See references/fal-account-bootstrap-agentcard-onboarding.md for exact provider facts, connector states, two-key design, Agentcard funding flow, restricted browser runner boundary, managed-fal alternative, source links, and pitfalls.
imageFile instead of semantic upload bucketspreviewUrl over saved URLs in gallery/share flows[object Object]credentials: 'include' for cookie-authenticated fetchesgeneration_only