Draft vs confirmed
You create a Shipment in one of two ways: booked-on-create (a single call) or draft + confirm (two calls, with an explicit confirmation step). When to use each is covered on the Shipping overview. This page focuses on what actually changes between the two states once you've made the choice: what you can edit, how confirmation works, how cancellation differs, and the single mutation path available after booking.
What's different between the two states
| Draft | Confirmed (booked) | |
|---|---|---|
| Carrier called | No | Yes |
| Label generated | No | Yes |
| Fees incurred | No | Yes |
| Editable via PATCH / PUT | Yes | No (use reprocess) |
| Tracking number | Absent | Present |
| Status | draft | booked (or further along the state machine) |
Editable states
Carriyo treats three statuses as freely editable via the standard
update endpoints: draft, error, and cancelled (a
freshly-created shipment starts as draft). Any other status
(booked, ready_to_ship,
in_transit, delivered, and the rest of the carrier lifecycle)
rejects PATCH and PUT outright. Two endpoints are available
on editable shipments:
PATCH /shipments/{id}: partial update, supply only the fields you're changing.PUT /shipments/{id}: full replace, the body becomes the new shipment state.
Editable fields include pickup and dropoff addresses, parcels,
items, payment, customs data, custom attributes, and the
carrier_account override.
One field is locked from the moment the shipment is created, not
just from confirmation: partner_shipment_reference. It's
your external identifier and uniqueness is enforced on it; you
can't change it without creating a new shipment.
The confirm endpoint
A draft becomes a booked shipment via
POST /shipments/{id}/confirm. The endpoint accepts an
optional body containing last-minute overrides (anything you'd
be allowed to PATCH) and applies them before booking.
Server-side, the confirm flow:
- Validates that the shipment is currently
draftorerror(the only confirmable statuses). - Applies any request body as a partial update: top-level fields you include are replaced wholesale (an included object replaces the stored one), and custom attributes merge key-by-key.
- Resolves the carrier. Explicit
carrier_accountwins; absent that, the existing account on the draft; absent that, the shipping rules engine picks one. - Sets
confirmation_dateand the customer-promise date. - Moves status to
pending, persists, then calls the carrier asynchronously. - On carrier success, status moves to
booked. On failure, it moves toerror.
The one-shot path (POST /shipments with draft=false) is the
same flow collapsed into a single call: it creates the draft and
immediately confirms it.
What's locked after confirmation
Once a shipment is booked, the available API operations narrow
sharply. PATCH and PUT are rejected. The carrier has already
accepted the booking, generated the label, and (often) scheduled
the pickup slot. The platform protects you from drift between
Carriyo's record and the carrier's reality.
The only mutation path on a booked shipment is reprocess (below).
A few targeted update endpoints still work post-booking for
specific operational needs (for example,
POST /shipments/{id}/update-scheduled-delivery-date to change
the delivery slot), but you can't restructure the shipment.
Reprocess: the only mutation path for booked shipments
POST /shipments/{id}/reprocess re-runs the booking with your
overrides applied. It's the canonical way to change anything
material about a booked shipment.
Reprocess accepts an optional body of overrides. Include only the fields you want to change:
- Switch carriers (the operator concept usually called
reassign). Include a different
carrier_account.carrier_id; Carriyo re-books on that account. - Fix bad pickup or dropoff data. Include the complete
corrected object, top-level objects are replaced wholesale, so send
the whole
dropoff(orpickup), not just the changed field. A new label is produced once the carrier re-books. - Retry a failed booking. When a shipment is in
error, reprocess with no body retries the same inputs; reprocess with corrections retries with the fixes.
Eligible statuses for reprocess: booked, ready_to_ship, error,
cancelled, out_for_collection, failed_collection_attempt,
plus several return-flow statuses.
Cancelling a draft vs a booked shipment
Cancellation uses the same endpoint
(POST /shipments/{id}/cancel), but the side effects differ
depending on what state you're in.
| From | Effect |
|---|---|
draft, error, pending | Local status flip to cancelled. No carrier call. Tracking reference released. |
booked, ready_to_ship, out_for_collection, failed_collection_attempt | Local status flips to cancelled immediately; an async carrier-cancel API call fires in parallel. The carrier confirms the cancellation through its own callback. |
Cancelled shipments are mutable again: cancelled is in the
editable-states set. You can edit fields and re-confirm the same
shipment without creating a new one.
Recovering from error
error is a recoverable state. A shipment lands there in one of two
ways, distinguished by error_details[].source: Carriyo's own
validation rejected it up front (CARRIYO, for example no carrier
could be assigned), or a carrier was assigned but rejected the booking
(CARRIER, for example address validation, restricted commodity, or
capacity).
The platform treats error symmetrically with draft:
- It's editable via
PATCH/PUT. - It's confirmable via
POST /shipments/{id}/confirm. - It's reprocessable via
POST /shipments/{id}/reprocess.
The typical recovery flow is: read the error details from the
shipment's error_details field, fix the offending input, then
either confirm (if the carrier should be the same) or reprocess
(if you're switching carriers).
Identical once confirmed
Both flows produce identical Shipment records once confirmed. A draft that's later confirmed is indistinguishable from a booked-on-create shipment. There's no "draft origin" mark on the record.
This means you can switch flows per-shipment without breaking downstream systems. Mostly book-on-create, occasionally use a draft for special cases, or vice versa.