curl --request POST \
--url https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"asset_id": "<string>",
"quantity": 2,
"components": [
{
"stockable_id": "<string>",
"stock_sources": [
{
"quantity": 2,
"asset_id": "<string>",
"group_id": "<string>"
}
]
}
],
"cost": 123
}
'import requests
url = "https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate"
payload = {
"asset_id": "<string>",
"quantity": 2,
"components": [
{
"stockable_id": "<string>",
"stock_sources": [
{
"quantity": 2,
"asset_id": "<string>",
"group_id": "<string>"
}
]
}
],
"cost": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
asset_id: '<string>',
quantity: 2,
components: [
{
stockable_id: '<string>',
stock_sources: [{quantity: 2, asset_id: '<string>', group_id: '<string>'}]
}
],
cost: 123
})
};
fetch('https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'asset_id' => '<string>',
'quantity' => 2,
'components' => [
[
'stockable_id' => '<string>',
'stock_sources' => [
[
'quantity' => 2,
'asset_id' => '<string>',
'group_id' => '<string>'
]
]
]
],
'cost' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate"
payload := strings.NewReader("{\n \"asset_id\": \"<string>\",\n \"quantity\": 2,\n \"components\": [\n {\n \"stockable_id\": \"<string>\",\n \"stock_sources\": [\n {\n \"quantity\": 2,\n \"asset_id\": \"<string>\",\n \"group_id\": \"<string>\"\n }\n ]\n }\n ],\n \"cost\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"asset_id\": \"<string>\",\n \"quantity\": 2,\n \"components\": [\n {\n \"stockable_id\": \"<string>\",\n \"stock_sources\": [\n {\n \"quantity\": 2,\n \"asset_id\": \"<string>\",\n \"group_id\": \"<string>\"\n }\n ]\n }\n ],\n \"cost\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"asset_id\": \"<string>\",\n \"quantity\": 2,\n \"components\": [\n {\n \"stockable_id\": \"<string>\",\n \"stock_sources\": [\n {\n \"quantity\": 2,\n \"asset_id\": \"<string>\",\n \"group_id\": \"<string>\"\n }\n ]\n }\n ],\n \"cost\": 123\n}"
response = http.request(request)
puts response.read_body{
"bundle_id": "<string>",
"asset_id": "<string>",
"quantity_assembled": 123,
"quantity_disassembled": 123,
"component_deductions": "<array>",
"component_returns": "<array>"
}{
"message": "<string>",
"errors": {}
}Assemble bundles from stock
Builds a quantity of bundles at a location by consuming the components from stock.
curl --request POST \
--url https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"asset_id": "<string>",
"quantity": 2,
"components": [
{
"stockable_id": "<string>",
"stock_sources": [
{
"quantity": 2,
"asset_id": "<string>",
"group_id": "<string>"
}
]
}
],
"cost": 123
}
'import requests
url = "https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate"
payload = {
"asset_id": "<string>",
"quantity": 2,
"components": [
{
"stockable_id": "<string>",
"stock_sources": [
{
"quantity": 2,
"asset_id": "<string>",
"group_id": "<string>"
}
]
}
],
"cost": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
asset_id: '<string>',
quantity: 2,
components: [
{
stockable_id: '<string>',
stock_sources: [{quantity: 2, asset_id: '<string>', group_id: '<string>'}]
}
],
cost: 123
})
};
fetch('https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'asset_id' => '<string>',
'quantity' => 2,
'components' => [
[
'stockable_id' => '<string>',
'stock_sources' => [
[
'quantity' => 2,
'asset_id' => '<string>',
'group_id' => '<string>'
]
]
]
],
'cost' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate"
payload := strings.NewReader("{\n \"asset_id\": \"<string>\",\n \"quantity\": 2,\n \"components\": [\n {\n \"stockable_id\": \"<string>\",\n \"stock_sources\": [\n {\n \"quantity\": 2,\n \"asset_id\": \"<string>\",\n \"group_id\": \"<string>\"\n }\n ]\n }\n ],\n \"cost\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"asset_id\": \"<string>\",\n \"quantity\": 2,\n \"components\": [\n {\n \"stockable_id\": \"<string>\",\n \"stock_sources\": [\n {\n \"quantity\": 2,\n \"asset_id\": \"<string>\",\n \"group_id\": \"<string>\"\n }\n ]\n }\n ],\n \"cost\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.exowpee.com/v1/catalog/bundles/{bundle}/populate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"asset_id\": \"<string>\",\n \"quantity\": 2,\n \"components\": [\n {\n \"stockable_id\": \"<string>\",\n \"stock_sources\": [\n {\n \"quantity\": 2,\n \"asset_id\": \"<string>\",\n \"group_id\": \"<string>\"\n }\n ]\n }\n ],\n \"cost\": 123\n}"
response = http.request(request)
puts response.read_body{
"bundle_id": "<string>",
"asset_id": "<string>",
"quantity_assembled": 123,
"quantity_disassembled": 123,
"component_deductions": "<array>",
"component_returns": "<array>"
}{
"message": "<string>",
"errors": {}
}bundles.populate
Conditions
- The bundle must not be archived.
- asset_id must be a location of the organization; the assembled bundles are stocked in there.
- components must list exactly the bundle’s recipe: a missing or extra stockable_id is refused, and each stockable_id may appear once.
- A component’s own asset_id, inventory_group_id or group_id is refused (even null); stock sources go in stock_sources.
- A tracked component must list stock_sources (at least one); an untracked component must not.
- Each stock source names exactly one of asset_id (a location) or group_id (a stock group), and the same location or group cannot appear twice for one component.
- For each tracked component the source quantities must add up to the recipe quantity times the number of bundles assembled.
- A source location must hold stock of that component, and a source group must still hold stock and belong to that component.
- Every component unit must be active.
- A shortfall of stock in a source is refused; nothing is changed.
- cost, when sent, is in major units, at least 0, with at most the currency’s decimals.
- Concurrent stock operations are retried up to three times; if they keep conflicting the call answers 409 and nothing is changed.
- Withdraws the required quantity of each tracked component from its listed stock sources and records the inventory movements and the matching entries in the books.
- Stocks the assembled bundles in at asset_id with the given total cost (0 when cost is omitted), creating the bundle’s stock record when needed, with the matching entries in the books.
- Untracked components take part in the recipe but no stock movement is made for them.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Identifier of the bundle (27-character KSUID string).
Body
Structural checks only. Recipe coverage, tracking, quantities per component and stock sources are resolved by BundleService::populate inside the bundle's scope.
Each tracked component lists its stock_sources; a source names one location (asset_id)
or one stock group (group_id) and the quantity, in recipe units, taken from it for the
whole operation.
Identifier of the location where the assembled bundles are stocked in. It must be a location of the organization.
Number of bundles to assemble, at least 1.
x >= 1The bundle's recipe: one entry for each component of the bundle, no more and no fewer.
1Show child attributes
Show child attributes
Total cost of the assembled bundles stocked in, in major units, at least 0 with at most the currency's decimals. Treated as 0 when omitted.
Response
BundleStockOperationResource
Identifier of the bundle that was assembled or detached.
Location where the bundles were stocked in (assembly) or taken out (detach).
Number of bundles assembled. Null on a detach.
Number of bundles taken apart. Null on an assembly.
On an assembly, one entry per recipe component with stockable_id, stockable_unit_id, quantity_deducted (what was withdrawn, in the recipe unit; 0 for an untracked component) and base_quantity_deducted. Null on a detach.
On a detach, one entry per component with stockable_id, stockable_unit_id, quantity_returned and base_quantity_returned. Null on an assembly.