A service account is how something that is not a person authenticates with your organization. A webhook sender, a script that reads records, a page embedding a dashboard — each gets its own credential, its own scopes, and its own audit trail.
They live at Settings → Service Accounts. Creating and editing one, and viewing its credentials, is limited to organization owners and admins.
Create one
New Service Account asks for three things.
Name is for you. Name it after the integration that will hold it — Stripe webhook ingest — so that revoking the right one later is obvious.
Scopes decide what the credential is allowed to do. At least one is required.
| Scope | Grants |
|---|---|
webhooks |
Sending data into Hodoflow through webhook requests. |
api_read |
Read-only REST access to workflows, runs, and warehouse records. |
api_write |
Any JSON API request that is not a read. |
embed |
Loading dashboards inside external sites through the embed channel. |
Grant the narrowest set that works. A webhook sender needs webhooks and
nothing else.
Run as is the one that surprises people. A service account does not have permissions of its own — it borrows a member's. Pick an organization member and every request authenticated with this credential executes as them, respecting their permissions. Only active members of the current organization are offered.
That means deactivating a person can change what a service account can reach. Point machine credentials at whoever should own the integration long-term.
The client ID and secret
Creating the account mints a pair: a client ID beginning cid_ and a client
secret beginning csec_. Neither embeds anything about your organization, so
neither is safe to treat as public.
Client Credentials on the service account's page shows both, each with a Copy button. Unlike most secrets, these stay retrievable — come back to this page whenever an integration needs re-configuring. Access is limited to owners and admins.
Getting an access token
The pair is not what you send with a request. Exchange it for a short-lived token first:
curl -X POST https://app.example.com/api/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "cid_...",
"client_secret": "csec_..."
}'
You can also send the pair as HTTP Basic auth instead of in the body. The response is the token, its type, and its lifetime in seconds:
{"access_token": "eyJ...", "token_type": "bearer", "expires_in": 900}
Fifteen minutes, so a long-lived integration exchanges again rather than caching
the token forever. Send it as Authorization: Bearer <access_token>.
A token carries the scopes and the run-as member that were set when it was issued, which is why a scope change takes effect on the next exchange rather than instantly.
Every response for a credential problem is the same 401 with
{"error": "invalid_client"} — missing credentials, wrong secret, unknown
client, and a deactivated account all look identical from the outside. That is
deliberate. Check the service account's status in Hodoflow rather than reading
the error.
Rotating the secret
Rotation is two steps, so there is no window where nothing works.
Stage new secret generates a second client ID and secret alongside the active pair. Both pairs authenticate at once. Copy the staged values from Client Credentials, where they appear under Staged credentials with a Pending promotion badge, and update your integrations.
Promote staged then makes the staged pair the active one, and the previous pair stops working immediately. Do it once your integrations are switched over and you have confirmed they still work.
Restage new secret replaces a staged pair you have not promoted yet. The pair you overwrite stops working immediately, so only restage if nothing has picked the staged values up.
Turning one off
Deactivate stops the credential from exchanging for tokens at all. It is reversible with Activate, which makes it the right tool for a suspected leak you are still investigating.
Deactivation is refused while an active workflow depends on the credential — deactivate the workflow first. Usage on the service account's page lists the workflow versions whose triggers authenticate with it, so you know which ones.
Delete is permanent, and any external system using the credential loses access the moment you confirm. It is refused while workflow triggers still reference it.
Related
- Triggers and webhooks — a webhook trigger
requires a service account holding the
webhooksscope. - Embeds — dashboard embeds use a share token, not a service account.
- The developer portal covers the exchange and the token's claims in detail at authentication.