Skip to main content

Common workflows

Copy-paste curl workflows for the most common API tasks. Request and response schemas for every endpoint are in the REST Reference; this page shows how the endpoints combine into real workflows.

All examples use the Cloud base URL https://tokentimer.ch. On self-hosted and Enterprise deployments, replace it with your own backend URL (default local port 4000). The core API (tokens, workspaces, alerts, monitoring, CertOps, audit) is identical across deployments; a few surfaces below only exist on one, marked with a Self-hosted / Enterprise only or Cloud only badge (the REST Reference carries the same badges per endpoint).

Setup: authenticate once

Every workflow below uses a session cookie jar and, for mutating requests, a CSRF token. See Authentication for details.

BASE=https://tokentimer.ch

# Log in (creates session cookie)
curl -s -c cookies.txt -X POST $BASE/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"me@example.com","password":"StrongPass123!"}'

# Fetch a CSRF token for POST/PUT/PATCH/DELETE requests
CSRF=$(curl -s -b cookies.txt $BASE/api/csrf-token | jq -r '.csrfToken')

# List workspaces to find your workspace ID
curl -s -b cookies.txt "$BASE/api/v1/workspaces?limit=20&offset=0" | jq '.'

All workspace-scoped operations must include the workspace ID, either in the path (/api/v1/workspaces/:id/...) or as workspace_id in the query or body on the legacy token routes. List endpoints paginate with limit and offset.

Tokens

  • POST /api/tokens: create a token
  • GET /api/tokens: list; filters: workspace_id (required), section (string or __none__ for no section), q, category, sort, limit, offset
  • PUT /api/tokens/:id: update
  • DELETE /api/tokens/:id: delete

Required create fields: workspace_id, name (3-100 chars), category, type.

Optional fields: expiresAt (defaults to never expires if omitted), section (max 120 chars), contact_group_id, domains, location (max 500 chars), used_by (max 500 chars), description, notes, contacts (max 500 chars). Category-specific: certificates take issuer, serial_number, subject; keys and secrets take key_size, algorithm; licenses take license_type, vendor, cost, renewal_url, renewal_date.

When a contact group defines thresholds overrides, the token uses those thresholds instead of the workspace defaults.

WS=00000000-0000-0000-0000-000000000000

# Create a token
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\",\"expiresAt\":\"2030-01-01\",\"workspace_id\":\"$WS\"}"

# List tokens for a workspace
curl -s -b cookies.txt "$BASE/api/tokens?workspace_id=$WS&limit=50&offset=0" | jq '.'

# Filter by section "prod", or tokens with no section
curl -s -b cookies.txt "$BASE/api/tokens?workspace_id=$WS&section=prod&limit=50" | jq '.'
curl -s -b cookies.txt "$BASE/api/tokens?workspace_id=$WS&section=__none__&limit=50" | jq '.'

# Update a token
curl -s -b cookies.txt -X PUT $BASE/api/tokens/123 \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{"name":"Renewed cert","expiresAt":"2031-01-01"}'

Workspaces and members

  • POST /api/v1/workspaces: create (plan is assigned server-side)
  • GET /api/v1/workspaces: list (includes your role)
  • GET /api/v1/workspaces/:id: details
  • PATCH /api/v1/workspaces/:id: rename
  • DELETE /api/v1/workspaces/:id: delete
  • GET /api/v1/workspaces/:id/members: list members
  • POST /api/v1/workspaces/:id/members: invite { email, role }
  • PATCH /api/v1/workspaces/:id/members/:userId: change role
  • DELETE /api/v1/workspaces/:id/members/:userId: remove
  • GET /api/v1/workspaces/:id/invitations: list pending invitations (never returns the invitation token)
  • DELETE /api/v1/workspaces/:id/invitations/:invitationId: cancel a pending invitation (manager or admin); responds 204 and emits an INVITATION_CANCELLED audit event
# Create workspace
curl -s -b cookies.txt -X POST $BASE/api/v1/workspaces \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{"name":"Platform"}' | jq '.'

# Invite a member (manager or admin)
curl -s -b cookies.txt -X POST $BASE/api/v1/workspaces/$WS/members \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{"email":"teammate@example.com","role":"viewer"}' | jq '.'

# List and cancel pending invitations
curl -s -b cookies.txt $BASE/api/v1/workspaces/$WS/invitations | jq '.'
curl -s -b cookies.txt -X DELETE -H "X-CSRF-Token: $CSRF" \
$BASE/api/v1/workspaces/$WS/invitations/INVITATION_ID

Transfer tokens between workspaces

Requires admin role on both workspaces, or workspace manager on both with at least two workspaces assigned.

curl -s -b cookies.txt -X POST $BASE/api/v1/workspaces/TARGET_WS_ID/transfer-tokens \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d "{\"from_workspace_id\":\"$WS\",\"token_ids\":[101,102,103]}" | jq '.'

Alert settings and webhooks

  • GET /api/v1/workspaces/:id/alert-settings: get settings (includes contact groups)
  • PUT /api/v1/workspaces/:id/alert-settings: update settings
  • POST /api/test-webhook: send a test message (Slack, Discord, Teams, PagerDuty, generic)
# Get alert settings
curl -s -b cookies.txt $BASE/api/v1/workspaces/$WS/alert-settings | jq '.'

# Update thresholds, channels, delivery window, and contact groups
curl -s -b cookies.txt -X PUT $BASE/api/v1/workspaces/$WS/alert-settings \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{
"alert_thresholds": [30,14,7,1,0],
"webhook_urls": [
{"name":"On-call Slack","url":"https://hooks.slack.com/services/...","kind":"slack"}
],
"email_alerts_enabled": true,
"whatsapp_alerts_enabled": true,
"delivery_window_start": "00:00",
"delivery_window_end": "23:59",
"delivery_window_tz": "UTC",
"contact_groups": [
{"id":"ops","name":"Ops Team","email_contact_ids":["uuid-1"],"whatsapp_contact_ids":["uuid-1","uuid-2"],"thresholds":[10,5],"webhook_names":["On-call Slack"]},
{"id":"finance","name":"Finance","email_contact_ids":["uuid-3"],"whatsapp_contact_ids":[]}
],
"default_contact_group_id": "ops"
}' | jq '.'

# Create a token wired to a contact group
curl -s -b cookies.txt -X POST $BASE/api/tokens \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d "{\"workspace_id\":\"$WS\",\"name\":\"API Key\",\"type\":\"api_key\",\"category\":\"key_secret\",\"expiresAt\":\"2026-01-01\",\"contact_group_id\":\"ops\"}" | jq '.'

# Test a webhook before saving it
curl -s -b cookies.txt -X POST $BASE/api/test-webhook \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{"url":"https://hooks.slack.com/services/...","kind":"slack"}' | jq '.'

Alert queue and stats

  • GET /api/alert-queue: queued alerts
  • GET /api/alert-stats: monthly stats (pass workspace_id)
curl -s -b cookies.txt "$BASE/api/alert-queue?limit=10&offset=0" | jq '.'
curl -s -b cookies.txt "$BASE/api/alert-stats?workspace_id=$WS" | jq '.'

Endpoint (SSL) monitoring

Adding an endpoint automatically creates a token tracking the SSL certificate. Health checks run on a configurable interval.

  • GET /api/v1/workspaces/:id/domains: list monitored endpoints with SSL info, health status, and response times
  • POST /api/v1/workspaces/:id/domains: add an endpoint; body: { url, health_check_enabled, check_interval, alert_after_failures }
  • PUT /api/v1/workspaces/:id/domains/:domainId: update settings
  • DELETE /api/v1/workspaces/:id/domains/:domainId: remove a monitor (does not delete the SSL token)
  • POST /api/v1/workspaces/:id/domains/:domainId/check: trigger a manual health check

Check intervals: 1min, 5min, 30min, hourly, daily. alert_after_failures is the number of consecutive failures before a "down" notification is sent (default 2); see Endpoint health alerts.

# Add an endpoint
curl -s -b cookies.txt -X POST $BASE/api/v1/workspaces/$WS/domains \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{"url":"https://example.com","health_check_enabled":true,"check_interval":"5min","alert_after_failures":3}' | jq '.'

# List, check, delete
curl -s -b cookies.txt $BASE/api/v1/workspaces/$WS/domains | jq '.'
curl -s -b cookies.txt -X POST -H "X-CSRF-Token: $CSRF" \
$BASE/api/v1/workspaces/$WS/domains/DOMAIN_ID/check | jq '.'
curl -s -b cookies.txt -X DELETE -H "X-CSRF-Token: $CSRF" \
$BASE/api/v1/workspaces/$WS/domains/DOMAIN_ID | jq '.'

Auto-sync Self-hosted / Enterprise only

Scheduled recurring integration scans. Auto-sync stores encrypted credentials and scan parameters, then runs scans on a configurable schedule. Available for GitHub and GitLab integrations on self-hosted deployments; TokenTimer Cloud does not offer auto-sync (this route returns 404), credentials are never stored there, see Integrations.

  • GET /api/v1/workspaces/:id/auto-sync: list all auto-sync configurations for the workspace
  • POST /api/v1/workspaces/:id/auto-sync: create a configuration; body: { provider, credentials, scan_params, frequency, preferred_time, timezone }
  • PUT /api/v1/workspaces/:id/auto-sync/:configId: update a configuration (credentials, frequency, ...)
  • DELETE /api/v1/workspaces/:id/auto-sync/:configId: delete a configuration (also deletes stored credentials)
  • POST /api/v1/workspaces/:id/auto-sync/:configId/run: trigger an immediate sync run
BASE=https://tokentimer.example.com # your self-hosted backend URL

# List auto-sync configs
curl -s -b cookies.txt "$BASE/api/v1/workspaces/WS_ID/auto-sync" | jq '.'

# Create auto-sync for GitHub
curl -s -b cookies.txt -X POST "$BASE/api/v1/workspaces/WS_ID/auto-sync" \
-H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
-d '{
"provider": "github",
"credentials": { "token": "ghp_xxx" },
"scan_params": { "includeClassicPAT": true, "includeFineGrainedPAT": true },
"frequency": "daily",
"preferred_time": "02:00",
"timezone": "Europe/Zurich"
}' | jq '.'

# Manually trigger a sync
curl -s -b cookies.txt -X POST -H "X-CSRF-Token: $CSRF" \
"$BASE/api/v1/workspaces/WS_ID/auto-sync/CONFIG_ID/run" | jq '.'

# Delete a config
curl -s -b cookies.txt -X DELETE -H "X-CSRF-Token: $CSRF" \
"$BASE/api/v1/workspaces/WS_ID/auto-sync/CONFIG_ID" | jq '.'

Certificates (CertOps)

Workspace-scoped certificate inventory routes, session-authenticated. On self-hosted deployments these require CERTOPS_ENABLED=true and return 404 when disabled (see the CertOps enablement runbook); on Cloud they are plan-gated instead and return 402 when the workspace plan does not include them. The routes accept public certificate material only; private keys are rejected with HTTP 422.

  • GET /api/v1/workspaces/:id/certops/certificates: list managed certificates
  • POST /api/v1/workspaces/:id/certops/certificates: register a public PEM
  • GET /api/v1/workspaces/:id/certops/certificates/:certId: certificate detail
  • GET /api/v1/workspaces/:id/certops/certificates/:certId/instances: rotation history
  • POST /api/v1/workspaces/:id/certops/certificates/:certId/retire: mark revoked or decommissioned
  • POST /api/v1/workspaces/:id/certops/imports: bulk import public certificates
  • GET /api/v1/workspaces/:id/certops/jobs: list executor jobs
  • POST /api/v1/workspaces/:id/certops/jobs: create an executor job manually (workspace manager; body: { operation, subjectType?, subjectId?, payload? }; source is forced to api)
# List managed certificates
curl -s -b cookies.txt \
"$BASE/api/v1/workspaces/$WS/certops/certificates?limit=50&offset=0" | jq '.'

# Create a manual executor job (workspace manager). Copy job.id for executor hooks.
curl -s -b cookies.txt -X POST -H "X-CSRF-Token: $CSRF" \
-H "Content-Type: application/json" \
-d '{"operation":"renew","subjectType":"managed_certificate","subjectId":"CERT_ID"}' \
"$BASE/api/v1/workspaces/$WS/certops/jobs" | jq '.'

Create jobs with Create a manual CertOps job (or the dashboard button), then report against that jobId on the machine-token surface. See Authentication → Machine API tokens and the Certificate Automation guide.

System administration Self-hosted / Enterprise only

Instance-level settings, available to system administrators on your own deployment (on Cloud, TokenTimer operates these; the routes do not exist there):

  • GET / PUT /api/admin/system-settings: SMTP, WhatsApp, and instance settings
  • POST /api/admin/test-smtp: send a test email
  • POST /api/admin/test-whatsapp: send a test WhatsApp message
  • POST /api/admin/users/:userId/system-admin: grant or revoke the system admin flag

Schemas are in the REST Reference; operational context is in the self-hosted configuration reference.

Billing Cloud only

TokenTimer Cloud exposes billing routes under /api/billing/* (checkout, Stripe customer portal, invoices, plan refresh). They require an admin session and exist only on Cloud; self-hosted and Enterprise deployments have no plans or payments, and quota/plan checks (402 responses) do not apply there.

These routes back the dashboard billing page and are not designed for automation: checkout and payment confirmation involve browser redirects to Stripe. Manage your subscription in the dashboard instead; see Billing & plans and Plan limits.

Audit and usage

  • GET /api/audit-events: latest events for the current user
  • GET /api/audit-events?scope=organization: organization scope (admin)
  • GET /api/v1/workspaces/:id/audit-events: workspace scope (manager or admin)
  • GET /api/organization/usage: aggregated organization usage metrics (admin)
curl -s -b cookies.txt "$BASE/api/audit-events?limit=50&offset=0" | jq '.'
curl -s -b cookies.txt "$BASE/api/v1/workspaces/$WS/audit-events?limit=50" | jq '.'
curl -s -b cookies.txt "$BASE/api/audit-events?scope=organization&limit=50" | jq '.'
curl -s -b cookies.txt $BASE/api/organization/usage | jq '.'