Fulfillment partner integration
This guide is for fulfillment partners integrating with ShipperOne — any party that physically fulfils orders on behalf of a tenant. The role is the same regardless of business model:
- Third-party logistics providers (3PLs) — receive orders, fulfil from contract warehouses, dispatch with their carriers.
- Dropshippers — receive orders, fulfil from supplier stock, dispatch directly to the customer.
- In-house warehouses — operated internally by the tenant, often running a WMS; integrate the same way as an external 3PL.
Whichever you are, the API contract is the same: poll the fulfillment order queue, decide whether to fulfil, dispatch the goods, and report back. Allocation and invoicing live in the ERP integration guide; a single integrator may combine both roles.
Audience and scope
Section titled “Audience and scope”You should follow this guide if your system needs to:
- Receive incoming fulfillment orders routed to one of your locations (accept / reject).
- Dispatch the goods with a carrier and report tracking back to ShipperOne (ship).
Stock allocation and invoicing are handled by the ERP — see the ERP integration guide. A single integrator may combine both roles by following both guides.
For the full stage-by-stage map of how a fulfillment order moves through the system, see Fulfillment order lifecycle in the Integrations overview. The action endpoints in scope for this guide:
POST /V1/fulfillmentOrder/accept— see API refPOST /V1/fulfillmentOrder/reject— see API refPOST /V1/fulfillmentOrder/ship— see API ref
The items[] payload
Section titled “The items[] payload”Every action endpoint (accept, reject, ship) takes an explicit items[] list that defines exactly which line items the call operates on. This single payload shape supports both full and partial operations:
- Full operation — pass every
item_idon the fulfillment order. The whole order transitions (accepted/rejected/shipped/ etc). - Partial operation — pass only the subset being acted on. Listed items transition; remaining items stay in their current state and the fulfillment order takes a
partially_*status.
All listed item_id values must belong to the referenced fulfillment order; unknown IDs return 400.
Partial operations — configurability
Section titled “Partial operations — configurability”Whether a fulfillment order accepts partial accept / reject / ship is governed by ShipperOne configuration. Two levels of control are supported:
- System-wide — a tenant-level setting enables or disables partial operations across all fulfillment orders.
- Per fulfillment order — when the sales channel captures explicit customer consent at checkout (e.g. “it’s OK to ship what’s available”), that consent flows into the fulfillment order and enables partials for that order only. Operator override in the ShipperOne admin is also possible for ad-hoc cases.
When partials are not enabled for a given fulfillment order, items[] must contain all of the order’s items; a subset is rejected with 400.
Integration guidance: design for full operation as the default path, and treat partial as an additive case. The payload shape is the same either way.
Step-by-step flow
Section titled “Step-by-step flow”1. Accept or reject
Section titled “1. Accept or reject”Poll for orders awaiting a fulfillment decision:
GET /rest/{store_code}/V1/fulfillmentOrders/pending_accept?page=1Authorization: Bearer <your-token>Accept: application/jsonFor each order, accept (you can fulfil) or reject (you cannot). Both endpoints take the standard { "order": { "order_id": "...", "items": [{ "item_id": ... }] } } shape.
POST /rest/{store_code}/V1/fulfillmentOrder/acceptPOST /rest/{store_code}/V1/fulfillmentOrder/rejectIdempotency — re-sending an accept (or reject) for items that are already in the target state is a no-op; the call returns the current order state without error.
After accept, the order moves into the allocation stage — handled by the ERP. Once allocation is confirmed by the ERP, the order appears in your pending_shipment queue. After reject, ShipperOne may reroute the rejected items to another location.
2. Pick, pack, and ship
Section titled “2. Pick, pack, and ship”Poll for orders ready to dispatch:
GET /rest/{store_code}/V1/fulfillmentOrders/pending_shipment?page=1Authorization: Bearer <your-token>Accept: application/jsonPick, pack, and dispatch with your carrier of choice, then report the shipment back to ShipperOne:
POST /rest/{store_code}/V1/fulfillmentOrder/shipAuthorization: Bearer <your-token>Content-Type: application/json
{ "shipment": { "order_id": "FO-000012345", "items": [ { "item_id": 55501, "qty": 1 }, { "item_id": 55502, "qty": 1 } ], "tracks": [ { "carrier_code": "dhl", "title": "DHL Express", "track_number": "JD0123456789" } ] }}Partial ship is supported on the same payload — pass only the items being dispatched in this shipment, leave the rest for a follow-up ship call. See POST /V1/fulfillmentOrder/ship for the full schema (qty per item, multiple tracks, optional COD amount, package value).
After shipment, the fulfillment order moves into pending_invoice. Invoicing is not part of the fulfillment partner’s scope — it is handled by the ERP, which polls pending_invoice and calls invoice.
Pagination, polling cadence, and idempotency
Section titled “Pagination, polling cadence, and idempotency”- Pagination — every polling endpoint accepts a
pagequery parameter (?page=1); page size is fixed at 100. Iterate until you receive an empty array. - Date filter — pass
date=yyyy-mm-dd hh:mm:ssto limit results to orders updated since that timestamp. Useful for incremental polling instead of scanning the full queue every time. - Polling cadence — recommended: poll each queue every 30–60 seconds during business hours. ShipperOne does not push webhooks today.
- Idempotency —
accept/reject/shipare all safe to retry. If the requested state transition has already been applied, the call returns the current state without re-processing.
Errors
Section titled “Errors”All endpoints return JSON-shaped errors:
| HTTP | Cause |
|---|---|
| 400 | Invalid query/body shape — bad page number, malformed date, unknown item_id, items[] required for non-partial-enabled orders, etc. |
| 401 | Missing or invalid Bearer token. |
| 403 | Token lacks the per-action ACL resource (e.g. Shipper_FulfillmentOrder::api_pending_accept). Contact support to extend the token’s scope. |
| 500 | Unexpected server-side error — safe to retry with exponential backoff. |
See each endpoint’s API Reference page for the full per-error trigger list.