API Authentication
TokenTimer has two authentication surfaces. Pick the one that matches your caller.
| You are building | Use |
|---|---|
| A script or tool that acts as a user (manage tokens, workspaces, alerts) | Session authentication |
| A CertOps executor, CI job, or renewal hook that reports certificate events | Machine API tokens |
Not sure? If you are not using TokenTimer's Certificate Lifecycle Management feature (certificate management guide), use session authentication.
Session authentication
Log in with your account credentials to receive a session cookie, then send it on every request.
The examples below use Bash, curl, and jq. Use an existing, verified account and replace the host with your own API origin for Core or Enterprise. Keep the cookie jar private: it grants access to your session.
BASE=https://tokentimer.ch
# 1. Fetch the CSRF token AND save its companion cookie before logging in
CSRF=$(curl -sS -c cookies.txt "$BASE/api/csrf-token" | jq -r '.csrfToken')
# 2. Log in using that header and cookie; save the new session cookie
curl -sS -b cookies.txt -c cookies.txt -X POST "$BASE/auth/login" \
-H "X-CSRF-Token: $CSRF" \
-H 'Content-Type: application/json' \
-d '{"email":"me@example.com","password":"StrongPass123!"}'
# 3. Verify the session; expect loggedIn: true
curl -sS -b cookies.txt "$BASE/api/session" | jq '.'
# 4. Refresh the CSRF token and cookie after login, before writing
CSRF=$(curl -sS -b cookies.txt -c cookies.txt "$BASE/api/csrf-token" | jq -r '.csrfToken')
If loggedIn is false, stop before running a write workflow. Complete two-factor authentication if prompted, or correct your account credentials.
A logged-in session response includes fields such as:
{
"loggedIn": true,
"user": {
"id": "3f6e...",
"email": "me@example.com",
"displayName": "Me"
}
}
CSRF token for mutating requests
CSRF protection applies to login as well as session-authenticated POST/PUT/PATCH/DELETE requests. Fetching a token rotates its companion cookie: save both with -b cookies.txt -c cookies.txt, then send the returned token in X-CSRF-Token:
# Fetch a CSRF token bound to your session
CSRF=$(curl -sS -b cookies.txt -c cookies.txt "$BASE/api/csrf-token" | jq -r '.csrfToken')
# Include it as a header on mutating calls
curl -s -b cookies.txt -X POST "$BASE/api/tokens" \
-H "X-CSRF-Token: $CSRF" \
-H 'Content-Type: application/json' \
-d '{"name":"My cert","category":"cert","type":"ssl_cert","workspace_id":"WS_ID"}'
Two-factor accounts
If your account has TOTP two-factor authentication enabled, POST /auth/login returns an intermediate response and you complete the login with POST /auth/verify-2fa. Send the cookie jar and X-CSRF-Token header with the verification request, save any updated cookies, then verify /api/session and refresh the CSRF token. See the REST Reference for the exact payloads.
Ending the session
curl -s -b cookies.txt -X POST "$BASE/api/logout"
Machine API tokens
Certificate Lifecycle Management (CLM) uses the existing CertOps technical API. The certops paths, token scopes, and configuration names below refer to that same feature.
Machine tokens (ttx_<id>_<secret>) authenticate non-human callers on the CertOps executor surface. They are workspace-bound, scoped, optionally expiring, and revocable.
Create one in the dashboard: workspace manager or admin role, Certificate Management → Settings → Machine API tokens (/certops/settings).
The plaintext token appears exactly once, in the create response. TokenTimer stores only a SHA-256 hash and cannot re-display it, including support staff. Store it in a secret manager immediately.
Scopes
Grant the minimum an executor needs:
| Scope | Grants |
|---|---|
certops:events:write | Report job lifecycle events |
certops:evidence:write | Attach evidence records (an events-only token cannot attach evidence) |
certops:read | Reserved; no machine-token inventory read route currently exists |
certops:jobs:read | Reserved; job reads currently require a human session |
Using the token
JOB_ID must already exist. Create it with Create a manual CertOps job or the dashboard Create manual job button before calling executor routes. Machine tokens cannot create jobs; an unknown id returns 404 CERTOPS_JOB_NOT_FOUND.
Send it as a bearer token. Machine-token routes are CSRF-exempt and have no session dependency.
curl -sS -X POST https://tokentimer.ch/api/v1/certops/jobs/JOB_ID/events \
-H "Authorization: Bearer ttx_abc123_s3cr3t..." \
-H "Content-Type: application/json" \
-d '{
"schemaVersion": 1,
"eventId": "evt-2026-07-12-000001",
"workspaceId": "WS_ID",
"jobId": "JOB_ID",
"status": "succeeded",
"eventType": "job.completed",
"occurredAt": "2026-07-12T10:00:00.000Z"
}'
A successful submission returns 202 Accepted:
{
"ok": true,
"eventId": "evt-2026-07-12-000001",
"jobId": "JOB_ID",
"status": "succeeded",
"evidenceIds": [],
"duplicate": false,
"idempotent": false
}
Rate limits and idempotency
Each machine token shares one rate-limit bucket of 120 requests per 60 seconds across all executor routes. On 429 CERTOPS_MACHINE_RATE_LIMITED, honor the Retry-After header. eventId makes submissions idempotent: replaying the same event is a safe no-op.
Common error codes
| HTTP | Code | Fix |
|---|---|---|
| 401 | CERTOPS_API_TOKEN_UNAUTHORIZED | Token missing, malformed, revoked, or expired. Create a new token. |
| 403 | CERTOPS_API_TOKEN_SCOPE_DENIED | Add the missing scope when creating the token. |
| 403 | CERTOPS_EXECUTOR_WORKSPACE_MISMATCH | Body workspaceId must match the token's workspace. |
| 404 | CERTOPS_JOB_NOT_FOUND | Create or look up a job first (POST/GET .../certops/jobs or Create manual job), then retry with that id. |
| 422 | PRIVATE_KEY_MATERIAL_REJECTED | Never send private keys. Remove key material from the payload. |
| 429 | CERTOPS_MACHINE_RATE_LIMITED | Back off per Retry-After, then retry with the same eventId. |
For the full executor workflow (events, evidence, redaction rules, certbot hooks), see the Certificate Automation guide and the connect an external executor runbook.