API Documentation
The Traction Hub API allows you to programmatically read and write your data — scorecards, issues, quarterly goals, to-dos, headlines, and more.
Base URL: https://tractionhubapp.com/api.php
Authentication
The API uses Bearer token authentication. Generate an API key from the Admin panel, then include it in the Authorization header of every request.
Generating a Key
- Sign in as an admin and go to Admin → API Keys
- Click New API Key, give it a name, and optionally set an expiry
- Copy the key immediately — it is shown once only and never stored in plaintext
Using the Key
Pass the key in the Authorization header on every request:
POST /api.php
Content-Type: application/json
Authorization: Bearer th_live_a3f1b2c4d5e6...
Key Format
Keys are prefixed with th_live_ followed by 48 hex characters. Store keys securely — treat them like passwords.
Key Scope
Each key inherits the permissions of the admin who created it and is scoped to your company's data only.
{ "error": "Not authenticated" }
API Keys
Manage API keys programmatically. All endpoints require an existing valid Bearer token with admin permissions.
| Field | Type | Description |
| tenant_id | integer required | Company ID the key belongs to |
| name | string required | Human label, e.g. Zapier integration |
| expires_at | string optional | Expiry date in YYYY-MM-DD. Omit for a non-expiring key. |
{ "action": "create_api_key", "tenant_id": 1, "name": "Zapier" }
{ "success": true, "id": 3, "key": "th_live_a3f1b2c4..." }
⚠ The key value is returned once only. Store it immediately.
| Field | Type | Description |
| tenant_id | integer required | Company ID |
{ "success": true, "keys": [
{
"id": 3,
"name": "Zapier",
"key_prefix": "th_live_a3f1b2c4",
"created_by_name": "Jane Smith",
"created_at": "2026-02-28 10:00:00",
"last_used_at": "2026-02-28 14:22:01",
"expires_at": null
}
]}
Note: only the first 16 characters of the key (key_prefix) are returned for identification. The full key is never retrievable after creation.
| Field | Type | Description |
| id | integer required | API key ID |
| tenant_id | integer required | Company ID (must match the key's tenant) |
{ "action": "revoke_api_key", "id": 3, "tenant_id": 1 }
{ "success": true }
Revocation is immediate and permanent. Any further request using the revoked key will receive a 401 response.
Scorecards
| Field | Type | Description |
| tenant_id | integer required | Your company ID |
| name | string required | Scorecard name (e.g. "Leadership Team") |
| description | string optional | Short description |
{ "action": "create_scorecard", "tenant_id": 1, "name": "Leadership Scorecard" }
{ "success": true, "id": 7 }
| Field | Type | Description |
| id | integer required | Scorecard ID |
| name | string required | New name |
| description | string optional | New description |
| Field | Type | Description |
| id | integer required | Scorecard ID to delete |
Metrics
| Field | Type | Description |
| scorecard_id | integer required | Parent scorecard ID |
| name | string required | Metric name (e.g. "New Leads") |
| owner | string optional | Person responsible |
| unit | string optional | Unit suffix: $, %, or custom (e.g. "hrs") |
| goal | number optional | Target value |
| goal_type | string optional | >=, <=, or =. Default: >= |
| Field | Type | Description |
| metric_id | integer required | Metric ID |
| week_date | string required | Monday of the week in YYYY-MM-DD format |
| value | number|null required | The value to record. Send null to clear. |
{ "action": "set_value", "metric_id": 14, "week_date": "2026-02-24", "value": 47 }
| Field | Type | Description |
| id | integer required | Metric ID |
| name | string optional | New name |
| owner | string optional | New owner name |
| unit | string optional | Unit suffix |
| goal | number|null optional | New goal value |
| goal_type | string optional | >=, <=, or = |
| Field | Type | Description |
| id | integer required | Metric ID |
Issues
| Field | Type | Description |
| tenant_id | integer required | Company ID |
| title | string required | Issue title |
| description | string optional | Additional detail |
| type | string optional | obstacle, idea, or process |
| priority | integer optional | 1 (low), 2 (medium), 3 (high). Default: 2 |
| Field | Type | Description |
| id | integer required | Issue ID |
| title | string optional | New title |
| status | string optional | open or solved |
| priority | integer optional | 1, 2, or 3 |
| Field | Type | Description |
| id | integer required | Issue ID |
Quarterly Goals
| Field | Type | Description |
| tenant_id | integer required | Company ID |
| title | string required | Rock title |
| owner_name | string required | Person owning this rock |
| quarter | string optional | Quarter label, e.g. 2026-Q1 |
| due_date | string optional | Due date in YYYY-MM-DD |
| status | string optional | not_started, on_track, off_track, done |
| description | string optional | Additional detail |
Same fields as create_rock plus id (required).
| Field | Type | Description |
| id | integer required | Rock ID |
To-Dos
| Field | Type | Description |
| tenant_id | integer required | Company ID |
| title | string required | Task description |
| assigned_to | string required | Assignee name |
| due_date | string optional | Due date in YYYY-MM-DD |
| Field | Type | Description |
| id | integer required | To-Do ID |
| status | string optional | pending or done |
| title | string optional | Updated title |
| assigned_to | string optional | Updated assignee |
| due_date | string optional | Updated due date |
| Field | Type | Description |
| id | integer required | To-Do ID |
Headlines
| Field | Type | Description |
| tenant_id | integer required | Company ID |
| title | string required | Headline text |
| type | string optional | good_news or heads_up |
| week_date | string optional | Week in YYYY-MM-DD (Monday). Defaults to current week. |
| Field | Type | Description |
| id | integer required | Headline ID |
People Analyzer
| Field | Type | Description |
| tenant_id | integer required | Company ID |
| seat_name | string required | Role/seat (e.g. "Integrator", "Sales Lead") |
| person_name | string required | Person's name |
| Field | Type | Description |
| id | integer required | Person ID |
| gets_it | string optional | yes, no, or sometimes |
| wants_it | string optional | yes, no, or sometimes |
| capacity | string optional | yes, no, or sometimes |
| notes | string optional | Free-form notes |
| reviewed_date | string optional | Date last reviewed: YYYY-MM-DD |
| Field | Type | Description |
| id | integer required | Person ID |
Error Codes
| HTTP Status | Meaning |
| 200 | Success — check the success field in the body |
| 400 | Unknown action or malformed request |
| 401 | Missing or invalid API key |
| 403 | Forbidden — insufficient permissions, or account subscription suspended |
| 200 + error | Business logic error — check the error field |
| 500 | Server or database error |
Notes & Limits
- All requests must be
POST with Content-Type: application/json
- API keys only have access to your own company's data
- There are no hard rate limits currently — please be respectful of shared resources
- IDs are integers. Always store them as integers, not strings
- Dates should use
YYYY-MM-DD format
- Week dates must be a Monday
Questions? Contact us through the admin panel or reply to any Traction Hub email.