Seller journeysOrder fulfilment

Order fulfilment, end to end

Order intake, reading, cancellation, shipment arrangement, marking shipped, and shipment reads are all available over the API. You can build the full order-to-fulfilment flow end to end.

Recommended architecture

Take live changes from webhooks; use GET /orders for reconciliation. Webhooks are the most efficient way to learn "what changed since I last looked" — subscribe to order.created and the status events. Use GET /orders with plain page/limit for periodic reconciliation; its date filters (created_after/created_before) and status filter support reconciliation windows.

  1. Receive the order

    Subscribe to order.created. The payload carries the order; treat delivery as at-least-once and deduplicate on the delivery ID. Also subscribe to order.updated, order.status.updated, order.cancelled and order.shipped to stay current.

  2. Read the detail
    GET/open/v1/orders/{id}orders:read
    GET/open/v1/orders/{id}/itemsorders:read

    The order carries the customer name and shipping address. The phone number is masked unless your app holds the customer:contact:read scope, and the buyer email is returned as buyerEmail only if your app holds customer:email:read.

    Note shipByDate — the platform's ship-by deadline for this order. It drives the eligible pickup dates below.

  3. Reconcile periodically
    GET/open/v1/ordersorders:read

    Page with page/limit. Use created_after/created_before, sort, cursor, and status for paging and reconciliation windows. Take live changes from webhooks, then reconcile with reads.

  4. Prepare the shipment

    These read routes let you pre-compute the pickup plan before you arrange.

    GET/open/v1/shipment/pickup-addressesorders:read

    Registered pickup addresses with per-address pickup_eligible and dropoff_eligible flags.

    GET/open/v1/orders/{id}/shipment/eligible-datesorders:read

    Server-authoritative dates honouring the ship-by cap and the PH holiday calendar, in Asia/Manila. Returns 422 PICKUP_DATES_UNAVAILABLE once the order has shipped.

    GET/open/v1/orders/{id}/shipment/pickup-slots?date=YYYY-MM-DDorders:read

    Slot availability for one date. A date with no slot returns available: false — that is a normal result, not an error.

  5. Arrange and ship
    POST/open/v1/orders/{id}/shipmentorders:write
    POST/open/v1/orders/{id}/shiporders:write

    Arrange a courier pickup with POST /orders/{id}/shipment — using the eligible dates and pickup slots from the read routes above — then mark the order shipped with POST /orders/{id}/ship. Both return the courier tracking number for the label and tracking routes that follow.

  6. Track and print
    GET/open/v1/orders/{id}/trackingorders:read
    GET/open/v1/orders/{id}/shipping-labelorders:read

    Tracking returns the carrier tracking number, the latest carrier scan in current_status, an explicit handover_status, and the latest scan event. The label is available as pdf_base64 (default), url or html.

    Both require an arranged shipment first — whether you arranged it over the API (POST /orders/{id}/shipment or /ship) or in Seller Center. Until then they return 422 SHIPMENT_NOT_ARRANGED / 422 SHIPPING_LABEL_UNAVAILABLE.

    For an arranged shipment with no carrier scan yet, read handover_status: READY_FOR_HANDOVER. Do not infer this state from a carrier tracking number plus current_status: null.

    {
      "success": true,
      "data": {
        "order_id": "order_123",
        "tracking_number": "TRACK123",
        "current_status": null,
        "handover_status": "READY_FOR_HANDOVER",
        "latest_event": null
      }
    }
    handover_statusMeaning
    READY_FOR_HANDOVERShipment booking is arranged and the parcel is awaiting courier pickup.
    IN_TRANSITCourier pickup or first-mile progress has started.
    SHIPPEDLast-mile or out-for-delivery progress.
    DELIVEREDCourier delivery is complete.
  7. Cancel when needed
    POST/open/v1/orders/{id}/cancelorders:write · Idempotency-Key required
    POST/open/v1/orders/bulk-cancelorders:write · max 50 sync

    Cancellation is valid from any pre-shipped state. Past that, 422 ORDER_NOT_CANCELLABLE — handle it as a return.

  8. Handle returns

    Returns are buyer-initiated. Subscribe to return.created, then review:

    ActionEndpoint
    List and read return casesGET /returns · GET /returns/{id}
    Approve the returnPOST /returns/{id}/approve
    Reject the returnPOST /returns/{id}/reject
    Read dispute reason codesGET /returns/dispute-reasons
    Approve the refundPOST /returns/{id}/approve-refund
    Dispute the returnPOST /returns/{id}/dispute

    Return cases come in three types: return_refund, cancellation and failed_delivery. GET /returns/{id} includes the dispute window and buyer evidence. All review actions are available over the API: approve, reject (with a reason code), approve-refund, and dispute (with a reason code and optional evidence).

  9. Reconcile settlement
    GET/open/v1/payoutsorders:read

    Per-order settlement for settled payouts. Filter by order_id and a released_after/released_before window; page with page/limit (limit up to 200). Note: the paging total is indicative, so meta.totalCount is not a global matching total — treat it as indicative and reconcile against your own records.