{"version":"0.1.0","authentication":{"methods":[{"type":"api_key","description":"Create an API key via POST /tokens/ (requires JWT). Use it as: Authorization: Bearer faro_<key>","header":"Authorization","prefix":"Bearer faro_"},{"type":"jwt","description":"Obtain a JWT via POST /auth/login with email and password. Use it as: Authorization: Bearer <jwt>","header":"Authorization","prefix":"Bearer "},{"type":"partner_token","description":"Partner Token: Bearer faro_partner_... for partner integrations. Include X-Faro-User header to identify end users.","header":"Authorization","prefix":"Bearer faro_partner_"}],"note":"API keys (faro_ prefix) are recommended for programmatic access. JWTs expire after 60 minutes. Partner tokens (faro_partner_ prefix) are used for partner integrations with the X-Faro-User header.","fastest_start":"POST /auth/agent-signup with {\"email\": \"...\"} returns a usable faro_ API key in one call (no password, no human). The account starts unverified: self-hosted tools work immediately; verifying the emailed link unlocks the free data tier and paid tools."},"endpoints":[{"method":"POST","path":"/auth/agent-signup","description":"Self-serve agent signup. Email only, no password: creates an account and returns a usable faro_ API key plus a magic login_url for the human. Account starts unverified (self-hosted tools only) until the emailed link is clicked.","auth_required":false,"parameters":[{"name":"email","in":"body","type":"string","description":"Email for the account; receives the verification link"},{"name":"token_name","in":"body","type":"string","description":"Optional label for the issued API key"}]},{"method":"POST","path":"/auth/resend-verification","description":"Re-send the email-verification link for the authenticated account. Verifying unlocks the free data tier and paid namespaces.","auth_required":true,"parameters":[]},{"method":"POST","path":"https://skill.askfaro.com/skills/{skill}/run","description":"Run a skill end-to-end. Served by the hosted skill agent (NOT this API host): hand it an intent, it selects and runs the underlying tools, enforces your budget, and bills you. Always returns HTTP 200 with a SkillResult envelope (read `status`: success | failed | needs_input). Accepts faro_ keys, JWTs, and partner tokens (faro_partner_ with X-Faro-User). Raw tools are internal plumbing and are not directly callable; skills are the only execution surface.","auth_required":true,"parameters":[{"name":"skill","in":"path","type":"string","description":"Skill id (discover via GET /tools/search)"},{"name":"intent","in":"body","type":"object","description":"What you want, e.g. {\"prompt\": \"...\"} or a structured object"},{"name":"max_credits","in":"body","type":"number","description":"Optional hard spend cap; the run aborts rather than exceed it"},{"name":"confirm_above","in":"body","type":"number","description":"Optional soft ceiling; a run that would cross it returns a quote (status=needs_input)"},{"name":"continuation","in":"body","type":"string","description":"Optional signed token from a prior quote, to resume that plan"}]},{"method":"GET","path":"/tools/search?q={query}","description":"Semantic search for tools across all active namespaces. Returns an envelope {items, returned, limit, query}; ranked top-k, so raise limit or refine the query if nothing fits (see `note`). Prefer this over listing all tools.","auth_required":false,"parameters":[{"name":"q","in":"query","type":"string","description":"Search query"},{"name":"limit","in":"query","type":"integer","description":"Max results (default 10, max 50)"}]},{"method":"GET","path":"/tools/","description":"List public tools from active namespaces. PAGINATED: returns an envelope {items, total, returned, limit, offset, has_more, next_offset}. There are hundreds of tools, so the default page (50) is NOT the full set; page with offset until has_more is false, or use /tools/search to find tools by intent.","auth_required":false,"parameters":[{"name":"limit","in":"query","type":"integer","description":"Page size (default 50, max 200)"},{"name":"offset","in":"query","type":"integer","description":"Pagination offset; use next_offset from the previous response"},{"name":"namespace","in":"query","type":"string","description":"Filter by namespace slug"}]},{"method":"GET","path":"/tools/{namespace}/{tool_name}","description":"Get details for a specific public tool.","auth_required":false,"parameters":[]},{"method":"GET","path":"/namespaces/public","description":"List active namespaces in the marketplace. PAGINATED: returns an envelope {items, total, returned, limit, offset, has_more, next_offset}. The default limit (200) returns the whole catalog in one call; if has_more is true, page with offset.","auth_required":false,"parameters":[{"name":"limit","in":"query","type":"integer","description":"Page size (default 200, max 200)"},{"name":"offset","in":"query","type":"integer","description":"Pagination offset; use next_offset from the previous response"}]},{"method":"GET","path":"/namespaces/public/{slug}","description":"Get full namespace detail including all public tools, README, and pricing.","auth_required":false,"parameters":[]},{"method":"GET","path":"/docs/namespaces/{slug}","description":"Get agent-friendly documentation for a namespace and its tools.","auth_required":false,"parameters":[]},{"method":"GET","path":"/docs/namespaces/{slug}/{tool_name}","description":"Get agent-friendly documentation for a single tool with curl example.","auth_required":false,"parameters":[]},{"method":"GET","path":"/credits/balance","description":"Get current credit balance.","auth_required":true,"parameters":[]},{"method":"POST","path":"/credits/purchase","description":"Start a credit top-up via Paddle checkout. Returns a Paddle transaction ID for the overlay.","auth_required":true,"parameters":[{"name":"amount_usd","in":"body","type":"integer","description":"Whole US dollars to top up (e.g. 20 → 20,000 credits)"}]},{"method":"GET","path":"/invocations/","description":"List your past invocations.","auth_required":true,"parameters":[]},{"method":"POST","path":"/tokens/","description":"Create an API key for programmatic access.","auth_required":true,"parameters":[{"name":"name","in":"body","type":"string","description":"Descriptive name for the token"}]},{"method":"POST","path":"/partners/","description":"Request to become a Faro partner.","auth_required":true,"parameters":[]},{"method":"GET","path":"/partners/me","description":"Get partner dashboard (balance, users, usage).","auth_required":true,"parameters":[]},{"method":"POST","path":"/partners/me/token/regenerate","description":"Regenerate partner API token.","auth_required":true,"parameters":[]},{"method":"POST","path":"/partners/users","description":"Provision a user with optional credit budget.","auth_required":true,"parameters":[]},{"method":"GET","path":"/partners/users","description":"List all provisioned users.","auth_required":true,"parameters":[]},{"method":"GET","path":"/partners/users/{external_id}","description":"Get specific user details and balance.","auth_required":true,"parameters":[]},{"method":"PATCH","path":"/partners/users/{external_id}/budget","description":"Adjust a user's credit budget.","auth_required":true,"parameters":[]},{"method":"GET","path":"/partners/users/{external_id}/usage","description":"Get per-tool usage breakdown for a user.","auth_required":true,"parameters":[]}],"pagination":{"summary":"List endpoints (/tools/, /namespaces/public) return a paginated envelope, NOT a bare array. A full page is not necessarily the full result set.","envelope_fields":{"items":"The array of results for this page.","total":"Total number of results matching the query.","returned":"Number of items in this page.","limit":"Page size used.","offset":"Offset used.","has_more":"true when more results exist beyond this page.","next_offset":"Offset to request for the next page (null when has_more is false).","note":"Present only when has_more is true: a plain-language instruction for fetching the rest."},"how_to_page":"If has_more is true, repeat the request with offset=next_offset (same limit) until has_more is false. To find tools without paging the whole catalog, use GET /tools/search?q=<intent>.","search_note":"/tools/search is relevance-ranked top-k (no offset): it returns {items, returned, limit, query}. If the page is full and nothing fits, raise limit (max 50) or refine the query."},"credits":{"exchange_rate":"1,000 credits = $1.00 USD (1 credit = $0.001)","free_tier":"Self-hosted tools and tools flagged free_tier cost 0 credits within a monthly allowance (larger once the account is verified) and run even at a $0 balance. Beyond the allowance the normal price applies.","minimum_purchase":"Credits are purchased via Paddle checkout at POST /credits/purchase (amount_usd in whole US dollars).","billing":"Credits are deducted per tool invocation based on the tool's pricing configuration.","pricing_modes":{"fixed_per_request":"A fixed number of credits per invocation.","tool_returned":"Credits determined by the tool's response (e.g., based on token usage)."}},"verification":{"summary":"Skills are tiered by access_tier: 'unverified' (self-hosted, no external provider), 'verified' (free proxied external data), 'paid' (priced). A new account is unverified and may only run 'unverified' skills; anything else fails with error.code 'auth' until the email is verified. A completed purchase also counts as verified. Partner traffic is always treated as verified.","verify":"Click the link from POST /auth/agent-signup (or registration), or call POST /auth/resend-verification for a fresh one."},"errors":{"summary":"A skill run returns HTTP 200 with a SkillResult envelope; read `status` and, on failure, `error.code`. The HTTP codes below are the transport-level errors (auth) plus the legacy codes other endpoints still use.","401":"Unauthorized, missing or invalid authentication token.","error.code auth":"The account's email is not verified for this skill, or a credential is missing. Verify via the emailed link or POST /auth/resend-verification.","error.code insufficient_credits":"Out of credits, top up at POST /credits/purchase before running a paid skill.","error.code invalid_input":"The intent is missing a required field, or the run would exceed max_credits.","error.code not_found":"No such skill.","error.code upstream_failed":"The underlying tool server returned an error; auto-refunded when priced charge_on: success."},"cli":{"name":"askfaro-cli","install":"pip install askfaro-cli","description":"Command-line client that wraps every endpoint in this API. Outputs JSON when stdout is not a TTY (agent-friendly), with stable exit codes for errors.","buyer_commands":["askfaro auth login","askfaro search '<natural language query>'","askfaro describe <namespace>/<tool>","askfaro run <skill> '<intent>'   # e.g. askfaro run image 'a red bicycle'"],"publisher_commands":["askfaro publisher register --display-name '<name>'","askfaro ns quick-setup --namespace <slug> --mcp-url <url>","askfaro init <slug>            # writes faro.yaml","askfaro push --publish         # save listing + submit for review","askfaro ns check <slug>        # local readiness check"],"agent_usage_hint":"Recommended for agents that can run shell commands, `askfaro search` returns each hit's id and schema in the same call, so you can pick a skill and `askfaro run` it without a second lookup."}}