Booking flow

Updated May 31, 20262 min read

When you create a shipment (or confirm a draft), Carriyo runs the booking flow. It has two parts: a synchronous part, validating the payload and selecting a carrier, that returns immediately with status pending; and an asynchronous part, the carrier's actual booking, whose outcome (booked with a label, or error) arrives later on a webhook. Knowing which part you're in helps you diagnose unexpected results.

The sequence

create / confirm
     │   synchronous: validate, select carrier, submit to carrier
     ├──▶ error    source: CARRIYO  (e.g. no carrier assignable)
     ▼
  pending   → returned to your call immediately
     │   asynchronous: carrier responds, delivered by webhook
     ├──▶ booked   tracking number + label generated
     └──▶ error    source: CARRIER  (carrier rejected)

Carrier selection

The first decision in the flow. Two paths:

  • Explicit selection. If your call carries carrier_account.carrier_id, the rule engine doesn't run and eligibility checks are bypassed. The named account is used as-is. Your code has made an operator-level choice and Carriyo honors it.

  • Automation. If carrier_account is absent, the rule engine fires for the (merchant, entity_type, country)-scoped Ruleset. Each rule is evaluated against the shipment data; when a rule matches, its target carrier account is then eligibility-checked before being used:

    • Account active
    • Merchant on the account's allowed list
    • network profile covers both pickup and dropoff
    • capacity profile threshold not exceeded

    If the matched rule's target account fails any check, the engine falls through to the next matching rule. The first rule whose target account passes all eligibility checks wins. If no rule yields an eligible account, the shipment lands in error immediately, synchronously, with error_details[].source: CARRIYO, and no carrier is contacted.

See Shipping rules for the rule-evaluation detail.

Rate computation

Once a carrier is locked in, the rate is computed:

  • Carrier Shipping Rates. If the account's Carrier shipping rates toggle is on, Carriyo calls the carrier's rates endpoint in real-time.
  • costing profile. If the toggle is off (or the carrier has no rates API), the configured Costing profile computes the rate from your fixed / weight-tier / COD-surcharge config.

Both produce the same result: a cost breakdown persisted on the shipment record.

Carrier booking call (asynchronous)

This is the moment that costs real money, and it happens after your API call has already returned pending. Carriyo packages the shipment into the carrier's request shape and submits it, without waiting for the reply.

When the carrier accepts, it returns a tracking number, a label (or labels), and, for cross-border, a commercial invoice; Carriyo persists them on the shipment and moves it to booked. When the carrier rejects (capacity, address validation, restricted commodity), the shipment moves to error with the carrier's message captured (error_details[].source: CARRIER). Either way the outcome is delivered on a status webhook, not in the original API response, see Book a shipment. To recover an errored shipment, see Fix or reassign a shipment.