Authenticate and list the workflows visible to a workspace-scoped service account. The request is read-only and explicitly limited to ten results, and an empty list is a successful first result.
What you will do
- Select the workspace the integration should use.
- Create a service account with only the
api_readscope and an active run-as member. - Collect its client credentials without putting the secret in shell history.
- Exchange those credentials at
POST /api/v1/oauth/tokenand inspect the complete successful token response. - Call
GET /api/json/v1/workflows?page[limit]=10and verify the body and response headers.
This path starts with JSON:API because it works in an empty workspace. GraphQL warehouse queries require an existing data model and records; webhook ingestion requires an active webhook workflow and its selected service account.
Prerequisites
- Application access: the base URL of your Hodoflow deployment. The examples
use
https://hodoflow.com; self-hosted installations substitute their own application host. - Setup role: an organization owner or admin can create the service account.
- Run-as access: at least one active organization member that should own the API request's permissions.
- Workspace: know which workspace the integration should see. Service accounts are created in the workspace currently selected in the application.
- Command line: Bash, cURL, and
jq. Confirm them withcurl --version,jq --version, andbash --version.
Use a private, disposable terminal session. Do not put a client secret or bearer
token in a URL, command-line argument, source file, .env file, shell history,
browser storage, screenshot, or support message. Use your normal secret manager
for a real integration.
Request
1. Create read-only access in the intended workspace
In the application, switch to the workspace the integration should use. Then go to Settings → Service Accounts, choose New Service Account, and set:
- Name: a specific integration name, such as
Reporting sync; - Scopes: select API read only; and
- Run as: select the intended active organization member.
Choose Create Service Account. You should land on Client Credentials and
see a client ID beginning with cid_ and a client secret beginning with
csec_. The workspace is not sent in an API request: it comes from the service
account you just created. The run-as member still bounds everything the account
can see.
For the product-side setup and permission model, see Service accounts. If no active member appears, activate or invite the intended member before continuing.
2. Set variables without recording the secret in history
Set the application URL, then read the credentials interactively. read -s
keeps the secret off the screen and out of the command text stored by Bash.
export HODOFLOW_BASE_URL="https://hodoflow.com"
read -r -p "Client ID: " CLIENT_ID
read -r -s -p "Client secret: " CLIENT_SECRET
printf '\n'
export CLIENT_ID CLIENT_SECRET
Paste only when each prompt is waiting. Do not replace the read commands with
literal credential assignments. Your current shell and its child processes can
use these values, so do this on a trusted machine and clean them up at the end.
You should see the client ID as you type it and no characters while entering the secret.
3. Exchange the credentials and inspect the response
Build the JSON from environment variables and stream it to cURL. The secret is in the request body, never the URL or a process argument.
TOKEN_RESPONSE="$(
jq -n '{
grant_type: "client_credentials",
client_id: env.CLIENT_ID,
client_secret: env.CLIENT_SECRET
}' |
curl --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--data-binary @- \
"$HODOFLOW_BASE_URL/api/v1/oauth/token"
)"
printf '%s\n' "$TOKEN_RESPONSE" | jq .
You should see all three success fields before extracting the token:
{
"access_token": "<redacted JWT>",
"token_type": "bearer",
"expires_in": 900
}
expires_in is seconds and defaults to 900, but deployments can configure it.
There is no refresh token. A production client should cache the bearer token for
slightly less than the returned lifetime, then exchange again.
Extract the two values only after verifying that response:
TOKEN="$(printf '%s\n' "$TOKEN_RESPONSE" | jq -er '.access_token')"
EXPIRES_IN="$(printf '%s\n' "$TOKEN_RESPONSE" | jq -er '.expires_in')"
printf 'Token received; expires in %s seconds.\n' "$EXPIRES_IN"
The command prints only the lifetime, not the bearer token.
4. List at most ten workflows
Use -i to include the response headers and -g to keep cURL from treating the
square brackets in page[limit] as a URL glob. The bearer header is streamed to
cURL through standard input so it is not placed in the command's arguments.
printf 'header = "Authorization: Bearer %s"\n' "$TOKEN" |
curl --silent --show-error --include --globoff --config - \
--header "Accept: application/vnd.api+json" \
"$HODOFLOW_BASE_URL/api/json/v1/workflows?page[limit]=10"
You should see HTTP/… 200, x-api-version: v1, a non-empty
x-request-id, and a JSON:API document with a data array. Keep the request ID
when troubleshooting; it is the correlation ID support can trace.
Expected response
A new or empty workspace returns 200 OK. The exact request URL is retained in
the self link; the request ID is different for every request.
HTTP/2 200
content-type: application/vnd.api+json; charset=utf-8
x-api-version: v1
x-request-id: <request-id>
{
"data": [],
"jsonapi": {
"version": "1.0"
},
"links": {
"first": "https://hodoflow.com/api/json/v1/workflows?page[limit]=10",
"next": null,
"prev": null,
"self": "https://hodoflow.com/api/json/v1/workflows?page[limit]=10"
},
"meta": {
"page": {}
}
}
data: [] means authentication, workspace selection, scope enforcement, and
serialization all succeeded; it does not mean the request failed. If workflows
already exist, data contains up to ten workflow resource objects instead.
Troubleshooting
Token exchange returns 400
The only accepted grant is client_credentials. Confirm the request body has
that exact grant_type. This response is not retryable until the request is
corrected.
Token exchange or API request returns 401
For the exchange, re-copy the client ID and secret and confirm the service account is active. For the API call, the token may have expired: exchange again and retry the read once. Do not log either credential while diagnosing it.
The API returns 403
The service account is authenticated but lacks api_read. An owner or admin
must edit the account and grant API read. Retrying the same token cannot add
a scope.
The API returns 404
Check the exact path: /api/json/v1/workflows. A resource-specific 404 can
also mean the run-as member is not allowed to see that object; Hodoflow does not
reveal whether a filtered object exists. Do not retry unchanged.
The API returns 429
Read the Retry-After response header, wait that many seconds, and retry the
read. Keep the x-request-id from the failed response. Do not use a fixed rapid
retry loop.
The response is HTML or has no version header
Confirm HODOFLOW_BASE_URL is the application host, not the developer
documentation host, and that the path includes /api/json/v1.
Before leaving the terminal, remove every sensitive variable:
unset CLIENT_ID CLIENT_SECRET TOKEN TOKEN_RESPONSE EXPIRES_IN
Next steps
- Inspect workflows and follow a run with the same
api_readaccess. - Add
api_writeonly when you are ready to implement an idempotent JSON:API write; keep read-only and write integrations separate where practical. - Run a bounded GraphQL warehouse query after you have a data model
and records.
factQueryalso requiresapi_read. - Configure webhook ingestion after creating and
activating a webhook workflow; its trigger requires the exact selected
service account with the
webhooksscope.