Releases
Releases represent scheduled material draws against a Hold-for-Release purchase order (an HFR order, also referred to as a buyout โ see OrderType). Each Release records when material is needed, where it should be delivered, which line items are being released and in what quantity, and the extended cost of that draw.
These endpoints expose the same release-level dates and dollar values shown in the Kojo Analytics Dashboard, so they can be pulled into Power BI or another reporting tool.
note
Cancelled releases are excluded by default from both endpoints. Pass includeCancelled=true to return them. If you are reconciling totals against the Analytics Dashboard, make sure both sides agree on whether cancelled releases are counted.
Schemaโ
Releaseโ
| Name | Type | Description | Example |
|---|---|---|---|
| id | ID | Unique Kojo internal identifier | "clr8adymd000112nocbtsetzx" |
| orderId | ID | ID of the purchase order this release belongs to | "clrrtqmy60007zay5y3kbb6x0" |
| purchaseOrderNumber | String? | PO number of the parent order, so bulk consumers can join without a second request | "PO-2025-001" |
| releaseNumber | String | Human-readable release identifier. Not guaranteed unique โ use id to identify a release | "REL-001" |
| needByDateDay | DateTime? | Day the released material is needed on site | "2025-09-15T00:00:00.000Z" |
| needByWindow | String? | Delivery window within the need-by day | "AM" |
| notes | String? | Release notes | "Deliver to north gate" |
| additionalNotes | String? | Further notes on the release | "Call site super on arrival" |
| cancelledAt | DateTime? | When the release was cancelled; null for active releases | "2025-08-02T14:11:07.221Z" |
| cancelledReason | String? | Reason recorded at cancellation | "Schedule pushed" |
| totalCost | Float | Extended cost of this release โ the sum of totalCost across its releaseItems. See How totalCost is derived | 12450.00 |
| deliveryLocation | Location? | Where the release is being delivered. Only id and name are returned | { "id": "clxyz456", "name": "Main Warehouse" } |
| releaseItems | ReleaseItem[] | The line items included in this release | |
| createdAt | DateTime | When the release was created | "2025-08-01T09:14:22.031Z" |
| createdById | ID? | ID of the user who created the release | "clr6fkyru0002q3dwbwh2t6j8" |
| updatedAt | DateTime | When the release was last updated | "2025-08-01T09:20:44.507Z" |
ReleaseItemโ
| Name | Type | Description | Example |
|---|---|---|---|
| id | ID | Unique release item identifier | "clxyz789" |
| releaseId | ID | ID of the release this item belongs to | "clr8adymd000112nocbtsetzx" |
| lineItemId | ID | ID of the order line item being released | "clxyzabc" |
| requisitionItemId | ID? | ID of the originating requisition item, when the release traces back to a requisition | "clxyzdef" |
| quantityReleased | Float | Quantity of the line item released in this release | 10 |
| backorderQuantity | Float | Quantity on backorder for this release item; 0 when none | 2 |
| totalCost | Float | Extended cost of the released quantity. See How totalCost is derived | 12450.00 |
| lineItem | ReleaseLineItem | Pricing detail for the released line item | |
| createdAt | DateTime | When the release item was created | "2025-08-01T09:14:22.031Z" |
| updatedAt | DateTime | When the release item was last updated | "2025-08-01T09:20:44.507Z" |
ReleaseLineItemโ
| Name | Type | Description | Example |
|---|---|---|---|
| id | ID | ID of the order line item | "clxyzabc" |
| description | String? | Line item description | "Steel Beam 10ft" |
| unitPrice | Float | Unit price of the line item, before any unit discount; 0 when unpriced | 1245.00 |
| extPrice | Float | Extended price for the released quantity. Equal to the release item's totalCost | 12450.00 |
How totalCost is derivedโ
totalCost is computed at request time from the parent order's line item pricing โ it is not a stored field. For each release item:
totalCost = round(quantityReleased ร unitPrice ร (1 โ unitDiscount รท 100) รท pricePerFactor, 2)
unitPriceandunitDiscountcome from the order line item. An unpriced line item contributes0.pricePerFactorreflects the line item's unit of measure:1000forM,100forC, and1for everything else (includingEAand blank). This matches how Kojo prices "per thousand" and "per hundred" units.
A release's totalCost is the sum of its release items' totalCost, and each lineItem.extPrice repeats the release item's totalCost for convenience.
Queriesโ
GET /orders/:orderId/releasesโ
Fetches every release on a single purchase order. Use this for the drill-down case, when you already have an order ID.
Parametersโ
| Name | Type | Default | Description | Example |
|---|---|---|---|---|
| orderId | ID | โ | Path parameter. The Kojo ID of the purchase order | "clrrtqmy60007zay5y3kbb6x0" |
| includeCancelled | Boolean? | false | Include cancelled releases in the response | true |
Results are ordered by createdAt descending. This endpoint is not paginated and does not accept the standard pagination parameters โ it returns every release on the order.
Responseโ
A list of Release objects, returned as a bare JSON array.
Errorsโ
| Status | Description |
|---|---|
404 | Order not found โ the order does not exist, has been deleted, or belongs to another organization. Kojo does not distinguish these cases, so a valid order ID from a different organization returns 404 rather than 403 |
Example Queryโ
GET https://api.kojo.tech/orders/clrrtqmy60007zay5y3kbb6x0/releases
Example Responseโ
[
{
"id": "clr8adymd000112nocbtsetzx",
"orderId": "clrrtqmy60007zay5y3kbb6x0",
"purchaseOrderNumber": "PO-2025-001",
"releaseNumber": "REL-001",
"needByDateDay": "2025-09-15T00:00:00.000Z",
"needByWindow": "AM",
"notes": "Deliver to north gate",
"additionalNotes": null,
"cancelledAt": null,
"cancelledReason": null,
"totalCost": 12450.0,
"createdAt": "2025-08-01T09:14:22.031Z",
"createdById": "clr6fkyru0002q3dwbwh2t6j8",
"updatedAt": "2025-08-01T09:20:44.507Z",
"deliveryLocation": {
"id": "clxyz456",
"name": "Main Warehouse"
},
"releaseItems": [
{
"id": "clxyz789",
"releaseId": "clr8adymd000112nocbtsetzx",
"lineItemId": "clxyzabc",
"requisitionItemId": null,
"quantityReleased": 10,
"backorderQuantity": 0,
"totalCost": 12450.0,
"createdAt": "2025-08-01T09:14:22.031Z",
"updatedAt": "2025-08-01T09:14:22.031Z",
"lineItem": {
"id": "clxyzabc",
"description": "Steel Beam 10ft",
"unitPrice": 1245.0,
"extPrice": 12450.0
}
}
]
}
]
GET /releasesโ
Fetches releases across your whole organization, with date and order filters and pagination. This is the endpoint to use for scheduled bulk pulls into a BI tool.
Parametersโ
| Name | Type | Default | Description | Example |
|---|---|---|---|---|
| orderId | ID? | โ | Return only releases on this purchase order | "clrrtqmy60007zay5y3kbb6x0" |
| needByDateFrom | DateTime? | โ | Return releases with needByDateDay on or after this instant (ISO 8601) | "2025-09-01T00:00:00.000Z" |
| needByDateTo | DateTime? | โ | Return releases with needByDateDay on or before this instant (ISO 8601) | "2025-09-30T00:00:00.000Z" |
| includeCancelled | Boolean? | false | Include cancelled releases in the response | true |
| limit | Int? | 100 | Maximum number of releases to return. Values above 500 are capped at 500 | 250 |
| offset | Int? | 0 | Number of releases to skip | 100 |
Results are ordered by createdAt descending.
note
This endpoint takes explicit query parameters rather than the filter[...] and orderBy conventions described in Filters โ filter[needByDateDay_gte] and orderBy are not supported here. Its pagination also differs from the standard defaults: limit defaults to 100 (not 500) and is capped at 500.
Notes on filter behavior:
- Date filters are independent. Supplying only
needByDateFromleaves the upper bound open; supplying onlyneedByDateToleaves the lower bound open. - Releases with no need-by date are excluded when you filter by date. A release whose
needByDateDayisnullcannot satisfy a range bound, so it drops out of the result set as soon as either date filter is supplied. Omit both filters to include undated releases. limitabove the cap does not error. Requestinglimit=1000returns at most 500 records and reportsmeta.limit: 500, so read your effective page size frommeta.limitrather than assuming it echoes your request.- Releases on deleted orders are excluded.
Responseโ
An object with pagination metadata and an array of releases.
| Name | Type | Description |
|---|---|---|
| meta | object | Pagination metadata |
| meta.total | Int | Total releases matching the filters, before pagination |
| meta.limit | Int | Effective page size actually applied, after the 500 cap |
| meta.offset | Int | Number of releases skipped |
| data | Release[] | The page of releases |
An offset past the end of the result set returns an empty data array with an accurate meta.total, so you can page until offset + data.length >= meta.total.
Errorsโ
| Status | Description |
|---|---|
400 | limit must be a non-negative integer or offset must be a non-negative integer โ a negative value was supplied |
404 | Order not found โ the orderId filter does not resolve to an order in your organization. An empty orderId= is treated as a lookup for an order with a blank ID and also returns 404; omit the parameter entirely to query all releases |
Example Queryโ
GET https://api.kojo.tech/releases?needByDateFrom=2025-09-01T00:00:00.000Z&needByDateTo=2025-09-30T00:00:00.000Z&limit=100
Example Responseโ
{
"meta": {
"total": 342,
"limit": 100,
"offset": 0
},
"data": [
{
"id": "clr8adymd000112nocbtsetzx",
"orderId": "clrrtqmy60007zay5y3kbb6x0",
"purchaseOrderNumber": "PO-2025-001",
"releaseNumber": "REL-001",
"needByDateDay": "2025-09-15T00:00:00.000Z",
"needByWindow": "AM",
"notes": "Deliver to north gate",
"additionalNotes": null,
"cancelledAt": null,
"cancelledReason": null,
"totalCost": 12450.0,
"createdAt": "2025-08-01T09:14:22.031Z",
"createdById": "clr6fkyru0002q3dwbwh2t6j8",
"updatedAt": "2025-08-01T09:20:44.507Z",
"deliveryLocation": {
"id": "clxyz456",
"name": "Main Warehouse"
},
"releaseItems": [
{
"id": "clxyz789",
"releaseId": "clr8adymd000112nocbtsetzx",
"lineItemId": "clxyzabc",
"requisitionItemId": null,
"quantityReleased": 10,
"backorderQuantity": 0,
"totalCost": 12450.0,
"createdAt": "2025-08-01T09:14:22.031Z",
"updatedAt": "2025-08-01T09:14:22.031Z",
"lineItem": {
"id": "clxyzabc",
"description": "Steel Beam 10ft",
"unitPrice": 1245.0,
"extPrice": 12450.0
}
}
]
}
]
}
Paging Through a Full Exportโ
GET https://api.kojo.tech/releases?limit=500&offset=0
GET https://api.kojo.tech/releases?limit=500&offset=500
GET https://api.kojo.tech/releases?limit=500&offset=1000
Stop when offset + data.length reaches meta.total.