Install
openclaw skills install @jlacroix82/api-proxySmart proxy for external API calls with retry, caching, rate limiting, and fallback providers. Key management with masked display. Zero external dependencies.
openclaw skills install @jlacroix82/api-proxyRead this first. This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.
Stop duplicating API logic. Start routing through one smart gateway.
API Gateway is a local Node.js HTTP client wrapper that gives one call:
x-ratelimit-remaining, auto-fallback)--call <provider> <endpoint> sends HTTPS requests and, for configured providers, attaches a Authorization: Bearer <key> header. The provider allowlist is strict: it is a domain-match check, not a string.includes() check. A URL like https://attacker.com/api?provider=openai will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in --keys output before adding sensitive keys.
API keys saved via --keys add are written to memory/api-gateway/keys.json in plaintext, with file permissions set to 0600 (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: OPENAI_API_KEY=sk-... — API Gateway auto-detects any PROVIDER_API_KEY variable (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY) and uses it without disk storage. It does NOT read arbitrary env:NAME references — only the PROVIDER_API_KEY pattern — so unrelated secrets are never pulled in.
The following files persist in memory/api-gateway/ after any operation:
keys.json — API key storage, chmod 0600cache.json — Metadata-only by default (status code, timestamp, response headers, response body length). The full response body is NOT stored unless you explicitly enable it per provider via --cache-full <provider>.request-log.json — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoint URLs, query strings, and request/response bodies are NOT written here. (Note: if you pass a URL or prompt inside a request body to --call, that body travels to the provider but is never persisted to the log or cache by this skill.)rate-limits.json — Per-provider rate-limit statecircuit-state.json — Per-provider circuit-breaker statefallbacks.json — Fallback provider mappingsAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with --cache --clear and --log --clear.
This skill uses only Node.js built-ins (http, https, fs, path). There is no package.json to install, no transitive dependencies, no npm install step. The code you read is the code that runs.
node skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{"model":"gpt-4","messages":[{"role":"user","content":"hello"}]}'
Retries up to 3 times with exponential backoff. Caches response metadata for 5 minutes.
node skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions
# List configured keys (masked, shows allowlist domains)
node skills/api-gateway/api-gateway.js --keys
# Add a key (with provider allowlist)
node skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com
# Remove a key
node skills/api-gateway/api-gateway.js --keys remove openai
export OPENAI_API_KEY=sk-abc123
node skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{"model":"gpt-4","messages":[]}'
The skill auto-detects PROVIDER_API_KEY env vars and uses them without disk storage. Stored keys take precedence if both are configured.
node skills/api-gateway/api-gateway.js --cache # Show cache entries (metadata only)
node skills/api-gateway/api-gateway.js --cache --clear # Clear cache
node skills/api-gateway/api-gateway.js --log # Show request log (coarse: provider, status class, time)
node skills/api-gateway/api-gateway.js --log --clear # Clear request log
node skills/api-gateway/api-gateway.js --rate openai # Rate limit status
node skills/api-gateway/api-gateway.js --fallback openai anthropic
node skills/api-gateway/api-gateway.js --circuit --status
node skills/api-gateway/api-gateway.js --circuit openai --reset
node skills/api-gateway/api-gateway.js --status
This is the most important section. The skill uses a domain allowlist to decide whether to inject the Authorization: Bearer header:
--keys add <provider> <key> --allow-domain <domain>, that domain is stored alongside the key.*.example.com wildcard).Example allowlist configurations:
# Strict: only api.openai.com gets the OpenAI key
--keys add openai sk-... --allow-domain api.openai.com
# Wildcard: any *.anthropic.com endpoint
--keys add anthropic sk-ant-... --allow-domain "*.anthropic.com"
# Multi-domain (repeat flag)
--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com
If you add a key WITHOUT --allow-domain, the key is still saved but the skill will refuse to attach it to any request until you add at least one allowlist entry. (You can edit keys.json to add allowDomains: ["api.openai.com"] directly.)
{status, headers (redacted), timestamp, bodyLength}. Body content is NOT stored.--cache-full <provider> enables full response body caching for that provider.x-ratelimit-remaining headers--ratememory/api-gateway/keys.json--circuit --status + --circuit <name> --resetData files stored in: memory/api-gateway/
keys.json — API key storage (chmod 0600)fallbacks.json — Fallback provider mappingscache.json — Response cache (metadata-only by default)rate-limits.json — Rate limit trackingrequest-log.json — Request history (coarse: provider, status class, timestamp, NOT endpoints)circuit-state.json — Circuit breaker state per providerOverride data directory:
--dir /path/to/data
# or env var
API_GATEWAY_DIR=/path/to/data node api-gateway.js --status
When making API calls:
--call <provider> <endpoint> [body] instead of direct fetch--keys add <provider> <key> --allow-domain <domain> before first usePROVIDER_API_KEY env vars bypass disk storage entirely. API Gateway auto-detects any PROVIDER_API_KEY environment variable (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented PROVIDER_API_KEY pattern — so unrelated secrets are never exposed to requests or local processing.--fallback primary secondary for critical providers--cache / --log during heartbeats to monitor usage--call --dry-run before executing important callsPROVIDER_API_KEY)--call sends your request (URL, headers, body, prompts) to the provider endpoint YOU specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust.cache.json (especially with --cache-full), and request-log.json persist this data to disk. Clear them after sensitive work (--log --clear, --cache --clear) and never call --cache-full for sensitive providers.--cache-full <provider> stores the ENTIRE response body (which may contain secrets, tokens, personal data, or proprietary content) in cache.json. This is a local data-exposure risk if the host/workspace is shared or later exfiltrated. Never use --cache-full with sensitive providers; prefer the default metadata-only cache.API_GATEWAY_ALLOW_HTTP=1 only for non-credential plaintext endpoints.PROVIDER_API_KEY pattern