These rules apply to every endpoint.
Responses
A successful response has this shape:
{
"status": 200,
"message": "Success: activity retrieved.",
"record": {}
}
message is a sentence for people. It starts with Success:. Do not parse it.
| Response | Where the data is |
|---|---|
| One record | record |
A paged list (/activities, /phase-codes, /equipment-catalog) | record.records, with the full match count in record.total |
| A reference list, and the Phase Codes of one activity | records at the top level, with no total and no paging |
| A batch result (import, apply, proposed changes) | record, with counts or one result per item |
A failed request has a different shape. See Errors.
Paging
List endpoints take limit and offset.
| Endpoint | limit | Default | offset |
|---|---|---|---|
GET /activities | 1 to 100 | 25 | 0 or more |
GET /phase-codes | 1 to 100 | 25 | 0 or more |
GET /equipment-catalog | 1 to 200 | 50 | 0 or more |
GET /activities?kind=Job&limit=100&offset=200
record.total is the number of records that match your filters. It is not the length of
the page. Read pages until offset is equal to or more than total.
GET /activities also takes all=true. It returns every match in one response, up to
10,000. More than 10,000 matches is a 400. Do not send limit or offset with
all=true.
Codes
| Record | How the code is stored | Unique in |
|---|---|---|
| Job, Work Order, Meet Point | Trimmed and in upper case. It never changes after the record is created. | The company, across all three kinds, active or not. A Job and a Meet Point cannot share a code. |
| Phase Code | Trimmed only. Its case and inner spaces are kept. | Its Job or Meet Point, active or not |
| Equipment | Trimmed, case kept. It never changes. | The company, compared without case, across every owner and division, active or not |
Dates and times
- A timestamp is ISO 8601 in UTC, for example
2026-11-03T15:04:05.123Z. - Send a timestamp with a
Zsuffix or an offset. - A plain date is
YYYY-MM-DD, and must be a real day. - A time zone is an IANA name, for example
America/Chicago. An offset such as-06:00, or an unknown name, gets400.
Locations
- Latitude and longitude are WGS 84 decimal degrees.
- A job-site boundary is one of these:
- A point and a radius:
latitude,longitudeandradiusMeters(1 to 1,609 m, default 201 m). Matrix TimeCard turns it into a boundary. - A drawn boundary:
boundary, a ring of 3 or more{ "lat", "lng" }points. The ring can be open or closed. No point can be more than 1 mile from its centre (the mean of its points).
- A point and a radius:
- A point or a boundary must be in the expected working area. A location that is not
plausible gets
400. - See Boundaries for the scopes that boundaries need.
Ownership
Every record has an owner, in sourceSystem:
| Who made the record | sourceSystem |
|---|---|
| Your API key | Your key's source system, for example acme-erp |
| A sync from another system | That system's name |
| An administrator, in the admin site | timecard |
Your key can change only the records that its own source system owns. A write to another
owner's record gets 409 conflict, or 403 not_owner for equipment.
An administrator can still change the name, address and point of your records in the admin
site. This is an override. Your record then shows isLocallyOverridden: true, and
overridden names the fields. Your own values stay in sourceValues (source on
equipment). An administrator can also take over a boundary. It then shows
isLocallyManaged: true, and your key cannot change it.
Safe updates
Every activity and piece of equipment has updatedAt. Send it back as expectedUpdatedAt
on a PATCH. If the record changed after you read it, the API refuses the update with
409 conflict and saves nothing. Read the record again, apply your change, and send it
again. The response to a successful PATCH carries the new updatedAt.
Any change to an activity moves its updatedAt, including a change to its Phase Codes.
A change to a boundary through
PATCH /activities/{activityId}/geofences/{geofenceId} does not
move it, because boundaries keep their own version history.
A PATCH that sends values the record already has changes nothing. It is safe to retry.
Nothing is deleted
The API never deletes a Job, Phase Code, boundary or piece of equipment. Punches point to them.
| To retire | Send |
|---|---|
| A Job, Work Order or Meet Point | PATCH /activities/{activityId} with "isActive": false |
| A Phase Code | PATCH /activities/{activityId}/phase-codes/{phaseCodeId} with "isActive": false |
| A boundary | PATCH /activities/{activityId}/geofences/{geofenceId} with "isActive": false |
| A piece of equipment | DELETE /equipment-catalog/{equipmentId}. This deactivates it. POST /equipment-catalog/{equipmentId}/reactivate undoes it. |
Audit
Every write is recorded with the key's name and the time. Your administrator can see who changed what.