Torgix API
Read and write your equipment data, export in bulk, and subscribe to webhooks. REST over HTTPS, JSON in and out, scoped to your account.
The API is included with every Torgix account at no extra cost. An admin turns it on and issues keys in the app under Settings → API & Webhooks. Every request is tenant-scoped to the account that owns the key, so you only ever see and touch your own data.
Base URL
https://app.torgix.ai/v1
v1, pinned in the path. Additive changes (new fields, new resources) won't break you; we'll version the path before any breaking change.Quickstart
Three steps to your first response. No SDK required.
1 · Create a key
An admin opens Settings → API & Webhooks in the app, switches the API on, and creates a key. The full secret is shown once, so copy it straight into your environment:
export TORGIX_KEY=tgx_test_xxxxxxxxxxxxxxxxxxxxxxxx
2 · Make a call
curl https://app.torgix.ai/v1/assets \ -H "Authorization: Bearer $TORGIX_KEY"
3 · Read the envelope
{
"data": [ { "id": 142, "name": "Excavator 320", "status": "active" } ],
"next_cursor": "142",
"request_id": "req_8a1c2f…"
}
That is the whole shape. Every read returns data plus a cursor and a request id. From here, jump to pagination to walk a full list, creating & updating to write back, or webhooks to get pushed changes instead of polling for them.
Authentication
Send your key as a bearer token on every request:
curl https://app.torgix.ai/v1/assets \ -H "Authorization: Bearer tgx_live_xxxxxxxxxxxxxxxxxxxxxxxx"
Keys are created in the app; the full secret is shown once at creation, so store it somewhere safe. You can set an optional IP allowlist per key, and revoke a key at any time. Missing or invalid credentials return 401; a key whose account has API access switched off returns 403.
Scopes & modes
Each key carries one or more scopes. A request that needs a scope the key lacks returns 403 insufficient_scope.
| Scope | Grants |
|---|---|
read | List, get, and poll events. |
write | Create, update, and batch. |
export | Bulk export endpoints. |
Keys are issued in live or test mode (the mode is part of the key prefix, e.g. tgx_live_… / tgx_test_…) so you can keep sandbox integrations separate.
OAuth 2.0
For apps that act on behalf of an account, use the authorization-code flow with PKCE instead of a static key. An admin registers a client in the app under Settings → API & Webhooks → OAuth applications, choosing public (PKCE only, for mobile/SPA) or confidential (also issued a client secret).
| Endpoint | URL |
|---|---|
| Authorize | https://app.torgix.ai/oauth/authorize |
| Token | https://app.torgix.ai/oauth/token |
1 · Send the user to authorize
Generate a PKCE code_verifier and its code_challenge = base64url(SHA-256(verifier)), then redirect:
https://app.torgix.ai/oauth/authorize?response_type=code
&client_id=tgxc_…
&redirect_uri=https://your-app/callback
&scope=read%20write
&state=xyz
&code_challenge=<challenge>&code_challenge_method=S256
The user signs in and approves; Torgix redirects back to your redirect_uri with ?code=…&state=….
2 · Exchange the code for tokens
curl https://app.torgix.ai/oauth/token \ -d grant_type=authorization_code \ -d code=<code> -d code_verifier=<verifier> \ -d redirect_uri=https://your-app/callback \ -d client_id=tgxc_… -d client_secret=tgxs_… # secret only for confidential clients
{ "access_token":"tgo_…", "token_type":"Bearer", "expires_in":3600,
"refresh_token":"tgo_…", "scope":"read write" }
3 · Call the API & refresh
Use the access token exactly like a key: Authorization: Bearer tgo_…. Access tokens last 1 hour; refresh with grant_type=refresh_token (refresh tokens last 30 days and rotate on each use, so store the newest one).
Requests & responses
Request bodies are JSON; set Content-Type: application/json on writes. Successful reads return an envelope:
{
"data": [ { "id": 142, "name": "Excavator 320", "status": "active" } ],
"next_cursor": "142",
"request_id": "req_8a1c2f…"
}
A single record returns { "data": { … }, "request_id": "…" }. Every response includes X-Request-Id (also echoed in the body). Quote it if you contact support.
Pagination, filtering & sorting
- Pagination is cursor-based by default. Read
next_cursorfrom a page and pass it as?cursor=to get the next one;nullmeans you've reached the end. Use?page_size=(default 50, max 200). - Sorting switches to numbered pages:
?sort=-created_at,name(up to 3 columns,-for descending) with?page=; the response carriespage,page_sizeandnext_page. - Field selection:
?fields=id,name,statusreturns only those fields. - Incremental sync:
?changed_since=2026-06-01T00:00:00Zreturns only records created/updated since that time. - Filtering: any field as a query param is an exact match,
?status=active. Put an operator in brackets for more:?hours[gte]=500,?status[in]=open,active,?name[like]=%320%,?cleared_at[null]=true. Operators:eq ne gt gte lt lte in nin like nlike null. Filters combine with AND. - Deleted rows are hidden. Add
?include_deleted=trueto see records that were soft-deleted.
curl "https://app.torgix.ai/v1/work_orders?status[in]=open,in_progress&sort=-created_at&page_size=100" \ -H "Authorization: Bearer $TORGIX_KEY"
Rate limits & fair use
Requests are limited to 10 per second per key. Each response carries X-RateLimit-Limit and X-RateLimit-Remaining; exceeding the limit returns 429 with Retry-After. Back off and retry.
Monthly fair-use guardrails keep the platform healthy: 100,000 records read and 2,000 records exported per month. Writes are uncapped. You can watch your usage against these limits in the app under Settings → API & Webhooks → Usage.
Errors
Errors share one shape:
{
"error": {
"code": "insufficient_scope",
"message": "This credential lacks the write scope.",
"field": null,
"request_id": "req_8a1c2f…"
}
}
| Status | Meaning |
|---|---|
400 | Malformed request (bad JSON, empty body, bad batch). |
401 | Missing or invalid credentials. |
403 | API access switched off, missing scope, or IP not allowlisted. |
404 | Not found in your account. |
405 | That write is not allowed on this resource (read-only, or create-only). |
409 | A request with the same Idempotency-Key is still in progress. |
422 | Write rejected. field names the offending column. |
429 | Rate limited. Honor Retry-After. |
501 | Not available: the resource is not provisioned for your account yet, or delete is not supported on it. |
Resources
51 resources are exposed, all through the same engine: every one supports list, get, export and aggregate, and 19 also accept writes. Fields mirror the record as you see it in the app, including any custom fields an admin has defined. Pull one record to learn its shape, or read the interactive reference.
| Resource | Path | Writes |
|---|---|---|
| Assets | /v1/assets | create + update + delete |
| Locations | /v1/locations | create + update + delete |
| Work orders | /v1/work_orders | create + update + delete |
| Maintenance logsCompleted service history. Append-only: a log is a record of work already done. | /v1/maintenance | create |
| PM schedulesPreventive maintenance schedules per asset (interval, last done, next due). | /v1/pm_schedules | read-only |
| Inspections | /v1/inspections | create |
| Issues | /v1/issues | create + update + delete |
| Activities | /v1/activities | read-only |
| Projects | /v1/projects | read-only |
| Rental contracts | /v1/rentals | read-only |
| Customers | /v1/customers | read-only |
| Parts requests | /v1/parts | read-only |
| Parts orders | /v1/parts_orders | read-only |
| Inventory | /v1/inventory | read-only |
| Warranties | /v1/warranties | read-only |
| Fuel logs | /v1/fuel_logs | create |
| Meter readings | /v1/meter_readings | create |
| Tire readings | /v1/tire_readings | create |
| Users | /v1/users | read-only |
| Audit logThe account audit log, for pulling into a SIEM. Filter by created_at, cursor by id. | /v1/audit_events | read-only |
| Compliance records | /v1/compliance | create + update + delete |
| Insurance | /v1/insurance | create + update + delete |
| DocumentsDocument metadata; the storage path is not exposed and uploads go through the app. | /v1/documents | read-only |
| True CostComputed True Cost rows per asset, including the CFO fields; read-only because they are derived. | /v1/costs | read-only |
| Cost inputsThe per-asset inputs True Cost is computed from (purchase, salvage, finance, insurance, storage). | /v1/cost_inputs | create + update + delete |
| Downtime | /v1/downtime | create |
| TelematicsLatest GPS and engine snapshot per asset, fed by the connected telematics provider. | /v1/telematics | read-only |
| Idle timeIdle events derived from telematics. | /v1/idle_time | read-only |
| Customer contacts | /v1/customer_contacts | create + update + delete |
| Inventory usage | /v1/inventory_usage | read-only |
| Project assets | /v1/project_assets | create |
| Fault codesDiagnostic trouble codes per asset (OBD-II, J1939, J1587) from telematics, import, or manual entry. Post one to record a code read off the machine. | /v1/faults | create |
| Recalls and bulletinsNHTSA recalls, OEM bulletins and manual notices matched to an asset, with a status workflow. | /v1/recalls | create |
| EV charge sessionsEV charging sessions: state of charge in and out, kWh added, duration. Fed by Samsara; post one for a charger that is not connected. | /v1/charge_logs | create |
| Tool checkoutsSmall-tool checkouts: what left the shop, where it went, when it came back, what was charged. | /v1/checkouts | read-only |
| EmployeesPeople for labor costing: position, pay basis, burden. Includes pay fields; issue keys accordingly. | /v1/employees | create + update + delete |
| Road callsJob-site repair trips by a service truck, costed by miles and mechanic time. | /v1/service_trips | read-only |
| Road call stopsThe stops on a road call, each tied to a work order with its share of the trip cost. | /v1/service_trip_stops | read-only |
| Vendor ordersParts orders placed through Commerce Connect vendors, with totals and status. | /v1/vendor_orders | read-only |
| Rental classesRental classes an asset can belong to (rate setup follows the rental billing release). | /v1/rental_classes | read-only |
| Rental catalogRentable items and services with their rates. | /v1/rental_catalog | read-only |
| Rental logisticsDeliveries and pickups scheduled against a rental contract. | /v1/rental_logistics | read-only |
| Daily telematics metersOne row per asset per day: engine hours, idle, odometer, fuel, PTO and regen hours, payload. Fed by Samsara, Motive or Rovi. | /v1/meter_daily | read-only |
| Fleet briefsAI fleet briefs generated for the account, by date. | /v1/fleet_briefs | read-only |
| Module briefsAI briefs generated per module and record. | /v1/module_briefs | read-only |
| Warranty assessmentsAI warranty verdict per work order: covered items, exclusions, rationale, confidence. | /v1/warranty_assessments | read-only |
| Inspection templatesInspection checklists defined by the account. | /v1/inspection_templates | read-only |
| State compliance requirementsState compliance requirements the account tracks, with authority, cadence and verification status. | /v1/compliance_requirements | read-only |
| Asset compliance requirementsWhich requirements apply to which asset, and whether each is satisfied. | /v1/asset_compliance_requirements | read-only |
| Warranty SKUsWarranty products the account sells or tracks. | /v1/warranty_skus | read-only |
| Asset photosPhoto metadata per asset (name, type, size, caption). The image itself is not served by the API. | /v1/asset_photos | read-only |
Some resources are provisioned per account (they answer 501 until the matching module is enabled). Import the OpenAPI spec into Postman, Insomnia, or a code generator for every path and parameter.
Reading
| Method | Path | Returns |
|---|---|---|
| GET | /v1/{resource} | A page of records. |
| GET | /v1/{resource}/{id} | One record. |
| GET | /v1/{resource}/aggregate | One number: ?metric=count, or sum:col, avg:col, min:col, max:col; add &group_by=col for one number per group. The same filters apply. |
curl https://app.torgix.ai/v1/assets/142 \ -H "Authorization: Bearer $TORGIX_KEY"
curl "https://app.torgix.ai/v1/work_orders/aggregate?metric=sum:total_cost&group_by=status" \ -H "Authorization: Bearer $TORGIX_KEY"
Creating, updating & deleting
| Method | Path | Does |
|---|---|---|
| POST | /v1/{resource} | Create a record. |
| PATCH | /v1/{resource}/{id} | Update supplied fields. On read-only resources that carry custom fields (customers, rentals, parts orders, inventory) a body of exactly {"custom_fields": {...}} is accepted. |
| DELETE | /v1/{resource}/{id} | Soft delete: the record gets a deleted_at stamp and drops out of reads. Nothing is ever hard-deleted; repeat the call and you get already_deleted. Resources without a deleted_at column answer 501. |
Your account is set automatically. company_id and internal columns (ids, timestamps) can't be supplied and are ignored. For anything that belongs to a machine (meter readings, fuel logs, faults, charge sessions) pass the asset_id; it is verified to belong to your account. Custom fields go in a custom_fields object keyed by the field's API key.
curl https://app.torgix.ai/v1/assets \ -H "Authorization: Bearer $TORGIX_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 7c1f-asset-import-0042" \ -d '{"name":"Excavator 320","asset_code":"EX-320","category":"Heavy"}'
Idempotency-Key on a create and a retry with the same key replays the original result instead of creating a duplicate (the response carries Idempotent-Replayed: true). A missing required field returns 422 with field set.Batch
POST /v1/{resource}/batch runs up to 200 create/update operations in one call. Each item reports its own status, so a bad row doesn't sink the batch. Create-only resources (logs) accept create items only.
curl https://app.torgix.ai/v1/meter_readings/batch \ -H "Authorization: Bearer $TORGIX_KEY" -H "Content-Type: application/json" \ -d '{"operations":[ {"method":"create","data":{"asset_id":142,"hours":1203}}, {"method":"create","data":{"asset_id":143,"hours":880}} ]}'
{ "results": [ {"status":201,"data":{…}}, {"status":201,"data":{…}} ], "request_id":"req_…" }
Export
GET /v1/{resource}/export (needs the export scope) bulk-pulls records as a JSON array, or newline-delimited JSON with ?format=ndjson. The same filters, fields and changed_since apply. Each call returns up to 2,000 rows with a truncated flag (or an X-Truncated header for ndjson) when there is more; narrow with changed_since or a filter and call again.
curl "https://app.torgix.ai/v1/assets/export?format=ndjson" \ -H "Authorization: Bearer $TORGIX_KEY"
Webhooks
Add an endpoint in the app under Settings → API & Webhooks, choose the events (or * for all), and Torgix will POST each matching event to your https:// URL. Event types follow <resource>.created, <resource>.updated and <resource>.deleted, for every resource in the table above. If your handler writes back through the API, send X-Torgix-Skip-Webhook: 1 on that request so it does not echo another event.
POST your-endpoint X-Torgix-Event: assets.updated X-Torgix-Event-Id: evt_4f1c… X-Torgix-Signature: t=1719190000,v1=<hex> { "id": "evt_4f1c…", "type": "assets.updated", "resource": "assets", "resource_id": 142, "data": { "id": 142, "status": "active" }, "created_at": "2026-06-24T01:00:00Z" }
Respond 2xx within 8 seconds. Failed deliveries retry at 1 min, 5 min, 30 min, 2 hr, 6 hr, then dead-letter; you can resend any delivery from the app. To avoid loops when your integration writes back to Torgix, include the X-Torgix-Skip-Webhook header on those API calls and no event is emitted.
Verifying signatures
The X-Torgix-Signature header is t=<unix>,v1=<hex>, where the hex is HMAC-SHA256 of "{t}.{rawRequestBody}" keyed with the endpoint's signing secret. Compare with a constant-time check and reject timestamps older than 5 minutes.
// Node.js: verify a Torgix webhook const crypto = require('crypto'); function verify(rawBody, header, secret) { const [tp, vp] = header.split(','); const t = tp.split('=')[1], sig = vp.split('=')[1]; if (Math.abs(Date.now()/1000 - Number(t)) > 300) return false; // stale const expected = crypto.createHmac('sha256', secret) .update(t + '.' + rawBody).digest('hex'); return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig)); }
Polling
Prefer to pull rather than receive? GET /v1/events returns recent events for your account. Cursor forward with the cursor of the last item, and optionally filter with ?event_type=.
curl "https://app.torgix.ai/v1/events?event_type=assets.updated" \ -H "Authorization: Bearer $TORGIX_KEY"