Split into Line Buckets
Split into Line Buckets
A quote or draft order often has to be fulfilled as several orders: one per site, per subsidiary or per billing account. Line buckets are how Nue does that. Each bucket groups some of the lines, carries its own account, billing account, contact, addresses and dates, and becomes its own order. These endpoints let an integration read, build, change, remove and finalize line buckets with the same rules as the Split Lines screen and Nue AI.
For the business walkthrough, see Split Quotes and Orders into Line Buckets via API and AI in the Knowledge Center.
Before you start
- Turn on Allow quote split into multiple orders (quotes) or Allow orders to be split into smaller orders (draft orders) in Nue Settings → Lifecycle Manager → Quotes and Orders. With a setting off, reads still work and report splitEnabled: false; every change is refused with SPLIT_NOT_ENABLED.
- Only a Draft order can be split. Activating an order first makes its split impossible.
- These endpoints are on the CPQ API and are available on Salesforce-integrated tenants.
- Quote and order endpoints take the Salesforce record id in the path. Lines are addressed by their Salesforce id too: Quote Line Item ids (0QL…) on a quote and Order Product ids (802…) on an order.
Endpoints
Endpoint | Method | Description |
|---|---|---|
/cpq/quotes/{quoteId}/line-buckets | GET | Read a quote's buckets and lines |
/cpq/orders/{orderId}/line-buckets | GET | Read a draft order's buckets and lines |
/cpq/quotes/{quoteId}/line-buckets:apply | POST | Create or change a quote's buckets and move lines into them |
/cpq/orders/{orderId}/line-buckets:apply | POST | The same, for a draft order |
/cpq/quotes/{quoteId}/line-buckets:delete | POST | Remove empty buckets from a quote |
/cpq/orders/{orderId}/line-buckets:delete | POST | Remove empty buckets from a draft order |
/cpq/quotes/{quoteId}/line-buckets:finalize | POST | Turn a quote's buckets into orders |
/cpq/orders/{orderId}/line-buckets:finalize | POST | Turn a draft order's buckets into smaller orders |
The same operations are available in Apex through GlobalLineBucketService (getLineBuckets, applyLineBuckets, deleteLineBuckets, finalizeLineBuckets) and to AI agents as the line-bucket tools of the Nue Lifecycle Manager.
Read Buckets
GET /cpq/quotes/0Q0E2000005oysXKAQ/line-buckets{
"header": {
"headerId": "0Q0E2000005oysXKAQ",
"headerType": "Quote",
"currencyIsoCode": "USD",
"totalAmount": 15516.4,
"splitEnabled": true,
"displayFields": [
{ "apiName": "Name", "label": "Line Bucket Name" },
{ "apiName": "Ruby__Account__c", "label": "Account" },
{ "apiName": "Ruby__StartDate__c", "label": "Start Date" }
]
},
"buckets": [
{
"bucketId": "a0VE200000Np1aBMAR",
"bucketKey": "harvey_downtown",
"name": "Harvey Downtown",
"isDefault": false,
"status": "Draft",
"totalAmount": 10237.6,
"displayFields": [
{ "apiName": "Ruby__Account__c", "label": "Account", "type": "REFERENCE", "value": "001E200002CLcNKIA1", "displayValue": "Smart Revenue" },
{ "apiName": "Ruby__StartDate__c", "label": "Start Date", "type": "DATE", "value": "2026-11-01", "displayValue": "2026-11-01" }
],
"lines": [
{ "lineId": "0QLE2000004NBjdOAG", "productName": "Nue Gem Edition", "lineType": "LineItem", "quantity": 10, "amount": 5000 },
{ "lineId": "0QLE2000004NBjeOAG", "productName": "Revenue Manager", "lineType": "LineItem", "quantity": 10, "amount": 0, "parentLineId": "0QLE2000004NBjdOAG" }
]
}
],
"issues": [],
"warnings": []
}Key behaviors
- Every bucket is returned, including the Default Bucket, which holds any line not placed elsewhere.
- header.displayFields lists the fields in the Line Bucket field set Fields Displayed In Bucket, in the admin's order. Each bucket's displayFields carries the value of each of those fields: value is the stored value and displayValue is what to show. A lookup's displayValue is the record's name, never its id, and an empty field comes back with value: null.
- parentLineId links a bundle option to its bundle. summaryLineId, startDate and endDate link a ramp year to its line and give its period.
- Reading is not gated by the split settings.
- The REST reply always lists every bucket and line. The summarized view of large splits is applied only by the Nue Lifecycle Manager MCP tools.
Create and Change Buckets
POST /cpq/quotes/0Q0E2000005oysXKAQ/line-buckets:apply{
"validateOnly": true,
"buckets": [
{
"bucketKey": "harvey_downtown",
"name": "Harvey Downtown",
"paymentTerm": "Net 45",
"allocations": [
{ "lineId": "0QLE2000004NBjdOAG", "includeChildLines": true },
{ "lineId": "0QLE2000004NBjiOAG", "includeChildLines": true }
]
},
{
"bucketKey": "harvey_north",
"name": "Harvey North",
"allocations": [
{ "lineId": "0QLE2000004NBjnOAG", "includeChildLines": true },
{ "lineId": "0QLE2000004NBjsOAG" }
]
}
]
}The response has the same shape as a read, showing the buckets as they would be (validateOnly: true) or as they are now saved (validateOnly: false).
Key behaviors
- One call describes the arrangement. A bucket is addressed by your own bucketKey, so sending the same key again updates that bucket instead of creating a second one. That makes a retried call safe. Keys starting with DEFAULT are reserved.
- Preview first. Set validateOnly: true to see the result without saving anything.
- Lines move whole. A line goes into exactly one bucket. Splitting one line's quantity across buckets isn't supported here and is refused (QUANTITY_SPLIT_NOT_SUPPORTED). Use the Split Lines screen for quantity splits.
- Children. includeChildLines: true carries all of a bundle's child lines with it. Without it, the bundle takes only the options that are priced from it. An option included in the bundle's price, tied to the bundle's quantity or priced per bundle can't be moved on its own (OPTION_FOLLOWS_BUNDLE). Other options, such as add-ons with their own price, can go to a different bucket.
- Apply never removes a bucket. A bucket you leave out stays as it was, with its lines. Use delete to remove one.
- Field values. Bucket fields can be set by name (billingAccountId, primaryContactId, startDate, paymentTerm, the billing and shipping address parts) or through fields. A value that won't reach the order is saved with a warning; set failOnUnmappedFields: true to refuse the call instead.
- Limits. One call takes up to 200 buckets and 800 line moves; a bundle's options and a ramp's years count as lines. Past either, the call is refused with REQUEST_TOO_LARGE and nothing is saved, so send it in parts.
- Large headers. On the first save of a quote or order with more than 800 lines in no bucket yet, a preview answers ADOPTION_REQUIRED. A save starts a background job that places those lines in the Default Bucket and answers ADOPTION_IN_PROGRESS with the job id. Wait for it, then send the change again.
- Locked buckets. A bucket that has become an order can't change (BUCKET_FINALIZED). Delete its Draft order, or cancel it if it was activated, to change it again.
Remove Buckets
POST /cpq/quotes/0Q0E2000005oysXKAQ/line-buckets:delete{ "bucketRefs": ["harvey_service"] }Only empty buckets that haven't become orders can be removed. A bucket that still holds lines is refused (BUCKET_NOT_EMPTY), so move its lines first. The Default Bucket can't be removed. The response's buckets are the ones that remain, and deleted names each bucket removed.
Turn Buckets into Orders
POST /cpq/quotes/0Q0E2000005oysXKAQ/line-buckets:finalize{
"allDraft": true,
"activateOrders": false
}{
"buckets": [
{ "bucketKey": "DEFAULT", "outcome": "SKIPPED_EMPTY" },
{ "bucketKey": "harvey_downtown", "outcome": "FINALIZED", "orderId": "801E200002DQ1aBIAT", "orderNumber": "00002617", "orderStatus": "Draft" },
{ "bucketKey": "harvey_north", "outcome": "FINALIZED", "orderId": "801E200002DQ1aCIAT", "orderNumber": "00002618", "orderStatus": "Draft" }
],
"warnings": []
}Key behaviors
- One order per bucket that holds lines. An empty bucket comes back SKIPPED_EMPTY and makes no order.
- Each bucket stands alone. A bucket comes back FINALIZED, ALREADY_FINALIZED, SKIPPED_EMPTY or FAILED with its reason, and one failure doesn't stop the others. Repeating a call can't create a second order for a bucket.
- Large requests. A bucket the call had no capacity left for comes back NOT_REACHED. Send another call with bucketRefs listing the NOT_REACHED buckets, and none that came back FAILED.
- Quote rules still apply. On a quote, the whole call is refused when the tenant only allows orders from approved quotes (QUOTE_NOT_APPROVED) or only from primary quotes (QUOTE_NOT_PRIMARY) and this quote isn't one.
- Draft by default. Orders are created as Draft. activateOrders: true activates them immediately, which provisions subscriptions, assets and entitlements that can only be cancelled afterward.
- Each bucket's fields copy to its order through the Line Bucket to Order object mapping and through fields with the same API name.
Permissions
To do this | Needs |
|---|---|
Read a quote's or order's buckets | Access to the quote or order |
Apply or delete on a quote | Manage Quote |
Apply or delete on an order | Manage Order |
Finalize | Manage Order |
On Salesforce, the user also needs read access to the line's Line Bucket field, which the Nue permission sets grant. Without it, every call is refused with LINE_BUCKET_NOT_READABLE instead of treating every bucket as empty.
Errors
Refused calls return a code and a plain message saying what to change. A refused apply or delete saves nothing; finalize works bucket by bucket, as described above.
Code | Meaning |
|---|---|
INVALID_HEADER_TYPE | The id is not a Quote or an Order id |
SPLIT_NOT_ENABLED | The split setting for quotes or orders is off |
QUANTITY_SPLIT_NOT_SUPPORTED | The call tried to split one line's quantity across buckets |
LINE_IN_TWO_BUCKETS | The same line was placed in two buckets |
OPTION_FOLLOWS_BUNDLE | An option priced from its bundle was moved without the bundle |
BUCKET_FINALIZED | The bucket has already become an order |
BUCKET_NOT_EMPTY | Delete was asked for a bucket that still holds lines |
REQUEST_TOO_LARGE | More than 200 buckets or 800 line moves in one call |
ADOPTION_REQUIRED / ADOPTION_IN_PROGRESS | A large header must first be prepared in the background |
LINE_BUCKET_NOT_READABLE | The user can't read which bucket each line is in |