Customer collection
A customer collection is the entity that represents a customer picking up their order in person at one of your locations. It tracks the parcel from when it's ready at the collection point through to handover. OTP verification confirms who physically receives the goods.
A collection is the pickup counterpart of a shipment. A delivery order ends in a shipment that a carrier moves to the customer; a collection order ends in a collection the customer picks up in person. Each marks the end of fulfillment for its delivery method.
A customer collection always belongs to a fulfillment order with
delivery_method = COLLECTION. The two entities are split
because they answer different questions:
- The fulfillment order says which lines, from which location, going to which collection point.
- The customer collection says the parcel is ready, the customer has been verified, the handover happened.
The model
A collection carries:
collection_id. Unique identifier, prefixedCOL_(e.g.COL_58).status. The lifecycle state (see below).partner_location_id. The Carriyo location id of the collection point: the fulfilling location for a local collection, the location the parcel was shipped to for a remote one.address. The collection point address, copied from the fulfillment order'scustomer_collection_address.packages. The parcels available for pickup, copied from the pack that created this collection.customer. Name, phone, and email of the person collecting. The email is where the OTP is sent.verification. The OTP verification state:method(alwaysOTP),status(pending,verified, oroverridden), and when it was verified.pack_id. The pack that created this collection.customer_collection_schedule. The customer's preferred pickup window, copied from the fulfillment order.notesandcarriyo_metadata. Free-text notes and custom key-value pairs.
Creation triggers
A customer collection is created automatically when a pack
completes: one per fulfillment order whose delivery_method is
COLLECTION and that carries a customer_collection_address.
There is no create endpoint.
The two collection scenarios from the Fulfillment orders page both produce one collection:
- Local collection. The customer collects at the fulfilling location, which is also the collection point. No shipment is created.
- Remote collection. The parcel is shipped from the fulfilling location to another location, and the customer collects it there. The pack creates that shipment before it completes, and the collection tracks the handover.
A COLLECTION fulfillment order without a
customer_collection_address needs no shipment, but it never
gets a collection.
Lifecycle states
A customer collection moves through five states:
open ─▶ ready_to_collect ─▶ collected
▲ │
│ reopen ├─▶ expired ─▶ cancelled (auto)
└───────────┤ ▲
│ │ unexpire
│ ▼
└─▶ cancelled (manual)
| Status | Meaning |
|---|---|
open | Created but not yet at the collection point. The location is still preparing the parcel or it's in transit. |
ready_to_collect | At the collection point. The customer can be notified and verified. |
collected | Handed over to the customer. Terminal: success. |
expired | The customer didn't collect within the configured window. Recoverable via unexpire if they show up late. |
cancelled | Either explicitly cancelled or auto-cancelled after expiry. Terminal. |
Transitions
| From | To | Trigger |
|---|---|---|
open | ready_to_collect | POST /orders/collections/{collectionId}/ready. Staff confirm the parcel is at the counter. |
ready_to_collect | collected | POST /orders/collections/{collectionId}/verification/verify-and-collect. Successful OTP verification, or staff override. |
ready_to_collect | expired | Auto-expire scheduler (see below). |
ready_to_collect | open | POST /orders/collections/{collectionId}/reopen. The parcel is no longer at the counter; the ready date is cleared and verification is reset to pending. |
expired | ready_to_collect | POST /orders/collections/{collectionId}/unexpire. Customer turned up late, give them another window. |
expired | cancelled | Auto-cancel scheduler (see below). |
open, ready_to_collect, expired | cancelled | POST /orders/collections/{collectionId}/cancel. Manual cancellation with optional cancellation_reason. |
OTP verification
Handover is gated on OTP verification, and there is no setting to turn it off. The flow:
- Send OTP.
POST /orders/collections/{collectionId}/verification/send-otpgenerates a 6-digit code and emails it to the customer. The response includesmasked_emailandotp_expires_atso staff can see where the code went without seeing the address. - Verify and collect.
POST /orders/collections/{collectionId}/verification/verify-and-collectaccepts the OTP from the customer. On match, the collection moves tocollected. - Override. Same endpoint with
override = trueand no OTP. For staff exceptions where the customer can prove identity but can't access the OTP. An OTP must still have been sent first; the endpoint refuses when no verification is in progress. Recorded asverification.status = overriddenfor audit. If a request carries both an OTP andoverride = true, the override wins and the OTP isn't checked.overridedefaults to false.
Constraints baked into the verification flow:
- 6 digits.
- 5-minute expiry from send.
- After 5 failed attempts, every further verify is refused until a new OTP is sent. Sending again issues a fresh code and resets the counter.
- 60-second cooldown between sends.
- The collection must be in
ready_to_collectfor both send and verify-and-collect.
A customer with no email can never be collected. Send OTP needs
the email, and verify-and-collect, override included, needs the
verification that only Send OTP creates. There is no other way
to reach collected, so make sure collection orders carry a
customer email.
Auto-expiry and auto-cancellation
Four order management settings govern the unattended timers:
| Setting | Effect |
|---|---|
customer_collection_auto_expire_enabled | When on, a ready_to_collect collection moves to expired after customer_collection_auto_expire_days days (default 7 when unset). |
customer_collection_auto_cancel_enabled | When on, an expired collection moves to cancelled after customer_collection_auto_cancel_days days (no default; unset or zero skips auto-cancel). Has no effect unless auto-expire is also on. |
Both flags are checked again when a timer fires. A timer
scheduled while a flag was on does nothing if the flag is off by
then. If the customer turns up after expiry, unexpire puts the
collection back into ready_to_collect and re-schedules
auto-expiry.
How the order closes after handover
When a collection is collected, Carriyo checks the parent fulfillment-order line items. Cancelling a collection does not close anything:
| Collection event | Line-item effect |
|---|---|
| Collected (OTP verified or overridden) | If every collection the line item belongs to is now collected or cancelled, the line item moves to closed. |
| Cancelled | No line-item change: the line items stay fulfilled, and no new collection can be created for them. The collection's verification state and timers are cleared. |
A line item can belong to more than one collection. It closes
only when every one of them is collected or cancelled, and
that check runs on collect, not on cancel. An order stays open
while any customer still has goods to collect.
No collection operation sends an order webhook, collecting included. The only message Carriyo sends is the OTP email, so poll the order or read the collection to follow a handover.
Lookup endpoints vs full record
Lookups by order, fulfillment order and pack return only
collection_id, tenant, partner_location_id, status and
creation_date per collection; use
GET /orders/collections/{collectionId} for the full record.
How it fits with other modules
- Fulfillment orders.
Every customer collection belongs to a
delivery_method = COLLECTIONfulfillment order. - Order lifecycle. A collected collection closes its fulfillment order's line items, which the order status follows.
- Locations. The
collection point is a location with the
collection_locationflag on. - Click and collect.
The upstream checkout flow that produces a
COLLECTIONorder.