---
name: "fetchbean"
description: "Use fetchbean when a task needs live external data the built-in tools can't get, or the user's own connected accounts. Read pages the built-in fetch fails on: x.com/Twitter, Reddit, LinkedIn, Instagram, JS-heavy SPAs, or anything that returned a 403 or bot interstitial. Run live search for recency-sensitive asks: latest, today, this week, just released, current price or status, or after a date. Act on the user's connected services phrased 'my <service>': 'my Linear issues', 'my PostHog or HogQL analytics', 'my Stripe, Dodo, or RevenueCat payments or refunds', 'my Fireflies meetings and action items', 'my Notion', 'my GitHub or GitLab', 'my Sentry', 'my Slack, Cloudflare, Supabase, or Render', read or write, one key. Catalog is live: run GET /discover?q=<task> before assuming a tool is missing. Also use when the user says fetchbean. Not for ordinary public pages, docs, or evergreen searches the built-in WebFetch or WebSearch already handle."
---

<!-- Generated from the fetchbean registry by services/api/scripts/gen-skill.ts. Do not edit by hand. -->

# fetchbean

> The tool layer for AI agents. One key for live web tools and the user's own connected SaaS accounts: clean, normalized tools over plain HTTP or MCP, with prepaid credits and admission-time spend controls. Provider failures and timeouts are billed zero.

## Install

Recommended: install this as a skill file in your agent's skills directory (no server to run).

```bash
# 1. save the skill file into YOUR agent's skills folder
#    Claude Code: ~/.claude/skills   Codex: ~/.codex/skills   (or wherever your agent loads skills)
SKILLS=~/.claude/skills        # set this to your agent's skills dir
mkdir -p "$SKILLS/fetchbean"
curl -fsSL https://fetchbean.com/skill.md -o "$SKILLS/fetchbean/SKILL.md"

# 2. save your key where any shell can read it (get it at https://fetchbean.com/app)
mkdir -p ~/.config/fetchbean
printf '%s' 'fb_...' > ~/.config/fetchbean/key
chmod 600 ~/.config/fetchbean/key
```

That is the whole setup. The HTTP tools below read your key from that file, which works in any shell (including the non-interactive shell an agent runs commands in). A `FETCHBEAN_API_KEY` env var, if you set one, takes precedence. Want native typed tools instead? Use the MCP server (see the MCP section at the end); it is an alternative, not a requirement.

## Base URL

```
https://api.fetchbean.com
```

## Authentication

Send your key on every request as the `X-API-Key` header, read from the file you saved (env var
wins if set). This one expression works first-try in any shell:

```bash
-H "X-API-Key: ${FETCHBEAN_API_KEY:-$(cat ~/.config/fetchbean/key 2>/dev/null)}"
```

Prefer to set it yourself? Export `FETCHBEAN_API_KEY`, or add it to Claude Code's `settings.json` `env` block (or Codex's `config.toml`); the expression above picks it up automatically.

Get a key at https://fetchbean.com/app (or email hi@fetchbean.com).

## Conventions

- Curated tools are `POST`, JSON in / JSON out. A few first-party utilities are plain `GET`; the rest are reached with `POST /v1/run` — each one below shows the exact call to make.
- Success returns the data directly with status `200`. Billing and trace ride in headers:
  `x-credits-charged` and `x-request-id`. There is no envelope around the body.
- Failure returns `{ "error": { "type", "code", "message", "retryable", "billable" } }` with a 4xx/5xx status and `x-request-id`.
- Provider failures and timeouts cost **zero** credits (the hold is refunded).
- Optional `Idempotency-Key` header makes a call exactly-once (safe to retry).

## When to use fetchbean over built-in tools

- **Pages a plain fetch can't reach.** Use fetchbean when a fetch or web read came back 403, a bot check, a captcha, or an empty JS shell (x.com, Reddit, LinkedIn and other client-rendered pages).
- **Recency-sensitive search.** Use fetchbean when the answer is recency-sensitive (latest, today, this week, current price or status, after a date) and your own knowledge may be stale.
- **The user's own accounts.** Use fetchbean when the user says "my <service>" (my Linear, my Stripe, my Notion, my Sentry): fetchbean holds their connected credential, so no per-service token is needed.
- **If a built-in fetch returns a 403 or an interstitial, retry the URL with fetchbean** (`read`, or `firecrawl_scrape` for JS-heavy pages).
- Ordinary public pages and evergreen searches: just use the built-in tools.

## Discovery (start here)

The catalog grows over time, so the curated list below is a snapshot, not the limit. Before assuming fetchbean can't do something, ask the current catalog (public, no key needed):

- `GET /discover?q=<task>`: ranked tools for a task, each with its provider, endpoint, and params (e.g. `?q=web search` or `?q=llm pricing`). Call one with `POST /v1/run` (or its curated tool); add `&meta=1` for credits/category. Use `GET /catalog` or `https://docs.fetchbean.com/openapi.json` for full input schemas.
- `GET /catalog`: the full, current provider + method catalog.

## Connections

Tools that act on **your own** provider account need a paste-key or OAuth connection at https://fetchbean.com/app (Connections tab). Provider API keys and OAuth tokens are stored encrypted, injected server-side, and not returned. Calling one before connecting returns a `credential_required` error.

Agent-subscription connections are separate credentials for Codex, Claude Code, or Antigravity. An org API key can retrieve an existing agent-subscription credential with `GET /v1/connections/{provider}/credential` and update it with `POST /v1/connections/{provider}/credential`, which supports unattended runners. These routes never return provider API keys or OAuth tokens.

Connected providers currently include: OpenRouter, SubmitForBacklinks, DEV Community, Fireflies, PostHog, Linear, RevenueCat, Expo, GitHub, Better Stack, Tailscale, GitLab, Notion, Dodo Payments, Spaceship, Supabase, Cloudflare, Stripe, Slack, Discord, Sentry, Trakt, Conductor, Clerk, Buffer, Bluesky, Render, Cal.com, Canny, ElevenLabs, Sarvam AI, Chatwoot, Intercom, Plain, Nomads.com, DigitalOcean, Monkeytype, Microsoft Clarity, Gemini, Calendly, Crisp, Miro, Replicate, Google Workspace (gws), Resend, Loops, Bing Webmaster, Strale. Find the exact tool for a task with `GET /discover?q=<task>`.

## Core tools

The most-used tools, one line each. This is a snapshot to get started; `GET /discover?q=<task>` returns the current set with provider, endpoint, and params. Use `GET /catalog` or `https://docs.fetchbean.com/openapi.json` for full input schemas.

- **search**: Web, news, or research-paper search with domain include/exclude lists, a freshness window or date range, and country/language targeting. Pass intent (why you are searching) for better-ranked results. `POST /v1/search` · from 2 credits · input: `query`, `max_results?`
- **read**: Read up to 10 URLs in one call as markdown, html, or a structured tree. CSS selectors scope what is extracted, and ttl accepts a cached copy instead of a live fetch. `POST /v1/read` · from 2 credits · input: `url`, `max_chars?`
- **firecrawl_scrape**: Scrape a URL to clean, LLM-ready markdown with JS rendering. Handles dynamic, script-heavy pages a plain reader misses. `POST /v1/firecrawl_scrape` · from 50 credits · input: `url`, `formats?`, `onlyMainContent?`
- **linear_issues**: List issues, filtered by team, state, assignee, or priority. `POST /v1/linear_issues` · 5 credits · input: `first?`, `team_key?`, `assigned_to_me?`, `state_type?`, `priority?`, `filter?`
- **github_repos**: A user's public repositories, newest-pushed first (stars, language, description). `POST /v1/github_repos` · 5 credits · input: `login`, `first?`
- **notion_search**: Full-text search across pages and databases. filter='page'|'database' narrows the object type. `POST /v1/notion_search` · 5 credits · input: `query?`, `filter?`, `page_size?`, `start_cursor?`
- **posthog_query**: Run a HogQL/SQL query over your PostHog events, persons, and analytics. The main PostHog read tool. `POST /v1/posthog_query` · 5 credits · input: `query`, `project_id?`

Example:

```bash
curl https://api.fetchbean.com/v1/search \
  -H "X-API-Key: ${FETCHBEAN_API_KEY:-$(cat ~/.config/fetchbean/key 2>/dev/null)}" \
  -H "Content-Type: application/json" \
  -d '{"query":"best vector databases","max_results":5}'
```

## First-party (fetchbean-hosted)

Small utilities served directly by fetchbean (no upstream provider).

- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts","input":{…}}` · Host and share a web page: publish a rendered markdown or interactive HTML page (report, dashboard, landing page, chart, slides, mini-app) to a shareable fetchbean URL a human opens in a browser. fetchbean handles the styling (Tailwind + a base stylesheet) and hosting; you send the content. Returns the link. For a completed local PDF, DOCX, PPTX, or XLSX, use the multipart file-artifact flow in the guide. (10 credits) · params: `title`, `type`, `content`, `visibility?`, `ttl?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/update","input":{…}}` · Revise an existing artifact in place (same URL). The prior version is kept for rollback. (3 credits) · params: `id`, `content`, `title?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/patch","input":{…}}` · Surgically edit an artifact with find/replace edits instead of resending the whole body — same URL, a version is snapshotted first. Best for small changes to a large artifact. (3 credits) · params: `id`, `edits`, `replace_all?`, `title?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/list","input":{…}}` · List your published web and file artifacts with durable ids, links, lifecycle state, engagement, and file metadata. Returns 100 at a time by default (500 max) alongside `total`, so page with limit + offset when total exceeds what came back. (1 credit) · params: `limit?`, `offset?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/mcp-servers","input":{…}}` · Search the third-party MCP server directory: what exists, who publishes it, whether it is remote, and how maintained it is. These are servers a user installs in their own client, not tools fetchbean runs. (1 credit) · params: `q?`, `category?`, `tag?`, `limit?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/get","input":{…}}` · Fetch a web artifact's content or a file artifact's metadata and authenticated exact-byte download URL. (1 credit) · params: `id`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/delete","input":{…}}` · Permanently delete an artifact and its version history. (1 credit) · params: `id`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/visibility","input":{…}}` · Change an artifact between unlisted (anyone with the link) and private (your org only). (1 credit) · params: `id`, `visibility`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/share","input":{…}}` · Grant viewer access to specific email addresses. Restricted viewers sign in with the invited address. (1 credit) · params: `id`, `emails`, `notify?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/shares","input":{…}}` · List the people who can open a restricted artifact. (1 credit) · params: `id`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/unshare","input":{…}}` · Remove one email address from an artifact's viewer list. (1 credit) · params: `id`, `email`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/rollback","input":{…}}` · Restore a prior version of an artifact (defaults to the most recent), keeping the same URL. Non-destructive: the current body is snapshotted first, so history is preserved and the restore is reversible. (3 credits) · params: `id`, `version_id?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/versions","input":{…}}` · The version timeline of an artifact (newest first): version id, title, and when it was saved. (1 credit) · params: `id`
- `GET /v1/quotes/random` · A random quote with its author. (1 credit) · params: none
- `GET /v1/jokes/random` · A random safe joke, optionally filtered by category, type, or search text. (1 credit) · params: `category?`, `type?`, `contains?`
- `GET /v1/facts/random` · A random fact with its source. (1 credit) · params: none
- `GET /v1/quotes` · Paginated list of quotes. (5 credits) · params: `limit?`, `skip?`
- `GET /v1/uuid` · Generate one or more UUIDs. (1 credit) · params: `count?`
- `GET /v1/email/deliverability` · Validate an email: syntax, DNS deliverability (MX), and disposable/free-provider/typo signals. (5 credits) · params: `email`, `dns?`, `typo?`, `disposable?`, `freeProvider?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/domain","input":{…}}` · Is a domain available? Plus registrar, created/expiry dates, and nameservers (via RDAP). (5 credits) · params: `domain`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/sitemap","input":{…}}` · Find a site's sitemaps (robots.txt + common paths) and extract its URLs. (5 credits) · params: `url`, `extract_links?`, `max_urls?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/youtube/transcript","input":{…}}` · Fetch a YouTube video's transcript: timed segments plus the joined plain text, with the title and channel. No key and nothing to connect. Pass lang for a specific caption track; if that track is missing, the error names the ones the video does have. (5 credits) · params: `url`, `lang?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/dns","input":{…}}` · Resolve a domain's DNS records (A/AAAA/MX/TXT/NS/CNAME/SOA/CAA/SRV). Pass types to limit. (5 credits) · params: `domain`, `types?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/geocode","input":{…}}` · Turn a place name into coordinates, with country, region, timezone and population. Answers from an index bundled with fetchbean rather than an upstream service, so an exact name match ranks first: asking for Leh gives Leh in Ladakh, not the much larger Le Havre. Historic and local names work too, so Bombay finds Mumbai. Each result says whether it matched the name, an alias, or a prefix. Covers settlements over 15,000 people. (5 credits) · params: `name`, `limit?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/geocode/reverse","input":{…}}` · What is at a set of coordinates: the nearest known settlements with their distance in km, closest first. Answers from the bundled index, so it works without an upstream call. (5 credits) · params: `latitude`, `longitude`, `limit?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/read","input":{…}}` · Fetch any URL and get back what it actually is, parsed: an article's text without the navigation, a PDF's text with its page count, a JSON body, an RSS or Atom feed as items, or a description of a binary file. If the page did not really load — a bot wall, a captcha, a client-rendered shell — it says so instead of handing back the markup as though it were the content, and a scanned PDF says it has no text layer rather than coming back empty. (5 credits) · params: `url`, `max_chars?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/url/meta","input":{…}}` · All metadata for a page: title, full meta tags, OpenGraph + Twitter cards, JSON-LD, icons, canonical. (5 credits) · params: `url`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/http/inspect","input":{…}}` · A URL's status, response headers, redirect chain, content-type, and security headers (no body). (5 credits) · params: `url`, `method?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/verify/image","input":{…}}` · Is an image AI-generated? Returns a clear is_ai_generated boolean + confidence, with every signal under meta: C2PA Content Credentials, EXIF/XMP tags, and a light forensic pass. Runs locally, no key. A positive is strong evidence; a negative is not proof a photo is real. (10 credits) · params: `url?`, `image_base64?`
- `GET /v1/llm/pricing` · Full LiteLLM row per model: token prices, tiered/batch rates, context windows, capability flags. Filter by model/provider/mode. (1 credit) · params: `model?`, `provider?`, `mode?`, `contains?`, `limit?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/models/search","input":{…}}` · Search every model across every host: filter by maker, by capability, by price ceiling or by intelligence floor. Answers 'cheapest model above quality X' and 'what supports computer use under $2 per 1M', which no single provider's own API can. (1 credit) · params: `q?`, `creator?`, `capability?`, `max_price_in?`, `min_intelligence?`, `sort?`, `limit?`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/models/lookup","input":{…}}` · Everywhere a model is served, cheapest first, with each host's own price, context window and capabilities. Hosts disagree: the same model may support tool calling on one and not another. (1 credit) · params: `slug`
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/models/hosts","input":{…}}` · Every host that serves models, how many each carries, and its median input price per 1M tokens. (1 credit) · params: none

## File artifacts

For a finished local PDF, DOCX, PPTX, or XLSX, send authenticated `multipart/form-data` to `POST /v1/artifacts/files` with a `file` part and optional `title`, `visibility`, and `ttl`. Do not put file bytes in `/v1/run`. The response returns the stable human URL, metadata, SHA-256, and an authenticated exact-byte download URL.
Later agents can use the normal artifact list/get tools to rediscover metadata, download exact bytes, and replace the file at the same identity with `POST /v1/artifacts/<id>/file`. Replacements preserve the prior exact file for pinned retrieval and rollback. Full lifecycle and multipart example: https://fetchbean.com/artifacts.md

## Raw provider access

`POST /v1/run` with `{ "provider": string, "endpoint": string, "input": object }` executes a registered operation from `/catalog`. Input is validated against that operation's schema. The result uses the operation's provider-specific shape rather than a provider-independent normalized shape.

## Identity

- `GET /v1/me` → `{ "org_id", "actor", "balance", "org": { "monthly_cap_credits" } }` (balance/cap in credits)
- `GET /v1/usage` → `{ "org_id", "balance", "summary" }`

## Errors

Typed JSON, e.g. `{ "error": { "type": "insufficient_credits", "code": "insufficient_credits", "message": "...", "retryable": false, "billable": false } }`.
Types map to status: `validation` 400, `auth` 401, `insufficient_credits` 402, `rate_limited` 429, `provider` 502, `timeout` 504.

What to do, by `code`:

- `credential_required` — the tool acts on the user's **own** account and it isn't connected. Ask the user to connect that provider at https://fetchbean.com/app?tab=connections (the catalog/discover entry carries the exact `connect_url`), then retry.
- `provider_error` — the `message` comes **straight from the upstream provider**, not fetchbean. It usually means a permission/scope limit, bad input, or a not-found on the user's own account (e.g. an API key lacking a scope) — surface the message to the user; it is not a fetchbean bug. Retry only if `retryable` is true.
- `invalid_input` / `validation` — fix the offending field named in `message`, then retry.
- `insufficient_credits` means the balance cannot cover the upfront hold. The user tops up at https://fetchbean.com/app. `spend_cap_exceeded` means the monthly admission cap must reset or be raised.
- `rate_limited` / `timeout` — transient; back off and retry. In general, **retry only when `retryable` is true**; provider failures and timeouts are billed zero.

## Credits

Prepaid. 1 credit = $0.0001, with a $5 minimum top-up and 5% bonus credits on top-ups of $50 or more. A call holds its fixed price or metered estimate before execution, then settles the actual charge. A metered charge can exceed that hold, the remaining balance, or the monthly cap after admission; the cap is an admission-time control.

## MCP

fetchbean runs a hosted MCP server (Streamable HTTP). Add it to any MCP client (Claude, Cursor, the Agent SDK):

```json
{
  "mcpServers": {
    "fetchbean": { "url": "https://api.fetchbean.com/mcp", "headers": { "X-API-Key": "fb_..." } }
  }
}
```

Over MCP you get four tools — `discover`, `describe`, `run`, and `request` — the same discover→run flow as HTTP, plus a way to log a genuinely missing need. Use `discover({ q })`, inspect uncertain schemas with `describe({ provider, endpoint })`, then call `run({ provider, endpoint, input })`. Over HTTP you also get the normalized `POST /v1/<tool>` shortcuts listed above.

Prefer a local stdio server? Run `npx -y fetchbean-mcp` with `FETCHBEAN_API_KEY` set — it proxies the same four tools to the hosted endpoint. See https://docs.fetchbean.com.
