Pass-through requests

Call any endpoint of a service's own API with the client's access attached.

Actions cover common jobs. A pass-through request covers everything else: you write the call the way the service's own docs describe it, and Operate As adds the client's access and sends it on. It works for every service in the catalog, and every plan includes it.

Build the URL

Take the call from the service's docs, drop its base URL, and put what's left after your client and the service's key:

https://api.operate.as/v1/clients/{clientId}/{service}/{path}
PartWhat it is
clientIdThe client's ID, from GET /v1/me/clients
serviceThe service's key, such as sheets, slack, hubspot
pathThe path from the service's API docs, after its base URL

So Google Sheets' own GET https://sheets.googleapis.com/v4/spreadsheets/1BxiM... becomes:

GET https://api.operate.as/v1/clients/6f1c2a7e-.../sheets/v4/spreadsheets/1BxiM...

Send it with your Operate As key, not the client's. Every service's base URL is on its page under Providers; pasted-key services are on API-key services.

curl "https://api.operate.as/v1/clients/6f1c2a7e-.../sheets/v4/spreadsheets/1BxiM..." \
  -H "Authorization: Bearer $OPERATE_AS_API_KEY"

The libraries and the MCP request tool send bodies as JSON. For a form or file body, such as Stripe's POST calls, use the HTTPS API as in the examples below, or the service's action, which encodes it for you.

The path stays under the service's API

A path with a .. or . segment, or a backslash, is refused with 400 (The path can't leave the service's API.). That stops a key that may reach one API on a host from reaching another API on the same host.

Encode anything in a segment that isn't a plain letter, digit or symbol the service expects. A range like Sheet1!A1:D10 can go as it is; a sheet name with a space needs %20. The libraries keep your slashes and encode the rest.

What's passed on

Part of your requestWhat happens
MethodGET, POST, PUT, PATCH and DELETE go on as sent
Query stringSent as is. Repeated parameters keep their order, so ?id=1&id=2 arrives with both
BodySent as the raw bytes, with your Content-Type. JSON, form-encoded and file bodies all work
HeadersOnly a short allowlist, below
HeaderWhy
Content-Type, AcceptWhat the body is, and what you want back
Idempotency-KeyLets a service, such as Stripe, ignore a retried create
Service-specific ones, such as Stripe-Version and Dropbox-API-ArgHeaders a service's API needs to work
developer-token, login-customer-id, linked-customer-idGoogle Ads wants your agency's own developer token on every call, and your manager account's ID when you work through one
DeveloperToken, CustomerId, CustomerAccountIdThe same for Microsoft Advertising
LinkedIn-VersionThe month of LinkedIn's marketing API you're writing against, such as 202509
X-Amz-TargetThe operation an AWS JSON API runs, such as DynamoDB_20120810.ListTables

Your own Authorization is never passed on.

How access is attached

The client connected byOperate As adds
Signing in (Google, Microsoft, Slack, HubSpot and the rest)Authorization: Bearer <the client's token>, renewed first if it's about to run out
Pasting a keyThe key in that service's header, such as x-api-key for Anthropic or api-key for Brevo, or as a query parameter, such as Pipedrive's api_token
Pasting a key and a second secretBoth, each where the service reads it, such as Datadog's DD-API-KEY and DD-APPLICATION-KEY
Pasting a key the API takes in its bodyThe key added to your JSON body, such as Mailchimp Transactional's key
Pasting a key the API takes in its addressThe key in the address itself, such as Telegram's /bot<token>/
Pasting AWS access keysAn AWS Signature Version 4 signature on each call, so the secret key never leaves Operate As
Either, when the API needs a versionNotion-Version for Notion, anthropic-version for Anthropic, revision for Klaviyo

The answer

The same result as an action:

{ "status": 200, "data": { "spreadsheetId": "1BxiM...", "sheets": [] }, "encoding": "json" }

encoding is "json", "text" or "base64". Binary answers, such as file downloads, come back base64-encoded in data. A service's error comes back the same way, with its status in status. Errors from Operate As itself, such as a client who needs to reconnect, are HTTP errors. See Errors.

Examples

Read a sheet's details:

curl "https://api.operate.as/v1/clients/6f1c2a7e-.../sheets/v4/spreadsheets/1BxiM...?includeGridData=false" \
  -H "Authorization: Bearer $OPERATE_AS_API_KEY"

Update cells:

curl -X PUT "https://api.operate.as/v1/clients/6f1c2a7e-.../sheets/v4/spreadsheets/1BxiM.../values/Sheet1!B2?valueInputOption=USER_ENTERED" \
  -H "Authorization: Bearer $OPERATE_AS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "values": [["Paid"]] }'

Batch reads repeat a parameter:

curl "https://api.operate.as/v1/clients/6f1c2a7e-.../sheets/v4/spreadsheets/1BxiM.../values:batchGet?ranges=A1:B2&ranges=D1:D5" \
  -H "Authorization: Bearer $OPERATE_AS_API_KEY"

Limiting keys to pass-through

A key with an actions list can only make pass-through calls to a service listed as <service>.request, such as hubspot.request. A key with no actions list can make pass-through calls to any service it may use. See API keys.

On this page