n8n
Use your clients' connected services from n8n workflows with the Operate As community node.
The Operate As node lets a workflow act with a client's connections: add a row to their sheet, post in their Slack, send from their Gmail. n8n holds one Operate As key. The client's access stays with Operate As, which attaches it on its own server for each call.
Install the node
Open community nodes
In self-hosted n8n, go to Settings → Community nodes and choose Install.
Install n8n-nodes-operate-as
Accept the risk notice and install. Operate As then shows up in the nodes panel.
n8n Cloud
n8n Cloud only installs community nodes n8n has verified. If Operate As isn't offered there, use the built-in HTTP Request node. See Without the node.
Add the credential
Create a key
In the dashboard, open API & webhooks and create a key limited to the clients and services this n8n needs. See API keys.
Create an Operate As API credential
| Field | What to put |
|---|---|
| API Key | Your key, starting oa_ |
| API URL | Leave it as https://api.operate.as, unless you run Operate As yourself |
n8n tests it by listing the clients the key can reach. If the test fails, check you copied the whole key and it isn't revoked.
The node, field by field
| Field | Operation | What it does |
|---|---|---|
| Client | Both | Whose connections to use. Lists only the clients the key can reach. Takes an expression too, such as {{ $json.clientId }} |
| Operation | Both | Run an Action for a ready-made step, or Custom Request for any endpoint |
| Action | Run an Action | Such as sheets: Add a row after the last row of a range. Only services this client has connected are listed |
| Inputs | Run an Action | The action's inputs, such as spreadsheet_id, range, values. Required ones are marked |
| Service | Custom Request | One of the client's connected services, such as sheets or hubspot |
| Method | Custom Request | GET, POST, PUT, PATCH or DELETE |
| Path | Custom Request | The path after the service's base URL, such as /v4/spreadsheets/{spreadsheetId}/values/Sheet1!A1:D10 |
| Query Parameters | Custom Request | A JSON object |
| Body | Custom Request | A JSON body, for POST, PUT and PATCH |
| Fail on Service Errors | Both | On by default: a 4xx or 5xx from the service stops the workflow. Off: the answer comes out as an item |
Every action and its inputs are on Actions. Custom Request is a pass-through request, so any endpoint the service documents works.
What comes out
Each item is the service's own response, with its HTTP status added as _status:
{
"range": "Sheet1!A1:D20",
"majorDimension": "ROWS",
"values": [["Date", "Patient", "Treatment", "Paid"]],
"_status": 200
}When the answer isn't a JSON object, such as a list or text, it's under data:
{ "data": [{ "id": "1" }, { "id": "2" }], "_status": 200 }With Fail on Service Errors off, route on {{ $json._status < 400 }} in an If node.
Recipes
| Input | Value |
|---|---|
spreadsheet_id | The ID in the sheet's address, after /d/ |
range | Bookings!A1 |
values | {{ [$json.date, $json.name, $json.treatment] }} |
The row lands in the client's own sheet, with the client's own Google access.
When a client's access ends
The node's calls are refused until the client reconnects, with a message like Miller Dental's Google access ended. Send them their link to reconnect. That refusal is HTTP 409 from Operate As, not the service.
Fail on Service Errors doesn't catch this
It only covers the service's own answers. Use Continue On Fail instead (Settings → On Error → Continue): the item comes out as { "error": "<the message>" }, ready for an alert step.
Better, hear about it first. Point an Operate As webhook at an n8n Webhook trigger and listen for connection.expired. You can then pause the client's workflows or post their reconnect link to your team. See Webhooks and Keeping access alive.
Without the node
n8n's built-in HTTP Request node works with no install.
Create a Header Auth credential
Name Authorization, value Bearer oa_... with your key.
Set up the HTTP Request node
Authentication: Generic Credential Type → Header Auth
Method: POST
URL: https://api.operate.as/v1/actions/slack.send_message
Send Body: JSON
Body: {
"clientId": "6f1c2a7e-...",
"input": { "channel": "#front-desk", "text": "New booking" }
}For any other endpoint, call https://api.operate.as/v1/clients/{clientId}/{service}/{path}. The answer is { "status", "data", "encoding" }, with the service's status in status. See the HTTPS API.