---
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, on prepaid credits you can't overspend. 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 live, registry-driven 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, or `/describe` for the full input schema.
- `GET /catalog` → the full, current provider + method catalog.

## Connections (bring your own key)

Some tools act on **your own** provider account, not fetchbean's. Connect that provider once at https://fetchbean.com/app (Connections tab): the key is verified, encrypted at rest, and used only to call that provider on your behalf, with upstream usage billed to your own account. Calling one before connecting returns a `credential_required` error.

Connected providers currently include: Fireflies, PostHog, Linear, RevenueCat, Expo, GitHub, Better Stack, GitLab, Notion, Dodo Payments, Spaceship, Supabase, Cloudflare, Stripe, Slack, Sentry, Trakt, Clerk, Buffer, Bluesky, Render, Cal.com, Canny, Bing Webmaster. 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 full, live set (provider, endpoint, params), and `/describe` gives the full input schema for any one.

- **search**: Search the web and get ranked results (title, url, description). Fetch a result's full text with the read or firecrawl_scrape tool. `POST /v1/search` · from 50 credits · input: `query`, `max_results?`
- **read**: Fetch a URL and return clean markdown, no nav or clutter. `POST /v1/read` · from 10 credits · input: `url`, `format?`
- **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. (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 artifacts (newest first): id, url, title, type, visibility, expiry, views. (1 credit) · params: none
- `POST /v1/run` with `{"provider":"fetchbean","endpoint":"/artifacts/get","input":{…}}` · Fetch one of your artifacts in full, including its current content body. (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/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 + the joined plain text. (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":"/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` · Token prices + context windows for LLMs, from the LiteLLM dataset. Filter by model/provider/mode. (1 credit) · params: `model?`, `provider?`, `mode?`, `contains?`, `limit?`

## Raw provider access

`POST /v1/run` with `{ "provider": string, "endpoint": string, "input": object }` forwards to the provider and returns its response **unchanged** (un-normalized). Use this for any method in `/catalog` that has no curated tool.

## 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` — the balance or org monthly cap is exhausted. The user tops up at https://fetchbean.com/app. Don't retry until they do.
- `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 ($1 = 10,000 credits). Each call reserves a ceiling, then settles the actual charge, so spend can never exceed your balance or optional org monthly cap.

## 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 three tools — `discover`, `describe`, and `run` — the same discover→run flow as HTTP: `discover({ q })` to find a tool, then `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 three tools to the hosted endpoint. See https://docs.fetchbean.com.
