RelayKey
← Docs

RelayKey for AI agents

A one-screen recipe for any AI agent (Cursor, Claude Code, Replit, ChatGPT, Codex, etc.) to start using a RelayKey-protected API key without receiving the real production key.

TL;DR

Swap the base URL and API key the agent already uses. That's it.

# Before - in your .env
UPSTREAM_BASE_URL = https://api.elevenlabs.io
UPSTREAM_API_KEY  = sk-real-production-key

# After - in your .env (verify .env is in .gitignore)
UPSTREAM_BASE_URL  = https://proxy.relaykey.ai/conn_xxx
RELAYKEY_API_KEY   = rk_proxy_xxx

Save the token in .env as RELAYKEY_API_KEY, the same variable name across every project so prompts and examples stay uniform. The agent keeps calling the upstream API the same way: same paths, same methods, same request shape. RelayKey enforces the RelayKey's scope, swaps in the real upstream key, forwards the request, and audits the result.

Discovery - /_discover

Every RelayKey proxy exposes a discovery endpoint. GET /_discover with your RELAYKEY_API_KEY and the proxy returns the full list of tools, base URLs, and allowed methods/paths the key can reach. This exists so agent setup is uniform across projects and survives grant changes. If the operator adds or revokes a tool later, you re-run discovery instead of asking for a new prompt.

curl -H "Authorization: Bearer $RELAYKEY_API_KEY" \
  https://proxy.relaykey.ai/_discover

The response shape:

{
  "name": "Kate Mason",
  "email": "[email protected]",
  "type": "recipient",
  "expires_at": "2026-06-01T00:00:00Z",
  "grants": [
    {
      "vendor": "HiBob",
      "connection_id": "conn_hibob",
      "base_url": "https://proxy.relaykey.ai/conn_hibob",
      "upstream_base_url": "https://api.hibob.com",
      "allowed_methods": ["GET"],
      "allowed_paths": ["/v1/people", "/v1/employments/*"]
    }
  ]
}

For each grant, point the SDK at base_url, never upstream_base_url. The upstream URL is shown only so you can recognize what tool the grant maps to. type is "recipient" for legacy/internal compatibility when one key-holder token covers many tools, or "credential" when it's scoped to a single integration.

What you'll be handed

  • Integration name (e.g. ElevenLabs).
  • Proxy base URL of the form https://proxy.relaykey.ai/conn_xxx.
  • Proxy token of the form rk_proxy_....
  • Upstream base URL (the API the RelayKey targets) - used only so you know what to swap.

What to do

  1. Find where the upstream base URL and API key are configured. Typical locations: .env, SDK constructor (new OpenAI({ baseURL, apiKey })), HTTP client config (axios.create({ baseURL })).
  2. Replace the upstream base URL with the proxy base URL.
  3. Replace the upstream API key with the rk_proxy_... token.
  4. Confirm with a single request:
curl -i https://proxy.relaykey.ai/conn_xxx/v1/voices \
  -H "Authorization: Bearer rk_proxy_..."

Expect a 200 from the upstream. The response also carries x-relaykey-decision: allowed.

Header style

Use whichever auth header the upstream SDK already uses. RelayKey accepts both:

Authorization: Bearer rk_proxy_...
x-api-key: rk_proxy_...

If you get blocked

RelayKey returns a structured JSON body when it blocks a request:

{
  "error": "path_not_allowed",
  "message": "Path /admin/users not allowed on this RelayKey",
  "allowed_patterns": ["/v1/*"],
  "allowed_methods": ["GET", "POST"]
}

Read allowed_patterns and allowed_methods and either retry within those constraints or report the mismatch to the human so they can widen the RelayKey's scope.

Multi-tool agent prompts

The user may hand you a single disposable RelayKey that grants access to several upstream APIs - one key for HiBob + Absorb + Greenhouse, etc. The prompt looks like this:

Hi Kate - I'm giving you scoped access to my tools through RelayKey for safety.

Disposable key (treat as a secret, works against every tool below):
RELAYKEY_API_KEY=rk_proxy_xxx

Save it to .env (and verify .env is in .gitignore - add it if missing).
Run discovery to see exactly what you have access to:
  curl -H "Authorization: Bearer $RELAYKEY_API_KEY" https://proxy.relaykey.ai/_discover

For each tool in the response, point that SDK at the grant's base_url and use
process.env.RELAYKEY_API_KEY as the API key. Example:
  new OpenAI({ baseURL: "https://proxy.relaykey.ai/conn_abc", apiKey: process.env.RELAYKEY_API_KEY })

Tools you have access to today (re-run discovery anytime - that is canonical):
  - HiBob: https://proxy.relaykey.ai/conn_abc (instead of https://api.hibob.com)
  - Absorb: https://proxy.relaykey.ai/conn_def (instead of https://acme.myabsorb.com/api/rest/v1)
  - Greenhouse: https://proxy.relaykey.ai/conn_ghi (instead of https://harvest.greenhouse.io/v1)

Docs: https://relaykey.ai/docs/agent-setup

The same RELAYKEY_API_KEY works against every proxy URL listed; the proxy enforces a different scope per tool internally. Different SDKs / client objects in your code, but they all share the one token. The inlined tool list is human-readable context. Discovery is canonical, so re-run it if the operator adds or revokes a grant later.

Things to avoid

  • Don't store rk_proxy_... tokens in client-side code (browser bundles, mobile applications). They are server-side credentials.
  • Don't log the token. It's still a secret.
  • Don't invent OAuth refresh flows through the proxy. Use only cataloged token_refresh Integrations whose refresh shape RelayKey supports; RelayKey still does not handle the user-facing OAuth login/callback flow.
  • Don't rewrite request bodies or paths beyond what the user told you. The proxy enforces a path allowlist; an agent that "improves" the upstream URL silently will produce confusing block responses.

Where to learn more