Browse documentation
Tutorial JSON:API

Make your first API request

Create read-only service-account access, exchange it for a short-lived token, and verify a bounded workflow-list response.

Goal: Authenticate and list the workflows visible to this service account.

View as Markdown

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

  1. Select the workspace the integration should use.
  2. Create a service account with only the api_read scope and an active run-as member.
  3. Collect its client credentials without putting the secret in shell history.
  4. Exchange those credentials at POST /api/v1/oauth/token and inspect the complete successful token response.
  5. Call GET /api/json/v1/workflows?page[limit]=10 and 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 with curl --version, jq --version, and bash --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

Related documentation