all docs
/ integrations

Portkey integration

Run Portkey traffic through the ACE gateway: endpoint, the headers a call sets, what passes through untouched, and a runnable example.

Put ACE behind Portkey (a config target whose custom_host is ACE) for one config change and no app change, or in front of it with x-ace-upstream-profile: portkey for full coverage. Portkey's cache, logs, budgets, retries and fallbacks stay in charge; ACE makes one attempt.

  • ACE behind: custom_host is ACE's /v1 for provider: "openai" and /anthropic/v1 for provider: "anthropic". A self-hosted Portkey calling a private ACE host needs it in TRUSTED_CUSTOM_HOSTS.
  • ACE in front: keep sending your Portkey headers. With a provider key stored on the channel the call is refused with a 403, so store the Portkey key and profile instead.

Endpoint: https://engine.acefleet.dev/v1/chat/completions · also https://engine.acefleet.dev/v1/responses, https://engine.acefleet.dev/anthropic/v1/messages. ACE credential: Authorization: Bearer ace_dev_... (x-api-key on /anthropic/v1/messages).

x-ace-upstream-profile: portkey names the profile.

Topology Shape
ACE in front
Full coverage. Client → ACE → https://api.portkey.ai/v1.
ACE behind
Default. Client → Portkey → ACE: a config target with custom_host = ACE's /v1 (or /anthropic/v1 for provider: anthropic), api_key = the ACE key, and forward_headers: ["x-ace-session"]; provider keys are stored on ACE. A config-only change; a fallback to a non-ACE target bypasses ACE.
Header Required Description
x-portkey-api-key
Yes
Your Portkey API key, sent as you send it to Portkey today; ACE relays it untouched. Model-catalog slugs (@provider/model) need no provider key. Per request only when the tenant has no provider key stored on the channel; with one stored the call is refused with a 403, so store the Portkey key instead.
x-portkey-config
Situational
A saved config id or inline config JSON, relayed untouched; an api_key inside inline JSON is never logged.

Passed through untouched

  • every x-portkey-* request header and traceparent
  • x-portkey-trace-id, x-portkey-cache-status, x-portkey-retry-attempt-count, x-portkey-last-used-option-index response headers

Storing the Portkey API key and the portkey profile as the tenant's openai (or anthropic) vendor key leaves the client changing only base_url and api_key. The tenant has one vendor key per channel, so this replaces any provider key stored there and sends all of the tenant's traffic on that channel through Portkey.

Portkey with ACE (cURL)

# ACE behind Portkey: save this config in Portkey and reference it by id.
#   {
#     "provider": "openai",
#     "custom_host": "https://engine.acefleet.dev/v1",
#     "api_key": "ace_dev_<your-dev-key>",
#     "forward_headers": ["x-ace-session"]
#   }
curl -X POST https://api.portkey.ai/v1/chat/completions \
  -H "x-portkey-api-key: <portkey-api-key>" \
  -H "x-portkey-config: pc-ace-<config-id>" \
  -H "x-ace-session: nightly-triage-0930" \
  -H "Content-Type: application/json" \
  -d '{ "model": "gpt-4o", "messages": [{ "role": "user", "content": "Summarise the failing checks." }] }'

# ACE in front of Portkey.
curl -X POST https://engine.acefleet.dev/v1/chat/completions \
  -H "Authorization: Bearer ace_dev_<your-dev-key>" \
  -H "x-ace-upstream-profile: portkey" \
  -H "x-portkey-api-key: <portkey-api-key>" \
  -H "x-portkey-trace-id: nightly-triage-0930" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "@openai-prod/gpt-4o",
    "messages": [{ "role": "user", "content": "Summarise the failing checks." }]
  }'