CanopyDocs

Endpoints

Operation reference for purchase orders, orders, shipments, inventory, and returns — with sample requests and responses.

All paths below are relative to your environment base URL (e.g. https://api.staging.canopywms.com) and require a bearer token with the listed scope. See Authentication and Conventions first.

Purchase orders

Create purchase orders with your own external PO number, update them, cancel them, and retrieve their received quantities and status. Purchase orders are modeled as inbound shipments under /api/receiving.

OperationMethod & pathScope
Create POPOST /api/receiving/shipmentsreceiving:write
List / search POsGET /api/receiving/shipmentsreceiving:read
Retrieve POGET /api/receiving/shipments/:idreceiving:read
Update POPATCH /api/receiving/shipments/:idreceiving:write
Cancel POPOST /api/receiving/shipments/:id/cancelreceiving:write
PO historyGET /api/receiving/shipments/:id/historyreceiving:read
Create a purchase order (idempotent on your external PO number)
curl -X POST https://api.staging.canopywms.com/api/receiving/shipments \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Idempotency-Key: 4d8f...-create-po-PO-2026-00184" \
  -H "Content-Type: application/json" \
  -d '{
    "externalPoNumber": "PO-2026-00184",
    "vendorName": "Sunbelt Co-Packers",
    "expectedArrival": "2026-07-05",
    "expectedCartons": 40,
    "lines": [
      { "skuId": "sku_sriracha17", "expectedQuantity": 240 },
      { "skuId": "sku_ketchup20",  "expectedQuantity": 300 }
    ]
  }'
Response — 201 Created
{
  "success": true,
  "data": {
    "id": "inb_9f2a...",
    "shipmentNumber": "RCV-20260629-00031",
    "externalPoNumber": "PO-2026-00184",
    "status": "PENDING",
    "vendorName": "Sunbelt Co-Packers",
    "expectedArrival": "2026-07-05T00:00:00.000Z",
    "totalExpected": 540,
    "totalReceived": 0,
    "totalDamaged": 0,
    "lines": [
      { "skuId": "sku_sriracha17", "expectedQuantity": 240, "receivedQuantity": 0, "status": "PENDING" },
      { "skuId": "sku_ketchup20",  "expectedQuantity": 300, "receivedQuantity": 0, "status": "PENDING" }
    ]
  }
}

Retrieve by external PO number via the list filter, and by internal id via the path:

Look up by your PO number, or by internal id
curl "https://api.staging.canopywms.com/api/receiving/shipments?externalPo=PO-2026-00184" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "https://api.staging.canopywms.com/api/receiving/shipments/inb_9f2a..."          -H "Authorization: Bearer $ACCESS_TOKEN"

As the warehouse receives the PO, the retrieved record reflects progress: status moves PENDING → IN_PROGRESS → COMPLETED, and totalReceived / per-line receivedQuantity fill in. A purchase_order.received webhook fires when receiving completes (see Webhooks).

Each list row also reports totalExpected, totalReceived, and totalDamaged, and the available filters are externalPo, shipmentNumber, status, vendorName, dateFrom/dateTo, updatedSince, and search.

Orders

Ingest orders, manage their lifecycle (hold / release / cancel), and retrieve them by your order number or sync them incrementally.

OperationMethod & pathScope
Create / ingest orderPOST /api/ordersorders:write
List / search ordersGET /api/ordersorders:read
Retrieve orderGET /api/orders/:idorders:read
Update orderPATCH /api/orders/:idorders:write
Hold / releasePATCH /api/orders/:id/hold · /releaseorders:write
Cancel / requeuePATCH /api/orders/:id/cancel · /requeueorders:write
Mark shipped / deliveredPOST /api/orders/:id/mark-shipped · /mark-deliveredorders:write
Add / update / remove linePOST·PATCH·DELETE /api/orders/:id/lines/...orders:write
Order historyGET /api/orders/:id/historyorders:read
Ingest an order
curl -X POST https://api.staging.canopywms.com/api/orders \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Idempotency-Key: 7a2c...-order-CC-10042" \
  -H "Content-Type: application/json" \
  -d '{
    "orderNumber": "CC-10042",
    "priority": "STANDARD",
    "customerName": "Emma Thompson",
    "customerEmail": "emma.thompson@example.com",
    "shippingMethod": "Standard",
    "shippingAddress": { "name": "Emma Thompson", "line1": "210 Congress Ave", "city": "Austin", "state": "TX", "zip": "78701", "country": "US" },
    "lines": [ { "skuId": "sku_sriracha17", "quantity": 2, "unitPrice": 6.49 } ]
  }'

Retrieve by your order number, filter by status, or pull everything changed since your last sync:

curl "https://api.staging.canopywms.com/api/orders?orderNumber=CC-10042" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "https://api.staging.canopywms.com/api/orders?status=SHIPPED&updatedSince=2026-06-29T00:00:00Z&sortBy=updatedAt&sortOrder=asc" -H "Authorization: Bearer $ACCESS_TOKEN"

The retrieved order exposes its status, lines (with quantityAllocated/quantityPicked/quantityPacked), tracking events, and a full edit history. An order.created webhook fires on ingest and order.shipped when it ships.

Orders that originate from a connected channel (e.g. Shopify) also carry the channel's order id, which is queryable via ?externalOrderId=.

Shipments

Buy carrier labels and retrieve shipment identifiers, tracking, carrier/service, and the actual historical label cost.

OperationMethod & pathScope
Create labelPOST /api/shipping/labelsshipping:write
List shipmentsGET /api/shipping/shipmentsshipping:read
Retrieve shipment (+ live tracking)GET /api/shipping/shipments/:idshipping:read
Live trackingGET /api/shipping/shipments/:id/trackshipping:read
Void labelPOST /api/shipping/shipments/:id/voidshipping:write
Shipped items (per-SKU)GET /api/shipping/shipped-itemsshipping:read
GET /api/shipping/shipments/:id — response
{
  "success": true,
  "data": {
    "id": "shp_3c1b...",
    "shipCode": "SHP-10231",
    "orderId": "ord_9a8b...",
    "orderNumber": "CC-10042",
    "trackingNumber": "1Z999AA10123456784",
    "carrierService": "UPS Ground",
    "shippingCost": 8.42,
    "rate": 8.02,
    "tax": 0.40,
    "totalPaid": 8.42,
    "weight": 52,
    "shipDate": "2026-06-28T15:10:00.000Z",
    "status": "IN_TRANSIT",
    "deliveredAt": null,
    "tracking": {
      "status": "in_transit",
      "events": [ { "status": "in_transit", "description": "Departed facility", "occurredAt": "2026-06-28T22:01:00Z" } ]
    }
  }
}

The GET /api/shipping/shipped-items report breaks shipping down per SKU, exposing quantityOrdered, quantityShipped, trackingNumber, carrierService, and the actual shippingCost per shipment — useful for reconciling outbound volume and freight spend.

Inventory

Read stock levels by SKU and by location.

OperationMethod & pathScope
List SKUs with stockGET /api/inventory/skusinventory:read
Retrieve a SKUGET /api/inventory/skus/:idinventory:read
Stock by locationGET /api/inventory/stockinventory:read

GET /api/inventory/skus returns each SKU's totalStock, allocated, available, backordered, locationCount, dailyVelocity, and daysOfStock. GET /api/inventory/stock returns one row per bin — binLabel, zoneName, warehouseName, quantity, isPickable, lotNumber, and expiresAt.

Returns

Read returns (RMAs) and their lines.

OperationMethod & pathScope
List returnsGET /api/returnsreturns:read
Retrieve a returnGET /api/returns/:idreturns:read

Each return exposes its rmaNumber, status, linked orderNumber, and per-line status. return.completed and return.cancelled webhooks fire on those transitions.

On this page