Run the hosted script
Paste the primary command above. The script checks for an existing key before registering again.
Let Claude Code identify itself
If ~/.claude.json exists, the script sends the required identity fields to /cli/auth/agent-register.
Ask a research question
Source ~/.ditto_free_tier.env, then call POST /v1/free/questions and poll GET /v1/jobs/{job_id}.
Use the fallback hosted script:
curl -sL https://cat.fish.dog/scripts/free-tier-auth.sh | bash
If previous_key_revoked is true, the prior
key string is gone, but replacement free-tier keys owned by the
same Fish.Dog user can still access earlier free-tier jobs and
saved work.
| Path | Use it when | What happens |
|---|---|---|
| Agent register | Claude Code is installed and ~/.claude.json exists. |
Reads Claude Code identity, calls POST /cli/auth/agent-register, and writes FISHDOG_FREE_TIER_API_KEY to ~/.ditto_free_tier.env. |
| OAuth fallback | No Claude Code identity file, non-Claude-Code client, or agent-register is disabled in the target environment. | Uses POST /cli/auth/start + POST /cli/auth/complete through a browser-based Google loopback flow. |
Preferred hosted script
Run the hosted wrapper and let the script tell you whether a manual browser fallback is needed.
curl -sL https://cat.fish.dog/scripts/agent-register.sh | bash
Fallback hosted script
Use the older OAuth helper directly if you already know the zero-touch path will not apply.
curl -sL https://cat.fish.dog/scripts/free-tier-auth.sh | bash
Manual API request example for agent-register
curl -s -X POST "https://cat.fish.dog/cli/auth/agent-register" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"anthropic_account_uuid": "550e8400-e29b-41d4-a716-446655440000",
"claude_install_id": "4111c046280c9fe601466edf051cfa0ea8208fb93840463149a218989b1a294d"
}'
Optional enrichment fields:
anthropic_org_uuid,
anthropic_account_created_at,
anthropic_org_type, and
anthropic_billing_type.
Test pricing before launch
Use the shared panel to validate willingness-to-pay and price cliffs before product launch or an investment decision.
Separate trust problems from price problems
Ask open-ended follow-ups, then validate whether churn or resistance is driven by credibility, experience, or cost.
Iterate in the same session
Start with a broad pain-discovery question, identify the pattern, then ask a narrower validation question within minutes.
Ask a question
curl -s -X POST "https://cat.fish.dog/v1/free/questions" \
-H "Authorization: Bearer $FISHDOG_FREE_TIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question":"What frustrates you most about grocery delivery?"}'
The response returns a queue confirmation plus job_id, not the final persona answers.
Poll for answers
curl -s -X GET "https://cat.fish.dog/v1/jobs/<job_id>" \
-H "Authorization: Bearer $FISHDOG_FREE_TIER_API_KEY"
Final answers live in result.results[].reply when
status becomes finished. Partial
completions include result.partial and
result.pending_job_ids.
POST /v1/free/questionsGET /v1/jobs/{job_id}for jobs owned by the same free-tier user accountGET /v1/billing/usagefor live rate and quota snapshots
- Research group CRUD
- Study-management flows
- Billing admin or other paid-plan endpoints
Reference response shapes
{
"ok": true,
"status": "complete",
"api_key": "rk_free_...",
"org_uuid": "...",
"previous_key_revoked": false
}
{
"status": "finished",
"result": {
"partial": false,
"count": 12,
"results": [
{
"id": 1,
"uuid": "...",
"name": "...",
"reply": "...",
"assistant_message_id": 123
}
]
},
"meta": {
"free_tier": true
}
}
Receive a signed upgrade link
A quota-exhausted free-tier org-admin now receives a signed /upgrade?org=...&token=... link instead of a direct Checkout URL.
Authenticate in the browser
The upgrade page shows both Google OAuth and magic-link sign-in so the user can create the first browser session safely.
Complete Checkout and rotate keys
Stripe Checkout upgrades the org to paid billing, then the checkout webhook mints a user-facing paid rk_live_* key.
{
"error": {
"code": "key_rotated_post_upgrade",
"details": {
"refresh_command": "curl -sL https://cat.fish.dog/scripts/agent-register.sh | bash"
}
}
}
Claude Code skills can handle this contract more seamlessly, but
curl users and custom scripts should treat
agent-register.sh as the manual paid-key refresh path.
Start the session
Call POST /cli/auth/start or run the fallback hosted script.
Open Google login
Use the returned authorization_url in the browser and complete consent.
Complete the loopback callback
The CLI captures code and state from the loopback redirect, then calls POST /cli/auth/complete.
curl -sL https://cat.fish.dog/scripts/free-tier-auth.sh | bash
Exact OAuth fallback endpoint examples
curl -s -X POST "https://cat.fish.dog/cli/auth/start" \
-H "Content-Type: application/json" \
-d '{"provider":"google","redirect_uri":"http://127.0.0.1:53682/oauth/callback"}'
curl -s -X POST "https://cat.fish.dog/cli/auth/complete" \
-H "Content-Type: application/json" \
-d '{"session_id":"<session_id>","code":"<code>","state":"<state>"}'
The loopback redirect must stay on 127.0.0.1 or
localhost. For production, the app base URL is
https://cat.fish.dog.
How do I get the key if I already use Claude Code?
Run curl -sL https://cat.fish.dog/scripts/agent-register.sh | bash.
That is the preferred path. It reads ~/.claude.json,
calls POST /cli/auth/agent-register, and saves the key
locally.
What if I am not using Claude Code?
Use the fallback script or the manual /cli/auth/start +
/cli/auth/complete Google OAuth flow. The HTML page keeps
that flow documented, but it is the secondary path now.
Where do the final answers live?
Submit the prompt with POST /v1/free/questions, keep the
returned job_id, and read final persona replies from
result.results[].reply when
GET /v1/jobs/{job_id} returns
status: "finished".
Can I inspect limits or quota without asking a question?
Yes. GET /v1/billing/usage works with the same free-tier
key and returns current rate and quota information.
What does login_required mean?
The Anthropic account belongs to a non-Stripe paid
organization (invoiced, direct-pay). Do not keep
trying to mint a free-tier key. Send the user to
https://cat.fish.dog/auth/login so they can manage paid-plan API keys in
the signed-in UI.
Stripe-billed paid orgs behave differently:
POST /cli/auth/agent-register returns
status: "complete" with a managed paid
rk_live_* key (broader scopes) directly, no
login_required hop. This is the post-upgrade
refresh path — your agent gets a working paid key in one
round-trip.
What should Claude Code do after setup succeeds?
Confirm that FISHDOG_FREE_TIER_API_KEY is saved, ask the
first research question, poll the returned job until it finishes, and
then iterate with a sharper follow-up prompt.