TorgixAPI Reference
torgix.ai Integrations OpenAPI spec

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 a paid add-on. 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
Versioning. The current version is v1, pinned in the path. Additive changes (new fields, new resources) won't break you; we'll version the path before any breaking change.

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 doesn't have the add-on active returns 403.

Scopes & modes

Each key carries one or more scopes. A request that needs a scope the key lacks returns 403 insufficient_scope.

ScopeGrants
readList, get, and poll events.
writeCreate, update, and batch.
exportBulk 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 — choose public (PKCE only, for mobile/SPA) or confidential (also issued a client secret).

EndpointURL
Authorizehttps://app.torgix.ai/oauth/authorize
Tokenhttps://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).

First-party. A client is registered by an account and authorized by a user of that same account, so tokens only ever reach that account's data. PKCE (S256) is required; authorization codes are single-use and expire in 10 minutes.

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

  • Pagination is cursor-based. Read next_cursor from a page and pass it as ?cursor= to get the next one; null means you've reached the end. Use ?page_size= (default 50, max 200).
  • Field selection: ?fields=id,name,status returns only those fields.
  • Incremental sync: ?changed_since=2026-06-01T00:00:00Z returns only records created/updated since that time.
  • Filtering: add any field as a query param for an exact match, e.g. ?status=active.
curl "https://app.torgix.ai/v1/work_orders?status=open&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…"
  }
}
StatusMeaning
400Malformed request (bad JSON, empty body, bad batch).
401Missing or invalid credentials.
403Add-on inactive, missing scope, or IP not allowlisted.
404Not found in your account.
422Write rejected — field names the offending column.
429Rate limited — honor Retry-After.

Resources

Eighteen resources are exposed. All support reading and export; the table shows which also accept writes in v1.

ResourcePathWrites
Assets/v1/assetscreate + update
Locations/v1/locationscreate + update
Work orders/v1/work_orderscreate + update
Issues/v1/issuescreate + update
Maintenance logs/v1/maintenancecreate
Inspections/v1/inspectionscreate
Fuel logs/v1/fuel_logscreate
Meter readings/v1/meter_readingscreate
PM schedules/v1/pm_schedulesread-only
Activities/v1/activitiesread-only
Projects/v1/projectsread-only
Rentals/v1/rentalsread-only
Customers/v1/customersread-only
Parts requests/v1/partsread-only
Parts orders/v1/parts_ordersread-only
Inventory/v1/inventoryread-only
Warranties/v1/warrantiesread-only
Users/v1/usersread-only

Fields mirror the record as you see it in the app. Pull a record with GET to learn its shape, or import the OpenAPI spec into Postman, Insomnia, or a code generator.

Reading

MethodPathReturns
GET/v1/{resource}A page of records.
GET/v1/{resource}/{id}One record.
curl https://app.torgix.ai/v1/assets/142 \
  -H "Authorization: Bearer $TORGIX_KEY"

Creating & updating

MethodPathDoes
POST/v1/{resource}Create a record.
PATCH/v1/{resource}/{id}Update supplied fields.

Your account is set automatically — company_id and internal columns (ids, timestamps) can't be supplied and are ignored. For child resources like meter readings or fuel logs, pass the asset_id; it's verified to belong to your account.

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. Send a unique 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.

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 — a JSON array, or newline-delimited JSON with ?format=ndjson. The same fields and changed_since filters apply. Results are capped by fair use with a truncated flag when there's more.

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.

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"