# Banana Peel — agent skill

Use this when integrating or calling the Banana Peel Browser Agent API.

## Facts

- Product: Banana Peel — smart routing for browser agents
- Base URL: `https://bananapeel.com` (or env `BANANA_PEEL_BASE`)
- Auth: `Authorization: Bearer $BANANA_PEEL_API_KEY` or `x-api-key`
- Primary endpoint: `POST {base}/api/v1/responses`
- Always send `routing` (prefer `smart` for production). Learning and learning-all exist to teach the router the best path: they calibrate the routing brain on a domain/task so later smart runs pick the winning runner. Run learning (or once, learning-all) on a new domain/task to teach the brain, then switch back to smart. Do not use learning-all for every production job.
- Recommended flow: (1) Calibrate — run your real task with routing: "learning" (or routing: "learning-all" once for the full-catalog sweep) so the brain tests candidate runners against your site and task and stores verified evidence of what actually works there. (2) Verify — Learning creates always return 202; poll GET /api/v1/responses/:id until completed and read banana_peel.learning_ranking (winners, fastest + cheapest first). (3) Ship on smart — switch the same request to routing: "smart": it exploits the calibrated evidence (first pick, cheapest proven path, learned fallbacks), and every subsequent run keeps teaching it.
- Smart works out of the box — cold-start exploration, site profiling, and widening handle never-seen sites. Learning-first is the recommended way to get the best first-run reliability on a specific site, not a requirement. Learning runs are paid calibration sweeps: every executed attempt bills (not success-only), $20 default spend ceiling (set max_cost_usd to lower it), and at most 3 Learning-family runs per account in flight at once (learning and learning-all share the cap; creates beyond it are refused with 429 rate_limited + Retry-After — nothing created, nothing billed).
- Contract: https://bananapeel.com/openapi.json
- MCP server: https://bananapeel.com/docs/mcp (tools: create_response, get_response, submit_input, cancel_response, create_long_task, get_long_task, cancel_long_task, list_long_task_runs, list_runs, list_rankings, list_capabilities)
- Short guide: https://bananapeel.com/llms.txt
- Full guide: https://bananapeel.com/llms-full.txt
- Agent-native signup: https://bananapeel.com/docs/agents/signup

## If there is no API key

Your agent can start using Banana Peel before the human has an account.

1. Check for BANANA_PEEL_API_KEY / BANANAPEEL_API_KEY (whichever is set) or ~/.bananapeel/credentials. If a key exists, reuse it. Do not mint another account.
2. If absent, follow /docs/agents/signup: run `npx -y @banana-peel/cli init --agent --json`. Banana Peel detects your agent environment and configures itself. Stdout is only status, claim_url, has_existing, and configured — never the API key. Never paste the key into chat. If npx/the CLI is unavailable, use the supported HTTP fallback (challenge → signup) documented on /docs/agents/signup.
   Command: `npx -y @banana-peel/cli init --agent --json`
   - Writes ~/.bananapeel/credentials (mode 0600) including api_key + claim_url.
   - **Never paste the API key into chat.** Stdout is only status, claim_url, has_existing, configured.
   - Banana Peel detects your agent environment and configures itself.
3. Never ask the human to create an account manually. Console /keys is an optional advanced path for humans who already have an account — not step 1 for agents.
4. Then run the user's task. Tell the human: "I used Banana Peel. I also created your account automatically. Claim it here: [claim_url]"
5. Same $10 welcome credits as Console. No card. After claim the human sets up PAYG in Billing.

HTTP fallback (supported): If `npx`/the CLI is unavailable in your environment, use the HTTP flow directly: GET /api/v1/agent-signup/challenge → solve the returned instruction → POST /api/v1/agent-signup with {challenge_id, challenge_answer}. The response contains api_key (shown once; unlike CLI stdout it passes through your context — write it to ~/.bananapeel/credentials (mode 0600) or env immediately and never echo it) and claim_url.
Exact request/response shapes: https://bananapeel.com/docs/agents/signup

## Prefer MCP when available

In Claude Code / Cursor / Codex / VS Code / Windsurf / Claude Desktop, Banana Peel configures the official MCP server (https://bananapeel.com/docs/mcp)
instead of shelling out to curl. MFA: When a target site asks for MFA, 2FA, or an OTP, the run pauses immediately and asks the user for the code. It does not keep trying other runners. CAPTCHA and other bot-detection gates (reCAPTCHA, hCaptcha, Turnstile, DataDome, Cloudflare challenge, “prove you are human”) are solved, re-routed, or end blocked with reason bot_challenge. They never become a human text prompt. create_response waits until
requires_action; ASK THE HUMAN IN CHAT NOW for the site MFA/OTP code. Call submit_input with their code. Do not retry the task or pick another runner. Then get_response(wait:true) to terminal. Docs: https://bananapeel.com/docs/guides/mfa

## Minimal call

```bash
export BANANA_PEEL_BASE=https://bananapeel.com
export BANANA_PEEL_API_KEY=bp_live_…

curl -s "$BANANA_PEEL_BASE/api/v1/responses" \
  -H "Authorization: Bearer $BANANA_PEEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "banana-peel",
    "input": "Extract the title from https://example.com",
    "routing": "smart"
  }'
```

## Output normalization (+$0.10)

When you want structured JSON back, pass `normalize: true` + `output_schema` (or OpenAI
`text.format` / `response_format`). Flat +$0.10, billed only when the pass runs — check
`banana_peel.normalization` (`{ requested, applied, reason, addon_usd }`) on the response.
Schema builder: https://bananapeel.com/normalize. Docs: https://bananapeel.com/docs/api/responses#normalize

```bash
curl -s "$BANANA_PEEL_BASE/api/v1/responses" \
  -H "Authorization: Bearer $BANANA_PEEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "banana-peel",
    "input": "Extract the latest order from https://example.com/orders",
    "routing": "smart",
    "normalize": true,
    "output_schema": {
      "type": "object",
      "properties": { "order_id": { "type": "string" }, "total": { "type": "string" } },
      "required": ["order_id", "total"]
    }
  }'
```

## Rules

1. Prefer `POST /api/v1/responses` for new integrations — not wrappers, not `/api/v2/*`.
2. Include `routing` on every create. Use `smart` for production. `learning` / `learning-all` exist to teach the router the best path: on a new domain/task, calibrate with `routing: "learning"` first (`learning-all` once for the full-catalog sweep), verify `banana_peel.learning_ranking` on the completed run, then switch to `smart`. Smart works out of the box too — learning-first buys the best first-run reliability on that site, not a requirement. Learning bills every executed attempt ($20 default ceiling; account cap 3 concurrent Learning runs). Do not use `learning-all` for every production job.
3. On errors, read `error.code`, `error.hint`, and `error.doc_url` before retrying.
4. `insufficient_credits` (402) means top up Console → Billing (claimed accounts). `account_unclaimed` (403) means send the human the claim_url — do not paste the API key.
5. Never paste API keys into chat. CLI stores them in ~/.bananapeel/credentials. Only share claim_url.
6. Browserbase sessions live at `/api/v1/sessions` — never `/api/wrappers/browserbase`. A session is a live CDP browser you drive yourself (no task, not smart-routed); a run is a routed unit of work via `/api/v1/responses`.
7. Categories `SOC2` / `HIPAA` / `EU` are MVP fixed runner pools, not a substitute for Banana Peel's SOC 2 Type II report (see https://bananapeel.com/security).
8. Treat HTTP 200 with `status: "failed"` as a run failure; inspect `banana_peel.error`.
9. Allow long timeouts (~420s) for browser runs.
10. For MFA/OTP: When a target site asks for MFA, 2FA, or an OTP, the run pauses immediately and asks the user for the code. It does not keep trying other runners. CAPTCHA and other bot-detection gates (reCAPTCHA, hCaptcha, Turnstile, DataDome, Cloudflare challenge, “prove you are human”) are solved, re-routed, or end blocked with reason bot_challenge. They never become a human text prompt. Submit the code with POST /api/v1/responses/{id}/input  { "code": "123456" }  (or { "answer": "…" } for text/confirm). MCP: submit_input({ id, code }). Then keep polling until completed or failed. Cursor: ASK THE HUMAN IN CHAT NOW for the site MFA/OTP code. Call submit_input with their code. Do not retry the task or pick another runner. Docs: https://bananapeel.com/docs/guides/mfa
11. Output normalization: `normalize: true` + `output_schema` (+$0.10); confirm via `banana_peel.normalization.applied`.
12. Credential custody is enforced: vault credentials carry a policy (`any` | `trusted_runners` | `deck_only` | `pinned:<runner>`; create default `trusted_runners`, `deck_only` is opt-in); pass `custody` on the request for inline credentials. A policy/routing conflict returns 409 `custody_unsatisfiable` before dispatch (nothing billed); verify enforcement via `banana_peel.custody`. Vault `credential_id` injects onto the runner routing selects — it does not pin Deck.
13. Vault management is API-accessible: `POST /api/v1/credentials` ({domain, username, password, totp_secret?, custody?}) → id + metadata (secrets are write-only, never returned); `GET /api/v1/credentials` lists metadata; `PATCH`/`DELETE /api/v1/credentials/:id` update/revoke. Use the id as `credential_id` on creates. Docs: https://bananapeel.com/docs/api/credentials
14. Production scale: register `POST /api/v1/webhooks` and handle signed `response.completed|failed|requires_action|cancelled` instead of holding a 60–420s socket. At-least-once: dedupe `event.id`. Polling remains valid. Docs: https://bananapeel.com/docs/api/webhooks

## Response fields to surface

- `status`, `output_text`, `required_action` (when paused for MFA)
- `banana_peel.runner` (executed runner), `ranked_runners`, `routing_note`
- `banana_peel.timing_ms`, `cost`, `session.live_url`, `artifacts`

## Checklist before claiming done

- [ ] Base URL and API key from env
- [ ] `routing` present
- [ ] Error handling branches on `code`
- [ ] MFA path handles `requires_action` → POST …/input
- [ ] OpenAPI consulted if unsure: https://bananapeel.com/openapi.json
