{"openapi":"3.1.0","info":{"title":"Crowd Cow 3PL partner API — proposed","version":"2026-09-08","summary":"Push orders and SKUs, track fulfillment, and quote shipping.","description":"This page describes the API as it will be when the current build-out is\nfinished. Anything marked **Coming** is not available yet; calling it today\nwill not find it. Everything else works now. Field names, filters and error\nshapes here are the contract, and changes to them are additive. The live\nreference is at https://3pl.crowdcow.com/api-reference.\n\nPush inventory and orders, reschedule, quote shipping and read delivery\ndates — programmatically. Base URL\n`https://www.crowdcow.com/api/fulfillment/v1`.\n\n## Authentication\n\nEvery request needs your key, in either header — they are the same\ncredential. Your Crowd Cow contact issues keys per organization; there is no\nself-serve key page.\n\n```\nX-Api-Key: \u003cYOUR_TOKEN\u003e\nAuthorization: Bearer \u003cYOUR_TOKEN\u003e\n```\n\nA missing or revoked key returns **401**. Quote and Shipping Calendar also\nrequire a 3PL organization key, and return **403** otherwise.\n\n## Errors\n\nEvery failure is [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457.html)\n`application/problem+json`, one shape for every endpoint and status.\n\n```json\n{\n  \"type\": \"/problems/validation-error\",\n  \"title\": \"Request is not valid.\",\n  \"status\": 400,\n  \"detail\": \"status must be one of: not_packed, packed, shipped, cancelled\",\n  \"instance\": \"/requests/7f1c3e2a-…\"\n}\n```\n\nBranch on `type`, not `detail`: `detail` is written for a person and may be\nreworded without notice. `instance` is the request id; quote it to us to\ntrace a request.\n\n| `type` | Status | When |\n|---|---|---|\n| `/problems/unauthorized` | 401 | No key, or a revoked one. |\n| `/problems/forbidden` | 403 | Your key cannot reach this endpoint or this organization. |\n| `/problems/not-found` | 404 | No such record on your account. |\n| `/problems/validation-error` | 400 / 422 | A bad parameter (400) or a bad request body (422). |\n| `/problems/policy-refused` | 422 | The change is not allowed on that order; `reasons` says why. |\n| `/problems/cursor-invalid` | 400 | A cursor we did not issue, or the filters changed mid-walk. |\n| `/problems/quota-exceeded` | 429 | You are over the rate limit; `Retry-After` says how long to wait. |\n\nTwo optional members carry the specifics: `errors` on a 422 from\n`PUT /orders` or `PUT /skus` (`[{ \"code\": \"invalid\", \"detail\": \"…\" }]`), and\n`reasons` on a policy refusal.\n\n**Keys that existed before 10 September 2026 keep the older bodies.** On\nsuch a key, nothing above applies: `PUT /orders` and `PUT /skus` are\n`{ \"errors\": [\"...\", \"...\"] }`, everything else is `{ \"message\": \"...\" }`,\nand the media type is `application/json`. Status codes are unchanged. Ask\nyour Crowd Cow contact to move your key to the modern bodies; there is no\nper-request switch.\n\n**Rotating your key does not change your shapes.** A replacement key issued\nfor an organization that holds one of these keeps the older bodies.\n\n**Two exceptions:** a **401** and a **429** always use the problem document,\nwhatever your key.\n\n## Fulfillment centers\n\nThe `fc` field, in requests and responses, uses these codes.\n\n| Code | Location |\n|---|---|\n| `dunmore` | Scranton, PA |\n| `dallas` | Dallas, TX |\n| `watsonville` | Watsonville, CA |\n\n## Lists and paging\n\nEvery list returns the same envelope.\n\n```json\n{ \"data\": [ … ], \"has_more\": true, \"next_cursor\": \"eyJ2Ijoi…\" }\n```\n\nFollow `next_cursor` until it comes back `null`. The same link is in a\n`Link: \u003c…\u003e; rel=\"next\"` header. `limit` defaults to 50, maximum 200; a\nlarger value is clamped.\n\nThe cursor is opaque; do not construct or parse one. It carries the filters\nit was issued under, so changing one part-way through a walk is a\n`400 /problems/cursor-invalid`; restart from the first page.\n\nThere is **no total count**, in the body or in a header. A walk visits every\nrow exactly once, even while rows are being written underneath it.\n\n## Rate limits\n\n**600 requests per minute per API key**, counted over a fixed 60-second\nwindow. Reads and writes share the one budget.\n\n**Coming: heavy reads get their own budget.** Reports, invoice detail paths\nand every `/summary` sibling will be counted under a second, lower per-key\nlimit as well, so a loop over reports cannot crowd out order lookups. It is\nreported in the same headers, under the policy name `per-key-reports`.\n\nTwo limits apply per IP address as well: **1,200 per minute** over every\nrequest to the API, with or without a key, and **60 per minute** over the\nrequests that carry **no** API key. This document is the exception: it is\npublic and counts against that 60, so fetch it when your client is built,\nnot on a loop.\n\nEvery response, successful or not, carries the IETF\n[RateLimit](https://www.ietf.org/archive/id/draft-ietf-httpapi-ratelimit-headers-11.html)\nfields:\n\n```\nRateLimit-Policy: \"per-key\";q=600;w=60\nRateLimit: \"per-key\";r=597;t=42\n```\n\n`q` is the quota and `w` the window in seconds; `r` is how many requests you\nhave left and `t` how many seconds until the window resets. Most requests\nare counted by more than one limit; the headers report whichever is closest\nto running out, so the policy named is `\"per-key\"`, `\"per-ip\"` or\n`\"per-ip-total\"`. There are no `X-RateLimit-*` headers.\n\nOver the limit you get **429** with `Retry-After` in whole seconds and an\n`application/problem+json` body, whatever your key. Wait `Retry-After`\nseconds and retry; nothing was processed, so a retry is safe for every\nendpoint.\n\n## Staging\n\n`staging.crowdcow.com` mirrors production and is reset from live data\nnightly. It needs HTTP basic auth as well as the `X-Api-Key` header; your\nCrowd Cow contact has those credentials.\n\n## What the API cannot do\n\nEach of these is available in the portal.\n\n- **Shipments** — tracking status, scan history, late and exception flags,\n  promised versus predicted arrival, lost or destroyed write-offs.\n- **Invoices** — list, detail, PDF, cost workbook.\n- **Inventory transactions** — receiving, picks, cycle counts, write-offs.\n- **Delivery performance** — on-time rate, average transit, alert counts.\n- **Reports** — month-end inventory, Sad Cow write-offs, lots.\n- **SKU archiving**, internal notes, images, weeks-of-stock and cost figures.\n- **Packs** — you can use a pack code in an order's items, but creating and\n  editing packs is portal-only.\n- **Users** — account management is portal-only.\n\nIf one of these blocks an integration you are building, email\n[fulfillment@crowdcow.com](mailto:fulfillment@crowdcow.com).\n\n## For AI agents\n\nThis document is public and needs no API key. Fetch it at\n`https://www.crowdcow.com/api/fulfillment/v1/openapi.json` and read it\nbefore writing integration code: it carries every endpoint, parameter, enum,\nstatus code and response schema, plus the behaviour above. Worked examples\nlive alongside the operations.\n","contact":{"name":"Crowd Cow","url":"https://3pl.crowdcow.com/api-reference"}},"servers":[{"url":"https://www.crowdcow.com/api/fulfillment/v1","description":"Production"},{"url":"https://staging.crowdcow.com/api/fulfillment/v1","description":"Staging (also behind HTTP basic auth)"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"tags":[{"name":"SKUs","description":"Keyed on `sku_id`, which is your own identifier and what an order's\n`items` reference. Every other field is overwritten by what you send, so\nsend the whole record each time — an omitted `barcode` clears the stored\none.\n\n`weight` is pounds; `width`, `length` and `height` are inches. Inventory\ncomes back per fulfillment center: `on_hand_quantity` is physical stock,\n`reserved_quantity` is committed to orders not yet shipped, and\n`available_quantity` is what you can still sell. Quote against\n`available_quantity`.\n"},{"name":"Orders","description":"Keyed on `order_id`. One order per request; there is no batch endpoint.\nAn update to a packed or shipped order is refused with `422` and a\nreason; `can_modify` on any order response tells you in advance.\n\n**`shipping_method` has three meanings.** Omitted — any existing override\nis left alone. `carrier` + `service` set — pin the order to that service.\nBoth explicitly null — clear the override and return to automatic routing.\n\n**`preferred_arrival_date` picks the slot, not the service.** Crowd Cow\npicks the plan arriving closest to your date, but will not buy a faster\nservice to hit it. A date in the past is ignored.\n\n**The ship-to state must agree with the ship-to ZIP.** A mismatch fails\nthe whole request with `422` and creates no order; resend once corrected.\nUnknown and non-US ZIPs pass. The city is not checked.\n\nOn the order object, `items` excludes Crowd Cow packing inserts — your own\nproducts only, at the quantity ordered, not the quantity picked — and\n`shipments` lists shipped shipments only, so an order that has not shipped\nhas an empty array.\n"},{"name":"Shipments","description":"Tracking, delivery state and exception flags for the boxes we ship for you.\nThe list covers shipments that have been labeled or shipped; an order not yet\npicked has no shipment row.\n\n`status` is `not_shipped`, `in_transit`, `out_for_delivery` or `delivered`.\n`last_scan` carries the most recent carrier scan; scan history is not exposed.\n`write_off` is `null`, `lost` or `destroyed_in_transit`, and a written-off box\nreports `days_late` of 0.\n\n`/shipments/summary` takes the same filters and returns the counts and carrier\nvocabulary a list header needs, so a page of rows never pays for them.\n"},{"name":"Inventory transactions","description":"Every movement of your stock in our warehouses: receipts, picks, cycle-count\ncorrections and write-offs.\n\n`quantity` is signed — receipts and upward corrections positive, picks and\nwrite-offs negative. `reason` is `receiving`, `pick`, `cycle_count`, `sad_cow`\nor `delivery`. `box_id`, `order_id` and `lot` are present when the movement has\none. Transfers between our own facilities and zero-quantity rows are excluded.\n\n`/inventory_transactions/summary` totals the same filtered set per SKU.\n"},{"name":"Invoices","description":"Your issued invoices, their charges and their documents. Only issued invoices\nare returned; drafts and voided invoices do not appear.\n\n`id` is the invoice number printed on the document, and the identifier every\ninvoice path takes. `status` is `sent` or `exported`. Money is a decimal string\nin dollars with its currency beside it, never cents. Sorted newest billing\nperiod first; `limit` and `cursor` work as they do on orders.\n\nShipment costs are their own paginated list rather than being inlined: the\nlargest invoice bills about 13,000 shipments.\n"},{"name":"Reports","description":"Three finished reports. One request returns the whole report: no cursor, no\nsummary sibling.\n\nMonth-end inventory counts units you own on hand at each fulfillment center at\nthe close of a month; `month` is `YYYY-MM` and defaults to the last completed\none. Sad Cow reports units written off, by SKU, center and reason. Delivery\nperformance returns the on-time rate, average transit and alert counts for a\nperiod, each against the prior one.\n"},{"name":"Quoting and dates","description":"An inventory-aware shipping quote for a cart, and the delivery dates\navailable to a destination. Both are 3PL organization keys only.\n\n- **`shipments`** — one entry per fulfillment center used. `fc.code` is\n  the internal code; `fc.display` is a customer-safe string that never\n  names the warehouse. A `reason` appears only when the requested date was\n  unavailable, or this is a secondary shipment because the primary center\n  was short.\n- **`unfulfillable`** — present only when something cannot be quoted. Each\n  entry carries `sku_id`, `quantity_requested`,\n  `quantity_available_across_all_fcs` and a reason:\n  `no_fc_has_inventory`, `insufficient_inventory_across_all_fcs`,\n  `no_shipping_options_available` or `no_eligible_shipment_plan`.\n- **`ground_eligibility`** — `eligible` is true only when every item ships\n  and every shipment is a ground service. `blockers` lists what the\n  nearest ground center is short on, each with a\n  `recommended_max_quantity` — reduce to that to keep ground. `eligible`\n  false with empty `blockers` means air was quoted for speed, not for lack\n  of stock.\n\nA cart whose items are all out of stock still returns **200** with an\nempty `shipments` array, so read `shipments`, `unfulfillable` and\n`advisory` rather than the status code. An **empty** `items` array is a\n`422`.\n\nOn the calendar, `weeks` defaults to 4 and is clamped to 1–12; a\nnon-integer is a `422`.\n"},{"name":"Meta","description":"This document. Public, and the only endpoint needing no API key."}],"paths":{"/skus":{"get":{"tags":["SKUs"],"operationId":"listSkus","summary":"List your SKUs, with inventory per fulfillment center","description":"Your SKUs, including archived ones, in pages of 50. `limit` and `cursor`\nwork as they do on orders.\n\n**If your key existed before 10 September 2026** this endpoint returns\nevery SKU as a bare JSON array, unpaged — there is no envelope, no\ncursor and no `Link` header, and `limit` is ignored rather than\nrefused.\n","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"archived","in":"query","description":"Archived SKUs are excluded by default. `include` returns them\nalongside the rest; `only` returns just them.\n","schema":{"type":"string","enum":["include","only"]}}],"responses":{"200":{"description":"A page of SKUs.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["SKUs"],"operationId":"upsertSku","summary":"Create or update a SKU","description":"Keyed on `sku_id`. Every other field is overwritten by what you send,\nso send the whole record each time — an omitted `barcode` clears the\nstored one.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuUpsertRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/SkuUpsertRequest"}}}},"responses":{"200":{"description":"The stored SKU.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Sku"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableErrors"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/orders":{"get":{"tags":["Orders"],"operationId":"searchOrders","summary":"Fetch orders","description":"An `id` lookup returns every order carrying that identifier: normally\none, an empty `data` if none match, more than one if you have reused an\nidentifier. There is no `404` here.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/orders?id=1234567' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nAll filters are optional and all combine. A value a filter cannot read\nis refused with a `400` naming the parameter.\n\n```bash\n# Everything shipping in a date window, oldest first\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/orders?ship_date_min=2026-06-01\u0026ship_date_max=2026-06-30\u0026sort=ship_date' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n\n# Anything mentioning a SKU, a recipient or one of your external references\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/orders?q=s_ribeye_12oz' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n\n# Cancelled orders only, 100 at a time\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/orders?status=cancelled\u0026limit=100' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nFollow `next_cursor` until it comes back `null`:\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/orders?limit=200' …\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/orders?limit=200\u0026cursor=eyJ2Ijoi…' …\n```\n\n**If your key existed before 10 September 2026** this endpoint still\nreturns a bare JSON array, and `page` / `per_page` / the `X-Total-*`\nheaders are gone. Pages are still `limit` rows, and the cursor cannot\ntravel in a bare array, so follow the `Link: rel=\"next\"` header.\n","parameters":[{"name":"id","in":"query","description":"Exact match on your `order_id`.","schema":{"type":"string"}},{"name":"q","in":"query","description":"Free text across your order id, your customer order id, our order\nnumber, the order token, the recipient name, SKU name, SKU id, and\nany `external_references` value.\n","schema":{"type":"string"}},{"name":"ship_date_min","in":"query","description":"`YYYY-MM-DD`, inclusive, on the scheduled ship date. A date we\ncannot read is a `400`, never a dropped filter.\n","schema":{"type":"string"}},{"name":"ship_date_max","in":"query","description":"`YYYY-MM-DD`, inclusive, on the scheduled ship date.","schema":{"type":"string"}},{"name":"start_date","in":"query","description":"The older spelling of `ship_date_min`, still accepted.","schema":{"type":"string"}},{"name":"end_date","in":"query","description":"The older spelling of `ship_date_max`, still accepted.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Mutually exclusive. An unrecognized value is a `400` naming the four.\n","schema":{"type":"string","enum":["not_packed","packed","shipped","cancelled"]}},{"name":"sort","in":"query","description":"`-` for descending. An unrecognized value is a `400`.","schema":{"type":"string","enum":["ship_date","-ship_date"],"default":"-ship_date"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"updated_at_min","in":"query","description":"RFC 3339. Returns orders changed at or after this instant, and\nswitches the default sort to `updated_at` ascending so a polling\nloop cannot miss a row. This is how you ask \"what changed since I\nlast looked\".\n","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of matching orders, newest ship date first.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["Orders"],"operationId":"upsertOrder","summary":"Create or update an order","description":"Keyed on `order_id`. One order per request; there is no batch endpoint.\nAn update to a packed or shipped order is refused with `422` and a\nreason; `can_modify` on any order response tells you in advance.\n\n```bash\ncurl --request PUT 'https://www.crowdcow.com/api/fulfillment/v1/orders' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n    \"order_id\": \"1234567\",\n    \"customer_order_id\": \"456\",\n    \"shipping_method\": { \"carrier\": \"UPS\", \"service\": \"Ground\" },\n    \"packaging\": { \"dry_ice_in_pounds\": 10 },\n    \"items\": [{ \"sku\": \"s_ribeye_12oz\", \"quantity\": 2 }],\n    \"shipping_address\": {\n      \"name\": \"John Doe\",\n      \"address_1\": \"123 Main St\", \"address_2\": \"Apt 1\",\n      \"city\": \"Kirkland\", \"state\": \"WA\", \"postal_code\": \"98033\",\n      \"phone_number\": \"1234567890\",\n      \"delivery_instructions\": \"Gate code 4432\"\n    },\n    \"billing_address\": {\n      \"address_1\": \"123 Billing St\", \"city\": \"Seattle\",\n      \"state\": \"WA\", \"postal_code\": \"98104\"\n    }\n  }'\n```\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderUpsertRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OrderUpsertRequest"}}}},"responses":{"200":{"description":"The stored order.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableErrors"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/orders/{id}/cancel":{"parameters":[{"$ref":"#/components/parameters/OrderId"}],"post":{"tags":["Orders"],"operationId":"cancelOrder","summary":"Cancel an order","description":"Cancelling an already-cancelled order is a no-op that returns `200` —\nsafe to retry. An order too far along returns `422` naming the reason.\n","responses":{"200":{"description":"The cancelled order.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/orders/{id}/override_ice":{"parameters":[{"$ref":"#/components/parameters/OrderId"}],"patch":{"tags":["Orders"],"operationId":"overrideOrderIce","summary":"Override the dry ice weight","description":"Send `dry_ice_in_pounds` or `dry_ice_in_kilograms` (converted and\nrounded). Sending the key with an empty value clears the override;\nomitting **both** keys is an error, not a clear.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverrideIceRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OverrideIceRequest"}}}},"responses":{"200":{"description":"The order, with the override applied.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/orders/{id}/override_shipping_method":{"parameters":[{"$ref":"#/components/parameters/OrderId"}],"patch":{"tags":["Orders"],"operationId":"overrideOrderShippingMethod","summary":"Pin the order to a carrier and service","description":"Send **both** `carrier` and `service`, or both empty to clear the\noverride and return the order to automatic routing. One without the\nother is a `422`. The order is rescheduled onto a plan matching the new\nservice; if none exists for its current ship date the request fails\nwith `422` and nothing changes.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverrideShippingMethodRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OverrideShippingMethodRequest"}}}},"responses":{"200":{"description":"The order, rescheduled onto the new service.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/orders/{id}/rescheduling_options":{"parameters":[{"$ref":"#/components/parameters/OrderId"}],"get":{"tags":["Orders"],"operationId":"listReschedulingOptions","summary":"The dates and services this order can move to","description":"An order that cannot be rescheduled returns `422` with the reason\nrather than an empty list. No shipping price is returned — 3PL rates\nare contracted at the account level.\n","responses":{"200":{"description":"The current plan and the plans available to move to.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReschedulingOptions"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/orders/{id}/reschedule":{"parameters":[{"$ref":"#/components/parameters/OrderId"}],"post":{"tags":["Orders"],"operationId":"rescheduleOrder","summary":"Move an order to one of its rescheduling options","description":"Pass an `arrival_date` from the options, plus either the\n`shipping_option_name` or a `carrier` + `service` pair.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescheduleRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/RescheduleRequest"}}}},"responses":{"200":{"description":"The rescheduled order.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/shipment_calendar":{"get":{"tags":["Quoting and dates"],"operationId":"getShipmentCalendar","summary":"Available fulfillment and arrival dates to a destination","description":"Independent of any cart — for rendering a delivery-date picker. 3PL\norganizations only; any other key is a `403`.\n","parameters":[{"name":"postal_code","in":"query","required":true,"description":"ZIP+4 and surrounding whitespace are normalized away. Fewer than\nthree digits is a `422`.\n","schema":{"type":"string"}},{"name":"weeks","in":"query","description":"Clamped to 1–12: a larger value is clamped, not rejected, and a\nnon-integer is a `422`.\n","schema":{"type":"integer","default":4}}],"responses":{"200":{"description":"Every plan inside the window, and the default pick.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentCalendar"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/quote":{"post":{"tags":["Quoting and dates"],"operationId":"createQuote","summary":"An inventory-aware shipping quote for a cart","description":"A cart whose items are all out of stock still returns `200` with\n`\"shipments\": []`, so read `shipments`, `unfulfillable` and `advisory`\nrather than the status code. An **empty** `items` array is a `422`.\n3PL organizations only; any other key is a `403`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/QuoteRequest"}}}},"responses":{"200":{"description":"The quote, as an estimate at quote time.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableMessage"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/openapi.json":{"get":{"tags":["Meta"],"operationId":"getOpenapiDocument","summary":"This document, as JSON","description":"The only endpoint that needs no API key.","security":[],"responses":{"200":{"description":"The OpenAPI 3.1 description of this API.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"type":"object"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/shipments":{"get":{"tags":["Shipments"],"operationId":"listShipments","summary":"Coming: list shipments","description":"Tracking, delivery state and exception flags for the boxes we ship for you. The\nlist covers shipments that have been labeled or shipped; an order not yet picked\nhas no shipment row.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/shipments?status=in_transit\u0026limit=100' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\n**Key on `id`.** It is stable for the life of the shipment. `shipment_number` is\nthe box's position among the order's shipments as they stand today and can\nchange.\n\n`status` is `not_shipped`, `in_transit`, `out_for_delivery` or `delivered`.\n`promised_arrival` is the date we committed to, `predicted_arrival` the\ncarrier's current estimate. `days_late` is measured against `promised_arrival`,\nand is 0 for a written-off shipment. `write_off` is `null`, `\"lost\"` or\n`\"destroyed_in_transit\"`. `last_scan` is the latest carrier scan; scan history\nis not available.\n\nFilters are all optional and all combine. A value we cannot parse is a `400`\nnaming the parameter. Paging follows `next_cursor` until it is `null`. There is\nno total in the body — ask `/shipments/summary`, which takes the same filters.\nChanging a filter part-way through a walk is a `400` `/problems/cursor-invalid`;\nrestart from the first page.\n\n**Polling for what changed.** `updated_at_min` returns everything written since\nthe moment you name. When it is present the sort becomes `updated_at` ascending.\nKeep the highest `updated_at` you saw and send it back next run.\n\n```bash\n# 1. Everything that changed since the last run\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/shipments?updated_at_min=2026-06-03T14:02:11Z\u0026limit=200' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n\n# 2. Plus a periodic sweep of what is still moving\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/shipments?status=in_transit' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\n**Three fields change without a write.** `days_late`, the late flag and\n`promised_arrival` can all differ from what you last read while `updated_at`\nstands still — rescheduling the order changes the promise without changing the\nshipment. Use both calls above: `updated_at_min` for what changed, and a\nperiodic read of what is still in flight. All three are derivable from the row\nyou hold.\n\nA carrier scan updates the shipment, not the order. Poll **shipments** for\ndelivery state and **orders** for order-level changes.\n","parameters":[{"name":"q","in":"query","description":"Free text across the tracking number, your order id, your customer\norder id, our order number, the order token, and the recipient's\nname, city and postal code.\n","schema":{"type":"string"}},{"name":"order_id","in":"query","description":"Exact match on the `order_id` a row carries — your own identifier\nwhere you sent one, our order number otherwise.\n","schema":{"type":"string"}},{"name":"status","in":"query","description":"Delivery stage, mutually exclusive. An unrecognized value is a `400`\nnaming the four.\n","schema":{"type":"string","enum":["not_shipped","in_transit","out_for_delivery","delivered"]}},{"name":"carrier","in":"query","description":"Exact match on `carrier`. `/shipments/summary` returns the carriers\nyou have shipped with, which is the vocabulary this accepts.\n","schema":{"type":"string"}},{"name":"late","in":"query","description":"`true` keeps only late boxes, `false` keeps only boxes that are not\nlate. Anything else is a `400`, never a filter that did nothing.\n","schema":{"type":"boolean"}},{"name":"tracking_alert","in":"query","description":"Same, on whether the carrier has posted a problem scan.","schema":{"type":"boolean"}},{"name":"never_arriving","in":"query","description":"Same, on whether the box has been written off.","schema":{"type":"boolean"}},{"name":"ship_date_min","in":"query","description":"`YYYY-MM-DD`, inclusive, on the scheduled ship date. A date we\ncannot read is a `400`, never a dropped filter.\n","schema":{"type":"string"}},{"name":"ship_date_max","in":"query","description":"`YYYY-MM-DD`, inclusive, on the scheduled ship date.","schema":{"type":"string"}},{"name":"delivered_at_min","in":"query","description":"RFC 3339, inclusive. A timestamp rather than a date, so a poller can\nask about a moment rather than being handed the whole day.\n","schema":{"type":"string","format":"date-time"}},{"name":"delivered_at_max","in":"query","description":"RFC 3339, inclusive.","schema":{"type":"string","format":"date-time"}},{"name":"updated_at_min","in":"query","description":"RFC 3339, inclusive, on `updated_at`. When it is present the default\nsort becomes `updated_at` ascending, so a walk visits changes in the\norder they happened.\n","schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","description":"`-` for descending. An unrecognized value is a `400`. Defaults to\n`-ship_date`, or `updated_at` when `updated_at_min` is given.\n","schema":{"type":"string","enum":["ship_date","-ship_date","carrier","-carrier","predicted_arrival","-predicted_arrival","delivered_at","-delivered_at","last_scan_at","-last_scan_at","updated_at","-updated_at","order_id","-order_id","destination","-destination","promised_arrival","-promised_arrival"]}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of matching shipments.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/shipments/summary":{"get":{"tags":["Shipments"],"operationId":"summarizeShipments","summary":"Coming: count shipments","description":"The counts above the list. Takes the same filters as `GET /shipments`, but\ncounts are taken over `q`, the date range and `carrier`, before `status`,\n`late`, `tracking_alert` and `never_arriving` apply — so a count still describes\nthe whole set once you narrow by one of them. `carriers` names the carriers you\nship with, and is the vocabulary the `carrier` filter accepts.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/shipments/summary?ship_date_min=2026-06-01\u0026ship_date_max=2026-06-30' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nEvery `/summary` sibling shares a smaller per-key budget: 60 requests per\nminute, separate from the 600 the rest of the API gets.\n","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"order_id","in":"query","schema":{"type":"string"}},{"name":"carrier","in":"query","schema":{"type":"string"}},{"name":"ship_date_min","in":"query","schema":{"type":"string"}},{"name":"ship_date_max","in":"query","schema":{"type":"string"}},{"name":"delivered_at_min","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"delivered_at_max","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"updated_at_min","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Counts over the filtered set, and the carriers you ship with.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentSummary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/reports/delivery_performance":{"get":{"tags":["Reports"],"operationId":"deliveryPerformanceReport","summary":"Coming: delivery performance","description":"How your boxes arrived over a period, against the period before it.\n`period_start` and `period_end` are optional; omit both for the default window,\nthe last completed week (Sunday–Saturday). One end on its own derives the other\n— a start alone runs seven days, an end alone runs back seven — and neither end\nruns past today.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/reports/delivery_performance?period_start=2026-08-01\u0026period_end=2026-08-31' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nEach of the six headline measures returns as a **current and prior pair**.\n`weeks` is the trailing 13-week series, `findings` what we flagged in the\nperiod, and `order_status_counts` is per organization, not pooled across the\nones you trade under.\n\nOne request returns the whole report: no cursor. `/reports/*` shares a smaller\nper-key budget: 60 requests per minute, separate from the 600 the rest of the\nAPI gets.\n","parameters":[{"name":"period_start","in":"query","description":"`YYYY-MM-DD`, inclusive, on the scheduled ship date. A date we cannot\nread is a `400`, never a silently different period.\n","schema":{"type":"string"}},{"name":"period_end","in":"query","description":"`YYYY-MM-DD`, inclusive, on the scheduled ship date.","schema":{"type":"string"}}],"responses":{"200":{"description":"The report for the requested period.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryPerformance"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/inventory_transactions":{"get":{"tags":["Inventory transactions"],"operationId":"listInventoryTransactions","summary":"Coming: the inventory ledger — one row per unit movement","description":"Every movement of your stock in our warehouses: receipts, picks, cycle-count\ncorrections and write-offs, newest first.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/inventory_transactions?occurred_at_min=2026-08-01\u0026occurred_at_max=2026-08-31' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\n`quantity` is signed: receipts and upward corrections positive, picks and\nwrite-offs negative. `reason` is `receiving`, `pick`, `cycle_count`, `sad_cow`\nor `delivery`. `box_id`, `order_id` and `lot` are present when the movement has\none. Transfers between our own facilities and zero-quantity rows are excluded.\n\n**The default scope is stock you own.** Your branded SKUs can also hold units\nCrowd Cow owns. This list, the month-end report and the Sad Cow report all count\nyour units only. `owner=all` widens the list to every movement on your SKUs and\nadds an `owner` field to each row.\n\nFilters are all optional and all combine. Paging follows `next_cursor` until it\nis `null`; there is no total in the body. Each row's `id` is stable, so an\noverlapping window can be de-duplicated on it.\n","parameters":[{"$ref":"#/components/parameters/MovementSkuId"},{"$ref":"#/components/parameters/MovementReason"},{"$ref":"#/components/parameters/MovementFc"},{"$ref":"#/components/parameters/MovementOccurredAtMin"},{"$ref":"#/components/parameters/MovementOccurredAtMax"},{"$ref":"#/components/parameters/MovementOwner"},{"name":"sort","in":"query","description":"Only `-occurred_at`. The ledger is read newest-first; asking for the\nother direction is a `400` rather than a page that quietly ignores\nyou.\n","schema":{"type":"string","enum":["-occurred_at"],"default":"-occurred_at"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of movements, newest first.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryTransactionList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/inventory_transactions/summary":{"get":{"tags":["Inventory transactions"],"operationId":"summarizeInventoryTransactions","summary":"Coming: per-SKU movement totals over the same filters","description":"The same filters as `GET /inventory_transactions`, totalled per SKU over the\nrange: one row per SKU, one field per reason, plus `total`. The whole filtered\nrange is summarized, not a page of it.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/inventory_transactions/summary?occurred_at_min=2026-08-01\u0026occurred_at_max=2026-08-31' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nOn the default scope these totals reconcile: a month of movements equals the\ndifference between that month's opening and closing month-end snapshots. With\n`owner=all` they do not, because the snapshots count only your units.\n\nEvery `/summary` sibling shares a smaller per-key budget: 60 requests per\nminute, separate from the 600 the rest of the API gets.\n","parameters":[{"$ref":"#/components/parameters/MovementSkuId"},{"$ref":"#/components/parameters/MovementReason"},{"$ref":"#/components/parameters/MovementFc"},{"$ref":"#/components/parameters/MovementOccurredAtMin"},{"$ref":"#/components/parameters/MovementOccurredAtMax"},{"$ref":"#/components/parameters/MovementOwner"}],"responses":{"200":{"description":"One line per SKU with a movement in range.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryTransactionSummary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/reports/month_end_inventory":{"get":{"tags":["Reports"],"operationId":"getMonthEndInventoryReport","summary":"Coming: units on hand per SKU per fulfillment centre at a month end","description":"Units of yours on hand at each fulfillment center at the close of a month.\n`month` is `YYYY-MM` and defaults to the last completed month. A future month\nreturns the current one rather than an error, and `as_of` always says which\nmoment you are reading.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/reports/month_end_inventory?month=2026-08' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nCounts the stock you own, as inventory transactions does. Your movements over\nSeptember equal the difference between the August and September closes.\n\nOne request returns the whole report: no cursor, no summary sibling.\n`/reports/*` shares a smaller per-key budget: 60 requests per minute, separate\nfrom the 600 the rest of the API gets.\n","parameters":[{"name":"month","in":"query","description":"Any date inside the month — `2026-08` and `2026-08-15` both report\nAugust. Defaults to the most recently completed month. A future\nmonth reports the current one; a date we cannot read is a `400`.\n","schema":{"type":"string"},"examples":{"month":{"value":"2026-08"}}}],"responses":{"200":{"description":"One line per SKU holding stock at the cutoff.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonthEndInventoryReport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/reports/sad_cow":{"get":{"tags":["Reports"],"operationId":"getSadCowReport","summary":"Coming: units written off over a date range, per SKU and per reason","description":"Units written off, by SKU, by fulfillment center and by reason, as positive\ncounts. `occurred_at_min` and `occurred_at_max` default to the last completed\nweek.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/reports/sad_cow?occurred_at_min=2026-08-24\u0026occurred_at_max=2026-08-30' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nCounts picking and counting write-offs, not stock refused at the receiving dock:\nthat product never became stock we held. Every unit here also appears in\ninventory transactions with reason `sad_cow`.\n\nOne request returns the whole report: no cursor. `/reports/*` shares a smaller\nper-key budget: 60 requests per minute, separate from the 600 the rest of the\nAPI gets.\n","parameters":[{"$ref":"#/components/parameters/ReportOccurredAtMin"},{"$ref":"#/components/parameters/ReportOccurredAtMax"}],"responses":{"200":{"description":"One line per SKU written off in the range.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SadCowReport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/invoices":{"get":{"tags":["Invoices"],"operationId":"listInvoices","summary":"Coming: your finalized 3PL invoices, newest period first","description":"Your issued invoices, newest billing period first. Only issued invoices are\nreturned; drafts and voided invoices do not appear, and are not reachable by\nnumber either.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/invoices' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\n`id` is the invoice number printed on the document, and the identifier every\n`/invoices` path below takes. `status` is `sent` or `exported`. Money is a\ndecimal string in dollars with its `currency` beside it, never cents. `limit`\nand `cursor` work as they do on orders.\n","parameters":[{"name":"sort","in":"query","description":"Only `period_start`, ascending or descending. Defaults to newest\nperiod first.\n","schema":{"type":"string","enum":["period_start","-period_start"],"default":"-period_start"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of invoices.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/invoices/{id}":{"get":{"tags":["Invoices"],"operationId":"getInvoice","summary":"Coming: one invoice, with its summary lines and document links","description":"The list row plus `line_items`, `bill_to`, `ship_to` and `documents`.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/invoices/10421' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\n`line_items` is the stored invoice's summary of charges, not a recalculation,\nand does not change when a rate card does. Per-charge detail is not inline; it\nis the two paged lists, `/order_costs` and `/shipment_costs`. This body is a\nfixed size whatever the invoice covers.\n","parameters":[{"$ref":"#/components/parameters/InvoiceNumber"}],"responses":{"200":{"description":"The invoice.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/InvoiceNotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/invoices/{id}/order_costs":{"get":{"tags":["Invoices"],"operationId":"listInvoiceOrderCosts","summary":"Coming: the invoice's Order Costs rows, one per billed order","description":"What each order on the invoice cost, one row per billed order, in a stable\norder. Paged.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/invoices/10421/order_costs?limit=200' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nThe rates are the frozen ones the invoice was calculated from; the delivery\naddress and order numbers are read live, so a later address correction shows\nhere without changing what you were charged.\n\nThe cost lists share a smaller per-key budget: 60 requests per minute, separate\nfrom the 600 the rest of the API gets.\n","parameters":[{"$ref":"#/components/parameters/InvoiceNumber"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of order-cost rows.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCostList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/InvoiceNotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/invoices/{id}/shipment_costs":{"get":{"tags":["Invoices"],"operationId":"listInvoiceShipmentCosts","summary":"Coming: the invoice's Shipment Costs rows, one per billed shipment","description":"The same, per shipment: one row per shipment billed on this invoice, oldest\nshipped first, with the frozen per-shipment charges split into the columns the\ndetail workbook uses. Paged; walk it with `next_cursor`.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/invoices/10421/shipment_costs?limit=200' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nThe cost lists share a smaller per-key budget: 60 requests per minute, separate\nfrom the 600 the rest of the API gets.\n","parameters":[{"$ref":"#/components/parameters/InvoiceNumber"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of shipment-cost rows.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"Link":{"$ref":"#/components/headers/LinkNext"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShipmentCostList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/InvoiceNotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/invoices/{id}/document.pdf":{"get":{"tags":["Invoices"],"operationId":"getInvoicePdf","summary":"Coming: the invoice PDF we emailed you","description":"Takes your API key alone and answers `302` to the stored file, so follow\nredirects.\n\n```bash\ncurl --location 'https://www.crowdcow.com/api/fulfillment/v1/invoices/10421/document.pdf' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e' \\\n  --output invoice-10421.pdf\n```\n\n**You get the stored document, not one rendered on request.** This is the copy\nmade when the invoice was emailed, so it cannot disagree with the copy in your\ninbox. An issued invoice with no stored copy answers `404` with a `detail`\nsaying the document has not been generated. Retrying will not produce one; send\nus the invoice number.\n\nThe document routes share a smaller per-key budget: 60 requests per minute,\nseparate from the 600 the rest of the API gets.\n","parameters":[{"$ref":"#/components/parameters/InvoiceNumber"}],"responses":{"302":{"$ref":"#/components/responses/StoredDocument"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/InvoiceNotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/invoices/{id}/detail.xlsx":{"get":{"tags":["Invoices"],"operationId":"getInvoiceDetailWorkbook","summary":"Coming: the invoice detail workbook we emailed you","description":"Takes your API key alone and answers `302` to the stored spreadsheet — Summary,\nOrder Costs and Shipment Costs in one file, the same rows the endpoints above\nreturn. Follow redirects.\n\n```bash\ncurl --location 'https://www.crowdcow.com/api/fulfillment/v1/invoices/10421/detail.xlsx' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e' \\\n  --output invoice-10421.xlsx\n```\n\n**You get the stored document, not one rendered on request.** This is the copy\nmade when the invoice was emailed. An issued invoice with no stored copy answers\n`404` with a `detail` saying the document has not been generated. Retrying will\nnot produce one; send us the invoice number.\n\nThe document routes share a smaller per-key budget: 60 requests per minute,\nseparate from the 600 the rest of the API gets.\n","parameters":[{"$ref":"#/components/parameters/InvoiceNumber"}],"responses":{"302":{"$ref":"#/components/responses/StoredDocument"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/InvoiceNotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"x-status":"coming"}},"/openapi-next.json":{"get":{"tags":["Meta"],"operationId":"getOpenapiNextDocument","summary":"The end-state document, as JSON","description":"The API as it will be when the current build-out is finished. Operations\nmarked `x-status: coming` are not available yet; everything else is what\nthis document describes. Public, and needs no API key.\n","security":[],"responses":{"200":{"description":"The OpenAPI 3.1 description of the end-state API.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"type":"object"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/skus/{sku_id}":{"get":{"tags":["SKUs"],"operationId":"getSku","x-status":"coming","summary":"Coming: one SKU, with what is committed against it","description":"One SKU by your own identifier, plus two figures the list does not carry:\n`pending_reservations` and `packed_not_shipped`.\n\n```bash\ncurl 'https://www.crowdcow.com/api/fulfillment/v1/skus/s_ribeye_12oz' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\nBoth count **your** orders only. Units of the same SKU committed to another\norganization's order are not included.\n","parameters":[{"name":"sku_id","in":"path","required":true,"description":"Your own SKU identifier.","schema":{"type":"string"}}],"responses":{"200":{"description":"The SKU.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Sku"}}}},"404":{"$ref":"#/components/responses/NotFound"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/skus/{sku_id}/archive":{"post":{"tags":["SKUs"],"operationId":"archiveSku","x-status":"coming","summary":"Coming: archive a SKU","description":"Archiving retires a SKU from the working list. History, movements and past\norders are untouched, and the SKU stays readable by id.\n\n```bash\ncurl --request POST 'https://www.crowdcow.com/api/fulfillment/v1/skus/s_ribeye_12oz/archive' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n\n**`GET /skus` excludes archived SKUs by default.** `archived=include` returns\nthem alongside the active ones; `archived=only` returns just them.\n","parameters":[{"name":"sku_id","in":"path","required":true,"description":"Your own SKU identifier.","schema":{"type":"string"}}],"responses":{"200":{"description":"The SKU, with `archived` updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Sku"}}}},"404":{"$ref":"#/components/responses/NotFound"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/skus/{sku_id}/unarchive":{"post":{"tags":["SKUs"],"operationId":"unarchiveSku","x-status":"coming","summary":"Coming: unarchive a SKU","description":"Returns an archived SKU to the default `GET /skus` list. History, movements and\npast orders are unaffected either way.\n\n```bash\ncurl --request POST 'https://www.crowdcow.com/api/fulfillment/v1/skus/s_ribeye_12oz/unarchive' \\\n  --header 'X-Api-Key: \u003cYOUR_TOKEN\u003e'\n```\n","parameters":[{"name":"sku_id","in":"path","required":true,"description":"Your own SKU identifier.","schema":{"type":"string"}}],"responses":{"200":{"description":"The SKU, with `archived` updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Sku"}}}},"404":{"$ref":"#/components/responses/NotFound"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Your key in an `X-Api-Key` header.","type":"apiKey","in":"header","name":"X-Api-Key"},"BearerAuth":{"description":"The same key as a bearer token. Either header works; they are one\ncredential, not two.\n","type":"http","scheme":"bearer"}},"parameters":{"OrderId":{"name":"id","in":"path","required":true,"description":"Your own `order_id`, as sent to `PUT /orders`.","schema":{"type":"string"}},"Limit":{"name":"limit","in":"query","description":"Page size. A value above the maximum is clamped rather than refused.\nZero, a negative and a non-integer are each a `400`.\n","schema":{"type":"integer","default":50,"maximum":200}},"Cursor":{"name":"cursor","in":"query","description":"The `next_cursor` from the previous page. Opaque: do not construct or\nparse one. It carries the filters it was issued under, so changing a\nfilter part-way through a walk is a `400 /problems/cursor-invalid`.\nStart the walk again from the first page when you see it.\n","schema":{"type":"string"}},"InvoiceNumber":{"name":"id","in":"path","required":true,"description":"The `invoice_number` printed on the document — the number your\naccounts-payable team already has. Not a database id; there is no\nendpoint that takes one.\n","schema":{"type":"string"}},"MovementSkuId":{"name":"sku_id","in":"query","description":"Your own SKU identifier. Repeat as `sku_id[]=` or comma-separate — a\nbare repeated `sku_id=` keeps only the last value, which is Rack, not\nus.\n","schema":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"MovementReason":{"name":"reason","in":"query","description":"Narrow to one kind of movement. `pick` covers picks out of a prepacked\ncase as well as ordinary ones.\n","schema":{"type":"string","enum":["receiving","pick","cycle_count","sad_cow","delivery"]}},"MovementFc":{"name":"fc","in":"query","description":"A fulfillment centre code — `dunmore` is Scranton, PA.","schema":{"type":"string"}},"ReportOccurredAtMin":{"name":"occurred_at_min","in":"query","description":"Inclusive start of the range, `YYYY-MM-DD`. `min_date` is accepted as an\nalias. Give neither end and you get the most recently completed\nSunday–Saturday week; give only this one and the range runs to today. A\nstart in the future collapses to today.\n","schema":{"type":"string","format":"date"}},"ReportOccurredAtMax":{"name":"occurred_at_max","in":"query","description":"Inclusive end of the range, covering the whole Pacific day. `max_date`\nis accepted as an alias. Give only this one and the range opens back to\nyour first write-off — never past this end. A future end clamps to\ntoday; the response's `period` always says what was actually read.\n","schema":{"type":"string","format":"date"}},"MovementOccurredAtMin":{"name":"occurred_at_min","in":"query","description":"Inclusive lower bound, `YYYY-MM-DD`, read in Pacific time. `min_date` is\naccepted as an alias. Unparseable is a `400`, never a silently ignored\nfilter.\n","schema":{"type":"string","format":"date"}},"MovementOccurredAtMax":{"name":"occurred_at_max","in":"query","description":"Inclusive upper bound, covering the whole Pacific day — a movement at\n23:50 on the last day is in. `max_date` is accepted as an alias.\n","schema":{"type":"string","format":"date"}},"MovementOwner":{"name":"owner","in":"query","description":"`mine` (the default) is stock you own; `all` widens to every movement on\nyour SKUs, including Crowd Cow-owned units. Only `mine` reconciles\nagainst the month-end snapshot.\n","schema":{"type":"string","enum":["mine","all"],"default":"mine"}}},"headers":{"RateLimit":{"description":"Where you stand against whichever limit is closest to running out, per\ndraft-ietf-httpapi-ratelimit-headers-11 — e.g. `\"per-key\";r=597;t=42`.\n`r` is the requests left, `t` the seconds until the window resets.\n","required":true,"schema":{"type":"string"}},"RateLimitPolicy":{"description":"The quota and window of that same limit — e.g. `\"per-key\";q=600;w=60`.\nThe policy is named `per-key`, `per-ip` or `per-ip-total`.\n","required":true,"schema":{"type":"string"}},"RetryAfter":{"description":"Whole seconds to wait before retrying. Always present on a 429, and\nalways a positive integer.\n","required":true,"schema":{"type":"string"}},"LinkNext":{"description":"RFC 8288 `\u003c…\u003e; rel=\"next\"`, the same page `next_cursor` points at.\nAbsent on the last page, which is how a header-following client knows\nthe walk is over.\n","required":false,"schema":{"type":"string"}}},"responses":{"Unauthorized":{"description":"No API key, or one we do not recognize. Always this shape, whatever key\nyou hold.\n","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Forbidden":{"description":"Your key cannot reach this endpoint: quote and shipment calendar are\n3PL accounts only, and the SKU endpoints need an account with a\nfulfillment vendor.\n","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"NotFound":{"description":"No order with that `order_id` in your account.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"BadRequest":{"description":"A parameter was unreadable, named a value that is not in its\nvocabulary, or the cursor was not one we issued.\n","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"UnprocessableMessage":{"description":"A request body was unreadable, or the order is too far along for the\nchange.\n","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"UnprocessableErrors":{"description":"The upsert failed. `errors` carries one entry per thing that was wrong.\n","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"TooManyRequests":{"description":"A rate limit was exceeded. Always this shape, whatever key you hold.\n`Retry-After` says how long to wait.\n","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"InvoiceNotFound":{"description":"No invoice of yours carries that number. A draft or voided invoice\nanswers the same way: neither is a document you hold, so neither is\nlisted or reachable. A document endpoint also answers this when the\ninvoice exists but was never emailed, so no file was ever stored — the\n`detail` says which case it is.\n","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"StoredDocument":{"description":"A redirect to the stored file. Follow `Location`; it is a time-limited\nURL, so fetch it rather than saving it.\n","headers":{"Location":{"description":"Where the stored file is.","required":true,"schema":{"type":"string"}},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"text/html":{"schema":{"type":"string"}}}}},"schemas":{"Problem":{"description":"RFC 9457. Branch on `type`, never on the wording of `detail` — `detail`\nis written for a person and may be reworded without notice.\n","type":"object","additionalProperties":false,"required":["type","title","status"],"properties":{"type":{"type":"string","description":"A relative, non-resolvable problem URI, e.g. `/problems/not-found`.","enum":["/problems/unauthorized","/problems/forbidden","/problems/not-found","/problems/validation-error","/problems/policy-refused","/problems/cursor-invalid","/problems/quota-exceeded"]},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string","description":"`/requests/\u003cid\u003e` — quote it to us and we can find the request.\n"},"errors":{"description":"One entry per field that failed validation of a request body.","type":"array","items":{"type":"object","additionalProperties":false,"required":["code","detail"],"properties":{"pointer":{"type":"string"},"code":{"type":"string"},"detail":{"type":"string"}}}},"reasons":{"description":"Why the change was refused, in plain sentences.","type":"array","items":{"type":"string"}}},"example":{"type":"/problems/validation-error","title":"Request is not valid.","status":400,"detail":"status must be one of: not_packed, packed, shipped, cancelled","instance":"/requests/7f1c3e2a-4b8d-4e91-9c2a-1f5e8d3b7a60"}},"OrderList":{"description":"A page of orders. No total is returned; walk with `next_cursor`.","type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"has_more":{"type":"boolean","description":"Whether a further page exists."},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; `null` on the last one."}},"example":{"data":[{"fc":"dunmore","order_id":"1234567","customer_order_id":"456","scheduled_fulfillment_date":"2026-06-02","can_modify":true,"cancelled_at":null,"shipping_method":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS"},"packaging":{"dry_ice_in_pounds":10},"items":[{"sku":"s_ribeye_12oz","quantity":2,"weight":"12 oz"},{"sku":"s_bison_burger_8pk","quantity":1,"weight":4.0}],"shipping_address":{"name":"John Doe","address_1":"123 Main St","address_2":"Apt 1","city":"Kirkland","state":"WA","postal_code":"98033","phone_number":"(206) 555-1212","delivery_instructions":"Gate code 4432"},"sender_name":"Jane Roe","gift_message":"Happy birthday, John!","billing_address":{"address_1":"123 Billing St","address_2":"Suite 500","city":"Seattle","state":"WA","postal_code":"98104"},"shipments":[{"tracking_number":"1Z999AA10123456784","carrier":"UPS","service":"Ground","tracking_url":"https://www.ups.com/track?tracknum=1Z999AA10123456784","anticipated_delivery_date":"2026-06-04","delivered_at":"2026-06-04T19:47:00Z","shipped_at":"2026-06-02T01:31:00Z"}],"updated_at":"2026-06-03T14:02:11Z"},{"fc":"dallas","order_id":"1234568","customer_order_id":"457","scheduled_fulfillment_date":"2026-06-09","can_modify":false,"cancelled_at":"2026-06-06T16:40:00Z","shipping_method":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS"},"packaging":{"dry_ice_in_pounds":10},"items":[{"sku":"s_bison_burger_8pk","quantity":2,"weight":4.0}],"shipping_address":{"name":"John Doe","address_1":"123 Main St","address_2":"Apt 1","city":"Kirkland","state":"WA","postal_code":"98033","phone_number":"(206) 555-1212","delivery_instructions":"Gate code 4432"},"sender_name":"Jane Roe","gift_message":"Enjoy!","billing_address":{"address_1":"123 Billing St","address_2":"Suite 500","city":"Seattle","state":"WA","postal_code":"98104"},"shipments":[],"updated_at":"2026-05-29T09:15:00Z"}],"has_more":true,"next_cursor":"eyJ2IjoiMjAyNi0wNi0wMiJ9"}},"SkuList":{"type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Sku"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"example":{"data":[{"id":"s_ribeye_12oz","name":"Ribeye 12oz","weight":0.75,"barcode":"0123456789012","width":2.0,"length":1.0,"height":3.0,"inventory":{"dunmore":{"on_hand_quantity":40,"reserved_quantity":12,"available_quantity":28},"dallas":{"on_hand_quantity":0,"reserved_quantity":0,"available_quantity":0},"watsonville":{"on_hand_quantity":15,"reserved_quantity":3,"available_quantity":12}}},{"id":"s_bison_burger_8pk","name":"Bison Burger 8pk","weight":2.0,"barcode":"0123456789029","width":6.0,"length":8.0,"height":2.5,"inventory":{"dunmore":{"on_hand_quantity":22,"reserved_quantity":4,"available_quantity":18},"dallas":{"on_hand_quantity":9,"reserved_quantity":1,"available_quantity":8},"watsonville":{"on_hand_quantity":0,"reserved_quantity":0,"available_quantity":0}}}],"has_more":true,"next_cursor":"eyJ2IjoiMjAyNi0wOC0xNCJ9"}},"FcCode":{"type":["string","null"],"description":"A fulfillment center code as this API spells it — `dunmore` is Scranton, PA.\n","examples":["dunmore"],"example":"dunmore"},"Sku":{"type":"object","additionalProperties":false,"required":["id","name","weight","barcode","width","length","height","inventory"],"properties":{"id":{"type":["string","null"],"description":"Your own SKU identifier."},"name":{"type":["string","null"]},"weight":{"type":["number","null"],"description":"Pounds."},"barcode":{"type":["string","null"]},"width":{"type":["number","null"],"description":"Inches."},"length":{"type":["number","null"],"description":"Inches."},"height":{"type":["number","null"],"description":"Inches."},"inventory":{"type":"object","description":"Keyed by fulfillment center code.","additionalProperties":{"$ref":"#/components/schemas/SkuInventory"}},"archived":{"type":"boolean","description":"Archived SKUs are excluded from the list unless you ask for them."},"perishable":{"type":"boolean"},"internal_notes":{"type":"string","description":"Your own notes. Writable through `PUT /skus`."},"images":{"type":"array","items":{"type":"string"},"description":"Image URLs."},"weeks_of_stock":{"type":"object","description":"Cover at current sales velocity: `total`, and one entry per\nfulfillment center.\n","properties":{"total":{"type":"number"},"by_fc":{"type":"object","additionalProperties":{"type":"number"}}}},"inventory_cost":{"type":"object","description":"Your cost basis per fulfillment center. Omitted for a SKU you\nresell rather than own.\n","additionalProperties":{"type":"string"}}},"example":{"id":"s_ribeye_12oz","name":"Ribeye 12oz","weight":0.75,"barcode":"0123456789012","width":2.0,"length":1.0,"height":3.0,"inventory":{"dunmore":{"on_hand_quantity":40,"reserved_quantity":12,"available_quantity":28},"dallas":{"on_hand_quantity":0,"reserved_quantity":0,"available_quantity":0},"watsonville":{"on_hand_quantity":15,"reserved_quantity":3,"available_quantity":12}}}},"SkuInventory":{"type":"object","additionalProperties":false,"required":["on_hand_quantity","reserved_quantity","available_quantity"],"properties":{"on_hand_quantity":{"type":"integer","description":"Physical stock."},"reserved_quantity":{"type":"integer","description":"Committed to orders not yet shipped."},"available_quantity":{"type":"integer","description":"What you can still sell. Quote against this."}},"example":{"on_hand_quantity":40,"reserved_quantity":12,"available_quantity":28}},"SkuUpsertRequest":{"type":"object","required":["sku_id"],"properties":{"sku_id":{"type":"string","description":"Your identifier. Stable — this is what order `items` reference."},"name":{"type":["string","null"]},"weight":{"type":["number","string","null"],"description":"Pounds."},"barcode":{"type":["string","null"]},"width":{"type":["number","string","null"],"description":"Inches."},"length":{"type":["number","string","null"],"description":"Inches."},"height":{"type":["number","string","null"],"description":"Inches."},"internal_notes":{"type":"string"},"perishable":{"type":"boolean"},"images":{"type":"array","items":{"type":"string"}}},"example":{"sku_id":"s_ribeye_12oz","name":"Ribeye 12oz","weight":0.75,"barcode":"0123456789012","width":2.0,"length":1.0,"height":3.0}},"Order":{"type":"object","additionalProperties":false,"required":["fc","order_id","customer_order_id","scheduled_fulfillment_date","can_modify","cancelled_at","shipping_method","packaging","items","shipping_address","sender_name","gift_message","billing_address","shipments","updated_at"],"properties":{"fc":{"$ref":"#/components/schemas/FcCode"},"order_id":{"type":["string","null"],"description":"Your own internal identifier."},"customer_order_id":{"type":["string","null"],"description":"The number your customer sees."},"scheduled_fulfillment_date":{"type":["string","null"],"format":"date"},"can_modify":{"type":"boolean","description":"Whether this order can still be changed through the API."},"cancelled_at":{"type":["string","null"],"format":"date-time"},"shipping_method":{"$ref":"#/components/schemas/OrderShippingMethod"},"packaging":{"$ref":"#/components/schemas/OrderPackaging"},"items":{"type":"array","description":"Your own products only — Crowd Cow packing inserts are excluded.","items":{"$ref":"#/components/schemas/OrderItem"}},"shipping_address":{"$ref":"#/components/schemas/ShippingAddress"},"sender_name":{"type":["string","null"]},"gift_message":{"type":["string","null"]},"billing_address":{"$ref":"#/components/schemas/BillingAddress"},"shipments":{"type":"array","description":"Shipped shipments only. An order that has not shipped has an empty\narray, not a placeholder.\n","items":{"$ref":"#/components/schemas/OrderShipment"}},"updated_at":{"type":"string","description":"RFC 3339 UTC. Changes whenever anything on the order does."}},"example":{"fc":"dunmore","order_id":"1234567","customer_order_id":"456","scheduled_fulfillment_date":"2026-06-02","can_modify":true,"cancelled_at":null,"shipping_method":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS"},"packaging":{"dry_ice_in_pounds":10},"items":[{"sku":"s_ribeye_12oz","quantity":2,"weight":"12 oz"},{"sku":"s_bison_burger_8pk","quantity":1,"weight":4.0}],"shipping_address":{"name":"John Doe","address_1":"123 Main St","address_2":"Apt 1","city":"Kirkland","state":"WA","postal_code":"98033","phone_number":"(206) 555-1212","delivery_instructions":"Gate code 4432"},"sender_name":"Jane Roe","gift_message":"Happy birthday, John!","billing_address":{"address_1":"123 Billing St","address_2":"Suite 500","city":"Seattle","state":"WA","postal_code":"98104"},"shipments":[{"tracking_number":"1Z999AA10123456784","carrier":"UPS","service":"Ground","tracking_url":"https://www.ups.com/track?tracknum=1Z999AA10123456784","anticipated_delivery_date":"2026-06-04","delivered_at":"2026-06-04T19:47:00Z","shipped_at":"2026-06-02T01:31:00Z"}],"updated_at":"2026-06-03T14:02:11Z"}},"OrderShippingMethod":{"type":"object","additionalProperties":false,"required":["carrier","service","shipping_option_name"],"properties":{"carrier":{"type":["string","null"]},"service":{"type":["string","null"]},"shipping_option_name":{"type":["string","null"]}},"example":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS"}},"OrderPackaging":{"type":"object","additionalProperties":false,"required":["dry_ice_in_pounds"],"properties":{"dry_ice_in_pounds":{"type":"integer","description":"Whole pounds."}},"example":{"dry_ice_in_pounds":10}},"OrderItem":{"type":"object","additionalProperties":false,"required":["sku","quantity","weight"],"properties":{"sku":{"type":["string","null"]},"quantity":{"type":["integer","null"],"description":"What was originally ordered, not what was picked."},"weight":{"type":["number","string","null"],"description":"Pounds as a number, unless the SKU opts into grams or ounces, in\nwhich case it is a labeled string such as `\"8 oz\"`.\n"}},"example":{"sku":"s_ribeye_12oz","quantity":2,"weight":"12 oz"}},"ShippingAddress":{"type":"object","additionalProperties":false,"required":["name","address_1","address_2","city","state","postal_code","phone_number","delivery_instructions"],"properties":{"name":{"type":["string","null"]},"address_1":{"type":["string","null"]},"address_2":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"phone_number":{"type":["string","null"]},"delivery_instructions":{"type":["string","null"]}},"example":{"name":"John Doe","address_1":"123 Main St","address_2":"Apt 1","city":"Kirkland","state":"WA","postal_code":"98033","phone_number":"(206) 555-1212","delivery_instructions":"Gate code 4432"}},"BillingAddress":{"type":"object","additionalProperties":false,"required":["address_1","address_2","city","state","postal_code"],"properties":{"address_1":{"type":["string","null"]},"address_2":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"postal_code":{"type":["string","null"]}},"example":{"address_1":"123 Billing St","address_2":"Suite 500","city":"Seattle","state":"WA","postal_code":"98104"}},"OrderShipment":{"type":"object","additionalProperties":false,"required":["tracking_number","carrier","service","tracking_url","anticipated_delivery_date","delivered_at","shipped_at"],"properties":{"tracking_number":{"type":["string","null"]},"carrier":{"type":["string","null"]},"service":{"type":["string","null"]},"tracking_url":{"type":["string","null"]},"anticipated_delivery_date":{"type":["string","null"],"format":"date"},"delivered_at":{"type":["string","null"],"format":"date-time"},"shipped_at":{"type":["string","null"],"format":"date-time"}},"example":{"tracking_number":"1Z999AA10123456784","carrier":"UPS","service":"Ground","tracking_url":"https://www.ups.com/track?tracknum=1Z999AA10123456784","anticipated_delivery_date":"2026-06-04","delivered_at":"2026-06-04T19:47:00Z","shipped_at":"2026-06-02T01:31:00Z"}},"OrderUpsertRequest":{"type":"object","required":["order_id","items","shipping_address"],"properties":{"order_id":{"type":"string","description":"Your internal identifier; the key for every other endpoint."},"customer_order_id":{"type":["string","null"]},"items":{"type":"array","items":{"type":"object","required":["sku","quantity"],"properties":{"sku":{"type":"string","description":"A SKU id, or one of your pack codes, which is expanded."},"quantity":{"type":["integer","string"]}}}},"shipping_address":{"$ref":"#/components/schemas/ShippingAddressInput"},"billing_address":{"$ref":"#/components/schemas/BillingAddressInput"},"fc":{"type":["string","null"],"description":"Pin to a fulfillment center. Omit to let Crowd Cow route."},"shipping_method":{"type":["object","null"],"description":"Omitted leaves any existing override alone; a carrier and service\npins the order; explicit nulls clear the override.\n","properties":{"carrier":{"type":["string","null"]},"service":{"type":["string","null"]}}},"packaging":{"type":["object","null"],"description":"Send one or the other. Kilograms are converted to pounds and\nrounded before the override is written.\n","properties":{"dry_ice_in_pounds":{"type":["number","string","null"]},"dry_ice_in_kilograms":{"type":["number","string","null"]}}},"sender_name":{"type":["string","null"]},"gift_message":{"type":["string","null"]},"recipient_name":{"type":["string","null"]},"recipient_email":{"type":["string","null"]},"email":{"type":["string","null"]},"preferred_arrival_date":{"type":["string","null"],"description":"The date your checkout promised. Picks the slot, not the service; a\ndate in the past is ignored.\n"},"external_references":{"type":"array","items":{"type":"object","properties":{"system":{"type":["string","null"]},"key":{"type":["string","null"]},"value":{"type":["string","null"]}}}},"source_system":{"type":["string","null"]},"origin_channel":{"type":["string","null"]}},"example":{"order_id":"1234567","customer_order_id":"456","items":[{"sku":"s_ribeye_12oz","quantity":2},{"sku":"s_bison_burger_8pk","quantity":1}],"shipping_address":{"name":"John Doe","address_1":"123 Main St","address_2":"Apt 1","city":"Kirkland","state":"WA","postal_code":"98033","phone_number":"(206) 555-1212","delivery_instructions":"Gate code 4432","country_code":"US"},"billing_address":{"name":"John Doe","address_1":"123 Billing St","address_2":"Suite 500","city":"Seattle","state":"WA","postal_code":"98104","phone_number":"(206) 555-1212"},"fc":"dunmore","shipping_method":{"carrier":"UPS","service":"Ground"},"packaging":{"dry_ice_in_pounds":10},"sender_name":"Jane Roe","gift_message":"Happy birthday, John!","recipient_name":"John Doe","recipient_email":"john.doe@example.com","email":"jane.roe@example.com","preferred_arrival_date":"2026-06-04","external_references":[{"system":"shopify","key":"order_gid","value":"gid://shopify/Order/5512341234567"}],"source_system":"shopify","origin_channel":"web"}},"ShippingAddressInput":{"type":"object","description":"The response carries all eight keys; a request may send any subset.\n`state` and `postal_code` must agree — a mismatch fails the whole\nrequest with `422` and no order is created. Unknown and non-US ZIPs\npass, and the city is not checked.\n","properties":{"name":{"type":["string","null"]},"address_1":{"type":["string","null"]},"address_2":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"phone_number":{"type":["string","null"]},"delivery_instructions":{"type":["string","null"]},"country_code":{"type":["string","null"],"description":"Read only by the state/ZIP consistency check, which skips non-US\naddresses. `country` is accepted as a synonym and used when\n`country_code` is blank. Neither is stored on the order, and\nneither comes back on the order object.\n"},"country":{"type":["string","null"]}},"example":{"name":"John Doe","address_1":"123 Main St","address_2":"Apt 1","city":"Kirkland","state":"WA","postal_code":"98033","phone_number":"(206) 555-1212","delivery_instructions":"Gate code 4432","country_code":"US","country":"United States"}},"BillingAddressInput":{"type":"object","properties":{"name":{"type":["string","null"]},"address_1":{"type":["string","null"]},"address_2":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"phone_number":{"type":["string","null"]}},"example":{"name":"John Doe","address_1":"123 Billing St","address_2":"Suite 500","city":"Seattle","state":"WA","postal_code":"98104","phone_number":"(206) 555-1212"}},"OverrideIceRequest":{"type":"object","description":"One of the two keys must be present. An empty value clears the\noverride; omitting both is a `422`.\n","properties":{"dry_ice_in_pounds":{"type":["number","string","null"]},"dry_ice_in_kilograms":{"type":["number","string","null"]}},"example":{"dry_ice_in_pounds":10}},"OverrideShippingMethodRequest":{"type":"object","properties":{"carrier":{"type":["string","null"]},"service":{"type":["string","null"]}},"example":{"carrier":"UPS","service":"Ground"}},"RescheduleRequest":{"type":"object","properties":{"arrival_date":{"type":["string","null"]},"shipping_option_name":{"type":["string","null"]},"carrier":{"type":["string","null"]},"service":{"type":["string","null"]}},"example":{"arrival_date":"2026-06-04","shipping_option_name":"MEM LH UPS","carrier":"UPS","service":"Ground"}},"ReschedulingOptions":{"type":"object","additionalProperties":false,"required":["order_id","current_arrival_date","current_shipping_option_name","options"],"properties":{"order_id":{"type":["string","null"]},"current_arrival_date":{"type":["string","null"],"format":"date"},"current_shipping_option_name":{"type":["string","null"]},"options":{"type":"array","items":{"$ref":"#/components/schemas/ReschedulingPlan"}}},"example":{"order_id":"1234567","current_arrival_date":"2026-06-04","current_shipping_option_name":"MEM LH UPS","options":[{"arrival_date":"2026-06-04","fulfillment_date":"2026-06-02","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dunmore","preferred":true},{"arrival_date":"2026-06-11","fulfillment_date":"2026-06-09","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dallas","preferred":false}]}},"ReschedulingPlan":{"type":"object","additionalProperties":false,"required":["arrival_date","fulfillment_date","transit_days","carrier","service","shipping_option_name","fc","preferred"],"properties":{"arrival_date":{"type":["string","null"],"format":"date"},"fulfillment_date":{"type":["string","null"],"format":"date"},"transit_days":{"type":["integer","null"]},"carrier":{"type":["string","null"]},"service":{"type":["string","null"]},"shipping_option_name":{"type":["string","null"]},"fc":{"$ref":"#/components/schemas/FcCode"},"preferred":{"type":"boolean"}},"example":{"arrival_date":"2026-06-04","fulfillment_date":"2026-06-02","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dunmore","preferred":true}},"ShipmentCalendar":{"type":"object","additionalProperties":false,"required":["postal_code","default_plan","plans"],"properties":{"postal_code":{"type":"string","description":"The normalized five-digit code the plans were built for."},"default_plan":{"description":"The first preferred ground plan, or null when none qualifies.","oneOf":[{"$ref":"#/components/schemas/CalendarPlan"},{"type":"null"}]},"plans":{"type":"array","items":{"$ref":"#/components/schemas/CalendarPlan"}}},"example":{"postal_code":"98101","default_plan":{"fulfillment_date":"2026-06-02","arrival_date":"2026-06-04","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dunmore","preferred":true,"tier":"preferred"},"plans":[{"fulfillment_date":"2026-06-02","arrival_date":"2026-06-04","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dunmore","preferred":true,"tier":"preferred"},{"fulfillment_date":"2026-06-02","arrival_date":"2026-06-04","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dunmore","preferred":true,"tier":"expedited"},{"fulfillment_date":"2026-06-03","arrival_date":"2026-06-05","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"WAT LH UPS","fc":"watsonville","preferred":false,"tier":"standard"},{"fulfillment_date":"2026-06-03","arrival_date":"2026-06-06","transit_days":3,"carrier":"UPS","service":"Ground","shipping_option_name":"DAL LH UPS","fc":"dallas","preferred":false,"tier":"standard"}]}},"CalendarPlan":{"type":"object","additionalProperties":false,"required":["fulfillment_date","arrival_date","transit_days","carrier","service","shipping_option_name","fc","preferred","tier"],"properties":{"fulfillment_date":{"type":"string","format":"date"},"arrival_date":{"type":"string","format":"date"},"transit_days":{"type":["integer","null"]},"carrier":{"type":["string","null"]},"service":{"type":["string","null"]},"shipping_option_name":{"type":["string","null"]},"fc":{"$ref":"#/components/schemas/FcCode"},"preferred":{"type":"boolean"},"tier":{"type":"string","enum":["preferred","standard","expedited"],"description":"A ground plan that also serves the expedited speed appears twice,\nonce per tier.\n"}},"example":{"fulfillment_date":"2026-06-02","arrival_date":"2026-06-04","transit_days":2,"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","fc":"dunmore","preferred":true,"tier":"preferred"}},"QuoteRequest":{"type":"object","required":["destination","items"],"properties":{"destination":{"type":"object","required":["postal_code"],"properties":{"postal_code":{"type":"string"}}},"items":{"type":"array","items":{"type":"object","required":["sku_id","quantity"],"properties":{"sku_id":{"type":"string","description":"Your own SKU identifier."},"quantity":{"type":["integer","string"],"description":"A positive integer."}}}},"requested_delivery_date":{"type":["string","null"],"format":"date","description":"If it cannot be met, the next available date is quoted and a\n`reason` is attached to that shipment.\n"}},"example":{"destination":{"postal_code":"98101"},"items":[{"sku_id":"s_ribeye_12oz","quantity":2},{"sku_id":"s_bison_burger_8pk","quantity":1}],"requested_delivery_date":"2026-06-05"}},"Quote":{"type":"object","additionalProperties":false,"required":["shipments","ground_eligibility","quoted_at","advisory"],"properties":{"shipments":{"type":"array","description":"One entry per fulfillment center used.","items":{"$ref":"#/components/schemas/QuoteShipment"}},"unfulfillable":{"type":"array","description":"Present only when something cannot be quoted.","items":{"$ref":"#/components/schemas/QuoteUnfulfillable"}},"ground_eligibility":{"$ref":"#/components/schemas/GroundEligibility"},"quoted_at":{"type":"string","format":"date-time"},"advisory":{"type":"string"}},"example":{"shipments":[{"fc":{"code":"dunmore","display":"ships from your area"},"items":[{"sku_id":"s_ribeye_12oz","quantity":2},{"sku_id":"s_bison_burger_8pk","quantity":1}],"fulfillment_date":"2026-06-02","delivery_date":"2026-06-04","transit_days":2,"rate":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","preferred":true}}],"ground_eligibility":{"eligible":true,"nearest_fc":{"code":"dunmore","display":"your nearest fulfillment warehouse"},"blockers":[]},"quoted_at":"2026-06-01T16:00:00Z","advisory":"Estimate at quote time. CC re-routes at order import if inventory has moved."}},"QuoteShipment":{"type":"object","additionalProperties":false,"required":["fc","items","fulfillment_date","delivery_date","transit_days","rate"],"properties":{"fc":{"$ref":"#/components/schemas/QuoteFc"},"items":{"type":"array","items":{"$ref":"#/components/schemas/QuoteItem"}},"fulfillment_date":{"type":"string","format":"date"},"delivery_date":{"type":"string","format":"date"},"transit_days":{"type":["integer","null"]},"rate":{"$ref":"#/components/schemas/QuoteRate"},"reason":{"type":"string","description":"Present only when noteworthy — the requested date was unavailable,\nor this is a secondary shipment because the primary center was short.\n"}},"example":{"fc":{"code":"dunmore","display":"ships from your area"},"items":[{"sku_id":"s_ribeye_12oz","quantity":2},{"sku_id":"s_bison_burger_8pk","quantity":1}],"fulfillment_date":"2026-06-02","delivery_date":"2026-06-04","transit_days":2,"rate":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","preferred":true},"reason":"requested_delivery_date_2026-06-05_not_offered_at_destination; next_available_used"}},"QuoteFc":{"type":"object","additionalProperties":false,"required":["code","display"],"properties":{"code":{"$ref":"#/components/schemas/FcCode"},"display":{"type":"string","description":"A customer-safe string that never names the warehouse."}},"example":{"code":"dunmore","display":"ships from your area"}},"QuoteItem":{"type":"object","additionalProperties":false,"required":["sku_id","quantity"],"properties":{"sku_id":{"type":"string"},"quantity":{"type":"integer"}},"example":{"sku_id":"s_ribeye_12oz","quantity":2}},"QuoteRate":{"type":"object","additionalProperties":false,"required":["carrier","service","shipping_option_name","preferred"],"properties":{"carrier":{"type":["string","null"]},"service":{"type":["string","null"]},"shipping_option_name":{"type":["string","null"]},"preferred":{"type":"boolean"}},"example":{"carrier":"UPS","service":"Ground","shipping_option_name":"MEM LH UPS","preferred":true}},"QuoteUnfulfillable":{"type":"object","additionalProperties":false,"required":["sku_id","quantity_requested","quantity_available_across_all_fcs","reason"],"properties":{"sku_id":{"type":"string"},"quantity_requested":{"type":"integer"},"quantity_available_across_all_fcs":{"type":"integer"},"reason":{"type":"string","enum":["no_fc_has_inventory","insufficient_inventory_across_all_fcs","no_shipping_options_available","no_eligible_shipment_plan"]}},"example":{"sku_id":"s_bison_burger_8pk","quantity_requested":1,"quantity_available_across_all_fcs":0,"reason":"no_fc_has_inventory"}},"GroundEligibility":{"type":"object","additionalProperties":false,"required":["eligible","nearest_fc","blockers"],"properties":{"eligible":{"type":"boolean","description":"True only when every item ships and every shipment is a ground\nservice. False with empty `blockers` means air was quoted for\nspeed, not for lack of stock.\n"},"nearest_fc":{"oneOf":[{"$ref":"#/components/schemas/QuoteFc"},{"type":"null"}]},"blockers":{"type":"array","description":"What the nearest ground center is short on.","items":{"$ref":"#/components/schemas/GroundBlocker"}}},"example":{"eligible":true,"nearest_fc":{"code":"dunmore","display":"your nearest fulfillment warehouse"},"blockers":[]}},"GroundBlocker":{"type":"object","additionalProperties":false,"required":["sku_id","requested_quantity","available_quantity","recommended_max_quantity","reason"],"properties":{"sku_id":{"type":"string"},"requested_quantity":{"type":"integer"},"available_quantity":{"type":"integer"},"recommended_max_quantity":{"type":"integer","description":"Reduce to this to keep ground shipping."},"reason":{"type":"string","enum":["insufficient_inventory_at_nearest_fc"]}},"example":{"sku_id":"s_ribeye_12oz","requested_quantity":2,"available_quantity":1,"recommended_max_quantity":1,"reason":"insufficient_inventory_at_nearest_fc"}},"ShipmentList":{"description":"No total, as everywhere else. `/shipments/summary` takes the same filters\nand answers the counting questions.\n","type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Shipment"}},"has_more":{"type":"boolean","description":"Whether a further page exists."},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; `null` on the last one."}},"example":{"data":[{"id":"shp_9f2c1a","order_id":"1234567","customer_order_id":"456","shipment_number":2,"ship_date":"2026-06-02","shipped_at":"2026-06-02T01:31:00Z","recipient":"John Doe","destination":"Kirkland, WA","carrier":"UPS","service":"Ground","tracking_number":"1Z999AA10123456784","tracking_url":"https://www.ups.com/track?tracknum=1Z999AA10123456784","status":"in_transit","last_scan":{"at":"2026-06-03T14:02:00Z","location":"Sparks, NV","message":"Departed facility"},"promised_arrival":"2026-06-04","predicted_arrival":"2026-06-05","delivered_at":null,"days_late":1,"late_reasons":["Carrier delay"],"tracking_alerts":["mechanical_delay"],"write_off":null,"updated_at":"2026-06-03T14:07:22Z"},{"id":"shp_7b41e0","order_id":"1234566","customer_order_id":"455","shipment_number":1,"ship_date":"2026-06-01","shipped_at":"2026-06-01T01:28:00Z","recipient":"Maria Alvarez","destination":"Austin, TX","carrier":"FedEx","service":"FEDEX_2_DAY","tracking_number":"398112345678","tracking_url":"https://www.fedex.com/fedextrack/?trknbr=398112345678","status":"delivered","last_scan":{"at":"2026-06-03T11:42:00Z","location":"Austin, TX","message":"Delivered, front door"},"promised_arrival":"2026-06-03","predicted_arrival":"2026-06-03","delivered_at":"2026-06-03T11:42:00Z","days_late":0,"late_reasons":[],"tracking_alerts":[],"write_off":null,"updated_at":"2026-06-03T11:45:10Z"}],"has_more":true,"next_cursor":"c2hpcG1lbnRzOnNoaXBfZGF0ZTpkZXNjfDIwMjYtMDYtMDF8c2hwXzdiNDFlMA"}},"Shipment":{"description":"One box.","type":"object","additionalProperties":false,"required":["id","order_id","shipment_number","status","days_late","late_reasons","tracking_alerts","updated_at"],"properties":{"id":{"type":"string","description":"Stable for the life of the box. `shipment_number` is an ordinal\nwithin its order and is not an identifier.\n"},"order_id":{"type":"string","description":"Your own identifier for the order where you sent one, our order\nnumber otherwise — the same value the `order_id` filter matches.\n"},"customer_order_id":{"type":["string","null"],"description":"The number your customer sees, where you sent one."},"shipment_number":{"type":"integer","description":"Which box of the order this is, from 1. An order that ships in one\nbox says 1.\n"},"ship_date":{"type":["string","null"],"description":"`YYYY-MM-DD`. The day the box was scheduled to leave."},"shipped_at":{"type":["string","null"],"format":"date-time","description":"When the carrier took it. Null until then."},"recipient":{"type":["string","null"]},"destination":{"type":["string","null"],"description":"City and state, e.g. `Seattle, WA`."},"carrier":{"type":["string","null"],"description":"The carrier as the label was bought, e.g. `UPS`, `FedEx`,\n`AxleHire` — the vocabulary the `carrier` filter accepts. It is the\ncarrier's own name, not a display name you may see elsewhere.\n"},"service":{"type":["string","null"],"description":"The carrier's own service code, e.g. `2ndDayAir`."},"tracking_number":{"type":["string","null"]},"tracking_url":{"type":["string","null"],"description":"The carrier's own tracking page for this box."},"status":{"type":"string","enum":["not_shipped","in_transit","out_for_delivery","delivered"],"description":"Delivery stage. A box out for delivery is also in transit; we report\nthe more specific one.\n"},"last_scan":{"description":"The carrier's most recent scan. Null before the first one.","oneOf":[{"type":"object","additionalProperties":false,"properties":{"at":{"type":["string","null"],"format":"date-time"},"location":{"type":["string","null"]},"message":{"type":["string","null"]}}},{"type":"null"}]},"promised_arrival":{"type":["string","null"],"description":"`YYYY-MM-DD`. The date we promised the recipient."},"predicted_arrival":{"type":["string","null"],"description":"`YYYY-MM-DD`. The carrier's own current estimate."},"delivered_at":{"type":["string","null"],"format":"date-time"},"days_late":{"type":"integer","description":"Days past the promise, counting to delivery or to today. `0` for a\nbox written off — a lost box is not late, it is gone.\n"},"late_reasons":{"type":"array","description":"Why it ran late. Empty for a box that is not late.","items":{"type":"string"}},"tracking_alerts":{"type":"array","description":"Problems the carrier has posted against this box.","items":{"type":"string"}},"write_off":{"type":["string","null"],"enum":[null,"lost","destroyed_in_transit"],"description":"Null unless the box was written off."},"updated_at":{"type":"string","format":"date-time","description":"Last write to the box, tracking scans included — the column\n`updated_at_min` filters on.\n"}},"example":{"id":"shp_9f2c1a","order_id":"1234567","customer_order_id":"456","shipment_number":2,"ship_date":"2026-06-02","shipped_at":"2026-06-02T01:31:00Z","recipient":"John Doe","destination":"Kirkland, WA","carrier":"UPS","service":"Ground","tracking_number":"1Z999AA10123456784","tracking_url":"https://www.ups.com/track?tracknum=1Z999AA10123456784","status":"in_transit","last_scan":{"at":"2026-06-03T14:02:00Z","location":"Sparks, NV","message":"Departed facility"},"promised_arrival":"2026-06-04","predicted_arrival":"2026-06-05","delivered_at":null,"days_late":1,"late_reasons":["Carrier delay"],"tracking_alerts":["mechanical_delay"],"write_off":null,"updated_at":"2026-06-03T14:07:22Z"}},"ShipmentSummary":{"type":"object","additionalProperties":false,"required":["total","late","tracking_alert","never_arriving","carriers"],"properties":{"total":{"type":"integer"},"late":{"type":"integer","description":"Past the promised date, and not written off."},"tracking_alert":{"type":"integer","description":"Carrying at least one problem scan."},"never_arriving":{"type":"integer","description":"Lost or destroyed in transit."},"carriers":{"type":"array","description":"Every carrier you have shipped with — the whole vocabulary of the\n`carrier` filter, not the carriers in the filtered set.\n","items":{"type":"string"}}},"example":{"total":1284,"late":47,"tracking_alert":23,"never_arriving":3,"carriers":["UPS","FedEx","OnTrac","AxleHire"]}},"DeliveryPerformance":{"type":"object","additionalProperties":false,"required":["period","tiles","weeks","findings","order_status_counts"],"properties":{"period":{"$ref":"#/components/schemas/ReportPeriod"},"tiles":{"$ref":"#/components/schemas/DeliveryTiles"},"weeks":{"type":"array","description":"Up to thirteen weeks, newest first, ending with the week your first\nshipment went out in. An empty week between two busy ones is real\nhistory and stays.\n","items":{"allOf":[{"$ref":"#/components/schemas/ReportPeriod"},{"$ref":"#/components/schemas/DeliveryFigures"}]}},"findings":{"type":"array","description":"What is worth your attention this period, by rule rather than by\njudgement. Empty when there is nothing to say.\n","items":{"$ref":"#/components/schemas/DeliveryFinding"}},"order_status_counts":{"type":"array","description":"Your orders in the period, by where they got to.","items":{"$ref":"#/components/schemas/OrderStatusCount"}}},"example":{"period":{"period_start":"2026-05-31","period_end":"2026-06-06"},"tiles":{"shipments":{"current":432,"prior":418},"on_time_rate":{"current":0.9438,"prior":0.9601},"late":{"current":24,"prior":17},"never_arriving":{"current":1,"prior":0},"tracking_alerts":{"current":18,"prior":14},"avg_transit_days":{"current":2.1,"prior":1.98}},"weeks":[{"period_start":"2026-05-31","period_end":"2026-06-06","shipments":432,"on_time_rate":0.9438,"late":24,"never_arriving":1,"tracking_alerts":18,"avg_transit_days":2.1},{"period_start":"2026-05-24","period_end":"2026-05-30","shipments":418,"on_time_rate":0.9601,"late":17,"never_arriving":0,"tracking_alerts":14,"avg_transit_days":1.98},{"period_start":"2026-05-17","period_end":"2026-05-23","shipments":455,"on_time_rate":0.9385,"late":28,"never_arriving":2,"tracking_alerts":21,"avg_transit_days":2.24},{"period_start":"2026-05-10","period_end":"2026-05-16","shipments":401,"on_time_rate":0.9502,"late":20,"never_arriving":0,"tracking_alerts":12,"avg_transit_days":2.05},{"period_start":"2026-05-03","period_end":"2026-05-09","shipments":388,"on_time_rate":0.9455,"late":21,"never_arriving":1,"tracking_alerts":15,"avg_transit_days":2.13},{"period_start":"2026-04-26","period_end":"2026-05-02","shipments":447,"on_time_rate":0.9309,"late":31,"never_arriving":2,"tracking_alerts":26,"avg_transit_days":2.41},{"period_start":"2026-04-19","period_end":"2026-04-25","shipments":410,"on_time_rate":0.9563,"late":18,"never_arriving":0,"tracking_alerts":11,"avg_transit_days":1.94},{"period_start":"2026-04-12","period_end":"2026-04-18","shipments":396,"on_time_rate":0.947,"late":21,"never_arriving":1,"tracking_alerts":16,"avg_transit_days":2.08},{"period_start":"2026-04-05","period_end":"2026-04-11","shipments":429,"on_time_rate":0.9394,"late":26,"never_arriving":0,"tracking_alerts":19,"avg_transit_days":2.19},{"period_start":"2026-03-29","period_end":"2026-04-04","shipments":373,"on_time_rate":0.9518,"late":18,"never_arriving":1,"tracking_alerts":13,"avg_transit_days":2.02},{"period_start":"2026-03-22","period_end":"2026-03-28","shipments":361,"on_time_rate":0.9613,"late":14,"never_arriving":0,"tracking_alerts":9,"avg_transit_days":1.91},{"period_start":"2026-03-15","period_end":"2026-03-21","shipments":344,"on_time_rate":0.9448,"late":19,"never_arriving":1,"tracking_alerts":12,"avg_transit_days":2.16},{"period_start":"2026-03-08","period_end":"2026-03-14","shipments":318,"on_time_rate":0.9367,"late":20,"never_arriving":2,"tracking_alerts":17,"avg_transit_days":2.28}],"findings":[{"message":"24 shipments arrived after the date we promised.","shipments":24,"query":{"late":true}},{"message":"18 shipments are carrying a carrier tracking alert.","shipments":18,"query":{"tracking_alert":true}},{"message":"1 shipment was written off as lost or destroyed.","shipments":1,"query":{"never_arriving":true}}],"order_status_counts":[{"organization":"SEABEAR","cancelled":12,"not_packed":14,"packed":90,"shipped":432,"total":548}]}},"ReportPeriod":{"type":"object","required":["period_start","period_end"],"properties":{"period_start":{"type":"string","description":"`YYYY-MM-DD`, inclusive."},"period_end":{"type":"string","description":"`YYYY-MM-DD`, inclusive."}},"example":{"period_start":"2026-08-01","period_end":"2026-08-31"}},"DeliveryFigures":{"type":"object","required":["shipments","on_time_rate","late","never_arriving","tracking_alerts","avg_transit_days"],"properties":{"shipments":{"type":"integer","description":"Boxes that went out in the period, by ship date."},"on_time_rate":{"type":["number","null"],"description":"On-time ÷ (on-time + late), 0–1. Leaves out boxes still inside their\npromise window and boxes written off. Null until there is something\nto rate.\n"},"late":{"type":"integer"},"never_arriving":{"type":"integer","description":"Lost or destroyed in transit."},"tracking_alerts":{"type":"integer"},"avg_transit_days":{"type":["number","null"],"description":"Mean wall-clock time from carrier handoff to delivery, in days — so a\n1pm-to-9am delivery is 0.8, not 1. Null with nothing delivered.\n"}},"example":{"shipments":432,"on_time_rate":0.9438,"late":24,"never_arriving":1,"tracking_alerts":18,"avg_transit_days":2.1}},"DeliveryTiles":{"description":"Each figure for the period, against the period before it.","type":"object","additionalProperties":false,"required":["shipments","on_time_rate","late","never_arriving","tracking_alerts","avg_transit_days"],"properties":{"shipments":{"$ref":"#/components/schemas/DeliveryTile"},"on_time_rate":{"$ref":"#/components/schemas/DeliveryTile"},"late":{"$ref":"#/components/schemas/DeliveryTile"},"never_arriving":{"$ref":"#/components/schemas/DeliveryTile"},"tracking_alerts":{"$ref":"#/components/schemas/DeliveryTile"},"avg_transit_days":{"$ref":"#/components/schemas/DeliveryTile"}},"example":{"shipments":{"current":432,"prior":418},"on_time_rate":{"current":0.9438,"prior":0.9601},"late":{"current":24,"prior":17},"never_arriving":{"current":1,"prior":0},"tracking_alerts":{"current":18,"prior":14},"avg_transit_days":{"current":2.1,"prior":1.98}}},"DeliveryTile":{"type":"object","additionalProperties":false,"required":["current","prior"],"properties":{"current":{"type":["number","null"]},"prior":{"type":["number","null"],"description":"The same figure for the period of equal length before it."}},"example":{"current":0.9438,"prior":0.9601}},"DeliveryFinding":{"type":"object","additionalProperties":false,"required":["message","shipments","query"],"properties":{"message":{"type":"string","description":"One plain sentence, written for a person to read."},"shipments":{"type":"integer","description":"How many boxes it is about."},"query":{"type":"object","description":"`GET /shipments` filters that list exactly those boxes. Add the\nperiod's dates to scope it to this report.\n","additionalProperties":true}},"example":{"message":"24 shipments arrived after the date we promised.","shipments":24,"query":{"late":true}}},"OrderStatusCount":{"description":"Buckets overlap on purpose: an order cancelled after it shipped counts\nin both, and `not_packed` is what is left of the total once the other\nthree come off.\n","type":"object","additionalProperties":false,"required":["organization","cancelled","not_packed","packed","shipped","total"],"properties":{"organization":{"type":"string","description":"The organization's code, e.g. `SEABEAR`."},"cancelled":{"type":"integer"},"not_packed":{"type":"integer"},"packed":{"type":"integer"},"shipped":{"type":"integer"},"total":{"type":"integer"}},"example":{"organization":"SEABEAR","cancelled":12,"not_packed":14,"packed":90,"shipped":432,"total":548}},"InventoryTransactionList":{"type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InventoryTransaction"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"example":{"data":[{"id":"inv_4c81a9","occurred_at":"2026-08-14T16:42:11Z","reason":"pick","quantity":-2,"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","fc":"dunmore","box_id":"B-88213","order_id":"1234567","lot":"L-2026-08-03","owner":"Four Sixes"},{"id":"inv_7b30d2","occurred_at":"2026-08-12T21:05:47Z","reason":"delivery","quantity":-1,"sku_id":"s_bison_burger_8pk","sku_name":"Bison Burger 8pk","fc":"watsonville","box_id":"B-88214","order_id":"1234568","lot":"L-2026-08-03","owner":"Four Sixes"}],"has_more":true,"next_cursor":"eyJ2IjoiMjAyNi0wOC0xNCJ9"}},"InventoryTransaction":{"type":"object","additionalProperties":false,"required":["id","occurred_at","reason","quantity","sku_id","sku_name","fc","box_id","order_id","lot","owner"],"properties":{"id":{"type":"string","description":"This movement's identifier. Opaque, and stable."},"occurred_at":{"type":"string","format":"date-time","description":"When we recorded it, RFC 3339 UTC."},"reason":{"type":"string","description":"The five filterable names, plus the movements that have no filter of\ntheir own — `fc_transfer` is stock moving between our centres, and\n`initial` is the opening balance from when a box entered the system.\n","enum":["receiving","pick","cycle_count","sad_cow","delivery","fc_transfer","pack_order","initial"]},"quantity":{"type":"integer","description":"Signed, in units — negative for anything leaving. A movement of zero\nis not a movement and is never listed.\n"},"sku_id":{"type":["string","null"],"description":"Your own SKU identifier."},"sku_name":{"type":["string","null"]},"fc":{"$ref":"#/components/schemas/FcCode"},"box_id":{"type":["string","null"],"description":"The physical case the units came out of or went into."},"order_id":{"type":["string","null"],"description":"Your own `order_id`, on a movement caused by an order."},"lot":{"type":["string","null"],"description":"The lot the case belongs to, when it has one."},"owner":{"type":"string","description":"Who paid for these units. Under the default every row is your own\nvendor; under `owner=all` this is what separates yours from ours.\n"}},"example":{"id":"inv_4c81a9","occurred_at":"2026-08-14T16:42:11Z","reason":"pick","quantity":-2,"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","fc":"dunmore","box_id":"B-88213","order_id":"1234567","lot":"L-2026-08-03","owner":"Four Sixes"}},"MonthEndInventoryReport":{"type":"object","additionalProperties":false,"required":["as_of","fcs","lines","total_units"],"properties":{"as_of":{"type":"string","format":"date-time","description":"The last moment counted. The end of the requested month, or now if\nthat month is still running.\n"},"fcs":{"type":"array","description":"The fulfillment centres holding your stock at the cutoff, in a\nstable order — read from the data, since FCs open, close and move.\n","items":{"$ref":"#/components/schemas/ReportFc"}},"lines":{"type":"array","description":"One per SKU with stock somewhere, by SKU name. A SKU sitting at zero\nat every FC is omitted.\n","items":{"$ref":"#/components/schemas/ReportLine"}},"total_units":{"type":"integer"}},"example":{"as_of":"2026-08-31T23:59:59Z","fcs":[{"code":"dunmore","name":"Scranton"},{"code":"dallas","name":"Dallas"},{"code":"watsonville","name":"Watsonville"}],"lines":[{"sku_id":"s_bison_burger_8pk","sku_name":"Bison Burger 8pk","units_by_fc":{"dunmore":120,"dallas":64,"watsonville":0},"total_units":184},{"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","units_by_fc":{"dunmore":40,"dallas":0,"watsonville":15},"total_units":55}],"total_units":239}},"SadCowReport":{"type":"object","additionalProperties":false,"required":["period","fcs","lines","units_by_reason","total_units"],"properties":{"period":{"$ref":"#/components/schemas/ReportPeriod"},"fcs":{"type":"array","description":"The fulfillment centres that wrote anything off in range.","items":{"$ref":"#/components/schemas/ReportFc"}},"lines":{"type":"array","description":"One per SKU written off in range, by SKU name. Units are positive\nmagnitudes — units lost, not signed movement.\n","items":{"$ref":"#/components/schemas/ReportLine"}},"units_by_reason":{"type":"object","description":"Why the units were written off, as recorded by the warehouse,\nlargest first. Anything unattributed groups as `Not recorded`.\n","additionalProperties":{"type":"integer"},"examples":[{"Damaged Packaging":7,"Discolored":2}]},"total_units":{"type":"integer"}},"example":{"period":{"period_start":"2026-08-01","period_end":"2026-08-31"},"fcs":[{"code":"dunmore","name":"Scranton"},{"code":"dallas","name":"Dallas"},{"code":"watsonville","name":"Watsonville"}],"lines":[{"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","units_by_fc":{"dunmore":5,"dallas":0,"watsonville":2},"total_units":7},{"sku_id":"s_bison_burger_8pk","sku_name":"Bison Burger 8pk","units_by_fc":{"dunmore":2,"dallas":1,"watsonville":0},"total_units":3}],"units_by_reason":{"Damaged Packaging":6,"Discolored":3,"Not recorded":1},"total_units":10}},"ReportFc":{"type":"object","additionalProperties":false,"required":["code","name"],"properties":{"code":{"$ref":"#/components/schemas/FcCode"},"name":{"type":["string","null"],"description":"What a person reads on the report, e.g. `Scranton`."}},"example":{"code":"dunmore","name":"Scranton"}},"ReportLine":{"type":"object","additionalProperties":false,"required":["sku_id","sku_name","units_by_fc","total_units"],"properties":{"sku_id":{"type":["string","null"]},"sku_name":{"type":["string","null"]},"units_by_fc":{"type":"object","description":"Units at each of the report's `fcs`, keyed by code. Every code in\n`fcs` is present, zero included, so a row is a complete row.\n","additionalProperties":{"type":"integer"}},"total_units":{"type":"integer"}},"example":{"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","units_by_fc":{"dunmore":40,"dallas":0,"watsonville":15},"total_units":55}},"InventoryTransactionSummary":{"type":"object","additionalProperties":false,"required":["lines","total"],"properties":{"lines":{"type":"array","description":"One per SKU with a movement in range, by SKU name.","items":{"$ref":"#/components/schemas/InventoryTransactionSummaryLine"}},"total":{"type":"integer","description":"The net of every line — what the filtered range did to the stock on\nhand, in units.\n"}},"example":{"lines":[{"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","receiving":120,"pick":-84,"cycle_count":-2,"sad_cow":-3,"delivery":-6,"total":23},{"sku_id":"s_bison_burger_8pk","sku_name":"Bison Burger 8pk","receiving":60,"pick":-22,"cycle_count":1,"sad_cow":-1,"delivery":-2,"total":36}],"total":59}},"InventoryTransactionSummaryLine":{"type":"object","additionalProperties":false,"required":["sku_id","sku_name","receiving","pick","cycle_count","sad_cow","delivery","total"],"properties":{"sku_id":{"type":["string","null"]},"sku_name":{"type":["string","null"]},"receiving":{"type":"integer"},"pick":{"type":"integer"},"cycle_count":{"type":"integer"},"sad_cow":{"type":"integer"},"delivery":{"type":"integer"},"total":{"type":"integer","description":"Every movement on this SKU, including the kinds with no column of\ntheir own, so the columns need not add up to it.\n"}},"example":{"sku_id":"s_ribeye_12oz","sku_name":"Ribeye 12oz","receiving":120,"pick":-84,"cycle_count":-2,"sad_cow":-3,"delivery":-6,"total":23}},"InvoiceList":{"type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"example":{"data":[{"id":"10421","period_start":"2026-08-01","period_end":"2026-08-31","doc_date":"2026-09-02","due_on":"2026-10-02","total":"18422.75","currency":"USD","status":"sent","emailed_at":"2026-09-02T16:04:00Z"},{"id":"10388","period_start":"2026-07-01","period_end":"2026-07-31","doc_date":"2026-08-03","due_on":"2026-09-02","total":"16903.12","currency":"USD","status":"exported","emailed_at":"2026-08-03T15:51:00Z"}],"has_more":true,"next_cursor":"eyJpZCI6IjEwMzg4Iiwic2VlbiI6MzR9"}},"Invoice":{"type":"object","additionalProperties":false,"required":["id","period_start","period_end","doc_date","due_on","total","currency","status","emailed_at"],"properties":{"id":{"type":"string","description":"The invoice number, as printed on the document. Pass it back as\n`{id}` on every other invoice endpoint.\n"},"period_start":{"type":"string","format":"date","description":"First day of the billing period."},"period_end":{"type":"string","format":"date","description":"Last day of the billing period, inclusive."},"doc_date":{"type":["string","null"],"format":"date","description":"The date on the document itself."},"due_on":{"type":["string","null"],"format":"date"},"total":{"type":"string","description":"The document total in dollars, to the cent."},"currency":{"type":"string"},"status":{"type":"string","enum":["sent","exported"],"description":"`exported` means it also reached our accounting system. Only these\ntwo are partner-facing; a draft or voided invoice is not listed.\n"},"emailed_at":{"type":["string","null"],"format":"date-time","description":"When we emailed it to you. Null means it was finalized but never\nsent, which is also when the document endpoints have no file.\n"}},"example":{"id":"10421","period_start":"2026-08-01","period_end":"2026-08-31","doc_date":"2026-09-02","due_on":"2026-10-02","total":"18422.75","currency":"USD","status":"sent","emailed_at":"2026-09-02T16:04:00Z"}},"InvoiceDetail":{"type":"object","additionalProperties":false,"required":["id","period_start","period_end","doc_date","due_on","total","currency","status","emailed_at","line_items","bill_to","ship_to","documents"],"properties":{"id":{"type":"string"},"period_start":{"type":"string","format":"date"},"period_end":{"type":"string","format":"date"},"doc_date":{"type":["string","null"],"format":"date"},"due_on":{"type":["string","null"],"format":"date"},"total":{"type":"string"},"currency":{"type":"string"},"status":{"type":"string","enum":["sent","exported"]},"emailed_at":{"type":["string","null"],"format":"date-time"},"line_items":{"type":"array","description":"The Summary rows, in the order the document prints them.","items":{"$ref":"#/components/schemas/InvoiceLineItem"}},"bill_to":{"type":"array","description":"The billing address, one entry per printed line.","items":{"type":"string"}},"ship_to":{"type":"array","items":{"type":"string"}},"documents":{"$ref":"#/components/schemas/InvoiceDocuments"}},"example":{"id":"10421","period_start":"2026-08-01","period_end":"2026-08-31","doc_date":"2026-09-02","due_on":"2026-10-02","total":"18422.75","currency":"USD","status":"sent","emailed_at":"2026-09-02T16:04:00Z","line_items":[{"no":1,"category":"Fulfillment","item_label":"Order Handling","description":"Pick, pack and label — first item of each order included","quantity":"3142","uom":"orders","unit_cost":"1.7500","extended_cost":"5498.50","adder_pct":"0.00","unit_price":"1.7500","extended_price":"5498.50"},{"no":2,"category":"Fulfillment","item_label":"Item Labor","description":"Additional items picked beyond the first on each order","quantity":"4918","uom":"items","unit_cost":"0.3500","extended_cost":"1721.30","adder_pct":"0.00","unit_price":"0.3500","extended_price":"1721.30"},{"no":3,"category":"Packaging","item_label":"Corrugate and Liners","description":"Insulated shipper, liner and void fill","quantity":"3142","uom":"boxes","unit_cost":"2.1000","extended_cost":"6598.20","adder_pct":"0.00","unit_price":"2.1000","extended_price":"6598.20"},{"no":4,"category":"Packaging","item_label":"Dry Ice","description":"Coolant charged on weight loaded at the fulfillment center","quantity":"16329.21","uom":"lbs","unit_cost":"0.1900","extended_cost":"3102.55","adder_pct":"0.00","unit_price":"0.1900","extended_price":"3102.55"},{"no":5,"category":"Storage","item_label":"Pallet Storage","description":"Average pallet positions held across the period","quantity":"412","uom":"pallet-months","unit_cost":"0.8500","extended_cost":"350.20","adder_pct":"0.00","unit_price":"0.8500","extended_price":"350.20"},{"no":6,"category":"Receiving","item_label":"Inbound Receiving","description":"Pallets received, verified and putaway","quantity":"96","uom":"pallets","unit_cost":"12.0000","extended_cost":"1152.00","adder_pct":"0.00","unit_price":"12.0000","extended_price":"1152.00"}],"bill_to":["Four Sixes Ranch","Attn: Accounts Payable","6666 Ranch Road","Guthrie, TX 79236","United States"],"ship_to":["Crowd Cow Fulfillment — Dunmore","1000 Keystone Industrial Park","Dunmore, PA 18512","United States"],"documents":{"pdf":"https://3pl.crowdcow.com/api/v1/invoices/10421/pdf","detail_xlsx":"https://3pl.crowdcow.com/api/v1/invoices/10421/detail.xlsx"}}},"InvoiceLineItem":{"type":"object","additionalProperties":false,"required":["no","category","item_label","description","quantity","uom","unit_cost","extended_cost","adder_pct","unit_price","extended_price"],"properties":{"no":{"type":"integer","description":"The line's position on the document, from 1."},"category":{"type":"string"},"item_label":{"type":"string","description":"The service name as printed."},"description":{"type":"string"},"quantity":{"type":["string","null"]},"uom":{"type":["string","null"],"description":"The unit the quantity counts — cases, pounds, orders."},"unit_cost":{"type":["string","null"],"description":"Rate per unit, to four decimal places, because a per-unit rate\nrounded to the cent does not reproduce the extended amount.\n"},"extended_cost":{"type":["string","null"]},"adder_pct":{"type":["string","null"]},"unit_price":{"type":["string","null"]},"extended_price":{"type":["string","null"]}},"example":{"no":4,"category":"Packaging","item_label":"Dry Ice","description":"Coolant charged on weight loaded at the fulfillment center","quantity":"16329.21","uom":"lbs","unit_cost":"0.1900","extended_cost":"3102.55","adder_pct":"0.00","unit_price":"0.1900","extended_price":"3102.55"}},"InvoiceDocuments":{"type":"object","additionalProperties":false,"required":["pdf","detail_xlsx"],"properties":{"pdf":{"type":"string","description":"Where to get the invoice PDF. Redirects to the stored file."},"detail_xlsx":{"type":"string","description":"Where to get the detail workbook. Redirects to the stored file."}},"example":{"pdf":"https://3pl.crowdcow.com/api/v1/invoices/10421/pdf","detail_xlsx":"https://3pl.crowdcow.com/api/v1/invoices/10421/detail.xlsx"}},"OrderCostList":{"type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceOrderCost"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"example":{"data":[{"order_id":"1234567","internal_order_id":"FS-2026-08-114532","order_token":"ord_9f2c1ab84e","delivery_city":"Portland","delivery_state":"OR","delivery_zip":"97214","item_count":6,"net_item_count":5,"item_rate":"0.3500","extended_item_labor":"1.75"},{"order_id":"1234568","internal_order_id":"FS-2026-08-114533","order_token":"ord_4b71e0c592","delivery_city":"Austin","delivery_state":"TX","delivery_zip":"78704","item_count":3,"net_item_count":2,"item_rate":"0.3500","extended_item_labor":"0.70"}],"has_more":true,"next_cursor":"eyJvcmRlcl90b2tlbiI6Im9yZF80YjcxZTBjNTkyIn0"}},"InvoiceOrderCost":{"type":"object","additionalProperties":false,"required":["order_id","internal_order_id","order_token","delivery_city","delivery_state","delivery_zip","item_count","net_item_count","item_rate","extended_item_labor"],"properties":{"order_id":{"type":["string","null"],"description":"Your own order identifier — the number your customer sees, falling\nback to your internal one.\n"},"internal_order_id":{"type":["string","null"]},"order_token":{"type":["string","null"],"description":"Our identifier for the order, as `GET /orders/{id}` reports it."},"delivery_city":{"type":["string","null"]},"delivery_state":{"type":["string","null"]},"delivery_zip":{"type":["string","null"]},"item_count":{"type":"integer","description":"Items picked for the order."},"net_item_count":{"type":"integer","description":"What was billed: the first item of an order is covered by the\norder-level charge, so this is one fewer.\n"},"item_rate":{"type":["string","null"]},"extended_item_labor":{"type":["string","null"]}},"example":{"order_id":"1234567","internal_order_id":"FS-2026-08-114532","order_token":"ord_9f2c1ab84e","delivery_city":"Portland","delivery_state":"OR","delivery_zip":"97214","item_count":6,"net_item_count":5,"item_rate":"0.3500","extended_item_labor":"1.75"}},"ShipmentCostList":{"type":"object","additionalProperties":false,"required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceShipmentCost"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"example":{"data":[{"shipped_on":"2026-08-14","carrier":"UPS","order_id":"1234567","internal_order_id":"FS-2026-08-114532","order_token":"ord_9f2c1ab84e","coolant_lbs":"6.50","delivery_city":"Portland","delivery_state":"OR","delivery_zip":"97214","fc_name":"Watsonville","box_name":"Medium Insulated Shipper (M-2)","shipping_option":"Ground","product_weight":"11.20","shipment_weight":"19.40","dry_ice_rate":"0.1900","dry_ice":"1.24","packaging":"2.10","last_mile":"9.86","line_haul":"3.42","labor":"3.50"},{"shipped_on":"2026-08-15","carrier":"OnTrac","order_id":"1234568","internal_order_id":"FS-2026-08-114533","order_token":"ord_4b71e0c592","coolant_lbs":"4.00","delivery_city":"Austin","delivery_state":"TX","delivery_zip":"78704","fc_name":"Dallas","box_name":"Small Insulated Shipper (S-1)","shipping_option":"Ground","product_weight":"6.80","shipment_weight":"12.10","dry_ice_rate":"0.1900","dry_ice":"0.76","packaging":"1.65","last_mile":"7.42","line_haul":"2.10","labor":"2.45"}],"has_more":true,"next_cursor":"eyJzaGlwbWVudF9pZCI6ODgxNDIsInNoaXBwZWRfb24iOiIyMDI2LTA4LTE1In0"}},"InvoiceShipmentCost":{"type":"object","additionalProperties":false,"required":["shipped_on","carrier","order_id","internal_order_id","order_token","coolant_lbs","delivery_city","delivery_state","delivery_zip","fc_name","box_name","shipping_option","product_weight","shipment_weight","dry_ice_rate","dry_ice","packaging","last_mile","line_haul","labor"],"properties":{"shipped_on":{"type":["string","null"],"format":"date"},"carrier":{"type":["string","null"]},"order_id":{"type":["string","null"]},"internal_order_id":{"type":["string","null"]},"order_token":{"type":["string","null"]},"coolant_lbs":{"type":["string","null"],"description":"Dry ice in the box, in pounds."},"delivery_city":{"type":["string","null"]},"delivery_state":{"type":["string","null"]},"delivery_zip":{"type":["string","null"]},"fc_name":{"type":["string","null"]},"box_name":{"type":["string","null"]},"shipping_option":{"type":["string","null"]},"product_weight":{"type":["string","null"],"description":"Weight of the contents."},"shipment_weight":{"type":["string","null"],"description":"What the carrier weighs — box, contents and dry ice. Null where we\nnever recorded a weight; it is not zero.\n"},"dry_ice_rate":{"type":["string","null"],"description":"Rate per pound of dry ice, to four places."},"dry_ice":{"type":["string","null"]},"packaging":{"type":["string","null"]},"last_mile":{"type":["string","null"]},"line_haul":{"type":["string","null"]},"labor":{"type":["string","null"]}},"example":{"shipped_on":"2026-08-14","carrier":"UPS","order_id":"1234567","internal_order_id":"FS-2026-08-114532","order_token":"ord_9f2c1ab84e","coolant_lbs":"6.50","delivery_city":"Portland","delivery_state":"OR","delivery_zip":"97214","fc_name":"Watsonville","box_name":"Medium Insulated Shipper (M-2)","shipping_option":"Ground","product_weight":"11.20","shipment_weight":"19.40","dry_ice_rate":"0.1900","dry_ice":"1.24","packaging":"2.10","last_mile":"9.86","line_haul":"3.42","labor":"3.50"}}}}}