Skip to content

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