Skip to content

Developers

Equipment

API docs: Equipment

The machines that your crews can record when they clock in. Each piece of equipment has a code that is unique in its company, a status and an optional assignment to a Job, Work Order or Meet Point.

statusMeaning
AActive. Only A equipment can be picked on the phone.
DDown
IInactive

A record that you read back can carry another status code that its owner sent.

Scopes: equipment:read to read, equipment:write to write. Your key can write only equipment that its own source system owns. A write to another owner's equipment gets 403 not_owner.

Back to the index · Conventions · Errors

Every endpoint can also return 401 (no key, or a key that is not valid, revoked or expired) and 503 (service_unavailable or instance_mismatch). The tables below list only the other statuses.

The Equipment object

FieldTypeDescription
equipmentIdintegerThe equipment's id
companyIdintegerThe company's id
companyCodestringThe company
divisionCodestring or nullThe division. It cannot change.
codestringThe equipment number. Unique in the company, compared without case. It cannot change.
descriptionstring or nullThe effective description: an administrator's override where one is set
statusstringThe effective status: A, D or I
ownershipstring or nullowned or rented (effective value)
assignedActivityobject or nullThe activity that the machine is on now, or null
assignedActivity.activityIdintegerThe activity's id
assignedActivity.codestringThe activity's code
assignedActivity.namestring or nullThe activity's name
assignedActivity.kindstringJob, WorkOrder or MeetPoint
assignedActivity.isActivebooleanWhether the activity is active
isActivebooleanFalse after the owner deactivates it
isAvailablebooleanTrue when isActive is true and the effective status is A. Only then can a crew pick the machine and clock in with it.
sourceSystemstringThe owner. It never changes.
isLocallyOverriddenbooleanTrue when an administrator overrides a field
overriddenFieldsarray of stringsThe fields that an override covers
source.descriptionstring or nullThe owner's own description, under any override
source.statusstringThe owner's own status
source.ownershipstring or nullThe owner's own ownership
source.assignedActivityIdinteger or nullThe owner's own assignment
source.sourceJobstring or nullThe raw job code from the owner's system, when a sync owns the equipment. Null otherwise.
lastLocationobject or nullThe last known position, when the owner reports one
lastLocation.latitudenumberLatitude
lastLocation.longitudenumberLongitude
lastLocation.seenAtstring or nullWhen the owner says the machine was seen (UTC)
syncedAtstring or nullWhen a sync last wrote the record. Null for equipment that no sync owns.
createdAtstringServer time
updatedAtstringServer time. Send it back as expectedUpdatedAt.

GET /equipment-catalog

Lists equipment, ordered by code. Filters use the effective values.

Scope: equipment:read

Query parameters

NameTypeRequiredDefaultAllowed valuesDescription
qstringNoFirst 100 characters are usedSearch the code and the description. Case does not matter.
companyCodestringNoKeep only this company
divisionCodestringNoKeep only this division
statusstringNoA, D, IKeep only this status
ownershipstringNoowned, rentedKeep only this ownership
sourceSystemstringNoKeep only this owner, for example your own source system
assignedActivityIdintegerNo1 or moreKeep only machines on this activity
unassignedstringNotrue, falsetrue keeps machines on no activity. false keeps machines on one. Not with assignedActivityId.
isActivestringNotrue, falseKeep only active or only inactive machines
isAvailablestringNotrue, falseKeep only machines that a crew can or cannot pick
isLocallyOverriddenstringNotrue, falseKeep only machines with or without an administrator's override
f_codestringNoMax 200 charactersA pattern filter on the code
f_descriptionstringNoMax 200 charactersA pattern filter on the description. Equipment with no description matches only a negation.
f_divisionCodestringNoMax 200 charactersA pattern filter on the division code
f_assignedActivitystringNoMax 200 charactersA pattern filter on the assigned activity's code, a space and its name. Not assigned: no text.
f_syncedAtstringNoMax 200 charactersA day filter on syncedAt. See pattern filters.
limitintegerNo501 to 200Page size
offsetintegerNo00 or moreRows to skip

Pattern filters

The f_ parameters narrow the list with a short pattern. Each one is added to every other filter (AND). Case does not matter. A pattern has at most 200 characters and 25 terms. A pattern that is too long or not valid gets 400.

TermMatches
textValues that contain text
=textThe value text exactly
!textValues that do not contain text
^textValues that start with text
!^textValues that do not start with text
!!Any value that is not empty
a*bA glob from the start to the end
>n, <nValues above or below a number
a-bA number range
a,ba or b
a&ba and b
!(a&b)Not the group in brackets

An empty value matches only a negation, so !! keeps equipment that has a value.

f_syncedAt takes days as m/d/yyyy only: =6/1/2026, >=6/1/2026, >6/1/2026, <=6/30/2026, <6/30/2026, the range 6/1/2026-6/30/2026 (both days included) and !! (synced at least once). Combine them with ,, & and !( ). Any other term gets 400. Days are counted in the service's default site time zone.

Example: f_code=^EX&f_description=excavator%26!mini.

Example request

curl "$TIMECARD_BASE_URL/equipment-catalog?companyCode=ACME&sourceSystem=acme-erp&limit=200" \
  -H "X-API-Key: $TIMECARD_API_KEY"

Example response 200 OK

{
  "status": 200,
  "message": "Success: equipment retrieved.",
  "record": {
    "total": 1,
    "records": [
      {
        "equipmentId": 3051,
        "companyId": 1,
        "companyCode": "ACME",
        "divisionCode": "PAVING",
        "code": "EX-210",
        "description": "CAT 320 excavator",
        "status": "A",
        "ownership": "owned",
        "assignedActivity": {
          "activityId": 48213,
          "code": "J-2026-104",
          "name": "Riverside Bridge Widening",
          "kind": "Job",
          "isActive": true
        },
        "isActive": true,
        "isAvailable": true,
        "sourceSystem": "acme-erp",
        "isLocallyOverridden": false,
        "overriddenFields": [],
        "source": {
          "description": "CAT 320 excavator",
          "status": "A",
          "ownership": "owned",
          "assignedActivityId": 48213,
          "sourceJob": null
        },
        "lastLocation": {
          "latitude": 30.2672,
          "longitude": -97.7431,
          "seenAt": "2026-11-03T14:55:00.000Z"
        },
        "syncedAt": null,
        "createdAt": "2026-11-03T15:00:12.000Z",
        "updatedAt": "2026-11-03T15:00:12.000Z"
      }
    ]
  }
}

Errors

StatuscodeWhen
400validation_failedA filter is not valid. detail names the parameter.
403insufficient_scopeThe key does not have equipment:read
500internal_errorThe equipment could not be read

GET /equipment-catalog/{equipmentId}

Returns one piece of equipment.

Scope: equipment:read

Path parameters

NameTypeRequiredDefaultAllowed valuesDescription
equipmentIdintegerYes1 or moreThe equipment's id

Example request

curl "$TIMECARD_BASE_URL/equipment-catalog/3051" \
  -H "X-API-Key: $TIMECARD_API_KEY"

Example response 200 OK

{
  "status": 200,
  "message": "Success: equipment retrieved.",
  "record": {
    "equipmentId": 3051,
    "companyCode": "ACME",
    "code": "EX-210",
    "status": "A",
    "isAvailable": true,
    "sourceSystem": "acme-erp",
    "updatedAt": "2026-11-03T15:00:12.000Z"
  }
}

The record has every field of the Equipment object. It is shortened here.

Errors

StatuscodeWhen
400validation_failedequipmentId is not a positive integer
403insufficient_scopeThe key does not have equipment:read
404not_foundNo equipment has this id within the key's companies
500internal_errorThe equipment could not be read

POST /equipment-catalog

Creates one piece of equipment, owned by your key's source system. The owner never changes.

Scope: equipment:write

Request body

NameTypeRequiredDefaultAllowed valuesDescription
codestringYes1 to 30 charactersThe equipment number. Trimmed, case kept. Must be free in the company, under any owner or division, active or not.
companyCodestringWhen the key covers more than one companyMax 10 charactersThe company
divisionCodestring or nullNo1 to 20 charactersThe division. It cannot change later.
descriptionstring or nullNo1 to 200 charactersThe description
statusstringNoAA, D, IActive, Down or Inactive
ownershipstring or nullNoowned, rentedOwned or rented
assignedActivityIdinteger or nullNo1 or moreThe Job, Work Order or Meet Point of the same company that the machine is on, active or not. Send a JSON number, not a string. Null means none.
lastLocationobject or nullNoThe last known position
lastLocation.latitudenumberYes-90 to 90Latitude
lastLocation.longitudenumberYes-180 to 180Longitude
lastLocation.seenAtstring or nullNoISO 8601 date-timeWhen the machine was seen (UTC)

Example request

curl -X POST "$TIMECARD_BASE_URL/equipment-catalog" \
  -H "X-API-Key: $TIMECARD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "companyCode": "ACME",
    "code": "EX-210",
    "description": "CAT 320 excavator",
    "divisionCode": "PAVING",
    "status": "A",
    "ownership": "owned",
    "assignedActivityId": 48213,
    "lastLocation": { "latitude": 30.2672, "longitude": -97.7431, "seenAt": "2026-11-03T14:55:00Z" }
  }'

Example response 201 Created

{
  "status": 201,
  "message": "Success: equipment created.",
  "record": {
    "equipmentId": 3051,
    "companyCode": "ACME",
    "divisionCode": "PAVING",
    "code": "EX-210",
    "description": "CAT 320 excavator",
    "status": "A",
    "ownership": "owned",
    "isActive": true,
    "isAvailable": true,
    "sourceSystem": "acme-erp",
    "updatedAt": "2026-11-03T15:00:12.000Z"
  }
}

The record has every field of the Equipment object. It is shortened here.

Errors

StatuscodeWhen
400validation_failedThe body is not valid JSON or breaks a rule, companyCode is missing when the key covers several companies, or assignedActivityId is not an activity of the company
403insufficient_scopeThe key does not have equipment:write
403forbiddenA key bound to one company names another, or the key has no source system
404not_foundcompanyCode names no active company that the key can reach
409code_takenThe company already has this equipment number, under any owner or division, active or not. Update or reactivate that record instead.
500internal_errorThe equipment could not be created. The record can still exist. Look it up by its code before you retry.

PATCH /equipment-catalog/{equipmentId}

Changes only the fields that you send. code, divisionCode and companyCode cannot change.

Scope: equipment:write

Path parameters

NameTypeRequiredDefaultAllowed valuesDescription
equipmentIdintegerYes1 or moreThe equipment's id

Request body

NameTypeRequiredDefaultAllowed valuesDescription
expectedUpdatedAtstringNo (recommended)ISO 8601 date-time with Z or an offsetThe updatedAt that you last read. If the equipment changed after that, you get 409 and nothing is saved.
descriptionstring or nullNo1 to 200 charactersThe description
statusstringNoA, D, IActive, Down or Inactive
ownershipstring or nullNoowned, rentedOwned or rented
assignedActivityIdinteger or nullNo1 or moreThe activity of the same company that the machine is on. Send a JSON number. Null removes the assignment.
lastLocationobject or nullNoThe last known position
lastLocation.latitudenumberYes-90 to 90Latitude
lastLocation.longitudenumberYes-180 to 180Longitude
lastLocation.seenAtstring or nullNoISO 8601 date-timeWhen the machine was seen (UTC)

Example request

curl -X PATCH "$TIMECARD_BASE_URL/equipment-catalog/3051" \
  -H "X-API-Key: $TIMECARD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expectedUpdatedAt": "2026-11-03T15:00:12.000Z",
    "status": "D",
    "assignedActivityId": null
  }'

Example response 200 OK

{
  "status": 200,
  "message": "Success: equipment updated.",
  "record": {
    "equipmentId": 3051,
    "code": "EX-210",
    "status": "D",
    "assignedActivity": null,
    "isAvailable": false,
    "updatedAt": "2026-11-03T15:30:44.000Z"
  }
}

The record has every field of the Equipment object. It is shortened here. When the values you send are already stored, nothing changes and the message is Success: nothing to change.

Errors

StatuscodeWhen
400validation_failedequipmentId is not a positive integer, the body is not valid JSON, names an unknown field or one that cannot change, or a value breaks its rule, or assignedActivityId is not an activity of the same company
403insufficient_scopeThe key does not have equipment:write
403forbiddenThe key has no source system
403not_ownerAnother source system owns this equipment
404not_foundNo equipment has this id within the key's companies
409conflictexpectedUpdatedAt does not match (the equipment changed after you read it), or the record kept changing during the write. Read it again and retry.
500internal_errorThe equipment could not be written

DELETE /equipment-catalog/{equipmentId}

Deactivates the equipment. Nothing is deleted. Crews can no longer pick it, and a clock-in that names it is refused. Undo it with POST /equipment-catalog/{equipmentId}/reactivate.

Scope: equipment:write

Path parameters

NameTypeRequiredDefaultAllowed valuesDescription
equipmentIdintegerYes1 or moreThe equipment's id

No request body.

Example request

curl -X DELETE "$TIMECARD_BASE_URL/equipment-catalog/3051" \
  -H "X-API-Key: $TIMECARD_API_KEY"

Example response 200 OK

{
  "status": 200,
  "message": "Success: equipment deactivated.",
  "record": {
    "equipmentId": 3051,
    "code": "EX-210",
    "isActive": false,
    "isAvailable": false,
    "updatedAt": "2026-11-03T15:41:02.000Z"
  }
}

The record has every field of the Equipment object. It is shortened here. When the equipment is already inactive, the message is Success: nothing to change.

Errors

StatuscodeWhen
400validation_failedequipmentId is not a positive integer
403insufficient_scopeThe key does not have equipment:write
403forbiddenThe key has no source system
403not_ownerAnother source system owns this equipment
404not_foundNo equipment has this id within the key's companies
409conflictThe record kept changing during the write. Read it again and retry.
500internal_errorThe equipment could not be written

POST /equipment-catalog/{equipmentId}/reactivate

Undoes a deactivation. The equipment is active again.

Scope: equipment:write

Path parameters

NameTypeRequiredDefaultAllowed valuesDescription
equipmentIdintegerYes1 or moreThe equipment's id

No request body.

Example request

curl -X POST "$TIMECARD_BASE_URL/equipment-catalog/3051/reactivate" \
  -H "X-API-Key: $TIMECARD_API_KEY"

Example response 200 OK

{
  "status": 200,
  "message": "Success: equipment reactivated.",
  "record": {
    "equipmentId": 3051,
    "code": "EX-210",
    "status": "D",
    "isActive": true,
    "isAvailable": false,
    "updatedAt": "2026-11-03T15:45:19.000Z"
  }
}

isAvailable is true again only when the status is A. The record has every field of the Equipment object. It is shortened here.

Errors

StatuscodeWhen
400validation_failedequipmentId is not a positive integer
403insufficient_scopeThe key does not have equipment:write
403forbiddenThe key has no source system
403not_ownerAnother source system owns this equipment
404not_foundNo equipment has this id within the key's companies
409conflictThe record kept changing during the write. Read it again and retry.
500internal_errorThe equipment could not be written