Layover Transfers¶
A layover is a leg that stops part-way, where the shipment is held before continuing to the destination. Set isLayover on the transporter and it gains two of its own timestamps, and each of its drivers has to say which leg they cover.
payload = {
"destinations": [
{
"recipientId": destinations[0]["id"],
"transferTypeId": transfer_type["id"],
"plannedRoute": "I-70 west, overnight in Columbia",
# The destination window: leaving the origin, arriving at the recipient.
"estimatedDepartureDateTime": "2026-09-18T08:00:00",
"estimatedArrivalDateTime": "2026-09-19T17:00:00",
"transporters": [
{
"transporterId": transporters[0]["id"],
"phoneNumberForQuestions": inputs["defaultPhoneNumberForQuestions"],
"isLayover": True,
# The layover window: checking in at the layover point,
# then checking back out of it.
"estimatedArrivalDateTime": "2026-09-18T18:00:00",
"estimatedDepartureDateTime": "2026-09-19T07:00:00",
"transporterDetails": [
{
"driverName": "Jane Doe",
"driverOccupationalLicenseNumber": "LIC12345",
"driverLicenseNumber": "D1234567",
"driverLayoverLeg": "ToLayover",
"vehicleMake": "Ford",
"vehicleModel": "Transit",
"vehicleLicensePlateNumber": "ABC1234",
},
{
"driverName": "John Roe",
"driverOccupationalLicenseNumber": "LIC67890",
"driverLicenseNumber": "D7654321",
"driverLayoverLeg": "FromLayover",
"vehicleMake": "Ram",
"vehicleModel": "ProMaster",
"vehicleLicensePlateNumber": "XYZ9876",
},
],
}
],
"packages": [{"id": package_id}],
}
]
}
Two different windows, four similar names
The transporter's estimatedArrivalDateTime and estimatedDepartureDateTime are the estimated check-in at and check-out from the layover point, not the origin and not the recipient. The destination carries its own pair with the same two names for the journey as a whole. Metrc's own form labels the transporter pair Est. Check-In and Est. Check-Out for exactly this reason.
They are accepted only on a layover leg. On an ordinary transporter they are dropped before the request reaches Metrc, which is what Metrc's own form does.
Layover legs¶
Each driver names the leg they cover in driverLayoverLeg:
| Value | Leg |
|---|---|
ToLayover | Origin to the layover point |
FromLayover | Layover point to the destination |
FromAndToLayover | Both legs, one driver |
The example above is a driver swap: one driver runs the shipment to the layover point, another takes it onward. For one driver running the whole route, send a single entry with FromAndToLayover.
What gets rejected¶
Metrc answers an incomplete layover with a 200 and quietly drops the layover, leaving a manifest that says something you did not ask for. Add applyDynamicValidation=true and T3 checks the leg is fully described before sending anything:
response = requests.post(
f"{API}/v2/transfers/create",
params={
"licenseNumber": "CUL00001",
"submit": "true",
"applyDynamicValidation": "true",
},
headers=HEADERS,
json=[payload],
)
| Mistake | Response |
|---|---|
No transporter estimatedArrivalDateTime or estimatedDepartureDateTime | 400 naming the missing field |
A driver with no driverLayoverLeg | 400 naming the transporterDetails index |
A driverLayoverLeg outside the three values above | 400 listing the valid ones |
driverLayoverLeg set while isLayover is not | 400; Metrc would ignore the leg and create an ordinary transfer |
Without the flag, none of this runs
Dynamic validation is opt-in. Omit applyDynamicValidation and an incomplete layover goes to Metrc as written, which is the case worth guarding: Metrc accepts it, returns 200, and the layover is simply not there.
This is the TRANSFER_LAYOVER_LEGS_COMPLETE check, so skipDynamicValidationChecks=TRANSFER_LAYOVER_LEGS_COMPLETE turns it off on its own if you need to send something unusual while keeping the rest.
Tracking the layover¶
Once a layover transfer is under way the transporter checks it in and out from the transfer hub: POST /v2/transfers/hub/check-in on arrival at the layover point and POST /v2/transfers/hub/check-out on departure. The times land on the delivery as transporterActualArrivalDateTime and transporterActualDepartureDateTime, which stay null on a direct run.
Layover fields work the same way on POST /v2/transfers/update and on transfer templates, so a regular layover route can be saved once and reused.
Next Steps¶
- Back to the standard flow: Creating Transfers.
- What the receiving licence sees: Receiving Transfers.