Headless Signup
Agent-directed browser-backed account creation with 6 MCP tools.
The signup flow lets an agent coordinate Doow account creation while sensitive identity operations (OAuth, password) remain in secure browser handoffs.
Endpoint
POST https://mcp.doow.co/mcp/signupAuthentication
The signup flow uses a flow capability token:
| Tool | Auth |
|---|---|
signup_begin | None (unauthenticated) |
| All other signup tools | Authorization: Flow hs_cap_... |
The flow capability is returned by signup_begin and must be included in all subsequent requests.
Tools
| Tool | Type | Description |
|---|---|---|
signup_begin | mutation | Start browser-backed signup flow |
signup_status | query | Poll flow status |
signup_save_profile | mutation | Save allowlisted profile draft |
signup_open_handoff | mutation | Issue next browser handoff |
signup_join_request | mutation | Submit join request for existing org |
signup_claim_tokens | mutation | Claim MCP tokens (one-time per flow) |
Flow statuses
| Status | Meaning | Agent action |
|---|---|---|
WAITING_FOR_OAUTH | User is in the browser choosing their SSO provider | Wait and guide user to complete sign-in |
OAUTH_VERIFIED | User signed in with SSO and can complete their profile | Call signup_open_handoff to issue the completion handoff |
JOIN_REQUEST_REQUIRED | User's email domain matches an existing organization | Call signup_join_request to request access |
WAITING_FOR_ADMIN | Join request sent and awaiting admin approval | Wait for admin to approve |
WAITING_FOR_BROWSER | Flow is waiting on the browser step | Wait for the browser step to finish |
COMPLETED | Signup finished and session is established | Call signup_claim_tokens to get MCP tokens |
FAILED | Flow failed due to an error | Show error and offer to restart |
EXPIRED | Flow timed out before completion | Start a new flow with signup_begin |
WAITING_FOR_BROWSER belongs to the declared status set, but the current server keeps a flow that waits on the browser at OAUTH_VERIFIED with next_action set to OPEN_COMPLETE_SIGNUP, so you may not observe it yet. Treat it as a wait if it appears.
Step 1: Begin flow
Call signup_begin to start a new signup flow. This is the only unauthenticated call.
{"jsonrpc": "2.0","id": 1,"method": "tools/call","params": { "name": "signup_begin", "arguments": { "email_hint": "user@example.com", "company_hint": "Acme Inc" }}}Response:
{"flow_id": "signup_abc123","flow_capability": "hs_cap_xyz789","handoff_url": "https://app.doow.co/signup#headless_handoff=hs_handoff_...","expires_at": "2026-09-21T14:00:00Z"}Save flow_id and flow_capability for subsequent calls.
Step 2: Open browser handoff
Direct the user to handoff_url. The agent should open this automatically:
# macOSopen "https://app.doow.co/signup#headless_handoff=hs_handoff_..."# Linuxxdg-open "https://app.doow.co/signup#headless_handoff=hs_handoff_..."# Windowsstart "https://app.doow.co/signup#headless_handoff=hs_handoff_..."Step 3: Poll status
Poll signup_status every 2-3 seconds to track progress:
{"jsonrpc": "2.0","id": 2,"method": "tools/call","params": { "name": "signup_status", "arguments": { "flow_id": "signup_abc123" }}}Include the flow capability header:
curl -X POST https://mcp.doow.co/mcp/signup \-H "Authorization: Flow hs_cap_xyz789" \-H "Content-Type: application/json" \-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"signup_status","arguments":{"flow_id":"signup_abc123"}}}'Response:
{"flow_id": "signup_abc123","status": "WAITING_FOR_OAUTH","next_action": "OPEN_OAUTH","organization_state": null,"email_masked": null}Step 4: Handle status transitions
The agent should respond to each status:
| Status | Agent behavior |
|---|---|
WAITING_FOR_OAUTH | "Select a sign-in provider to continue..." |
OAUTH_VERIFIED | Optionally call signup_save_profile, then signup_open_handoff for "Complete password and terms..." |
JOIN_REQUEST_REQUIRED | Ask user, then call signup_join_request |
WAITING_FOR_ADMIN | "Waiting for admin approval..." |
WAITING_FOR_BROWSER | "Finish the browser step to continue..." |
COMPLETED | "Signup complete!" then call signup_claim_tokens |
FAILED | Show error, offer to restart |
EXPIRED | "Session expired." then call signup_begin |
Save profile (optional)
If the agent has profile data, it can pre-fill via signup_save_profile:
{"jsonrpc": "2.0","id": 3,"method": "tools/call","params": { "name": "signup_save_profile", "arguments": { "flow_id": "signup_abc123", "first_name": "Jane", "last_name": "Smith", "business_name": "Acme Inc", "work_place_role": "Finance Manager", "country_of_incorporation": "US", "default_spending_currency": "USD" }}}Join existing organization
If JOIN_REQUEST_REQUIRED, the user's email domain matches an existing org:
{"jsonrpc": "2.0","id": 4,"method": "tools/call","params": { "name": "signup_join_request", "arguments": { "flow_id": "signup_abc123", "message": "Hi, I'd like to join the team." }}}After submission, status transitions to WAITING_FOR_ADMIN until an org admin approves.
Issue completion handoff
When status is OAUTH_VERIFIED (with next_action: "OPEN_COMPLETE_SIGNUP"), the user needs to complete password and terms in the browser. Call signup_open_handoff to issue the completion URL:
{"jsonrpc": "2.0","id": 4,"method": "tools/call","params": { "name": "signup_open_handoff", "arguments": { "flow_id": "signup_abc123" }}}Response:
{"handoff_url": "https://app.doow.co/complete-signup#headless_handoff=hs_handoff_...","expires_at": "2026-09-21T14:30:00Z"}Open this URL for the user to complete password setup and accept terms. Poll signup_status until COMPLETED.
Step 5: Claim MCP tokens
When status: "COMPLETED" and next_action: "OPEN_ONBOARDING", claim tokens:
{"jsonrpc": "2.0","id": 5,"method": "tools/call","params": { "name": "signup_claim_tokens", "arguments": { "flow_id": "signup_abc123" }}}Response:
{"mcp_access_token": "eyJ...","mcp_refresh_token": "mcp_rt_...","flow_id": "signup_abc123"}Step 6: Continue to onboarding
Use the claimed MCP token to authenticate onboarding requests:
curl -X POST https://mcp.doow.co/mcp/onboarding \-H "Authorization: Bearer eyJ..." \-H "Content-Type: application/json" \-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"onboarding_status","arguments":{}}}'See Headless Onboarding for the complete onboarding flow.
Tool reference
-
signup_begin— Start a new browser-backed signup flow.Field Type Required Description email_hintstring No Pre-fill email field company_hintstring No Pre-fill company field Returns:
flow_id,flow_capability,handoff_url,status,expires_at -
signup_status— Check the current flow status.Field Type Required Description flow_idstring Yes The flow ID from signup_beginReturns:
flow_id,status,next_action,email_masked,organization_state,profile,error_codesignup_statusdoes not returnexpires_at; read the expiry fromsignup_beginorsignup_open_handoff.error_codeis present only when status isFAILED, andorganization_stateonly once the flow is routed to an organization. -
signup_save_profile— Save allowlisted profile fields.Field Type Required Description flow_idstring Yes The flow ID first_namestring No User's first name last_namestring No User's last name business_namestring No Company name work_place_rolestring No User's role country_of_incorporationstring No ISO country code default_spending_currencystring No ISO currency code financial_year_startstring No Month (e.g. "January") inactivity_periodinteger No Days -
signup_open_handoff— Issue a new browser handoff URL.Field Type Required Description flow_idstring Yes The flow ID Returns:
handoff_url,expires_atOnly valid while the flow is
OAUTH_VERIFIED. -
signup_join_request— Submit a request to join an existing organization.Field Type Required Description flow_idstring Yes The flow ID messagestring No Message to org admin -
signup_claim_tokens— Claim MCP tokens for onboarding (one-time per flow).Field Type Required Description flow_idstring Yes The flow ID Returns:
mcp_access_token,mcp_refresh_token,flow_id