The one thing an agent needs is a programmatic inbox it can read (the AgentMail pattern). The API key is minted at signup but stays inert until the agent confirms a 6-digit code emailed to that inbox — so control of the inbox is what proves the workspace is really yours.
The loop
GET /v1/capabilities under the onboarding key, so a capabilities-first agent never has to read this page.
1. Discover
onboarding block: self_serve: true, the two steps below (both auth_required: false), and verification_gates_usage: true — i.e. the key does nothing until you verify.
2. Sign up
201 with api_key.key (an fl_… token) and otp_delivered. The key is inert: any authenticated call returns 403 email_not_verified until step 3. If otp_delivered is false, the email could not be sent — the key can’t be verified, so retry with a reachable inbox.
Calling signup again with the same email rotates the key and re-sends the OTP, so knowing an email alone never yields a working key.
3. Verify the emailed OTP
Read the 6-digit code from the inbox you signed up with, then:200, the key from step 2 works immediately. (Five wrong guesses burn the code; call /v1/signup again for a fresh one.)
4. Render
Waiting for a job to finish
An autonomous agent has no public endpoint to receive webhooks, so it waits by long-polling. CallGET /v1/renders/{id}?wait=25 (or GET /v1/tasks/{id}?wait=25): the request blocks until the job reaches a terminal status (completed, failed, or cancelled) or ~25 seconds elapse, then returns the current status. One call replaces a poll loop — which matters most over MCP, where every poll is a separate tool call. If it returns still in flight (Retry-After: 0 is set), just call again. The same ?wait= works for preview renders.
