Machine clients (client credentials)
A machine client is for scripts, scheduled jobs and integrations (a GRC tool, a ticketing system, a data pipeline) that call the API as themselves, not as a person. It uses the OAuth 2 client credentials grant.
Register the client (admins)
Section titled “Register the client (admins)”In Admin → API → Clients, select New API client and choose Machine client:
- Acting role: User, Reviewer or Approver. The client acts with that role. It can never be an admin.
- Scopes: what the client may ask for, limited to what its acting role allows. See Scopes.
- Libraries (optional): restrict the client to some libraries. None ticked means every library.
audit:read: a separate checkbox, because it lets the client read your organization’s whole audit log (for a SIEM).- Secret expires in: 90 days by default, at most 365.
Tradecraft shows the client id (tco_…) and the client secret (tcs_…). Copy the secret now: it is shown once and Tradecraft keeps only a hash. If you lose it, create a new secret.
A machine client belongs to your organization, not to the admin who created it, and keeps working if that admin leaves.
Get an access token
Section titled “Get an access token”Send the client id and secret with HTTP Basic authentication (client_secret_basic; secrets in the body are not accepted) to the token endpoint. scope is optional: leave it out to get every scope the client is allowed, or ask for fewer.
curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \ -d grant_type=client_credentials \ -d "scope=assessments:read knowledge:read knowledge:ask" \ https://api.tradecrafthub.ai/oauth/tokenasync function getToken(scope?: string): Promise<string> { const res = await fetch("https://api.tradecrafthub.ai/oauth/token", { method: "POST", headers: { Authorization: `Basic ${btoa(`${process.env.CLIENT_ID}:${process.env.CLIENT_SECRET}`)}`, "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ grant_type: "client_credentials", ...(scope ? { scope } : {}) }), }) if (!res.ok) throw new Error(`token: ${res.status} ${JSON.stringify(await res.json())}`) const body = (await res.json()) as { access_token: string; expires_in: number; scope: string } return body.access_token}The response:
{ "access_token": "tca_…", "token_type": "Bearer", "expires_in": 3600, "scope": "assessments:read knowledge:ask knowledge:read" }Access tokens last one hour. There is no refresh token with client credentials: ask for a new token when the old one expires. Then call the API with Authorization: Bearer <access_token>.
The token endpoint answers OAuth errors ({ "error", "error_description" }):
invalid_client(401): wrong client id or secret, an expired or revoked secret, or a disabled client.unauthorized_client: the client is not a machine client, the plan has no API, or the API is turned off.invalid_scope: a scope the client is not allowed.invalid_target: aresourceother than the API (https://api.tradecrafthub.ai).
The token endpoint allows 60 requests a minute per client: reuse a token until it expires instead of asking for one per call.
What a machine client can do
Section titled “What a machine client can do”- The same as a person with its acting role, within its scopes and libraries.
- It cannot Send to Finalize or Finalize: those scopes are for people only (see Apps acting for people).
- Answers it proposes always wait for an approver, whatever its acting role, labelled API · client name in the review queue.
- Its actions are audited as
service:<client id>with the client’s name.
Rotate and revoke secrets
Section titled “Rotate and revoke secrets”A client can have at most two active secrets, so you can rotate without downtime:
- In Admin → API → Clients, rotate the secret and choose when the old one ends: Rotate (end old now), (old ends in 24 h) or (old ends in 7 days).
- Deploy the new secret to your integration.
- The old secret stops working at the time you chose.
Admins and your organization’s security contacts are warned 14 and 3 days before a secret expires. Revoking a secret takes effect at the next token request; access tokens already issued with it keep working until they expire, at most one hour later. Disabling the client stops it at once.
Admin → API → Usage shows requests, errors and rate-limited requests per client per day.