Last updated

Appendix

Beta. The Universal PUSH endpoint is in active development; documentation and behavior are subject to change before general availability.

Request Envelope

Every request body is a JSON object with the Full Truckload data under the truckload key.

FieldTypeRequiredDescription
customerAccountNumberstringNoThe project44 tenant ID of the customer the tracking data is for. Maximum 128 characters.
truckloadobjectYesThe Full Truckload (FTL) body.

customerAccountNumber is the customer's project44 tenant ID — obtain it from the customer or your project44 integration representative.

FTL Mode Body (truckload)

FieldTypeRequiredDescription
identifiersobjectYesShipment-resolving identifiers. See Identifier Reference.
shipmentEventobjectConditionalA single tracking event. Requires type and dateTime. At least one of shipmentEvent, readings or stops must be present.
readingsobjectConditionalPosition and/or sensor readings, with its own dateTime. At least one of shipmentEvent, readings or stops must be present.
stopsarrayConditionalUpdates to stops that already exist on the shipment, such as a carrier ETA or an appointment window. At least one of shipmentEvent, readings or stops must be present. See stops[].
extensionsobjectNoReserved for carrier-specific extension fields.

Objects

Field references for the nested objects under truckload. Timestamps are ISO 8601 date-times (for example 2026-06-01T08:30:00Z) and must not be more than 5 minutes in the future.

shipmentEvent

FieldTypeRequiredDescription
typestringYesThe event type. See FTL Event Types.
dateTimestringYesISO 8601 date-time of the event (for example 2026-06-01T08:30:00Z).
stopNumberintegerNo1-based stop sequence the event applies to.
stopReferenceIdstringNoCarrier's reference id for the stop.
stopIdstringNoproject44 stop id, if known.
descriptionstringNoFree-text note. Maximum 1024 characters.
sourcestringNoUNKNOWN, CARRIER, or CONTRACT.
exceptionCodestringNoCarrier exception code, if any.

readings

FieldTypeRequiredDescription
dateTimestringYesISO 8601 date-time of the readings (for example 2026-06-01T08:30:00Z).
positionobjectConditionalGPS position. At least one of position or sensor is required.
sensorobjectConditionalTelematics/sensor readings. At least one of position or sensor is required.

readings.position

FieldTypeRequiredDescription
latitudenumberYesDecimal degrees, -90 to 90.
longitudenumberYesDecimal degrees, -180 to 180.
altitudenumberNoMeters.
speednumberNoSpeed, expressed in speedUnit.
headingnumberNoDegrees, 0–359.
speedUnitstringNoKILOMETERS_PER_HOUR or MILES_PER_HOUR.

readings.sensor

FieldTypeDescription
ignitionStatusstringON, OFF, or UNKNOWN.
reeferobjectReefer unit status (see below).
fuelobjectFuel reading (see below).
ambientTemperatureobjectAmbient temperature with value and unit (see below).
zonesarrayPer-zone temperature readings, maximum 5 (see below).
tirePressurearrayTire pressure readings, maximum 22 (see below).
shockobjectShock event reading (see below).
vibrationobjectVibration reading (see below).

readings.sensor.reefer

FieldTypeDescription
statestringON, OFF, UNKNOWN.
powerSourcestringDIESEL, ELECTRIC, LIQUEFIED_PETROLEUM_GAS, BATTERY, UNKNOWN.
operatingModestringCONTINUOUS, CYCLE_SENTRY, START_STOP, UNKNOWN.
engineRpmintegerReefer engine RPM.
engineHoursnumberCumulative engine hours.
voltagenumberReefer battery voltage.

readings.sensor.fuel

FieldTypeDescription
typestringDIESEL, GASOLINE, ELECTRIC, LIQUEFIED_NATURAL_GAS, COMPRESSED_NATURAL_GAS.
currentLevelnumber0–100.
capacitynumberTank capacity.
fuelUnitstringPERCENT, LITER, GALLON, PERCENT_REMAINING, KWH.

readings.sensor.zones[]

Each temperature zone. All temperatures in a zone share the zone's temperatureUnit.

FieldTypeDescription
idstringZONE1–ZONE5. Single-zone units send ZONE1.
returnAirTemperaturenumber-100 to 100.
dischargeAirTemperaturenumber-100 to 100.
supplyAirTemperaturenumber-100 to 100.
setPointnumberTarget temperature, -100 to 100.
temperatureUnitstringCELSIUS or FAHRENHEIT.
humidityobject{ "percentage": 0–100 }.
batteryobject{ "percentage": 0–100, "isCharging": boolean }.
doorStatestringOPEN, CLOSED, UNKNOWN.

readings.sensor.ambientTemperature

FieldTypeDescription
valuenumberAmbient temperature.
unitstringCELSIUS or FAHRENHEIT.

readings.sensor.tirePressure[]

FieldTypeDescription
axleinteger1-based axle number.
positionstringLEFT, RIGHT, INNER_LEFT, OUTER_LEFT, INNER_RIGHT, OUTER_RIGHT.
psinumber0–250.
alarmStatestringOK, LOW, HIGH, CRITICAL, UNKNOWN.

readings.sensor.shock

FieldTypeDescription
magnitudenumberShock magnitude.
unitstringG.
axisstringX, Y, Z, RESULTANT.
durationInMillisecondsintegerDuration of the shock event.
thresholdExceededbooleanWhether a configured threshold was exceeded.
thresholdValuenumberThe configured threshold.

readings.sensor.vibration

FieldTypeDescription
valuenumberVibration value.
unitstringG, G_RMS, IN_PER_SEC, MM_PER_SEC, MIL, UM, DB, VDV.
axisstringX, Y, Z, RESULTANT.
frequencyInHertznumberDominant frequency.

stops[]

Each entry updates one stop that already exists on the shipment. project44 never creates, removes or reorders stops from this array. Identify the stop with stopNumber or stopReferenceId, and always send at least one value to set. An entry that identifies a stop but carries neither carrierEstimatedArrivalDateTime nor carrierAppointmentWindow is accepted and simply has no effect, so it will not tell you that something is missing.

FieldTypeRequiredDescription
stopNumberintegerConditional1-based position of the stop on the shipment. The most reliable way to identify a stop.
stopReferenceIdstringConditionalCarrier's reference id for the stop. Maximum 255 characters.
stopTypestringNoPICKUP or DELIVERY. Use only when the shipment has exactly one stop of that type.
stopIdstringNoproject44 stop id. Accepted, but identify the stop with stopNumber or stopReferenceId.
carrierEstimatedArrivalDateTimestringNoYour estimated arrival at the stop. Must include a UTC offset or Z — see the note below.
carrierAppointmentWindowobjectNoA dock appointment window for the stop.

carrierEstimatedArrivalDateTime and carrierAppointmentWindow use different time formats on purpose. An ETA is an instant, so carrierEstimatedArrivalDateTime must carry a UTC offset or the Z designator, for example 2026-06-01T14:30:00-05:00. An appointment window is a wall-clock commitment at the dock, so its times are local to the stop. An offset is optional there: send the plain wall-clock time, and if you do include an offset it is honoured.

stops[].carrierAppointmentWindow

FieldTypeRequiredDescription
startDateTimestringYesWhen the window starts, as the wall-clock time at the stop, for example 2026-06-01T15:00:00. Do not convert to UTC.
endDateTimestringYesWhen the window ends, in the same format. Must be later than startDateTime.

The carrier appointment window is displayed separately from the customer appointment window and does not override it. Both remain visible.


Identifier Reference

The identifiers object uses named keys, not a polymorphic typed array. At least one of billOfLadingNumber or orderNumber is required; each value is a string with a maximum length of 256 characters.

CategoryKeyDescription
ShipmentbillOfLadingNumberThe shipment's bill of lading (BOL) number.
ShipmentorderNumberThe shipment's order number.
CarrierscacThe SCAC of the carrier the data is about (for example XPPP).
CarrierdotNumberThe US DOT number of the carrier the data is about.
CarriermcNumberThe MC number of the carrier the data is about.

The shipment is resolved from billOfLadingNumber and orderNumber only. The carrier keys scac, dotNumber, and mcNumber identify the carrier the data is about, and are only needed when you push for another carrier. Leading and trailing whitespace on identifier values is trimmed before matching.

Unrecognized identifier keys are silently ignored, not rejected. identifiers is not a closed set of keys: it accepts up to 250 keys, and any key other than the five listed above is accepted, counted towards that limit, and then dropped. A misspelled carrier key — for example carrierScac instead of scac — therefore returns 202 and looks successful, while carrier attribution is silently lost. Confirm the exact spelling of every key you send before you go live.

A misspelled shipment-resolving key behaves differently. Because at least one of billOfLadingNumber or orderNumber is required, sending only bolNumber leaves the request with no resolving identifier and it is rejected with 400 rather than accepted. The silent-202 case above applies to unrecognized keys sent alongside a valid resolving identifier.

Pushing for Another Carrier

Normally you push tracking data for your own shipments, and no carrier identifier is needed: project44 uses the credentials on the request to work out which carrier the data is about.

A carrier identifier is only needed when those two are different — for example when a telematics provider or fleet aggregator pushes for the carriers whose fleets it manages. Two roles are involved:

  • Reporting carrier — the party that holds the API credentials and makes the request.
  • Subject carrier — the carrier the data is about, that is, the carrier on the shipment. The subject carrier does nothing at request time.

When the reporting carrier and the subject carrier are different, name the subject carrier in the identifiers object using whichever of scac, dotNumber, or mcNumber that carrier has. A carrier without a SCAC, for example, is identified by dotNumber or mcNumber. All values are strings.

JSON
{
  "truckload": {
    "identifiers": {
      "billOfLadingNumber": "BOL-20260601-001",
      "scac": "XPPP"
    }
  }
}

project44 must authorize you to report for each subject carrier before you start. This cannot be set up by yourself — contact your project44 integration representative. Use only the keys scac, dotNumber, and mcNumber; any other spelling is accepted with a 202 response and then ignored, and the carrier the data is about is lost.

Stop Coupling

Stop-coupled events reference a stop through the shipmentEvent object (not identifiers), using any of stopReferenceId, stopId, or stopNumber. All three are optional. When more than one is present, they are resolved in the priority order stopReferenceId > stopId > stopNumber.

Entries in stops[] identify their stop independently of shipmentEvent, using stopReferenceId, stopNumber or stopType, resolved in that order. A stop update that matches no stop on the shipment is discarded.


FTL Event Types

The endpoint accepts project44's standard shipment event types plus the truckload terminal events ARRIVED_AT_TERMINAL and DEPARTED_TERMINAL. The complete list is in the reference documentation. Other values are accepted and stored but do not change the shipment's status; only the events below produce a status milestone:

Event typeDescription
ARRIVAL_AT_STOPVehicle has arrived at the stop.
DEPARTURE_FROM_STOPVehicle has departed from the stop.
LOAD_ONTO_VEHICLEFreight is being loaded onto the vehicle.
UNLOAD_FROM_VEHICLEFreight is being unloaded from the vehicle.
DELIVERYFreight has been delivered.
GATE_INUnit has entered the gate/facility.
GATE_OUTUnit has exited the gate/facility.
DISPATCHVehicle has been dispatched.
ARRIVED_AT_TERMINALUnit has arrived at a terminal.
DEPARTED_TERMINALUnit has departed a terminal.

Events that do not map to a milestone (for example PICKED_UP, OUT_FOR_DELIVERY) are accepted with 202 and stored, but do not change the shipment's status. A position update flows whenever readings.position is present, regardless of the event type.


Migrating from the Truckload Status-Update Endpoint

If you already send Truckload tracking data to /api/v4/capacityproviders/tl/shipments/statusUpdates (see Send Tracking Updates), the table below maps what you send today to its Universal PUSH equivalent. For complete payloads, see Send Tracking Updates.

Truckload status-update endpointUniversal PUSHNotes
Payload top levelFTL tracking data nested under truckloadThe tracking data moves one level down, under the truckload key. customerAccountNumber is the exception and stays at the top level, alongside truckload.
customerIdcustomerAccountNumberIdentifies the customer the tracking data is for. It stays at the top level and does not move under truckload. customerAccountNumber is the customer's project44 tenant ID, so confirm the value to send with your project44 integration representative rather than reusing your existing customerId value unchanged.
shipmentIdentifiers[], an array of {type, value}identifiers, an object with named keysType BILL_OF_LADING becomes identifiers.billOfLadingNumber; type ORDER becomes identifiers.orderNumber. At least one of the two is still required.
carrierIdentifier {type: SCAC, value}identifiers.scacUse identifiers.dotNumber or identifiers.mcNumber for a carrier that has no SCAC. Still only needed when you push for another carrier — see Pushing for Another Carrier.
eventStopNumbershipmentEvent.stopNumbershipmentEvent.stopReferenceId and shipmentEvent.stopId are also available — see Stop Coupling.
utcTimestampshipmentEvent.dateTime and/or readings.dateTimeThe event and the readings each carry their own timestamp and are independent. When you send both objects and only have one time, send the same value in both. For a readings-only payload — the POSITION migration above — set readings.dateTime only. Universal PUSH timestamps are ISO 8601 date-times with the UTC designator, for example 2026-06-01T08:30:00Z.
latitude / longitudereadings.position.latitude / readings.position.longitudePosition now lives in the readings object rather than at the top level.
eventType: ARRIVEDshipmentEvent.type: ARRIVAL_AT_STOP
eventType: DEPARTEDshipmentEvent.type: DEPARTURE_FROM_STOP
eventType: LOADINGshipmentEvent.type: LOAD_ONTO_VEHICLE
eventType: UNLOADINGshipmentEvent.type: UNLOAD_FROM_VEHICLE
eventType: DELIVEREDshipmentEvent.type: DELIVERY
eventType: POSITIONNo shipmentEventThere is no POSITION event type. Send a readings-only payload instead: omit shipmentEvent and send readings with a position.
shipmentStops[].stopNumberstops[].stopNumberStill 1-based. stops[] updates stops that already exist on the shipment.
shipmentStops[].carrierSuppliedEtastops[].carrierEstimatedArrivalDateTimeThe legacy value is a UTC instant, written either bare (2025-01-05T10:30:00) or with an explicit zero offset (2025-01-05T10:30:00+0000). carrierEstimatedArrivalDateTime always requires an offset or the Z designator, so add Z to the bare form and rewrite +0000 as Z. Both become 2025-01-05T10:30:00Z.
shipmentStops[].appointmentWindowstops[].carrierAppointmentWindowSame wall-clock-at-the-stop semantics, same startDateTime / endDateTime.
shipmentStops[].appointmentWindow.localTimeZoneIdentifierNo equivalentUniversal PUSH has no time-zone field. Times are interpreted in the stop's own time zone, which is what omitting localTimeZoneIdentifier did on the legacy endpoint.

Any field you send today that is not listed above has no direct one-to-one equivalent. Contact your project44 integration representative before you migrate it, rather than guessing at a mapping.


Payload Limits

EntityLimit
Total payload1 MB
identifiers keys250
Identifier value length256 characters
stops[] items100
readings.sensor.zones[] items5
readings.sensor.tirePressure[] items22

Error Response Codes

If there was a problem with your request, you will receive one of the following HTTP status codes:

Status codeMeaning
400 Bad RequestSynchronous schema validation failed. The response body lists each violation. The event was not accepted.
401 UnauthorizedAuthentication credentials are missing or invalid.
403 ForbiddenYour credentials are not authorized to push for this tenant.
404 Not FoundThe requested resource does not exist.
413 Content Too LargePayload exceeds the 1 MB size limit.

No 5xx status is surfaced externally.

Error Response Body

Validation errors return the standard project44 ApiError envelope. errors[] may carry more than one entry (for example, an empty identifiers object returns three). errorMessage and source are returned null; supportReferenceId is a reference id to quote when contacting project44 support.

JSON
{
  "httpStatusCode": 400,
  "httpMessage": "Bad Request",
  "errorMessage": null,
  "errors": [
    {
      "severity": "ERROR",
      "message": "$.truckload.readings.position: required property 'latitude' not found",
      "diagnostic": "MISSING_REQUIRED_FIELD at $.truckload.readings.position",
      "source": null
    }
  ],
  "supportReferenceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
Error Response FieldDescription
httpStatusCodeThe value of the HTTP status code.
httpMessageA brief description of the HTTP status code.
errorMessageA detailed description of the error. Returned null for schema-validation errors.
errorsAn array containing one entry per violation.
errors.severityThe severity of the message. Possible values: ERROR, WARNING, INFO.
errors.messageThe JSON path of the offending field plus the reason.
errors.diagnosticA machine-readable diagnostic code and the JSON path (for example MISSING_REQUIRED_FIELD at $.truckload.identifiers).
errors.sourceThe originator of the error. Returned null for schema-validation errors.
supportReferenceIdA reference identifier to quote when contacting project44 support.