Relay
Call third-party APIs on behalf of your users without handling their provider credentials.
Relay calls third-party APIs on your users’ behalf without exposing their credentials to your application. Send the request to WorkOS, and relay attaches the user’s credential server-side and streams the provider’s response back.
Relay is in early access. Contact support via email or Slack to request access for your environment.
Relay is a forward HTTP proxy built for AI agents and other untrusted runtimes. With access tokens, your infrastructure fetches a provider access token and calls the provider directly, so the token exists inside the calling environment, where it can be copied, logged, or leaked. With relay, the provider credential never leaves WorkOS: the agent authenticates with your WorkOS API key and names the user it acts for.
Relay removes provider credentials from the calling environment, not the WorkOS API key. That key authenticates every WorkOS API call for the environment, so treat it as a secret even in a sandbox: inject it at request time rather than baking it into agent-visible code or prompts, and rotate it from the API Keys section of the dashboard if a runtime is compromised.
Every proxied request follows the same lifecycle:
- Authenticate. Your WorkOS API key is verified and determines the environment. The key is stripped from the request and is never sent upstream.
- Resolve the user. The
X-Relay-Userheader identifies the user the request acts on behalf of, scoped byX-Relay-Organizationwhen the connection belongs to an organization. - Look up the connected account. WorkOS finds the user’s Pipes connection
for the provider you named. If the user hasn’t connected, or needs to
reconnect, relay returns a
402response. - Resolve the credential. WorkOS retrieves and refreshes OAuth access tokens, retrieves stored API keys, or mints access tokens from stored client credentials, depending on how the account is connected.
- Inject and forward. Relay control headers, cookies, and forwarding metadata are stripped, the provider credential is injected into the provider’s configured request header, and the request is forwarded over HTTPS.
- Stream the response. The provider’s status, headers, and body are streamed
back verbatim, with an added
X-Relay-Upstream-Statusheader.
Relay builds on your existing Pipes setup. You need:
- A WorkOS API key for the environment, from the API Keys section of the WorkOS Dashboard.
- The target provider enabled for your environment, configured in the Pipes section of the dashboard or through the data integration API.
- A connected account for the user, created through the provider’s OAuth flow, by entering an API key, or with the client credentials endpoint.
Relay uses the connected account’s authentication method – OAuth, API key, or client credentials – without changing the relay request format. The provider’s Relay configuration determines which methods it accepts and how the credential is presented upstream.
The base URL is https://api.workos.com/relay, and any HTTP method is
accepted. To convert a direct provider call into a proxied one:
- Keep the method, body, and content headers as they are.
- Send the request to the relay base URL, and move the original URL into the
X-Relay-URLheader. - Authenticate with your WorkOS API key in
Authorization. - Name the user in
X-Relay-User, addingX-Relay-Organizationfor organization-scoped connections.
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer followed by your WorkOS API key. Determines the environment. Never forwarded to the provider. |
X-Relay-User |
Yes | The ID of the user the request acts on behalf of, for example user_01EHZ…. Must belong to the API key’s environment. |
X-Relay-Organization |
Conditional | The organization the connection was authorized under, for example org_01KV9…. Required when the connection is organization-scoped, and must be omitted when it isn’t. |
X-Relay-URL |
URL routing only | The full upstream URL, including path and query string. Must use HTTPS. |
X-Relay-Provider |
No | The provider slug to relay to, for example github. Optional with URL routing, where the provider is otherwise resolved from the host. |
All other request headers, including Content-Type, Accept, and
provider-specific headers, are forwarded unchanged. See
limits and behavior for the headers that are stripped.
Put the complete upstream URL in X-Relay-URL. The provider is resolved from the
URL’s host, so your code keeps working with the provider’s real URLs. Name the
provider explicitly with X-Relay-Provider when the host is ambiguous, or when
you would rather not depend on host inference.
Alternatively, prefix the provider’s API path with the relay base URL and
the provider’s slug. The slug in the path selects the provider, and the path and
query string are appended to the provider’s default API host, so
/relay/github/user proxies to
https://api.github.com/user.
URL routing is the better default: it can reach any of a provider’s allowed hosts rather than only the default one, and it keeps the provider’s own URLs intact in your code and logs.
Pipes connections are either scoped to an organization or user-only, and the connection lookup requires an exact match on that scope:
- If the user authorized the provider under an organization, requests must
include
X-Relay-Organizationwith that organization’s ID. - If the user authorized the provider without an organization, the header must be omitted.
A scope mismatch in either direction returns the same 402
relay_authorization_required response as a user who never connected at all.
If a connected user keeps getting a 402, check that the
X-Relay-Organization header matches the organization on their connected
account before asking them to re-authorize.
When the user has no usable connection for the provider – they never connected,
their OAuth grant was revoked, or their token can no longer be refreshed – the
response is 402 Payment Required:
For OAuth connections, surface the authorization_url, let the user complete
the provider’s authorization flow, then retry the original request.
authorization_url is null for API key and client credentials connections.
Collect or rotate those credentials through the Pipes widget,
the upsert API key endpoint,
or the client credentials endpoint,
then retry. It can also be null when a provider’s OAuth configuration is
incomplete.
Authorization-required responses use 402, not 401 or 403, so they can’t
be confused with a WorkOS authentication failure (401) or a
provider-returned 401 or 403 passed through from upstream.
On success you receive the provider’s status code, headers, and body exactly as
the provider sent them, streamed as they arrive. Provider errors are passed
through untouched, so a GitHub 404 comes back as a 404 with GitHub’s own
error body.
Every proxied response carries an X-Relay-Upstream-Status header with the
provider’s status code. Its presence means the request reached the provider, so
you can distinguish an upstream 404 from a relay 404 such as an unknown
provider.
| Behavior | Detail |
|---|---|
| Request body | Forwarded byte-for-byte, up to 5 MB. GET and HEAD requests send no body. |
| Upstream timeout | 30 seconds. A provider that doesn’t respond in time yields 502 relay_upstream_error. |
| HTTPS only | X-Relay-URL must use HTTPS. Credentials are never injected into a plaintext request. |
| Host allowlist | Requests can only target a supported provider’s allowed hosts. Anything else is rejected before the request is sent. |
| Redirects | Not followed. Redirect responses are returned as-is. |
| Stripped request headers | Hop-by-hop headers such as Connection and Transfer-Encoding, Cookie, forwarding metadata such as X-Forwarded-*, Via, and X-Real-IP, your Authorization header, and anything prefixed X-Relay- or X-WorkOS-. |
| Stripped response headers | Hop-by-hop headers and Set-Cookie. Compressed bodies are decoded in transit, so Content-Encoding and Content-Length may be removed. |
Relay supports the active providers below. With path routing, the request goes to the provider’s base API host. With URL routing, any listed host is allowed. The provider must also be enabled for your environment.
The Authentication column shows the methods explicitly configured for each provider. Relay can also mint tokens for eligible client credentials connections; contact support to confirm provider eligibility during early access.
| Provider | Slug | Authentication | Allowed hosts |
|---|---|---|---|
| Acuity Scheduling | acuity-scheduling |
OAuth | acuityscheduling.com |
| Addepar | addepar |
OAuth | api.addepar.com |
| Adobe | adobe |
OAuth | ims-na1.adobelogin.com |
| Aimfox | aimfox |
OAuth, API key | api.aimfox.com |
| Aircall | aircall |
OAuth | api.aircall.io |
| Airtable | airtable |
OAuth, API key | api.airtable.com |
| Anthropic | anthropic |
API key | api.anthropic.com |
| Apaleo | apaleo |
OAuth | api.apaleo.com |
| Apollo.io | apollo-oauth |
OAuth, API key | app.apollo.io |
| Asana | asana |
OAuth, API key | app.asana.com |
| Ashby | ashby |
API key | api.ashbyhq.com |
| Atlassian | atlassian |
OAuth, API key | api.atlassian.com |
| Attio | attio |
OAuth, API key | api.attio.com |
| Autodesk | autodesk |
OAuth | developer.api.autodesk.com |
| BambooHR | bamboohr |
OAuth | api.bamboohr.com |
| beehiiv | beehiiv |
API key | api.beehiiv.com |
| Bing Webmasters | bing-webmasters |
OAuth | www.bing.com |
| BitBucket | bitbucket |
OAuth | api.bitbucket.org |
| Bitly | bitly |
OAuth, API key | api-ssl.bitly.com |
| BoldSign | boldsign |
OAuth, API key | api.boldsign.com |
| Box | box |
OAuth | api.box.com, upload.box.com |
| Braintree | braintree |
OAuth | api.braintreegateway.com |
| Brandfetch | brandfetch |
API key | api.brandfetch.io |
| Brex | brex |
OAuth, API key | platform.brexapis.com |
| Buffer | buffer |
OAuth | api.buffer.com |
| Cal.com | cal-dot-com |
OAuth, API key | api.cal.com |
| Calendly | calendly |
OAuth, API key | api.calendly.com |
| Candis | candis |
OAuth | api.candis.io |
| Canva | canva |
OAuth | api.canva.com |
| CircleCI | circleci |
API key | circleci.com |
| Clerk | clerk |
API key | api.clerk.com |
| CleverReach | cleverreach |
OAuth | rest.cleverreach.com |
| ClickUp | clickup |
OAuth, API key | api.clickup.com |
| Close | close |
OAuth, API key | api.close.com |
| Cloudbeds | cloudbeds |
OAuth, API key | api.cloudbeds.com, hotels.cloudbeds.com |
| Cloudflare | cloudflare |
OAuth, API key | api.cloudflare.com |
| Cohere | cohere |
API key | api.cohere.com |
| Confluence | confluence |
OAuth | api.atlassian.com |
| Constant Contact | constant-contact |
OAuth | api.cc.email |
| Conta Azul | conta-azul |
OAuth | api-v2.contaazul.com |
| Contentful | contentful |
OAuth | api.contentful.com |
| Copper | copper |
OAuth | api.copper.com |
| Crowdin | crowdin |
OAuth | api.crowdin.com |
| Datadog | datadog |
OAuth | api.datadoghq.com |
| DATEV | datev |
OAuth | api.datev.de |
| Deel | deel |
OAuth, API key | api.letsdeel.com |
| Deepgram | deepgram |
API key | api.deepgram.com |
| DeepSeek | deepseek |
API key | api.deepseek.com |
| Dialpad | dialpad |
OAuth, API key | dialpad.com |
| DigitalOcean | digitalocean |
OAuth, API key | api.digitalocean.com |
| Digits | digits |
OAuth | connect.digits.com |
| Discord | discord |
OAuth, API key | discord.com |
| Dovetail | dovetail |
API key | dovetail.com |
| DrChrono | drchrono |
OAuth | app.drchrono.com |
| Dropbox | dropbox |
OAuth | api.dropboxapi.com, content.dropboxapi.com |
| Dropbox Sign | dropbox-sign |
OAuth, API key | api.hellosign.com |
| ElevenLabs | elevenlabs |
API key | api.elevenlabs.io |
| Employment Hero | employment-hero |
OAuth | api.employmenthero.com |
| Envoy | envoy |
OAuth, API key | api.envoy.com |
| Eventbrite | eventbrite |
OAuth, API key | www.eventbriteapi.com |
| Exa | exa |
API key | api.exa.ai |
| Factorial | factorial |
OAuth, API key | api.factorialhr.com |
| Fathom | fathom |
OAuth, API key | api.fathom.ai |
| Figma | figma |
OAuth, API key | api.figma.com |
| Firecrawl | firecrawl |
API key | api.firecrawl.dev |
| Fireworks | fireworks |
API key | api.fireworks.ai |
| Fly.io | fly-io |
OAuth, API key | api.machines.dev |
| Fortnox | fortnox |
OAuth | api.fortnox.se |
| Frame.io | frame-io |
OAuth, API key | api.frame.io |
| Frame.io V4 | frame-io-v4 |
OAuth, API key | api.frame.io |
| FreeAgent | freeagent |
OAuth | api.freeagent.com |
| FreshBooks | freshbooks |
OAuth | api.freshbooks.com |
| Front | front |
OAuth, API key | api2.frontapp.com |
| G2 | g2 |
API key | data.g2.com |
| Gamma | gamma |
OAuth, API key | public-api.gamma.app |
| GitHub | github |
OAuth, API key | api.github.com |
| GitLab | gitlab |
OAuth, API key | gitlab.com |
| Gmail | gmail |
OAuth | gmail.googleapis.com |
google |
OAuth | www.googleapis.com |
|
| Google BigQuery | bigquery |
OAuth | bigquery.googleapis.com |
| Google Calendar | google-calendar |
OAuth | www.googleapis.com |
| Google Docs | google-docs |
OAuth | www.googleapis.com |
| Google Drive | google-drive |
OAuth | www.googleapis.com |
| Google Gemini | google-gemini |
OAuth, API key | generativelanguage.googleapis.com |
| Google Meet | google-meet |
OAuth | www.googleapis.com |
| Google Sheets | google-sheets |
OAuth | www.googleapis.com |
| Google Slides | google-slides |
OAuth | www.googleapis.com |
| Grain | grain |
OAuth, API key | api.grain.com |
| Granola | granola |
API key | public-api.granola.ai |
| Greenhouse | greenhouse |
API key | harvest.greenhouse.io |
| Greenhouse (Ingestion API) | greenhouse-ingestion |
OAuth | api.greenhouse.io |
| Gusto | gusto |
OAuth | api.gusto.com |
| Harvest | harvest |
OAuth, API key | api.harvestapp.com |
| Health Gorilla | health-gorilla |
OAuth | api.healthgorilla.com |
| Help Scout | helpscout |
OAuth | api.helpscout.net |
| HeyGen | heygen |
OAuth, API key | api2.heygen.com |
| HOVER | hover |
OAuth | api.hover.to |
| HubSpot | hubspot |
OAuth, API key | api.hubapi.com |
| Hugging Face | hugging-face |
OAuth | huggingface.co |
| incident.io | incident-io |
API key | api.incident.io |
| Intercom | intercom |
OAuth, API key | api.intercom.io |
| Intralinks | intralinks |
OAuth | api.intralinks.com |
| Jira | jira |
OAuth | api.atlassian.com |
| Jobber | jobber |
OAuth | api.getjobber.com |
| Kakao | kakao |
OAuth, API key | kapi.kakao.com |
| Keap | keap |
OAuth | api.infusionsoft.com |
| Kernel | kernel |
API key | api.onkernel.com |
| Klaviyo | klaviyo |
OAuth, API key | a.klaviyo.com |
| LaunchDarkly | launchdarkly |
OAuth | app.launchdarkly.com |
| Lever | lever |
OAuth, API key | api.lever.co |
| Linear | linear |
OAuth, API key | api.linear.app |
linkedin |
OAuth | api.linkedin.com |
|
| Local Falcon | local-falcon |
API key | api.localfalcon.com |
| Lokalise | lokalise |
OAuth, API key | api.lokalise.com |
| Luma | luma |
API key | public-api.luma.com |
| Mailgun | mailgun |
API key | api.eu.mailgun.net, api.mailgun.net |
| Manufact | manufact |
API key | cloud.manufact.com |
| Mem0 | mem0 |
API key | api.mem0.ai |
| Mercury | mercury |
OAuth, API key | api.mercury.com |
| Microsoft | microsoft |
OAuth | graph.microsoft.com |
| Microsoft OneDrive | microsoft-onedrive |
OAuth | graph.microsoft.com |
| Microsoft OneNote | microsoft-onenote |
OAuth | graph.microsoft.com |
| Microsoft Outlook | microsoft-outlook |
OAuth | graph.microsoft.com |
| Microsoft Outlook Calendar | microsoft-outlook-calendar |
OAuth | graph.microsoft.com |
| Microsoft SharePoint | microsoft-sharepoint |
OAuth | graph.microsoft.com |
| Microsoft Teams | microsoft-teams |
OAuth | graph.microsoft.com |
| Microsoft To-Do | microsoft-todo |
OAuth | graph.microsoft.com |
| Miro | miro |
OAuth, API key | api.miro.com, miro.com |
| Mollie | mollie |
OAuth, API key | api.mollie.com |
| Monday.com | monday |
OAuth, API key | api.monday.com |
| Motive | motive |
OAuth, API key | api.gomotive.com, api.keeptruckin.com |
| Mural | mural |
OAuth | app.mural.co |
| Neon | neon |
OAuth, API key | console.neon.tech |
| Netlify | netlify |
OAuth, API key | api.netlify.com |
| ngrok | ngrok |
API key | api.ngrok.com |
| Notion | notion |
OAuth, API key | api.notion.com |
| npm | npm |
API key | registry.npmjs.org |
| OpenAI | openai |
API key | api.openai.com |
| OpenRouter | openrouter |
API key | openrouter.ai |
| Orb | orb |
API key | api.withorb.com |
| Outreach | outreach |
OAuth | api.outreach.io |
| PagerDuty | pagerduty |
OAuth, API key | api.pagerduty.com |
| PandaDoc | pandadoc |
OAuth, API key | api.pandadoc.com |
| Pardot | pardot |
OAuth | pi.demo.pardot.com, pi.pardot.com |
| PayPal | paypal |
OAuth | api-m.paypal.com |
| Pennylane | pennylane |
OAuth, API key | app.pennylane.com |
| Perk | perk |
OAuth, API key | api.travelperk.com |
| Perplexity | perplexity |
API key | api.perplexity.ai |
| Plain | plain |
API key | core-api.uk.plain.com |
| PlanetScale | planetscale |
OAuth | api.planetscale.com |
| Podium | podium |
OAuth | api.podium.com |
| Postman | postman |
API key | api.getpostman.com |
| PreciseFP | precisefp |
OAuth | app.precisefp.com |
| Procore | procore |
OAuth | api.procore.com |
| Productboard | productboard |
OAuth, API key | api.productboard.com |
| QuickBooks | quickbooks |
OAuth | quickbooks.api.intuit.com |
| QuickBooks Time | tsheetsteam |
OAuth | rest.tsheets.com |
| Railway | railway |
API key | backboard.railway.com |
| Ramp | ramp |
OAuth | api.ramp.com |
| Reapit | reapit |
OAuth | platform.reapit.cloud |
reddit |
OAuth | oauth.reddit.com |
|
| Render | render |
API key | api.render.com |
| Replicate | replicate |
API key | api.replicate.com |
| Resend | resend |
API key | api.resend.com |
| RingCentral | ring-central |
OAuth | platform.ringcentral.com |
| Sage | sage |
OAuth | api.accounting.sage.com |
| Sage Intacct | sage-intacct |
OAuth | api.intacct.com |
| Salesloft | salesloft |
OAuth, API key | api.salesloft.com |
| Salesmsg | salesmsg |
OAuth | api.salesmessage.com |
| Segment | segment |
API key | api.segmentapis.com |
| Sellsy | sellsy |
OAuth | api.sellsy.com |
| SendGrid | sendgrid |
API key | api.sendgrid.com |
| Sentry | sentry |
OAuth, API key | sentry.io |
| Serval | serval |
OAuth | public.api.serval.com |
| ServiceM8 | servicem8 |
OAuth, API key | api.servicem8.com |
| signNow | signnow |
OAuth | api.signnow.com |
| Slack | slack |
OAuth | slack.com |
| Slack User | slack-user |
OAuth | slack.com |
| Socket | socket |
API key | api.socket.dev |
| Spotify | spotify |
OAuth | api.spotify.com |
| Stripe | stripe |
OAuth, API key | api.stripe.com |
| Stripe Connect | stripe-connect |
OAuth, API key | api.stripe.com |
| SurveyMonkey | survey-monkey |
OAuth, API key | api.surveymonkey.com |
| Teamleader Focus | teamleader |
OAuth | api.focus.teamleader.eu |
| Ticket Tailor | ticket-tailor |
API key | api.tickettailor.com |
| TickTick | ticktick |
OAuth | api.ticktick.com |
| TikTok | tiktok |
OAuth | open.tiktokapis.com |
| Timely | timely |
OAuth | api.timelyapp.com |
| Todoist | todoist |
OAuth | api.todoist.com |
| Tremendous | tremendous |
OAuth, API key | api.tremendous.com |
| TriNet HR Platform (Zenefits) | zenefits |
OAuth | api.trinet.com, api.zenefits.com |
| Typeform | typeform |
OAuth, API key | api.typeform.com |
| VideoAsk | videoask |
OAuth | api.videoask.com |
| Wave Accounting | wave-accounting |
OAuth, API key | gql.waveapps.com |
| Wealthbox | wealthbox |
OAuth, API key | api.crmworkspace.com |
| Webex | webex |
OAuth, API key | webexapis.com |
| Webflow | webflow |
OAuth, API key | api.webflow.com |
| WHOOP | whoop |
OAuth | api.prod.whoop.com |
| Wix | wix |
OAuth | www.wixapis.com |
| WorkOS | workos |
API key | api.workos.com |
| X.com | x-com |
OAuth, API key | api.twitter.com, api.x.com |
| xAI | xai |
API key | api.x.ai |
| Xero | xero |
OAuth | api.xero.com |
| Zapier | zapier |
OAuth | api.zapier.com |
| Zendesk Sell | zendesk-sell |
OAuth, API key | api.getbase.com |
| Zeplin | zeplin |
OAuth | api.zeplin.dev |
| Zoom | zoom |
OAuth | api.zoom.us |
Errors generated by relay are JSON objects with code and message
fields. Provider errors are passed through unchanged, so check for
X-Relay-Upstream-Status to tell the two apart.
| Status | Code | Meaning |
|---|---|---|
401 |
– | Missing or invalid WorkOS API key. |
400 |
relay_missing_url |
URL routing was used but the X-Relay-URL header is absent. |
400 |
relay_invalid_url |
X-Relay-URL isn’t a valid URL or doesn’t use HTTPS, or the resolved target host isn’t one of the provider’s allowed hosts. |
400 |
relay_user_required |
The X-Relay-User header is absent. |
400 |
relay_user_not_found |
No user with that ID exists in the API key’s environment. |
400 |
relay_provider_conflict |
The path slug and the X-Relay-Provider header name different providers. |
400 |
relay_credential_invalid |
The stored credential can’t be presented to the provider – it needs to be replaced. |
402 |
relay_authorization_required |
The user has no usable connection for this provider, or the organization scope doesn’t match. The authorization_url may be null. |
404 |
relay_provider_not_found |
The slug or the X-Relay-URL host doesn’t match a supported provider, or the provider isn’t enabled in this environment. |
404 |
relay_provider_not_configured |
The provider has no relay configuration for the way this account is connected. |
404 |
– | A generic 404 with no code field means relay isn’t enabled for this environment. |
502 |
relay_credential_error |
The user’s credential couldn’t be resolved, for a reason that re-authorization won’t fix. |
502 |
relay_upstream_error |
The provider was unreachable or timed out. |