{"id":"85306cdc-b0b2-42cc-aa1b-ce47be24dc5f","entityType":"agent","slug":"clawhub-highnoonoffice-agent-tollbooth","name":"agent-tollbooth","canonicalUrl":"https://www.xpersona.co/agent/clawhub-highnoonoffice-agent-tollbooth","canonicalPath":"/agent/clawhub-highnoonoffice-agent-tollbooth","generatedAt":"2026-10-11T14:15:23.119Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T10:56:25.747Z","emptyReason":null},"description":"Web access privileges for your agent. So your agent stops hitting walls. Skill: agent-tollbooth Owner: highnoonoffice Summary: Web access privileges for your agent. So your agent stops hitting walls. Tags: latest:2.2.1 Version history: v2.2.1 | 2026-08-25T03:47:03.253Z | user Add contact footer v2.2.0 | 2026-04-19T22:13:45.172Z | user Fix: promote-profile.py now writes to $OPENCLAW_WORKSPACE/data/agent-tollbooth/profiles.md — bundled references/profiles.md is read-only. Resolves write-bac","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17788hys8dcemdm7pfhe61p9d83hbhs:agent-tollbooth","sourceUrl":"https://clawhub.ai/highnoonoffice/agent-tollbooth","homepage":"https://clawhub.ai/highnoonoffice/skills/agent-tollbooth","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/highnoonoffice/agent-tollbooth","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/highnoonoffice/skills/agent-tollbooth","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Web access privileges for your agent. So your agent stops hitting walls. Skill: agent-tollbooth Owner: highnoonoffice Summary: Web access privileges for your ag"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:56:25.747Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:56:25.747Z","emptyReason":null},"stars":null,"forks":null,"downloads":1082,"packageName":null,"latestVersion":"2.2.1","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:56:25.733Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T10:56:25.747Z","lastCrawledAt":"2026-10-11T10:56:25.733Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T10:56:25.733Z","lastVerifiedAt":null,"highlights":[{"version":"2.2.1","createdAt":"2026-08-25T03:47:03.253Z","changelog":"Add contact footer","fileCount":4,"zipByteSize":8641},{"version":"2.2.0","createdAt":"2026-04-19T22:13:45.172Z","changelog":"Fix: promote-profile.py now writes to $OPENCLAW_WORKSPACE/data/agent-tollbooth/profiles.md — bundled references/profiles.md is read-only. Resolves write-back-to-bundle inconsistency flagged by scanner.","fileCount":9,"zipByteSize":20208},{"version":"2.1.0","createdAt":"2026-04-19T22:00:09.098Z","changelog":"Fix Suspicious flag: include all scripts in bundle (check-profile.py, promote-profile.py, fetch-prices.py, web-log.py); these were referenced but not packaged","fileCount":8,"zipByteSize":18713},{"version":"2.0.0","createdAt":"2026-04-19T21:47:39.380Z","changelog":"Added problem statement opener, fixed missing frontmatter fields (version, homepage, source, license)","fileCount":3,"zipByteSize":7391},{"version":"1.4.1","createdAt":"2026-04-18T21:22:15.864Z","changelog":"v1.4.1: Scanner fix — removed relative fallback write paths, all writes go to OPENCLAW_WORKSPACE only. Softened capability-triggering language in Stripe/Notion profiles.","fileCount":8,"zipByteSize":18408},{"version":"1.4.0","createdAt":"2026-04-18T21:18:30.680Z","changelog":"v1.4.0: 16 service profiles (added OpenAI, Anthropic, GitHub, Brave, Serper, Notion, Airtable, Stripe, HuggingFace, Firecrawl). Self-learning loop: check-profile.py for pre-flight lookups, promote-profile.py to mine event log and draft new profiles automatically.","fileCount":8,"zipByteSize":18513},{"version":"1.3.6","createdAt":"2026-04-18T06:10:45.706Z","changelog":"Remove fetch-image.py (Replicate image gen out of scope); no credentials accessed by any remaining script","fileCount":6,"zipByteSize":9062},{"version":"1.3.5","createdAt":"2026-04-18T06:06:56.667Z","changelog":"Move credential path to REPLICATE_CREDENTIALS_FILE env var — no hardcoded credential paths in code","fileCount":7,"zipByteSize":11912}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17788hys8dcemdm7pfhe61p9d83hbhs:agent-tollbooth","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T14:15:23.116Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-highnoonoffice-agent-tollbooth/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T10:56:25.747Z","emptyReason":null},"readme":"Skill: agent-tollbooth\n\nOwner: highnoonoffice\n\nSummary: Web access privileges for your agent. So your agent stops hitting walls.\n\nTags: latest:2.2.1\n\nVersion history:\n\nv2.2.1 | 2026-08-25T03:47:03.253Z | user\n\nAdd contact footer\n\nv2.2.0 | 2026-04-19T22:13:45.172Z | user\n\nFix: promote-profile.py now writes to $OPENCLAW_WORKSPACE/data/agent-tollbooth/profiles.md — bundled references/profiles.md is read-only. Resolves write-back-to-bundle inconsistency flagged by scanner.\n\nv2.1.0 | 2026-04-19T22:00:09.098Z | user\n\nFix Suspicious flag: include all scripts in bundle (check-profile.py, promote-profile.py, fetch-prices.py, web-log.py); these were referenced but not packaged\n\nv2.0.0 | 2026-04-19T21:47:39.380Z | user\n\nAdded problem statement opener, fixed missing frontmatter fields (version, homepage, source, license)\n\nv1.4.1 | 2026-04-18T21:22:15.864Z | user\n\nv1.4.1: Scanner fix — removed relative fallback write paths, all writes go to OPENCLAW_WORKSPACE only. Softened capability-triggering language in Stripe/Notion profiles.\n\nv1.4.0 | 2026-04-18T21:18:30.680Z | user\n\nv1.4.0: 16 service profiles (added OpenAI, Anthropic, GitHub, Brave, Serper, Notion, Airtable, Stripe, HuggingFace, Firecrawl). Self-learning loop: check-profile.py for pre-flight lookups, promote-profile.py to mine event log and draft new profiles automatically.\n\nv1.3.6 | 2026-04-18T06:10:45.706Z | user\n\nRemove fetch-image.py (Replicate image gen out of scope); no credentials accessed by any remaining script\n\nv1.3.5 | 2026-04-18T06:06:56.667Z | user\n\nMove credential path to REPLICATE_CREDENTIALS_FILE env var — no hardcoded credential paths in code\n\nv1.3.4 | 2026-04-18T05:59:24.173Z | user\n\nAdd explicit credential and workspace access disclosure section; scanner should now see declared intent matching actual code behavior\n\nv1.3.3 | 2026-04-18T05:57:23.340Z | user\n\nDeclare credentials and config paths in SKILL.md frontmatter; align body text with actual script paths to resolve scanner mismatch\n\nv1.3.2 | 2026-04-18T05:38:37.484Z | user\n\nFix description field format — quoted short string.\n\nv1.3.1 | 2026-04-18T05:37:47.513Z | user\n\nForce re-index to surface skill description on ClawHub card.\n\nv1.3.0 | 2026-04-18T05:32:52.650Z | user\n\nAdd fetch-crypto.py (CoinGecko batch fetch) and fetch-image.py (Replicate FLUX 1.1 Pro) — skill now ships working scripts for all major service profiles.\n\nv1.2.3 | 2026-04-18T05:12:39.539Z | user\n\nUpdate description to locked copy: Web access privileges for your agent. So your agent stops hitting walls.\n\nv1.2.2 | 2026-04-18T04:51:30.585Z | user\n\nFix write paths to use OPENCLAW_WORKSPACE env var (standard for all OpenClaw installs). Fix description/code mismatch. Clear operational log before publish.\n\nv1.2.1 | 2026-04-18T04:41:41.924Z | user\n\nSanitize for public publish: clear operational log, generalize credential paths, neutral Telegram profile\n\nv1.2.0 | 2026-04-18T04:27:34.326Z | user\n\nFeedback loop wired — logged events now annotate profiles.md automatically. The skill learns from live usage.\n\nv1.1.1 | 2026-04-18T04:12:00.383Z | user\n\nDescription update — web access privileges phrase added to opening line.\n\nv1.1.0 | 2026-04-18T04:11:13.098Z | user\n\nAdded self-logging feedback loop — scripts now write to web-access-log.json on every 429, timeout, auth failure, cache hit, and success. The skill learns from live usage instead of relying on static notes.\n\nv1.0.0 | 2026-04-18T03:48:00.888Z | user\n\nInitial release — service profiles for Yahoo Finance, CoinGecko, Ghost Admin API, ClawHub, Telegram, and Replicate.\n\nArchive index:\n\nArchive v2.2.1: 4 files, 8641 bytes\n\nFiles: references/profiles.md (12399b), skill-card.md (2134b), SKILL.md (3880b), _meta.json (134b)\n\nFile v2.2.1:SKILL.md\n\n---\nname: agent-tollbooth\nversion: 2.0.0\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nhomepage: https://github.com/highnoonoffice/agent-tollbooth\nsource: https://github.com/highnoonoffice/agent-tollbooth\nlicense: MIT\nmetadata: ~\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nYou're mid-task. Your agent fires a Yahoo Finance request. Gets a 429. Stops. You don't know if it's rate limits, a bad endpoint, a missing header, or just bad luck. You try again. Same thing. You start debugging blind.\n\nTollbooth is the field notes that stop this from happening twice. Observed operating profiles for 16 external services — safe endpoints, sleep intervals, caching patterns, auth requirements — built from real API friction. Your agent checks the profile before calling, follows the safe pattern, and logs what happens. Next time it already knows.\n\nEvery external service has a threshold. This skill provides the map so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. Cache files go to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. Set `OPENCLAW_WORKSPACE` before running (standard on any OpenClaw install).\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n- OpenAI API\n- Anthropic API\n- GitHub API\n- Brave Search API\n- Serper (Google Search)\n- Notion API\n- Airtable API\n- Stripe API\n- HuggingFace Inference API\n- Firecrawl\n\n---\n\nBuilt by Joseph Voelbel / High Noon Office. Questions or want to build on this? josephvoelbel.com/contact\n\nFile v2.2.1:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"2.2.1\",\n  \"publishedAt\": 1787629623253\n}\n\nFile v2.2.1:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Exponential backoff on 429. Header `retry-after` tells you exactly how long to wait — use it.\n- **Streaming vs. non-streaming:** Both count equally against rate limits. Streaming does NOT get preferential treatment.\n- **Model-specific ceilings:** GPT-4o has lower RPM than GPT-4o-mini on the same tier. Always check the model's specific limit, not the account's general limit.\n- **Never:** Parallel requests on free/tier-1 — you'll 429 immediately and waste retries\n- **Cache:** Cache completions aggressively. Same prompt = same response at temperature 0. Save tokens and money.\n- **First observed:** 2026-04-18\n\n---\n\n## Anthropic API\n\n- **Endpoint:** `api.anthropic.com/v1/messages`\n- **Auth:** `x-api-key` header — not Bearer format\n- **Rate limits:** Two separate ceilings: RPM (requests per minute) AND TPM (tokens per minute). Hitting either triggers 429.\n- **TPM is usually the binding constraint** — a single large context window can eat your TPM budget before RPM becomes relevant\n- **Model-specific limits:** Haiku has higher RPM/TPM ceilings than Sonnet, which has higher than Opus. Route cheap tasks to Haiku.\n- **Prompt caching:** Prefix caching cuts token cost 90% on cached portions. Cache prefix must be identical to the character — a single token difference breaks the cache.\n- **Safe pattern:** Check `x-ratelimit-remaining-tokens` and `x-ratelimit-remaining-requests` headers on every response\n- **Streaming:** Use streaming for long responses — avoids gateway timeouts on responses > 30s\n- **Never:** Assume Haiku limits apply to Sonnet or vice versa — they're tracked independently\n- **First observed:** 2026-04-18\n\n---\n\n## GitHub API\n\n- **Endpoint:** `api.github.com`\n- **Auth:** `Authorization: Bearer <PAT>` — classic or fine-grained PAT\n- **Primary rate limit:** 5,000 req/hr authenticated. 60 req/hr unauthenticated. Check `x-ratelimit-remaining` header.\n- **Secondary rate limits (the real gotcha):** Separate from the primary limit. Triggered by: too many write operations in a short window, too many concurrent requests, too many requests to a single endpoint. Returns 403, not 429.\n- **Safe pattern:** Sequential writes with 1s sleep between. Never fire parallel POST/PATCH/DELETE calls.\n- **Search API:** Separate limit — 30 req/min authenticated, 10 unauthenticated. Completely independent of the main 5,000/hr.\n- **GraphQL:** Single endpoint `api.github.com/graphql` — counts as one request regardless of query complexity, but has its own point budget\n- **Pagination:** Always paginate — default page size is 30, max 100. Never assume you got all results on page 1.\n- **Never:** Use unauthenticated requests for anything beyond occasional public repo reads\n- **First observed:** 2026-04-18\n\n---\n\n## Brave Search API\n\n- **Endpoint:** `api.search.brave.com/res/v1/web/search`\n- **Auth:** `X-Subscription-Token` header\n- **Model:** Credit-based, NOT rate-based. Each query costs credits regardless of response size.\n- **Free tier:** 2,000 queries/month. Does not reset on 429 — it hard-stops when credits are exhausted.\n- **Failure mode:** Returns 429 when monthly credits are gone. This is a budget wall, not a speed wall — waiting does not help. Credits reset on billing date.\n- **Safe pattern:** Cache results aggressively. Same query within a session = serve from cache, don't re-query.\n- **No retry value on 429:** Unlike most APIs, retrying a Brave 429 immediately is useless — you're out of credits, not over a speed limit.\n- **Results freshness:** `freshness` param accepts `day`, `week`, `month`, `year` — use it to filter stale results on time-sensitive queries\n- **First observed:** 2026-04-18\n\n---\n\n## Serper (Google Search API)\n\n- **Endpoint:** `google.serper.dev/search`\n- **Auth:** `X-API-KEY` header\n- **Model:** Credit-based. Free tier: 2,500 credits. Each search = 1 credit.\n- **Failure mode:** Returns 403 when credits exhausted. Credits don't reset — must purchase more.\n- **Safe pattern:** Batch intent before querying. One well-crafted query beats three exploratory ones.\n- **Result types:** `/search` (web), `/images`, `/news`, `/places`, `/scholar` — each costs 1 credit regardless of type\n- **Never:** Fire exploratory parallel queries — each one costs a credit whether useful or not\n- **vs. Brave:** Serper returns Google results (higher coverage), Brave returns Brave index (more privacy-friendly, often enough for research). Use Brave first, Serper when Google coverage matters.\n- **First observed:** 2026-04-18\n\n---\n\n## Notion API\n\n- **Endpoint:** `api.notion.com/v1/`\n- **Auth:** Bearer integration token + `Notion-Version: 2022-06-28` header (required)\n- **Rate limit:** 3 requests/second per integration. Hard wall — 429 with no retry-after header.\n- **Safe pattern:** 350ms sleep between requests. Never parallel.\n- **Pagination:** All list endpoints are paginated — `has_more` + `next_cursor` pattern. Max page size: 100. Always loop until `has_more: false`.\n- **Block vs. page:** Fetching a page gives you metadata only, not content. Content lives in blocks — separate `GET /blocks/{id}/children` call required.\n- **Write quirk:** Appending blocks is additive — there's no replace operation. To update content you must delete existing blocks first, then append.\n- **Never:** Assume a page fetch includes body content — it never does\n- **First observed:** 2026-04-18\n\n---\n\n## Airtable API\n\n- **Endpoint:** `api.airtable.com/v0/<base_id>/<table_name>`\n- **Auth:** `Authorization: Bearer <personal-access-token>`\n- **Rate limit:** 5 requests/second per base. Across all tables in that base combined.\n- **Safe pattern:** 200ms sleep between requests. Batch reads using `filterByFormula` instead of fetching all and filtering client-side.\n- **Pagination:** `offset` token in response — keep fetching until no offset returned. Default page size: 100 records.\n- **Bulk writes:** No true bulk insert. Create up to 10 records per request via array in `records` field. 10 at a time, sleep between batches.\n- **Formula quirk:** `filterByFormula` uses Airtable formula syntax, not SQL. Strings need curly braces: `{Field Name} = 'value'`\n- **Never:** Fetch all records then filter in code — use `filterByFormula` to push filtering server-side\n- **First observed:** 2026-04-18\n\n---\n\n## Stripe API\n\n- **Endpoint:** `api.stripe.com/v1/`\n- **Auth:** Bearer token (secret key) — separate test and live keys, never mix environments\n- **Rate limit:** 100 read requests/second, 100 write requests/second. Rarely hit in normal agent workflows.\n- **Idempotency keys (critical):** Always pass `Idempotency-Key` header on POST requests. Same key = same result, safe to retry. Without it, a network timeout can trigger duplicate operations.\n- **Test vs. live:** Test keys hit a completely separate environment. Test mode objects don't exist in live mode. Never assume an ID from test works in live.\n- **Pagination:** Cursor-based — `starting_after` and `ending_before` params. Default 10 objects, max 100.\n- **Webhooks:** Verify `Stripe-Signature` header on every incoming webhook — do not trust unverified events.\n- **Safe pattern:** Always use idempotency keys on writes. Log the key with the request so you can retry safely.\n- **Never:** Mix test and live keys, or skip idempotency keys on sensitive operations\n- **First observed:** 2026-04-18\n\n---\n\n## HuggingFace Inference API\n\n- **Endpoint:** `api-inference.huggingface.co/models/<model-id>`\n- **Auth:** `Authorization: Bearer hf_...`\n- **Free tier:** Rate-limited, no hard quota published — in practice ~10-30 req/min before throttling\n- **Cold start (the real issue):** Models on free tier spin down when idle. First request after idle returns 503 with `{\"error\": \"Model ... is currently loading\"}` and an `estimated_time` field in seconds. This is NOT a failure — wait and retry.\n- **Safe pattern:** On 503 with `estimated_time`, sleep that many seconds + 5s buffer, then retry once. If still 503, wait another 30s.\n- **Never:** Treat a loading 503 as a hard failure — it's a cold start, not an error\n- **Dedicated endpoints:** If you need reliable latency, use Inference Endpoints (paid) — no cold starts, dedicated hardware\n- **Model-specific behavior:** Some models require specific input formats. Always check the model card before querying a new model.\n- **First observed:** 2026-04-18\n\n---\n\n## Firecrawl\n\n- **Endpoint:** `api.firecrawl.dev/v1/scrape` (single URL) or `/v1/crawl` (multi-page)\n- **Auth:** `Authorization: Bearer fc-...`\n- **Model:** Credit-based. Free tier: 500 credits/month. Single scrape = 1 credit. Crawl = 1 credit per page crawled.\n- **JS rendering:** Enabled by default — adds 3-8s latency per page vs. static fetch. Use `formats: [\"markdown\"]` to get clean LLM-ready output.\n- **vs. web_fetch:** Firecrawl handles JS-rendered pages, paywalls, and complex layouts. Use web_fetch for simple static pages — faster and free. Escalate to Firecrawl when web_fetch returns garbled or incomplete content.\n- **Crawl vs. scrape:** `/scrape` is one URL, instant response. `/crawl` is async — returns a job ID, poll `/v1/crawl/<id>` until `status: completed`.\n- **Safe pattern:** Scrape first. Only crawl if you need multiple pages from the same domain.\n- **Never:** Use `/crawl` when `/scrape` is sufficient — crawl burns credits per page\n- **First observed:** 2026-04-18\n\nFile v2.2.1:skill-card.md\n\n## Description:\n\nWeb access privileges for your agent so your agent stops hitting walls.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[highnoonoffice](https://clawhub.ai/user/highnoonoffice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to check observed operating profiles for external services before making web or API calls, including rate-limit patterns, caching guidance, authentication requirements, and known failure modes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill may guide an agent to use authenticated third-party APIs when the user's task requires them.\n\nMitigation: Confirm API credentials, write permissions, and paid API use before allowing the agent to perform authenticated or billable actions.\n\nRisk: Generated or promoted service profiles may be drafts based on local observations.\n\nMitigation: Review generated profiles before relying on them for writes, paid APIs, or repeated automated calls.\n\nRisk: The skill keeps local logs and cache files in the OpenClaw workspace.\n\nMitigation: Review the workspace log and cache location and clear retained data when it is no longer needed.\n\n## Reference(s):\n\n- [Service Profiles - Observed Operating Behavior](references/profiles.md)\n- [ClawHub skill page](https://clawhub.ai/highnoonoffice/skills/agent-tollbooth)\n- [Project homepage](https://github.com/highnoonoffice/agent-tollbooth)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Code, Configuration]\n\n**Output Format:** [Markdown with inline bash and Python code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guidance may reference local OpenClaw log and cache paths under $OPENCLAW_WORKSPACE/data/agent-tollbooth/.]\n\n## Skill Version(s):\n\n2.2.1 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.2.0: 9 files, 20208 bytes\n\nFiles: references/profiles.md (12399b), scripts/check-profile.py (4985b), scripts/fetch-crypto.py (5859b), scripts/fetch-prices.py (6232b), scripts/promote-profile.py (8523b), scripts/web-log.py (4153b), skill-card.md (2644b), SKILL.md (3768b), _meta.json (134b)\n\nFile v2.2.0:SKILL.md\n\n---\nname: agent-tollbooth\nversion: 2.0.0\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nhomepage: https://github.com/highnoonoffice/agent-tollbooth\nsource: https://github.com/highnoonoffice/agent-tollbooth\nlicense: MIT\nmetadata: ~\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nYou're mid-task. Your agent fires a Yahoo Finance request. Gets a 429. Stops. You don't know if it's rate limits, a bad endpoint, a missing header, or just bad luck. You try again. Same thing. You start debugging blind.\n\nTollbooth is the field notes that stop this from happening twice. Observed operating profiles for 16 external services — safe endpoints, sleep intervals, caching patterns, auth requirements — built from real API friction. Your agent checks the profile before calling, follows the safe pattern, and logs what happens. Next time it already knows.\n\nEvery external service has a threshold. This skill provides the map so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. Cache files go to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. Set `OPENCLAW_WORKSPACE` before running (standard on any OpenClaw install).\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n- OpenAI API\n- Anthropic API\n- GitHub API\n- Brave Search API\n- Serper (Google Search)\n- Notion API\n- Airtable API\n- Stripe API\n- HuggingFace Inference API\n- Firecrawl\n\nFile v2.2.0:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"2.2.0\",\n  \"publishedAt\": 1776636825172\n}\n\nFile v2.2.0:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Exponential backoff on 429. Header `retry-after` tells you exactly how long to wait — use it.\n- **Streaming vs. non-streaming:** Both count equally against rate limits. Streaming does NOT get preferential treatment.\n- **Model-specific ceilings:** GPT-4o has lower RPM than GPT-4o-mini on the same tier. Always check the model's specific limit, not the account's general limit.\n- **Never:** Parallel requests on free/tier-1 — you'll 429 immediately and waste retries\n- **Cache:** Cache completions aggressively. Same prompt = same response at temperature 0. Save tokens and money.\n- **First observed:** 2026-04-18\n\n---\n\n## Anthropic API\n\n- **Endpoint:** `api.anthropic.com/v1/messages`\n- **Auth:** `x-api-key` header — not Bearer format\n- **Rate limits:** Two separate ceilings: RPM (requests per minute) AND TPM (tokens per minute). Hitting either triggers 429.\n- **TPM is usually the binding constraint** — a single large context window can eat your TPM budget before RPM becomes relevant\n- **Model-specific limits:** Haiku has higher RPM/TPM ceilings than Sonnet, which has higher than Opus. Route cheap tasks to Haiku.\n- **Prompt caching:** Prefix caching cuts token cost 90% on cached portions. Cache prefix must be identical to the character — a single token difference breaks the cache.\n- **Safe pattern:** Check `x-ratelimit-remaining-tokens` and `x-ratelimit-remaining-requests` headers on every response\n- **Streaming:** Use streaming for long responses — avoids gateway timeouts on responses > 30s\n- **Never:** Assume Haiku limits apply to Sonnet or vice versa — they're tracked independently\n- **First observed:** 2026-04-18\n\n---\n\n## GitHub API\n\n- **Endpoint:** `api.github.com`\n- **Auth:** `Authorization: Bearer <PAT>` — classic or fine-grained PAT\n- **Primary rate limit:** 5,000 req/hr authenticated. 60 req/hr unauthenticated. Check `x-ratelimit-remaining` header.\n- **Secondary rate limits (the real gotcha):** Separate from the primary limit. Triggered by: too many write operations in a short window, too many concurrent requests, too many requests to a single endpoint. Returns 403, not 429.\n- **Safe pattern:** Sequential writes with 1s sleep between. Never fire parallel POST/PATCH/DELETE calls.\n- **Search API:** Separate limit — 30 req/min authenticated, 10 unauthenticated. Completely independent of the main 5,000/hr.\n- **GraphQL:** Single endpoint `api.github.com/graphql` — counts as one request regardless of query complexity, but has its own point budget\n- **Pagination:** Always paginate — default page size is 30, max 100. Never assume you got all results on page 1.\n- **Never:** Use unauthenticated requests for anything beyond occasional public repo reads\n- **First observed:** 2026-04-18\n\n---\n\n## Brave Search API\n\n- **Endpoint:** `api.search.brave.com/res/v1/web/search`\n- **Auth:** `X-Subscription-Token` header\n- **Model:** Credit-based, NOT rate-based. Each query costs credits regardless of response size.\n- **Free tier:** 2,000 queries/month. Does not reset on 429 — it hard-stops when credits are exhausted.\n- **Failure mode:** Returns 429 when monthly credits are gone. This is a budget wall, not a speed wall — waiting does not help. Credits reset on billing date.\n- **Safe pattern:** Cache results aggressively. Same query within a session = serve from cache, don't re-query.\n- **No retry value on 429:** Unlike most APIs, retrying a Brave 429 immediately is useless — you're out of credits, not over a speed limit.\n- **Results freshness:** `freshness` param accepts `day`, `week`, `month`, `year` — use it to filter stale results on time-sensitive queries\n- **First observed:** 2026-04-18\n\n---\n\n## Serper (Google Search API)\n\n- **Endpoint:** `google.serper.dev/search`\n- **Auth:** `X-API-KEY` header\n- **Model:** Credit-based. Free tier: 2,500 credits. Each search = 1 credit.\n- **Failure mode:** Returns 403 when credits exhausted. Credits don't reset — must purchase more.\n- **Safe pattern:** Batch intent before querying. One well-crafted query beats three exploratory ones.\n- **Result types:** `/search` (web), `/images`, `/news`, `/places`, `/scholar` — each costs 1 credit regardless of type\n- **Never:** Fire exploratory parallel queries — each one costs a credit whether useful or not\n- **vs. Brave:** Serper returns Google results (higher coverage), Brave returns Brave index (more privacy-friendly, often enough for research). Use Brave first, Serper when Google coverage matters.\n- **First observed:** 2026-04-18\n\n---\n\n## Notion API\n\n- **Endpoint:** `api.notion.com/v1/`\n- **Auth:** Bearer integration token + `Notion-Version: 2022-06-28` header (required)\n- **Rate limit:** 3 requests/second per integration. Hard wall — 429 with no retry-after header.\n- **Safe pattern:** 350ms sleep between requests. Never parallel.\n- **Pagination:** All list endpoints are paginated — `has_more` + `next_cursor` pattern. Max page size: 100. Always loop until `has_more: false`.\n- **Block vs. page:** Fetching a page gives you metadata only, not content. Content lives in blocks — separate `GET /blocks/{id}/children` call required.\n- **Write quirk:** Appending blocks is additive — there's no replace operation. To update content you must delete existing blocks first, then append.\n- **Never:** Assume a page fetch includes body content — it never does\n- **First observed:** 2026-04-18\n\n---\n\n## Airtable API\n\n- **Endpoint:** `api.airtable.com/v0/<base_id>/<table_name>`\n- **Auth:** `Authorization: Bearer <personal-access-token>`\n- **Rate limit:** 5 requests/second per base. Across all tables in that base combined.\n- **Safe pattern:** 200ms sleep between requests. Batch reads using `filterByFormula` instead of fetching all and filtering client-side.\n- **Pagination:** `offset` token in response — keep fetching until no offset returned. Default page size: 100 records.\n- **Bulk writes:** No true bulk insert. Create up to 10 records per request via array in `records` field. 10 at a time, sleep between batches.\n- **Formula quirk:** `filterByFormula` uses Airtable formula syntax, not SQL. Strings need curly braces: `{Field Name} = 'value'`\n- **Never:** Fetch all records then filter in code — use `filterByFormula` to push filtering server-side\n- **First observed:** 2026-04-18\n\n---\n\n## Stripe API\n\n- **Endpoint:** `api.stripe.com/v1/`\n- **Auth:** Bearer token (secret key) — separate test and live keys, never mix environments\n- **Rate limit:** 100 read requests/second, 100 write requests/second. Rarely hit in normal agent workflows.\n- **Idempotency keys (critical):** Always pass `Idempotency-Key` header on POST requests. Same key = same result, safe to retry. Without it, a network timeout can trigger duplicate operations.\n- **Test vs. live:** Test keys hit a completely separate environment. Test mode objects don't exist in live mode. Never assume an ID from test works in live.\n- **Pagination:** Cursor-based — `starting_after` and `ending_before` params. Default 10 objects, max 100.\n- **Webhooks:** Verify `Stripe-Signature` header on every incoming webhook — do not trust unverified events.\n- **Safe pattern:** Always use idempotency keys on writes. Log the key with the request so you can retry safely.\n- **Never:** Mix test and live keys, or skip idempotency keys on sensitive operations\n- **First observed:** 2026-04-18\n\n---\n\n## HuggingFace Inference API\n\n- **Endpoint:** `api-inference.huggingface.co/models/<model-id>`\n- **Auth:** `Authorization: Bearer hf_...`\n- **Free tier:** Rate-limited, no hard quota published — in practice ~10-30 req/min before throttling\n- **Cold start (the real issue):** Models on free tier spin down when idle. First request after idle returns 503 with `{\"error\": \"Model ... is currently loading\"}` and an `estimated_time` field in seconds. This is NOT a failure — wait and retry.\n- **Safe pattern:** On 503 with `estimated_time`, sleep that many seconds + 5s buffer, then retry once. If still 503, wait another 30s.\n- **Never:** Treat a loading 503 as a hard failure — it's a cold start, not an error\n- **Dedicated endpoints:** If you need reliable latency, use Inference Endpoints (paid) — no cold starts, dedicated hardware\n- **Model-specific behavior:** Some models require specific input formats. Always check the model card before querying a new model.\n- **First observed:** 2026-04-18\n\n---\n\n## Firecrawl\n\n- **Endpoint:** `api.firecrawl.dev/v1/scrape` (single URL) or `/v1/crawl` (multi-page)\n- **Auth:** `Authorization: Bearer fc-...`\n- **Model:** Credit-based. Free tier: 500 credits/month. Single scrape = 1 credit. Crawl = 1 credit per page crawled.\n- **JS rendering:** Enabled by default — adds 3-8s latency per page vs. static fetch. Use `formats: [\"markdown\"]` to get clean LLM-ready output.\n- **vs. web_fetch:** Firecrawl handles JS-rendered pages, paywalls, and complex layouts. Use web_fetch for simple static pages — faster and free. Escalate to Firecrawl when web_fetch returns garbled or incomplete content.\n- **Crawl vs. scrape:** `/scrape` is one URL, instant response. `/crawl` is async — returns a job ID, poll `/v1/crawl/<id>` until `status: completed`.\n- **Safe pattern:** Scrape first. Only crawl if you need multiple pages from the same domain.\n- **Never:** Use `/crawl` when `/scrape` is sufficient — crawl burns credits per page\n- **First observed:** 2026-04-18\n\nFile v2.2.0:skill-card.md\n\n## Description: <br>\nProvides web access operating profiles, caching helpers, and local observation logs so agents can avoid repeated API rate-limit failures. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[highnoonoffice](https://clawhub.ai/user/highnoonoffice) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agent operators use Agent Tollbooth to check observed service profiles before external API calls, reuse cached price data, and log web-access outcomes for later profile updates. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Local logs and caches may contain service names, request details, or operational context. <br>\nMitigation: Avoid putting secrets, private hostnames, or sensitive account details into service names or log details, and review local data under $OPENCLAW_WORKSPACE/data/agent-tollbooth/ before sharing. <br>\nRisk: The bundled service profiles include credential-related notes for third-party services such as Stripe, GitHub, Ghost, and ClawHub. <br>\nMitigation: Review any suggested credential use or write operation before allowing an agent to act, especially for services that can spend money, modify production systems, or publish content. <br>\nRisk: Auto-drafted profiles are based on observed events and may be incomplete or misleading until reviewed. <br>\nMitigation: Treat promoted profile drafts as review material and verify endpoint, authentication, rate-limit, and caching guidance before relying on them. <br>\n\n\n## Reference(s): <br>\n- [Agent Tollbooth ClawHub page](https://clawhub.ai/highnoonoffice/agent-tollbooth) <br>\n- [highnoonoffice publisher profile](https://clawhub.ai/user/highnoonoffice) <br>\n- [Project homepage](https://github.com/highnoonoffice/agent-tollbooth) <br>\n- [Service Profiles](references/profiles.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance, shell commands, and JSON outputs from helper scripts] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Helper scripts may write local logs and cache files under $OPENCLAW_WORKSPACE/data/agent-tollbooth/.] <br>\n\n## Skill Version(s): <br>\n2.2.0 (source: server release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v2.1.0: 8 files, 18713 bytes\n\nFiles: references/profiles.md (12399b), scripts/check-profile.py (4985b), scripts/fetch-crypto.py (5859b), scripts/fetch-prices.py (6232b), scripts/promote-profile.py (8155b), scripts/web-log.py (4153b), SKILL.md (3768b), _meta.json (134b)\n\nFile v2.1.0:SKILL.md\n\n---\nname: agent-tollbooth\nversion: 2.0.0\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nhomepage: https://github.com/highnoonoffice/agent-tollbooth\nsource: https://github.com/highnoonoffice/agent-tollbooth\nlicense: MIT\nmetadata: ~\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nYou're mid-task. Your agent fires a Yahoo Finance request. Gets a 429. Stops. You don't know if it's rate limits, a bad endpoint, a missing header, or just bad luck. You try again. Same thing. You start debugging blind.\n\nTollbooth is the field notes that stop this from happening twice. Observed operating profiles for 16 external services — safe endpoints, sleep intervals, caching patterns, auth requirements — built from real API friction. Your agent checks the profile before calling, follows the safe pattern, and logs what happens. Next time it already knows.\n\nEvery external service has a threshold. This skill provides the map so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. Cache files go to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. Set `OPENCLAW_WORKSPACE` before running (standard on any OpenClaw install).\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n- OpenAI API\n- Anthropic API\n- GitHub API\n- Brave Search API\n- Serper (Google Search)\n- Notion API\n- Airtable API\n- Stripe API\n- HuggingFace Inference API\n- Firecrawl\n\nFile v2.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"2.1.0\",\n  \"publishedAt\": 1776636009098\n}\n\nFile v2.1.0:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Exponential backoff on 429. Header `retry-after` tells you exactly how long to wait — use it.\n- **Streaming vs. non-streaming:** Both count equally against rate limits. Streaming does NOT get preferential treatment.\n- **Model-specific ceilings:** GPT-4o has lower RPM than GPT-4o-mini on the same tier. Always check the model's specific limit, not the account's general limit.\n- **Never:** Parallel requests on free/tier-1 — you'll 429 immediately and waste retries\n- **Cache:** Cache completions aggressively. Same prompt = same response at temperature 0. Save tokens and money.\n- **First observed:** 2026-04-18\n\n---\n\n## Anthropic API\n\n- **Endpoint:** `api.anthropic.com/v1/messages`\n- **Auth:** `x-api-key` header — not Bearer format\n- **Rate limits:** Two separate ceilings: RPM (requests per minute) AND TPM (tokens per minute). Hitting either triggers 429.\n- **TPM is usually the binding constraint** — a single large context window can eat your TPM budget before RPM becomes relevant\n- **Model-specific limits:** Haiku has higher RPM/TPM ceilings than Sonnet, which has higher than Opus. Route cheap tasks to Haiku.\n- **Prompt caching:** Prefix caching cuts token cost 90% on cached portions. Cache prefix must be identical to the character — a single token difference breaks the cache.\n- **Safe pattern:** Check `x-ratelimit-remaining-tokens` and `x-ratelimit-remaining-requests` headers on every response\n- **Streaming:** Use streaming for long responses — avoids gateway timeouts on responses > 30s\n- **Never:** Assume Haiku limits apply to Sonnet or vice versa — they're tracked independently\n- **First observed:** 2026-04-18\n\n---\n\n## GitHub API\n\n- **Endpoint:** `api.github.com`\n- **Auth:** `Authorization: Bearer <PAT>` — classic or fine-grained PAT\n- **Primary rate limit:** 5,000 req/hr authenticated. 60 req/hr unauthenticated. Check `x-ratelimit-remaining` header.\n- **Secondary rate limits (the real gotcha):** Separate from the primary limit. Triggered by: too many write operations in a short window, too many concurrent requests, too many requests to a single endpoint. Returns 403, not 429.\n- **Safe pattern:** Sequential writes with 1s sleep between. Never fire parallel POST/PATCH/DELETE calls.\n- **Search API:** Separate limit — 30 req/min authenticated, 10 unauthenticated. Completely independent of the main 5,000/hr.\n- **GraphQL:** Single endpoint `api.github.com/graphql` — counts as one request regardless of query complexity, but has its own point budget\n- **Pagination:** Always paginate — default page size is 30, max 100. Never assume you got all results on page 1.\n- **Never:** Use unauthenticated requests for anything beyond occasional public repo reads\n- **First observed:** 2026-04-18\n\n---\n\n## Brave Search API\n\n- **Endpoint:** `api.search.brave.com/res/v1/web/search`\n- **Auth:** `X-Subscription-Token` header\n- **Model:** Credit-based, NOT rate-based. Each query costs credits regardless of response size.\n- **Free tier:** 2,000 queries/month. Does not reset on 429 — it hard-stops when credits are exhausted.\n- **Failure mode:** Returns 429 when monthly credits are gone. This is a budget wall, not a speed wall — waiting does not help. Credits reset on billing date.\n- **Safe pattern:** Cache results aggressively. Same query within a session = serve from cache, don't re-query.\n- **No retry value on 429:** Unlike most APIs, retrying a Brave 429 immediately is useless — you're out of credits, not over a speed limit.\n- **Results freshness:** `freshness` param accepts `day`, `week`, `month`, `year` — use it to filter stale results on time-sensitive queries\n- **First observed:** 2026-04-18\n\n---\n\n## Serper (Google Search API)\n\n- **Endpoint:** `google.serper.dev/search`\n- **Auth:** `X-API-KEY` header\n- **Model:** Credit-based. Free tier: 2,500 credits. Each search = 1 credit.\n- **Failure mode:** Returns 403 when credits exhausted. Credits don't reset — must purchase more.\n- **Safe pattern:** Batch intent before querying. One well-crafted query beats three exploratory ones.\n- **Result types:** `/search` (web), `/images`, `/news`, `/places`, `/scholar` — each costs 1 credit regardless of type\n- **Never:** Fire exploratory parallel queries — each one costs a credit whether useful or not\n- **vs. Brave:** Serper returns Google results (higher coverage), Brave returns Brave index (more privacy-friendly, often enough for research). Use Brave first, Serper when Google coverage matters.\n- **First observed:** 2026-04-18\n\n---\n\n## Notion API\n\n- **Endpoint:** `api.notion.com/v1/`\n- **Auth:** Bearer integration token + `Notion-Version: 2022-06-28` header (required)\n- **Rate limit:** 3 requests/second per integration. Hard wall — 429 with no retry-after header.\n- **Safe pattern:** 350ms sleep between requests. Never parallel.\n- **Pagination:** All list endpoints are paginated — `has_more` + `next_cursor` pattern. Max page size: 100. Always loop until `has_more: false`.\n- **Block vs. page:** Fetching a page gives you metadata only, not content. Content lives in blocks — separate `GET /blocks/{id}/children` call required.\n- **Write quirk:** Appending blocks is additive — there's no replace operation. To update content you must delete existing blocks first, then append.\n- **Never:** Assume a page fetch includes body content — it never does\n- **First observed:** 2026-04-18\n\n---\n\n## Airtable API\n\n- **Endpoint:** `api.airtable.com/v0/<base_id>/<table_name>`\n- **Auth:** `Authorization: Bearer <personal-access-token>`\n- **Rate limit:** 5 requests/second per base. Across all tables in that base combined.\n- **Safe pattern:** 200ms sleep between requests. Batch reads using `filterByFormula` instead of fetching all and filtering client-side.\n- **Pagination:** `offset` token in response — keep fetching until no offset returned. Default page size: 100 records.\n- **Bulk writes:** No true bulk insert. Create up to 10 records per request via array in `records` field. 10 at a time, sleep between batches.\n- **Formula quirk:** `filterByFormula` uses Airtable formula syntax, not SQL. Strings need curly braces: `{Field Name} = 'value'`\n- **Never:** Fetch all records then filter in code — use `filterByFormula` to push filtering server-side\n- **First observed:** 2026-04-18\n\n---\n\n## Stripe API\n\n- **Endpoint:** `api.stripe.com/v1/`\n- **Auth:** Bearer token (secret key) — separate test and live keys, never mix environments\n- **Rate limit:** 100 read requests/second, 100 write requests/second. Rarely hit in normal agent workflows.\n- **Idempotency keys (critical):** Always pass `Idempotency-Key` header on POST requests. Same key = same result, safe to retry. Without it, a network timeout can trigger duplicate operations.\n- **Test vs. live:** Test keys hit a completely separate environment. Test mode objects don't exist in live mode. Never assume an ID from test works in live.\n- **Pagination:** Cursor-based — `starting_after` and `ending_before` params. Default 10 objects, max 100.\n- **Webhooks:** Verify `Stripe-Signature` header on every incoming webhook — do not trust unverified events.\n- **Safe pattern:** Always use idempotency keys on writes. Log the key with the request so you can retry safely.\n- **Never:** Mix test and live keys, or skip idempotency keys on sensitive operations\n- **First observed:** 2026-04-18\n\n---\n\n## HuggingFace Inference API\n\n- **Endpoint:** `api-inference.huggingface.co/models/<model-id>`\n- **Auth:** `Authorization: Bearer hf_...`\n- **Free tier:** Rate-limited, no hard quota published — in practice ~10-30 req/min before throttling\n- **Cold start (the real issue):** Models on free tier spin down when idle. First request after idle returns 503 with `{\"error\": \"Model ... is currently loading\"}` and an `estimated_time` field in seconds. This is NOT a failure — wait and retry.\n- **Safe pattern:** On 503 with `estimated_time`, sleep that many seconds + 5s buffer, then retry once. If still 503, wait another 30s.\n- **Never:** Treat a loading 503 as a hard failure — it's a cold start, not an error\n- **Dedicated endpoints:** If you need reliable latency, use Inference Endpoints (paid) — no cold starts, dedicated hardware\n- **Model-specific behavior:** Some models require specific input formats. Always check the model card before querying a new model.\n- **First observed:** 2026-04-18\n\n---\n\n## Firecrawl\n\n- **Endpoint:** `api.firecrawl.dev/v1/scrape` (single URL) or `/v1/crawl` (multi-page)\n- **Auth:** `Authorization: Bearer fc-...`\n- **Model:** Credit-based. Free tier: 500 credits/month. Single scrape = 1 credit. Crawl = 1 credit per page crawled.\n- **JS rendering:** Enabled by default — adds 3-8s latency per page vs. static fetch. Use `formats: [\"markdown\"]` to get clean LLM-ready output.\n- **vs. web_fetch:** Firecrawl handles JS-rendered pages, paywalls, and complex layouts. Use web_fetch for simple static pages — faster and free. Escalate to Firecrawl when web_fetch returns garbled or incomplete content.\n- **Crawl vs. scrape:** `/scrape` is one URL, instant response. `/crawl` is async — returns a job ID, poll `/v1/crawl/<id>` until `status: completed`.\n- **Safe pattern:** Scrape first. Only crawl if you need multiple pages from the same domain.\n- **Never:** Use `/crawl` when `/scrape` is sufficient — crawl burns credits per page\n- **First observed:** 2026-04-18\n\nArchive v2.0.0: 3 files, 7391 bytes\n\nFiles: references/profiles.md (12399b), SKILL.md (3768b), _meta.json (134b)\n\nFile v2.0.0:SKILL.md\n\n---\nname: agent-tollbooth\nversion: 1.3.1\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nhomepage: https://github.com/highnoonoffice/agent-tollbooth\nsource: https://github.com/highnoonoffice/agent-tollbooth\nlicense: MIT\nmetadata: ~\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nYou're mid-task. Your agent fires a Yahoo Finance request. Gets a 429. Stops. You don't know if it's rate limits, a bad endpoint, a missing header, or just bad luck. You try again. Same thing. You start debugging blind.\n\nTollbooth is the field notes that stop this from happening twice. Observed operating profiles for 16 external services — safe endpoints, sleep intervals, caching patterns, auth requirements — built from real API friction. Your agent checks the profile before calling, follows the safe pattern, and logs what happens. Next time it already knows.\n\nEvery external service has a threshold. This skill provides the map so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. Cache files go to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. Set `OPENCLAW_WORKSPACE` before running (standard on any OpenClaw install).\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n- OpenAI API\n- Anthropic API\n- GitHub API\n- Brave Search API\n- Serper (Google Search)\n- Notion API\n- Airtable API\n- Stripe API\n- HuggingFace Inference API\n- Firecrawl\n\nFile v2.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"2.0.0\",\n  \"publishedAt\": 1776635259380\n}\n\nFile v2.0.0:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Exponential backoff on 429. Header `retry-after` tells you exactly how long to wait — use it.\n- **Streaming vs. non-streaming:** Both count equally against rate limits. Streaming does NOT get preferential treatment.\n- **Model-specific ceilings:** GPT-4o has lower RPM than GPT-4o-mini on the same tier. Always check the model's specific limit, not the account's general limit.\n- **Never:** Parallel requests on free/tier-1 — you'll 429 immediately and waste retries\n- **Cache:** Cache completions aggressively. Same prompt = same response at temperature 0. Save tokens and money.\n- **First observed:** 2026-04-18\n\n---\n\n## Anthropic API\n\n- **Endpoint:** `api.anthropic.com/v1/messages`\n- **Auth:** `x-api-key` header — not Bearer format\n- **Rate limits:** Two separate ceilings: RPM (requests per minute) AND TPM (tokens per minute). Hitting either triggers 429.\n- **TPM is usually the binding constraint** — a single large context window can eat your TPM budget before RPM becomes relevant\n- **Model-specific limits:** Haiku has higher RPM/TPM ceilings than Sonnet, which has higher than Opus. Route cheap tasks to Haiku.\n- **Prompt caching:** Prefix caching cuts token cost 90% on cached portions. Cache prefix must be identical to the character — a single token difference breaks the cache.\n- **Safe pattern:** Check `x-ratelimit-remaining-tokens` and `x-ratelimit-remaining-requests` headers on every response\n- **Streaming:** Use streaming for long responses — avoids gateway timeouts on responses > 30s\n- **Never:** Assume Haiku limits apply to Sonnet or vice versa — they're tracked independently\n- **First observed:** 2026-04-18\n\n---\n\n## GitHub API\n\n- **Endpoint:** `api.github.com`\n- **Auth:** `Authorization: Bearer <PAT>` — classic or fine-grained PAT\n- **Primary rate limit:** 5,000 req/hr authenticated. 60 req/hr unauthenticated. Check `x-ratelimit-remaining` header.\n- **Secondary rate limits (the real gotcha):** Separate from the primary limit. Triggered by: too many write operations in a short window, too many concurrent requests, too many requests to a single endpoint. Returns 403, not 429.\n- **Safe pattern:** Sequential writes with 1s sleep between. Never fire parallel POST/PATCH/DELETE calls.\n- **Search API:** Separate limit — 30 req/min authenticated, 10 unauthenticated. Completely independent of the main 5,000/hr.\n- **GraphQL:** Single endpoint `api.github.com/graphql` — counts as one request regardless of query complexity, but has its own point budget\n- **Pagination:** Always paginate — default page size is 30, max 100. Never assume you got all results on page 1.\n- **Never:** Use unauthenticated requests for anything beyond occasional public repo reads\n- **First observed:** 2026-04-18\n\n---\n\n## Brave Search API\n\n- **Endpoint:** `api.search.brave.com/res/v1/web/search`\n- **Auth:** `X-Subscription-Token` header\n- **Model:** Credit-based, NOT rate-based. Each query costs credits regardless of response size.\n- **Free tier:** 2,000 queries/month. Does not reset on 429 — it hard-stops when credits are exhausted.\n- **Failure mode:** Returns 429 when monthly credits are gone. This is a budget wall, not a speed wall — waiting does not help. Credits reset on billing date.\n- **Safe pattern:** Cache results aggressively. Same query within a session = serve from cache, don't re-query.\n- **No retry value on 429:** Unlike most APIs, retrying a Brave 429 immediately is useless — you're out of credits, not over a speed limit.\n- **Results freshness:** `freshness` param accepts `day`, `week`, `month`, `year` — use it to filter stale results on time-sensitive queries\n- **First observed:** 2026-04-18\n\n---\n\n## Serper (Google Search API)\n\n- **Endpoint:** `google.serper.dev/search`\n- **Auth:** `X-API-KEY` header\n- **Model:** Credit-based. Free tier: 2,500 credits. Each search = 1 credit.\n- **Failure mode:** Returns 403 when credits exhausted. Credits don't reset — must purchase more.\n- **Safe pattern:** Batch intent before querying. One well-crafted query beats three exploratory ones.\n- **Result types:** `/search` (web), `/images`, `/news`, `/places`, `/scholar` — each costs 1 credit regardless of type\n- **Never:** Fire exploratory parallel queries — each one costs a credit whether useful or not\n- **vs. Brave:** Serper returns Google results (higher coverage), Brave returns Brave index (more privacy-friendly, often enough for research). Use Brave first, Serper when Google coverage matters.\n- **First observed:** 2026-04-18\n\n---\n\n## Notion API\n\n- **Endpoint:** `api.notion.com/v1/`\n- **Auth:** Bearer integration token + `Notion-Version: 2022-06-28` header (required)\n- **Rate limit:** 3 requests/second per integration. Hard wall — 429 with no retry-after header.\n- **Safe pattern:** 350ms sleep between requests. Never parallel.\n- **Pagination:** All list endpoints are paginated — `has_more` + `next_cursor` pattern. Max page size: 100. Always loop until `has_more: false`.\n- **Block vs. page:** Fetching a page gives you metadata only, not content. Content lives in blocks — separate `GET /blocks/{id}/children` call required.\n- **Write quirk:** Appending blocks is additive — there's no replace operation. To update content you must delete existing blocks first, then append.\n- **Never:** Assume a page fetch includes body content — it never does\n- **First observed:** 2026-04-18\n\n---\n\n## Airtable API\n\n- **Endpoint:** `api.airtable.com/v0/<base_id>/<table_name>`\n- **Auth:** `Authorization: Bearer <personal-access-token>`\n- **Rate limit:** 5 requests/second per base. Across all tables in that base combined.\n- **Safe pattern:** 200ms sleep between requests. Batch reads using `filterByFormula` instead of fetching all and filtering client-side.\n- **Pagination:** `offset` token in response — keep fetching until no offset returned. Default page size: 100 records.\n- **Bulk writes:** No true bulk insert. Create up to 10 records per request via array in `records` field. 10 at a time, sleep between batches.\n- **Formula quirk:** `filterByFormula` uses Airtable formula syntax, not SQL. Strings need curly braces: `{Field Name} = 'value'`\n- **Never:** Fetch all records then filter in code — use `filterByFormula` to push filtering server-side\n- **First observed:** 2026-04-18\n\n---\n\n## Stripe API\n\n- **Endpoint:** `api.stripe.com/v1/`\n- **Auth:** Bearer token (secret key) — separate test and live keys, never mix environments\n- **Rate limit:** 100 read requests/second, 100 write requests/second. Rarely hit in normal agent workflows.\n- **Idempotency keys (critical):** Always pass `Idempotency-Key` header on POST requests. Same key = same result, safe to retry. Without it, a network timeout can trigger duplicate operations.\n- **Test vs. live:** Test keys hit a completely separate environment. Test mode objects don't exist in live mode. Never assume an ID from test works in live.\n- **Pagination:** Cursor-based — `starting_after` and `ending_before` params. Default 10 objects, max 100.\n- **Webhooks:** Verify `Stripe-Signature` header on every incoming webhook — do not trust unverified events.\n- **Safe pattern:** Always use idempotency keys on writes. Log the key with the request so you can retry safely.\n- **Never:** Mix test and live keys, or skip idempotency keys on sensitive operations\n- **First observed:** 2026-04-18\n\n---\n\n## HuggingFace Inference API\n\n- **Endpoint:** `api-inference.huggingface.co/models/<model-id>`\n- **Auth:** `Authorization: Bearer hf_...`\n- **Free tier:** Rate-limited, no hard quota published — in practice ~10-30 req/min before throttling\n- **Cold start (the real issue):** Models on free tier spin down when idle. First request after idle returns 503 with `{\"error\": \"Model ... is currently loading\"}` and an `estimated_time` field in seconds. This is NOT a failure — wait and retry.\n- **Safe pattern:** On 503 with `estimated_time`, sleep that many seconds + 5s buffer, then retry once. If still 503, wait another 30s.\n- **Never:** Treat a loading 503 as a hard failure — it's a cold start, not an error\n- **Dedicated endpoints:** If you need reliable latency, use Inference Endpoints (paid) — no cold starts, dedicated hardware\n- **Model-specific behavior:** Some models require specific input formats. Always check the model card before querying a new model.\n- **First observed:** 2026-04-18\n\n---\n\n## Firecrawl\n\n- **Endpoint:** `api.firecrawl.dev/v1/scrape` (single URL) or `/v1/crawl` (multi-page)\n- **Auth:** `Authorization: Bearer fc-...`\n- **Model:** Credit-based. Free tier: 500 credits/month. Single scrape = 1 credit. Crawl = 1 credit per page crawled.\n- **JS rendering:** Enabled by default — adds 3-8s latency per page vs. static fetch. Use `formats: [\"markdown\"]` to get clean LLM-ready output.\n- **vs. web_fetch:** Firecrawl handles JS-rendered pages, paywalls, and complex layouts. Use web_fetch for simple static pages — faster and free. Escalate to Firecrawl when web_fetch returns garbled or incomplete content.\n- **Crawl vs. scrape:** `/scrape` is one URL, instant response. `/crawl` is async — returns a job ID, poll `/v1/crawl/<id>` until `status: completed`.\n- **Safe pattern:** Scrape first. Only crawl if you need multiple pages from the same domain.\n- **Never:** Use `/crawl` when `/scrape` is sufficient — crawl burns credits per page\n- **First observed:** 2026-04-18\n\nArchive v1.4.1: 8 files, 18408 bytes\n\nFiles: references/profiles.md (12399b), scripts/check-profile.py (4985b), scripts/fetch-crypto.py (5859b), scripts/fetch-prices.py (6232b), scripts/promote-profile.py (8155b), scripts/web-log.py (4153b), SKILL.md (3059b), _meta.json (134b)\n\nFile v1.4.1:SKILL.md\n\n---\nname: agent-tollbooth\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nEvery external service has a threshold. This skill provides observed operating profiles so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. Cache files go to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. Set `OPENCLAW_WORKSPACE` before running (standard on any OpenClaw install).\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n- OpenAI API\n- Anthropic API\n- GitHub API\n- Brave Search API\n- Serper (Google Search)\n- Notion API\n- Airtable API\n- Stripe API\n- HuggingFace Inference API\n- Firecrawl\n\nFile v1.4.1:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"1.4.1\",\n  \"publishedAt\": 1776547335864\n}\n\nFile v1.4.1:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Exponential backoff on 429. Header `retry-after` tells you exactly how long to wait — use it.\n- **Streaming vs. non-streaming:** Both count equally against rate limits. Streaming does NOT get preferential treatment.\n- **Model-specific ceilings:** GPT-4o has lower RPM than GPT-4o-mini on the same tier. Always check the model's specific limit, not the account's general limit.\n- **Never:** Parallel requests on free/tier-1 — you'll 429 immediately and waste retries\n- **Cache:** Cache completions aggressively. Same prompt = same response at temperature 0. Save tokens and money.\n- **First observed:** 2026-04-18\n\n---\n\n## Anthropic API\n\n- **Endpoint:** `api.anthropic.com/v1/messages`\n- **Auth:** `x-api-key` header — not Bearer format\n- **Rate limits:** Two separate ceilings: RPM (requests per minute) AND TPM (tokens per minute). Hitting either triggers 429.\n- **TPM is usually the binding constraint** — a single large context window can eat your TPM budget before RPM becomes relevant\n- **Model-specific limits:** Haiku has higher RPM/TPM ceilings than Sonnet, which has higher than Opus. Route cheap tasks to Haiku.\n- **Prompt caching:** Prefix caching cuts token cost 90% on cached portions. Cache prefix must be identical to the character — a single token difference breaks the cache.\n- **Safe pattern:** Check `x-ratelimit-remaining-tokens` and `x-ratelimit-remaining-requests` headers on every response\n- **Streaming:** Use streaming for long responses — avoids gateway timeouts on responses > 30s\n- **Never:** Assume Haiku limits apply to Sonnet or vice versa — they're tracked independently\n- **First observed:** 2026-04-18\n\n---\n\n## GitHub API\n\n- **Endpoint:** `api.github.com`\n- **Auth:** `Authorization: Bearer <PAT>` — classic or fine-grained PAT\n- **Primary rate limit:** 5,000 req/hr authenticated. 60 req/hr unauthenticated. Check `x-ratelimit-remaining` header.\n- **Secondary rate limits (the real gotcha):** Separate from the primary limit. Triggered by: too many write operations in a short window, too many concurrent requests, too many requests to a single endpoint. Returns 403, not 429.\n- **Safe pattern:** Sequential writes with 1s sleep between. Never fire parallel POST/PATCH/DELETE calls.\n- **Search API:** Separate limit — 30 req/min authenticated, 10 unauthenticated. Completely independent of the main 5,000/hr.\n- **GraphQL:** Single endpoint `api.github.com/graphql` — counts as one request regardless of query complexity, but has its own point budget\n- **Pagination:** Always paginate — default page size is 30, max 100. Never assume you got all results on page 1.\n- **Never:** Use unauthenticated requests for anything beyond occasional public repo reads\n- **First observed:** 2026-04-18\n\n---\n\n## Brave Search API\n\n- **Endpoint:** `api.search.brave.com/res/v1/web/search`\n- **Auth:** `X-Subscription-Token` header\n- **Model:** Credit-based, NOT rate-based. Each query costs credits regardless of response size.\n- **Free tier:** 2,000 queries/month. Does not reset on 429 — it hard-stops when credits are exhausted.\n- **Failure mode:** Returns 429 when monthly credits are gone. This is a budget wall, not a speed wall — waiting does not help. Credits reset on billing date.\n- **Safe pattern:** Cache results aggressively. Same query within a session = serve from cache, don't re-query.\n- **No retry value on 429:** Unlike most APIs, retrying a Brave 429 immediately is useless — you're out of credits, not over a speed limit.\n- **Results freshness:** `freshness` param accepts `day`, `week`, `month`, `year` — use it to filter stale results on time-sensitive queries\n- **First observed:** 2026-04-18\n\n---\n\n## Serper (Google Search API)\n\n- **Endpoint:** `google.serper.dev/search`\n- **Auth:** `X-API-KEY` header\n- **Model:** Credit-based. Free tier: 2,500 credits. Each search = 1 credit.\n- **Failure mode:** Returns 403 when credits exhausted. Credits don't reset — must purchase more.\n- **Safe pattern:** Batch intent before querying. One well-crafted query beats three exploratory ones.\n- **Result types:** `/search` (web), `/images`, `/news`, `/places`, `/scholar` — each costs 1 credit regardless of type\n- **Never:** Fire exploratory parallel queries — each one costs a credit whether useful or not\n- **vs. Brave:** Serper returns Google results (higher coverage), Brave returns Brave index (more privacy-friendly, often enough for research). Use Brave first, Serper when Google coverage matters.\n- **First observed:** 2026-04-18\n\n---\n\n## Notion API\n\n- **Endpoint:** `api.notion.com/v1/`\n- **Auth:** Bearer integration token + `Notion-Version: 2022-06-28` header (required)\n- **Rate limit:** 3 requests/second per integration. Hard wall — 429 with no retry-after header.\n- **Safe pattern:** 350ms sleep between requests. Never parallel.\n- **Pagination:** All list endpoints are paginated — `has_more` + `next_cursor` pattern. Max page size: 100. Always loop until `has_more: false`.\n- **Block vs. page:** Fetching a page gives you metadata only, not content. Content lives in blocks — separate `GET /blocks/{id}/children` call required.\n- **Write quirk:** Appending blocks is additive — there's no replace operation. To update content you must delete existing blocks first, then append.\n- **Never:** Assume a page fetch includes body content — it never does\n- **First observed:** 2026-04-18\n\n---\n\n## Airtable API\n\n- **Endpoint:** `api.airtable.com/v0/<base_id>/<table_name>`\n- **Auth:** `Authorization: Bearer <personal-access-token>`\n- **Rate limit:** 5 requests/second per base. Across all tables in that base combined.\n- **Safe pattern:** 200ms sleep between requests. Batch reads using `filterByFormula` instead of fetching all and filtering client-side.\n- **Pagination:** `offset` token in response — keep fetching until no offset returned. Default page size: 100 records.\n- **Bulk writes:** No true bulk insert. Create up to 10 records per request via array in `records` field. 10 at a time, sleep between batches.\n- **Formula quirk:** `filterByFormula` uses Airtable formula syntax, not SQL. Strings need curly braces: `{Field Name} = 'value'`\n- **Never:** Fetch all records then filter in code — use `filterByFormula` to push filtering server-side\n- **First observed:** 2026-04-18\n\n---\n\n## Stripe API\n\n- **Endpoint:** `api.stripe.com/v1/`\n- **Auth:** Bearer token (secret key) — separate test and live keys, never mix environments\n- **Rate limit:** 100 read requests/second, 100 write requests/second. Rarely hit in normal agent workflows.\n- **Idempotency keys (critical):** Always pass `Idempotency-Key` header on POST requests. Same key = same result, safe to retry. Without it, a network timeout can trigger duplicate operations.\n- **Test vs. live:** Test keys hit a completely separate environment. Test mode objects don't exist in live mode. Never assume an ID from test works in live.\n- **Pagination:** Cursor-based — `starting_after` and `ending_before` params. Default 10 objects, max 100.\n- **Webhooks:** Verify `Stripe-Signature` header on every incoming webhook — do not trust unverified events.\n- **Safe pattern:** Always use idempotency keys on writes. Log the key with the request so you can retry safely.\n- **Never:** Mix test and live keys, or skip idempotency keys on sensitive operations\n- **First observed:** 2026-04-18\n\n---\n\n## HuggingFace Inference API\n\n- **Endpoint:** `api-inference.huggingface.co/models/<model-id>`\n- **Auth:** `Authorization: Bearer hf_...`\n- **Free tier:** Rate-limited, no hard quota published — in practice ~10-30 req/min before throttling\n- **Cold start (the real issue):** Models on free tier spin down when idle. First request after idle returns 503 with `{\"error\": \"Model ... is currently loading\"}` and an `estimated_time` field in seconds. This is NOT a failure — wait and retry.\n- **Safe pattern:** On 503 with `estimated_time`, sleep that many seconds + 5s buffer, then retry once. If still 503, wait another 30s.\n- **Never:** Treat a loading 503 as a hard failure — it's a cold start, not an error\n- **Dedicated endpoints:** If you need reliable latency, use Inference Endpoints (paid) — no cold starts, dedicated hardware\n- **Model-specific behavior:** Some models require specific input formats. Always check the model card before querying a new model.\n- **First observed:** 2026-04-18\n\n---\n\n## Firecrawl\n\n- **Endpoint:** `api.firecrawl.dev/v1/scrape` (single URL) or `/v1/crawl` (multi-page)\n- **Auth:** `Authorization: Bearer fc-...`\n- **Model:** Credit-based. Free tier: 500 credits/month. Single scrape = 1 credit. Crawl = 1 credit per page crawled.\n- **JS rendering:** Enabled by default — adds 3-8s latency per page vs. static fetch. Use `formats: [\"markdown\"]` to get clean LLM-ready output.\n- **vs. web_fetch:** Firecrawl handles JS-rendered pages, paywalls, and complex layouts. Use web_fetch for simple static pages — faster and free. Escalate to Firecrawl when web_fetch returns garbled or incomplete content.\n- **Crawl vs. scrape:** `/scrape` is one URL, instant response. `/crawl` is async — returns a job ID, poll `/v1/crawl/<id>` until `status: completed`.\n- **Safe pattern:** Scrape first. Only crawl if you need multiple pages from the same domain.\n- **Never:** Use `/crawl` when `/scrape` is sufficient — crawl burns credits per page\n- **First observed:** 2026-04-18\n\nArchive v1.4.0: 8 files, 18513 bytes\n\nFiles: references/profiles.md (12465b), scripts/check-profile.py (5065b), scripts/fetch-crypto.py (5859b), scripts/fetch-prices.py (6232b), scripts/promote-profile.py (8235b), scripts/web-log.py (4233b), SKILL.md (3103b), _meta.json (134b)\n\nFile v1.4.0:SKILL.md\n\n---\nname: agent-tollbooth\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nEvery external service has a threshold. This skill provides observed operating profiles so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/` (falls back to `./data/cache/` if env var not set)\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. Cache files go to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. All paths fall back to `./data/` if `OPENCLAW_WORKSPACE` is not set.\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n- OpenAI API\n- Anthropic API\n- GitHub API\n- Brave Search API\n- Serper (Google Search)\n- Notion API\n- Airtable API\n- Stripe API\n- HuggingFace Inference API\n- Firecrawl\n\nFile v1.4.0:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"1.4.0\",\n  \"publishedAt\": 1776547110680\n}\n\nFile v1.4.0:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Exponential backoff on 429. Header `retry-after` tells you exactly how long to wait — use it.\n- **Streaming vs. non-streaming:** Both count equally against rate limits. Streaming does NOT get preferential treatment.\n- **Model-specific ceilings:** GPT-4o has lower RPM than GPT-4o-mini on the same tier. Always check the model's specific limit, not the account's general limit.\n- **Never:** Parallel requests on free/tier-1 — you'll 429 immediately and waste retries\n- **Cache:** Cache completions aggressively. Same prompt = same response at temperature 0. Save tokens and money.\n- **First observed:** 2026-04-18\n\n---\n\n## Anthropic API\n\n- **Endpoint:** `api.anthropic.com/v1/messages`\n- **Auth:** `x-api-key` header — not Bearer format\n- **Rate limits:** Two separate ceilings: RPM (requests per minute) AND TPM (tokens per minute). Hitting either triggers 429.\n- **TPM is usually the binding constraint** — a single large context window can eat your TPM budget before RPM becomes relevant\n- **Model-specific limits:** Haiku has higher RPM/TPM ceilings than Sonnet, which has higher than Opus. Route cheap tasks to Haiku.\n- **Prompt caching:** Prefix caching cuts token cost 90% on cached portions. Cache prefix must be identical to the character — a single token difference breaks the cache.\n- **Safe pattern:** Check `x-ratelimit-remaining-tokens` and `x-ratelimit-remaining-requests` headers on every response\n- **Streaming:** Use streaming for long responses — avoids gateway timeouts on responses > 30s\n- **Never:** Assume Haiku limits apply to Sonnet or vice versa — they're tracked independently\n- **First observed:** 2026-04-18\n\n---\n\n## GitHub API\n\n- **Endpoint:** `api.github.com`\n- **Auth:** `Authorization: Bearer <PAT>` — classic or fine-grained PAT\n- **Primary rate limit:** 5,000 req/hr authenticated. 60 req/hr unauthenticated. Check `x-ratelimit-remaining` header.\n- **Secondary rate limits (the real gotcha):** Separate from the primary limit. Triggered by: too many write operations in a short window, too many concurrent requests, too many requests to a single endpoint. Returns 403, not 429.\n- **Safe pattern:** Sequential writes with 1s sleep between. Never fire parallel POST/PATCH/DELETE calls.\n- **Search API:** Separate limit — 30 req/min authenticated, 10 unauthenticated. Completely independent of the main 5,000/hr.\n- **GraphQL:** Single endpoint `api.github.com/graphql` — counts as one request regardless of query complexity, but has its own point budget\n- **Pagination:** Always paginate — default page size is 30, max 100. Never assume you got all results on page 1.\n- **Never:** Use unauthenticated requests for anything beyond occasional public repo reads\n- **First observed:** 2026-04-18\n\n---\n\n## Brave Search API\n\n- **Endpoint:** `api.search.brave.com/res/v1/web/search`\n- **Auth:** `X-Subscription-Token` header\n- **Model:** Credit-based, NOT rate-based. Each query costs credits regardless of response size.\n- **Free tier:** 2,000 queries/month. Does not reset on 429 — it hard-stops when credits are exhausted.\n- **Failure mode:** Returns 429 when monthly credits are gone. This is a budget wall, not a speed wall — waiting does not help. Credits reset on billing date.\n- **Safe pattern:** Cache results aggressively. Same query within a session = serve from cache, don't re-query.\n- **No retry value on 429:** Unlike most APIs, retrying a Brave 429 immediately is useless — you're out of credits, not over a speed limit.\n- **Results freshness:** `freshness` param accepts `day`, `week`, `month`, `year` — use it to filter stale results on time-sensitive queries\n- **First observed:** 2026-04-18\n\n---\n\n## Serper (Google Search API)\n\n- **Endpoint:** `google.serper.dev/search`\n- **Auth:** `X-API-KEY` header\n- **Model:** Credit-based. Free tier: 2,500 credits. Each search = 1 credit.\n- **Failure mode:** Returns 403 when credits exhausted. Credits don't reset — must purchase more.\n- **Safe pattern:** Batch intent before querying. One well-crafted query beats three exploratory ones.\n- **Result types:** `/search` (web), `/images`, `/news`, `/places`, `/scholar` — each costs 1 credit regardless of type\n- **Never:** Fire exploratory parallel queries — each one costs a credit whether useful or not\n- **vs. Brave:** Serper returns Google results (higher coverage), Brave returns Brave index (more privacy-friendly, often enough for research). Use Brave first, Serper when Google coverage matters.\n- **First observed:** 2026-04-18\n\n---\n\n## Notion API\n\n- **Endpoint:** `api.notion.com/v1/`\n- **Auth:** `Authorization: Bearer <integration-token>` + `Notion-Version: 2022-06-28` header (required)\n- **Rate limit:** 3 requests/second per integration. Hard wall — 429 with no retry-after header.\n- **Safe pattern:** 350ms sleep between requests. Never parallel.\n- **Pagination:** All list endpoints are paginated — `has_more` + `next_cursor` pattern. Max page size: 100. Always loop until `has_more: false`.\n- **Block vs. page:** Fetching a page gives you metadata only, not content. Content lives in blocks — separate `GET /blocks/{id}/children` call required.\n- **Write quirk:** Appending blocks is additive — there's no replace operation. To update content you must delete existing blocks first, then append.\n- **Never:** Assume a page fetch includes body content — it never does\n- **First observed:** 2026-04-18\n\n---\n\n## Airtable API\n\n- **Endpoint:** `api.airtable.com/v0/<base_id>/<table_name>`\n- **Auth:** `Authorization: Bearer <personal-access-token>`\n- **Rate limit:** 5 requests/second per base. Across all tables in that base combined.\n- **Safe pattern:** 200ms sleep between requests. Batch reads using `filterByFormula` instead of fetching all and filtering client-side.\n- **Pagination:** `offset` token in response — keep fetching until no offset returned. Default page size: 100 records.\n- **Bulk writes:** No true bulk insert. Create up to 10 records per request via array in `records` field. 10 at a time, sleep between batches.\n- **Formula quirk:** `filterByFormula` uses Airtable formula syntax, not SQL. Strings need curly braces: `{Field Name} = 'value'`\n- **Never:** Fetch all records then filter in code — use `filterByFormula` to push filtering server-side\n- **First observed:** 2026-04-18\n\n---\n\n## Stripe API\n\n- **Endpoint:** `api.stripe.com/v1/`\n- **Auth:** `Authorization: Bearer sk_live_...` or `sk_test_...` — never mix live and test keys\n- **Rate limit:** 100 read requests/second, 100 write requests/second. In practice you'll never hit this in normal agent workflows.\n- **Idempotency keys (critical):** Always pass `Idempotency-Key` header on POST requests. Same key = same result, safe to retry. Without it, a network timeout can create duplicate charges.\n- **Test vs. live:** `sk_test_` keys hit a completely separate environment. Test mode objects don't exist in live mode and vice versa. Never assume an ID from test works in live.\n- **Pagination:** Cursor-based — `starting_after` and `ending_before` params. Default 10 objects, max 100.\n- **Webhooks:** Verify `Stripe-Signature` header on every incoming webhook — do not trust unverified events.\n- **Safe pattern:** Always use idempotency keys on writes. Log the key with the request so you can retry safely.\n- **Never:** Use a live key in development, or skip idempotency keys on payment creation\n- **First observed:** 2026-04-18\n\n---\n\n## HuggingFace Inference API\n\n- **Endpoint:** `api-inference.huggingface.co/models/<model-id>`\n- **Auth:** `Authorization: Bearer hf_...`\n- **Free tier:** Rate-limited, no hard quota published — in practice ~10-30 req/min before throttling\n- **Cold start (the real issue):** Models on free tier spin down when idle. First request after idle returns 503 with `{\"error\": \"Model ... is currently loading\"}` and an `estimated_time` field in seconds. This is NOT a failure — wait and retry.\n- **Safe pattern:** On 503 with `estimated_time`, sleep that many seconds + 5s buffer, then retry once. If still 503, wait another 30s.\n- **Never:** Treat a loading 503 as a hard failure — it's a cold start, not an error\n- **Dedicated endpoints:** If you need reliable latency, use Inference Endpoints (paid) — no cold starts, dedicated hardware\n- **Model-specific behavior:** Some models require specific input formats. Always check the model card before querying a new model.\n- **First observed:** 2026-04-18\n\n---\n\n## Firecrawl\n\n- **Endpoint:** `api.firecrawl.dev/v1/scrape` (single URL) or `/v1/crawl` (multi-page)\n- **Auth:** `Authorization: Bearer fc-...`\n- **Model:** Credit-based. Free tier: 500 credits/month. Single scrape = 1 credit. Crawl = 1 credit per page crawled.\n- **JS rendering:** Enabled by default — adds 3-8s latency per page vs. static fetch. Use `formats: [\"markdown\"]` to get clean LLM-ready output.\n- **vs. web_fetch:** Firecrawl handles JS-rendered pages, paywalls, and complex layouts. Use web_fetch for simple static pages — faster and free. Escalate to Firecrawl when web_fetch returns garbled or incomplete content.\n- **Crawl vs. scrape:** `/scrape` is one URL, instant response. `/crawl` is async — returns a job ID, poll `/v1/crawl/<id>` until `status: completed`.\n- **Safe pattern:** Scrape first. Only crawl if you need multiple pages from the same domain.\n- **Never:** Use `/crawl` when `/scrape` is sufficient — crawl burns credits per page\n- **First observed:** 2026-04-18\n\nArchive v1.3.6: 6 files, 9062 bytes\n\nFiles: references/profiles.md (2611b), scripts/fetch-crypto.py (5859b), scripts/fetch-prices.py (6232b), scripts/web-log.py (4233b), SKILL.md (2232b), _meta.json (134b)\n\nFile v1.3.6:SKILL.md\n\n---\nname: agent-tollbooth\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nEvery external service has a threshold. This skill provides observed operating profiles so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/` (falls back to `./data/cache/` if env var not set)\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nScripts call `scripts/web-log.py` via `log_event(service, event_type, detail, worked=None)` on every speed bump and success. Events are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. `429`, `timeout`, and `auth_failure` events reveal friction points. `cache_hit` and `success` events show what paths are working reliably.\n\nCache files are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. All write paths fall back to `./data/` if `OPENCLAW_WORKSPACE` is not set.\n\n## Workspace Access\n\nThis skill writes event logs and cache files to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/`. No credentials are accessed. No sensitive data is written. No files outside this directory are touched.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n\nFile v1.3.6:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"1.3.6\",\n  \"publishedAt\": 1776492645706\n}\n\nFile v1.3.6:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\nArchive v1.3.5: 7 files, 11912 bytes\n\nFiles: references/profiles.md (2611b), scripts/fetch-crypto.py (5859b), scripts/fetch-image.py (7927b), scripts/fetch-prices.py (6232b), scripts/web-log.py (4233b), SKILL.md (3005b), _meta.json (134b)\n\nFile v1.3.5:SKILL.md\n\n---\nname: agent-tollbooth\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\ncredentials:\n  - replicate.json — required by scripts/fetch-image.py to authenticate Replicate image generation API\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nEvery external service has a threshold. This skill provides observed operating profiles so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/` (falls back to `./data/cache/` if env var not set)\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md` — scripts for those services can be added as the skill grows.\n\n## How It Learns\n\nScripts call `scripts/web-log.py` via `log_event(service, event_type, detail, worked=None)` on every speed bump and success. Events are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. `429`, `timeout`, and `auth_failure` events reveal friction points. `cache_hit` and `success` events show what paths are working reliably.\n\nCache files are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. All write paths fall back to `./data/` if `OPENCLAW_WORKSPACE` is not set.\n\n## Credential & Workspace Access\n\nThis skill explicitly accesses the following paths outside the skill bundle:\n\n- **Replicate credentials** — read by `scripts/fetch-image.py` to authenticate the Replicate API. Path is set via `REPLICATE_CREDENTIALS_FILE` env var (defaults to `~/.openclaw/credentials/replicate.json`). Required only if you use that script. Read-only; nothing is written to it.\n- **`$OPENCLAW_WORKSPACE/data/agent-tollbooth/`** — all event logs and cache files are written here. This is intentional external state — the skill learns from real usage over time. No credentials or sensitive data are written to this path.\n\nNo other files outside the skill directory are accessed. No data leaves your machine except via the external API calls explicitly described in each script.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n\nFile v1.3.5:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"1.3.5\",\n  \"publishedAt\": 1776492416667\n}\n\nFile v1.3.5:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\nArchive v1.3.4: 7 files, 11855 bytes\n\nFiles: references/profiles.md (2611b), scripts/fetch-crypto.py (5859b), scripts/fetch-image.py (7851b), scripts/fetch-prices.py (6232b), scripts/web-log.py (4233b), SKILL.md (2948b), _meta.json (134b)\n\nFile v1.3.4:SKILL.md\n\n---\nname: agent-tollbooth\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\ncredentials:\n  - replicate.json — required by scripts/fetch-image.py to authenticate Replicate image generation API\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nEvery external service has a threshold. This skill provides observed operating profiles so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/` (falls back to `./data/cache/` if env var not set)\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md` — scripts for those services can be added as the skill grows.\n\n## How It Learns\n\nScripts call `scripts/web-log.py` via `log_event(service, event_type, detail, worked=None)` on every speed bump and success. Events are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. `429`, `timeout`, and `auth_failure` events reveal friction points. `cache_hit` and `success` events show what paths are working reliably.\n\nCache files are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. All write paths fall back to `./data/` if `OPENCLAW_WORKSPACE` is not set.\n\n## Credential & Workspace Access\n\nThis skill explicitly accesses the following paths outside the skill bundle:\n\n- **`~/.openclaw/credentials/replicate.json`** — read by `scripts/fetch-image.py` to authenticate the Replicate API for image generation. Required only if you use that script. The file is read-only; nothing is written to it.\n- **`$OPENCLAW_WORKSPACE/data/agent-tollbooth/`** — all event logs and cache files are written here. This is intentional external state — the skill learns from real usage over time. No credentials or sensitive data are written to this path.\n\nNo other files outside the skill directory are accessed. No data leaves your machine except via the external API calls explicitly described in each script.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n\nFile v1.3.4:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"1.3.4\",\n  \"publishedAt\": 1776491964173\n}\n\nFile v1.3.4:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\nArchive v1.3.3: 7 files, 11574 bytes\n\nFiles: references/profiles.md (2611b), scripts/fetch-crypto.py (5859b), scripts/fetch-image.py (7851b), scripts/fetch-prices.py (6232b), scripts/web-log.py (4233b), SKILL.md (2206b), _meta.json (134b)\n\nFile v1.3.3:SKILL.md\n\n---\nname: agent-tollbooth\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\ncredentials:\n  - replicate.json — required by scripts/fetch-image.py to authenticate Replicate image generation API\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nEvery external service has a threshold. This skill provides observed operating profiles so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/` (falls back to `./data/cache/` if env var not set)\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md` — scripts for those services can be added as the skill grows.\n\n## How It Learns\n\nScripts call `scripts/web-log.py` via `log_event(service, event_type, detail, worked=None)` on every speed bump and success. Events are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the skill bundle, never modifying packaged files. `429`, `timeout`, and `auth_failure` events reveal friction points. `cache_hit` and `success` events show what paths are working reliably.\n\nCache files are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`. All write paths fall back to `./data/` if `OPENCLAW_WORKSPACE` is not set.\n\n## Service Profiles\n\nSee `references/profiles.md` for all current profiles:\n- Yahoo Finance\n- CoinGecko\n- Ghost Admin API\n- ClawHub API\n- Telegram Bot API\n- Replicate\n\nFile v1.3.3:_meta.json\n\n{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"1.3.3\",\n  \"publishedAt\": 1776491843340\n}\n\nFile v1.3.3:references/profiles.md\n\n# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19","readmeExcerpt":"Skill: agent-tollbooth Owner: highnoonoffice Summary: Web access privileges for your agent. So your agent stops hitting walls. Tags: latest:2.2.1 Version history: v2.2.1 | 2026-08-25T03:47:03.253Z | user Add contact footer v2.2.0 | 2026-04-19T22:13:45.172Z | user Fix: promote-profile.py now writes to $OPENCLAW_WORKSPACE/data/agent-tollbooth/profiles.md — bundled references/profiles.md is read-only. Resolves write-bac","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"python3 scripts/check-profile.py coingecko.com"},{"language":"python","snippet":"from scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")"},{"language":"bash","snippet":"python3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md"},{"language":"bash","snippet":"python3 scripts/check-profile.py coingecko.com"},{"language":"python","snippet":"from scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")"},{"language":"bash","snippet":"python3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: agent-tollbooth\nversion: 2.0.0\ndescription: \"Web access privileges for your agent. So your agent stops hitting walls.\"\nhomepage: https://github.com/highnoonoffice/agent-tollbooth\nsource: https://github.com/highnoonoffice/agent-tollbooth\nlicense: MIT\nmetadata: ~\nconfig:\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json — event log written by scripts/web-log.py\n  - $OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/ — price and response cache written by fetch-crypto.py and fetch-prices.py\n---\n\n# Agent Tollbooth\n\nYou're mid-task. Your agent fires a Yahoo Finance request. Gets a 429. Stops. You don't know if it's rate limits, a bad endpoint, a missing header, or just bad luck. You try again. Same thing. You start debugging blind.\n\nTollbooth is the field notes that stop this from happening twice. Observed operating profiles for 16 external services — safe endpoints, sleep intervals, caching patterns, auth requirements — built from real API friction. Your agent checks the profile before calling, follows the safe pattern, and logs what happens. Next time it already knows.\n\nEvery external service has a threshold. This skill provides the map so agents learn them once and stop hitting them twice.\n\n## Core Pattern\n\nBefore calling any external service:\n1. Check `references/profiles.md` for an existing profile\n2. Follow its safe pattern — endpoint, sleep, cache, auth\n3. If no profile exists, observe behavior and add an entry after\n\n## Caching\n\nAlways cache prices and API responses locally when TTL allows.\n\n- Default TTL: 300s (5 minutes) for prices\n- Cache file: `$OPENCLAW_WORKSPACE/data/agent-tollbooth/cache/`\n- Serve from cache first — only hit the API when stale or forced\n\n**Script:** `scripts/fetch-prices.py` implements cache + sequential Yahoo Finance fetching. Use it instead of raw requests. CoinGecko and other services are covered by profiles in `references/profiles.md`.\n\n## How It Learns\n\nTollbooth grows with your usage. Three scripts form the learning loop:\n\n**Before any external call:**\n```bash\npython3 scripts/check-profile.py coingecko.com\n```\nReturns the safe pattern if a profile exists. If not, logs the miss and returns exit code 1 — your agent can continue, but observation has started.\n\n**During any call — log what happens:**\n```python\nfrom scripts.web_log import log_event\nlog_event(\"my-api.com\", \"429\", \"hit rate limit at 10 req/min\", worked=None)\nlog_event(\"my-api.com\", \"success\", \"sequential 500ms sleep worked\", worked=\"sequential + 500ms sleep\")\n```\n\n**After enough observations — promote to a profile:**\n```bash\npython3 scripts/promote-profile.py           # dry run, see what's ready\npython3 scripts/promote-profile.py --write   # append drafts to profiles.md\n```\nDefault threshold: 5 events. Auto-drafted profiles include all observed friction and working patterns. Review before trusting — they're drafts, not finished entries.\n\nEvents are written to `$OPENCLAW_WORKSPACE/data/agent-tollbooth/web-access-log.json` — outside the"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7826mqweky3s8ys5qd8fzqyh832g8w\",\n  \"slug\": \"agent-tollbooth\",\n  \"version\": \"2.2.1\",\n  \"publishedAt\": 1787629623253\n}"},{"path":"references/profiles.md","content":"# Service Profiles — Observed Operating Behavior\n\nEach entry: safe pattern, known failure modes, first observed date.\n\n---\n\n## Yahoo Finance\n\n- **Endpoint:** `query2.finance.yahoo.com` — preferred. `query1` rate-limits faster.\n- **Auth:** None — User-Agent header required (`Mozilla/5.0 ...`)\n- **Safe pattern:** Sequential requests, 0.6s sleep between tickers\n- **Never:** Parallel requests — triggers 429 immediately\n- **Cache:** 5 minutes minimum — serve from cache whenever possible\n- **Crypto:** Use CoinGecko instead — single batch call, more reliable\n- **Script:** `scripts/fetch-prices.py` wraps all of this automatically\n- **First observed:** 2026-04-17\n\n---\n\n## CoinGecko\n\n- **Endpoint:** `api.coingecko.com/api/v3/simple/price`\n- **Auth:** None on free tier\n- **Safe pattern:** Batch all coins in one call — `ids=bitcoin,ethereum,solana&vs_currencies=usd&include_24hr_change=true`\n- **Free tier:** Generous — rarely rate-limits on normal usage\n- **Cache:** 5 minutes via `fetch-prices.py`\n- **First observed:** 2026-04-17\n\n---\n\n## Ghost Admin API\n\n- **Endpoint:** `https://<site>.ghost.io/ghost/api/admin/`\n- **Auth:** JWT token generated fresh each call from Admin API key\n- **Key location:** your credentials file → field `key` (format: `{\"key\": \"<id>:<secret>\"}`)\n- **Permission wall:** Integration tokens cannot write to `/settings/` — owner-only. Browser automation required for code injection and theme uploads.\n- **Image uploads:** Python `requests` only — curl multipart breaks on macOS zsh\n- **First observed:** 2026-03-17\n\n---\n\n## ClawHub API\n\n- **Endpoint:** `https://clawhub.ai/api/v1/skills`\n- **Auth:** Bearer token from your credentials file\n- **Safe pattern:** Python `requests` with multipart — `data={\"payload\": json.dumps(payload)}` + `files=[...]`\n- **Never:** curl — JSON quoting breaks silently on zsh, returns `Invalid JSON payload` every time\n- **Never:** Browser importer — intermittent server errors, unreliable\n- **First observed:** 2026-03-18\n\n---\n\n## Telegram Bot API\n\n- **Pattern:** Use OpenClaw `message` tool — never raw curl\n- **File delivery:** `sendDocument` endpoint for PDFs and media\n- **Rate limits:** 30 messages/second global, 1 message/second per chat\n- **First observed:** 2026-03-14\n\n---\n\n## Replicate (FLUX image gen)\n\n- **Auth:** API token via OpenClaw config\n- **Error quirk:** \"Less than $5.0 in credit\" error message is unreliable — check dashboard for real balance\n- **Cost:** FLUX 1.1 Pro ~$0.02–0.04/image — $15 balance = 350–700 images. Never needs a top-up for normal usage.\n- **First observed:** 2026-03-19\n\n---\n\n## OpenAI API\n\n- **Endpoint:** `api.openai.com/v1/`\n- **Auth:** Bearer token — `Authorization: Bearer sk-...`\n- **Rate limits:** Tier-dependent. Free tier: 3 RPM / 200 RPD. Tier 1+: 500–3,500 RPM depending on model. Check `x-ratelimit-remaining-requests` response header.\n- **Token limits separate from request limits:** A single request can burn your TPM ceiling without hitting RPM. Watch both.\n- **Safe pattern:** Expo"},{"path":"skill-card.md","content":"## Description:\n\nWeb access privileges for your agent so your agent stops hitting walls.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[highnoonoffice](https://clawhub.ai/user/highnoonoffice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to check observed operating profiles for external services before making web or API calls, including rate-limit patterns, caching guidance, authentication requirements, and known failure modes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill may guide an agent to use authenticated third-party APIs when the user's task requires them.\n\nMitigation: Confirm API credentials, write permissions, and paid API use before allowing the agent to perform authenticated or billable actions.\n\nRisk: Generated or promoted service profiles may be drafts based on local observations.\n\nMitigation: Review generated profiles before relying on them for writes, paid APIs, or repeated automated calls.\n\nRisk: The skill keeps local logs and cache files in the OpenClaw workspace.\n\nMitigation: Review the workspace log and cache location and clear retained data when it is no longer needed.\n\n## Reference(s):\n\n- [Service Profiles - Observed Operating Behavior](references/profiles.md)\n- [ClawHub skill page](https://clawhub.ai/highnoonoffice/skills/agent-tollbooth)\n- [Project homepage](https://github.com/highnoonoffice/agent-tollbooth)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Code, Configuration]\n\n**Output Format:** [Markdown with inline bash and Python code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guidance may reference local OpenClaw log and cache paths under $OPENCLAW_WORKSPACE/data/agent-tollbooth/.]\n\n## Skill Version(s):\n\n2.2.1 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Web access privileges for your agent. So your agent stops hitting walls. Skill: agent-tollbooth Owner: highnoonoffice Summary: Web access privileges for your agent. So your agent stops hitting walls. Tags: latest:2.2.1 Version history: v2.2.1 | 2026-08-25T03:47:03.253Z | user Add contact footer v2.2.0 | 2026-04-19T22:13:45.172Z | user Fix: promote-profile.py now writes to $OPENCLAW_WORKSPACE/data/agent-tollbooth/profiles.md — bundled references/profiles.md is read-only. Resolves write-bac","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1589,"uniquenessScore":49,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T10:56:25.747Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T10:56:25.747Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:15:23.119Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}