Developers
The Tri-Gig API
Read and write a workspace from your own systems. A key belongs to one workspace and can do nothing outside it. Create one under Workspace settings → API keys; it is shown once.
Calling it
curl https://app.trigig.com/api/v1/contacts \
-H "Authorization: Bearer tg_live_…"
curl -X POST https://app.trigig.com/api/v1/contacts \
-H "Authorization: Bearer tg_live_…" -H "Content-Type: application/json" \
-d '{"first_name":"Ada","last_name":"Okafor","email":"ada@example.com"}'- Responses are
{ data, next_cursor }for lists and{ data }for one thing. Errors are{ error: { code, message } }with the matching status. - 120 requests a minute per key. Over that you get
429; wait and try again. - Read-only keys can only
GET. Writes fire the same rules as the same action on screen. - Version 1. Breaking changes will come as
/api/v2, never as a change to v1.
Endpoints
| GET | /api/v1/me | The workspace this key belongs to, what it may do, and its enterprise parent or companies if any. |
| GET | /api/v1/contacts | Contacts, newest first. ?limit=50&cursor=<created_at> |
| POST | /api/v1/contacts | Add a contact: first_name, last_name, email, phone, company, custom{}. Fires the same rules as adding one on screen. |
| GET | /api/v1/contacts/{id} | One contact. |
| PATCH | /api/v1/contacts/{id} | Change a contact. Send only the fields that change; custom{} is merged, not replaced. |
| DELETE | /api/v1/contacts/{id} | Delete a contact. 204. It lands in What changed and can be put back from there. |
| GET | /api/v1/projects | Projects, newest first. |
| GET | /api/v1/tasks | Tasks, newest first. |
| POST | /api/v1/tasks | Add a task: title, description, due_date, assigned_user_id, project_id. |
| GET | /api/v1/tasks/{id} | One task. |
| PATCH | /api/v1/tasks/{id} | Change a task: title, description, status (todo, in_progress, done), due_date, assigned_user_id, project_id, contact_id, custom{}. |
| DELETE | /api/v1/tasks/{id} | Delete a task. 204. |
| GET | /api/v1/invoices | Invoices with their line items, newest first. ?status=draft|sent|paid… Read-only: money moves through the product, not a key. |
| GET | /api/v1/calendar | Events on the shared calendar. ?from=&to= (ISO) bound by start time; a personal key also sees that person’s own events. |
| GET | /api/v1/lists | The lists this workspace added, with their fields. |
| GET | /api/v1/lists/{id}/records | Records in a list, newest first. |
| POST | /api/v1/lists/{id}/records | Add a record: { data: { <field_key>: value } }. Required fields are enforced; unknown keys are dropped. Fires the list’s rules. |
| GET | /api/v1/lists/{id}/records/{recordId} | One record. |
| PATCH | /api/v1/lists/{id}/records/{recordId} | Change a record: { data: { <field_key>: value } }. Only the keys sent change; a required field cannot be emptied. |
| DELETE | /api/v1/lists/{id}/records/{recordId} | Delete a record. 204. |
Keys that act as a person
A key is either the workspace’s or one person’s. Tick Acts as me when creating it and every write it makes is checked against that person’s permissions and recorded in What changed under their name. Trig makes its changes through this same door, so a rule that stops a person also stops Trig acting for them.
Webhooks
Add one under Workspace settings → API keys with an https URL and the events you want. Each delivery is a JSON POST; a failed one (anything but a 2xx within ten seconds) is retried after 1, 2, 4, 8 and 16 minutes, then given up.
POST <your url>
Content-Type: application/json
X-TriGig-Event: contact:created
X-TriGig-Delivery: <delivery id>
X-TriGig-Signature: t=1696262400,v1=<hex>
{ "event": "contact:created", "workspace_id": "…", "sent_at": "…", "data": { "contact": { … } } }To check it: take t from the header, compute HMAC-SHA256 of <t>.<raw body> with your signing secret, hex-encode it, and compare with v1 in constant time. Refuse anything whose t is more than five minutes old.
// Node
import { createHmac, timingSafeEqual } from 'node:crypto'
const [t, v1] = sig.split(',').map(p => p.split('=')[1])
const expect = createHmac('sha256', SECRET).update(`${t}.${rawBody}`).digest('hex')
const ok = timingSafeEqual(Buffer.from(expect, 'hex'), Buffer.from(v1, 'hex')) && Math.abs(Date.now() / 1000 - Number(t)) < 300Events you can subscribe to: contact:created, contact:updated, contact:deleted, task_created, task_completed, invoice:created, invoice:sent, invoice:paid, and custom:<list id>:created / updated / deleted for any list — or * for all of them.