Custom & capacity fields
Read and configure your workspace's stop custom fields and capacity fields through the Upper Crew API.
Custom fields and capacity fields let you attach your own data to every stop in Upper. Custom fields are free-form attributes — text, numbers, or yes/no toggles — that you define once and then fill in per stop (for example an order ID, a gate code, or a "fragile" flag). Capacity fields are quantity attributes used for load planning, each with a label and a unit (for example Boxes / counts or Weight / kg), so Upper can balance how much each driver carries.
Both sets of fields live at the workspace (owner) level: the API always reads and writes the configuration for the account owner, regardless of which team member's token is used. There are five custom field slots (custom1–custom5) and five capacity field slots (capacity1–capacity5).
All endpoints below use the base URL https://teamapi.upperinc.com/api/v1 and require your API token. See Authentication for how to obtain and send your token.
Custom fields require the Custom fields feature in your plan. If it's not enabled, the custom-field endpoints return HTTP 400 with "Custom fields feature is not available in your plan." The capacity-field endpoints do not perform this plan check.
Get custom fields
GET /api/v1/ext-get-custom-fields
Header: x-api-token: <your token>
Returns the full configuration of all five stop custom field slots, plus a list of which slots are currently enabled.
Parameters
No parameters.
Example request
curl -X GET "https://teamapi.upperinc.com/api/v1/ext-get-custom-fields" \
-H "x-api-token: YOUR_API_TOKEN"Example response
{
"code": 200,
"message": "Custom fields retrieved successfully.",
"data": {
"custom_fields": {
"custom1": {
"type": "text",
"name": "custom_field[]",
"value": [],
"default_value": "",
"required": false,
"maxlength": 2000,
"label": "Order ID",
"sort_order": 1,
"enable": true,
"total": false,
"count": false,
"average": false
},
"custom2": {
"type": "text",
"name": "custom_field[]",
"value": [],
"default_value": "",
"required": false,
"maxlength": 2000,
"label": "",
"sort_order": 1,
"enable": false,
"total": false,
"count": false,
"average": false
},
"custom3": { "type": "text", "label": "", "enable": false },
"custom4": { "type": "text", "label": "", "enable": false },
"custom5": { "type": "text", "label": "", "enable": false }
},
"enabled_fields": ["custom1"]
}
}The exact set of properties returned for each slot reflects whatever has been saved for your workspace. Slots that have never been configured fall back to defaults (type text, disabled, empty label).
Update custom fields
POST /api/v1/ext-update-custom-fields
Header: x-api-token: <your token>
Updates one or more custom field slots. The request body is a JSON object keyed by slot name (custom1–custom5); each value is an object containing only the properties you want to change. Properties you omit keep their existing saved value (the update is merged, not replaced).
Parameters
The top-level keys are the slot names. Within each slot object, the following properties are accepted:
| Name | Type | Required | Description |
|---|---|---|---|
| (slot key) | object | Yes | One of custom1, custom2, custom3, custom4, custom5. Any other key is rejected. |
type | string | No | Field input type. One of text, boolean, number. |
name | string | No | Internal field name. |
value | mixed | No | Stored value(s) for the field. |
required | boolean | No | Whether the field is mandatory on a stop. |
maxlength | number | No | Maximum length; must be numeric. |
label | string | No | Display label. Required (non-empty) when enable is true. |
enable | boolean | No | Whether the field is active. When true, label must be provided. |
total | boolean | No | Show a total of this field across the route. |
count | boolean | No | Show a count of this field across the route. |
average | boolean | No | Show an average of this field across the route. |
If you set enable to true for a slot, you must also provide a non-empty label — otherwise the request fails with "label is required when enable is true for <slot>". Sending an invalid slot key, an unknown property, an out-of-range type, or a non-numeric maxlength also returns HTTP 400 with a descriptive message.
Example request
curl -X POST "https://teamapi.upperinc.com/api/v1/ext-update-custom-fields" \
-H "x-api-token: YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"custom1": {
"type": "text",
"label": "Order ID",
"enable": true,
"required": true,
"maxlength": 50
},
"custom2": {
"type": "boolean",
"label": "Fragile",
"enable": true
}
}'Example response
{
"code": 200,
"message": "Custom fields updated successfully.",
"data": {
"custom_fields": "{\"custom1\":{\"type\":\"text\",\"name\":\"custom_field[]\",\"value\":[],\"default_value\":\"\",\"required\":true,\"maxlength\":50,\"label\":\"Order ID\",\"sort_order\":1,\"enable\":true,\"total\":false,\"count\":false,\"average\":false},\"custom2\":{\"type\":\"boolean\",\"name\":\"custom_field[]\",\"value\":[],\"default_value\":\"\",\"required\":false,\"maxlength\":2000,\"label\":\"Fragile\",\"sort_order\":1,\"enable\":true,\"total\":false,\"count\":false,\"average\":false},\"custom3\":{\"type\":\"text\",\"name\":\"custom_field[]\",\"value\":[],\"default_value\":\"\",\"required\":false,\"maxlength\":2000,\"label\":\"\",\"sort_order\":1,\"enable\":false,\"total\":false,\"count\":false,\"average\":false},\"custom4\":{ /* …disabled… */ },\"custom5\":{ /* …disabled… */ }}",
"custom_fields_enabled": "{\"custom1\":{\"type\":\"text\",\"name\":\"custom_field[]\",\"value\":[],\"default_value\":\"\",\"required\":true,\"maxlength\":50,\"label\":\"Order ID\",\"sort_order\":1,\"enable\":true,\"total\":false,\"count\":false,\"average\":false},\"custom2\":{\"type\":\"boolean\",\"name\":\"custom_field[]\",\"value\":[],\"default_value\":\"\",\"required\":false,\"maxlength\":2000,\"label\":\"Fragile\",\"sort_order\":1,\"enable\":true,\"total\":false,\"count\":false,\"average\":false}}"
}
}On this endpoint both custom_fields and custom_fields_enabled are returned as JSON-encoded strings. custom_fields holds all five slots; custom_fields_enabled holds only the slots that are enabled. Parse the string (e.g. JSON.parse(...)) to read the values. (The /* …disabled… */ markers above are just to keep the example short — the real string contains the full default object for every slot.)
Get capacity fields
GET /api/v1/ext-get-capacity-fields
Header: x-api-token: <your token>
Returns the configuration of all five capacity field slots, plus a list of which slots are currently enabled.
Parameters
No parameters.
Example request
curl -X GET "https://teamapi.upperinc.com/api/v1/ext-get-capacity-fields" \
-H "x-api-token: YOUR_API_TOKEN"Example response
{
"code": 200,
"message": "Capacity fields retrieved successfully.",
"data": {
"capacity_fields": {
"capacity1": {
"label": "Boxes",
"unit": "counts",
"enable": true,
"required": false,
"total": false,
"count": false,
"average": false
},
"capacity2": {
"label": "Volume",
"unit": "m³",
"enable": true,
"required": false,
"total": false,
"count": false,
"average": false
},
"capacity3": {
"label": "Weight",
"unit": "kg",
"enable": false,
"required": false,
"total": false,
"count": false,
"average": false
},
"capacity4": {
"label": "",
"unit": "",
"enable": false,
"required": false,
"total": false,
"count": false,
"average": false
},
"capacity5": {
"label": "",
"unit": "",
"enable": false,
"required": false,
"total": false,
"count": false,
"average": false
}
},
"enabled_fields": ["capacity1", "capacity2"]
}
}Update capacity fields
POST /api/v1/ext-update-capacity-fields
Header: x-api-token: <your token>
Updates one or more capacity field slots. The request body is a JSON object keyed by slot name (capacity1–capacity5); each value is an object containing only the properties you want to change. Omitted properties keep their existing saved value (the update is merged, not replaced).
Parameters
The top-level keys are the slot names. Within each slot object, the following properties are accepted:
| Name | Type | Required | Description |
|---|---|---|---|
| (slot key) | object | Yes | One of capacity1, capacity2, capacity3, capacity4, capacity5. Any other key is rejected. |
label | string | No | Display label. Required (non-empty) when enable is true. |
unit | string | No | Unit of measure (for example kg, counts, m³). Required (non-empty) when enable is true. |
enable | boolean | No | Whether the field is active. When true, both label and unit must be provided. |
required | boolean | No | Whether the field is mandatory on a stop. |
total | boolean | No | Show a total of this field across the route. |
count | boolean | No | Show a count of this field across the route. |
average | boolean | No | Show an average of this field across the route. |
When you enable a capacity slot, both label and unit are required. A missing label fails with "label is required when enable is true for <slot>" and a missing unit with "unit is required when enable is true for <slot>". Invalid slot keys or unknown properties return HTTP 400.
Example request
curl -X POST "https://teamapi.upperinc.com/api/v1/ext-update-capacity-fields" \
-H "x-api-token: YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"capacity3": {
"label": "Weight",
"unit": "kg",
"enable": true,
"total": true
}
}'Example response
{
"code": 200,
"message": "Capacity fields updated successfully.",
"data": {
"capacity_fields": "{\"capacity1\":{\"label\":\"Boxes\",\"unit\":\"counts\",\"enable\":true,\"required\":false,\"total\":false,\"count\":false,\"average\":false},\"capacity2\":{\"label\":\"Volume\",\"unit\":\"m³\",\"enable\":true,\"required\":false,\"total\":false,\"count\":false,\"average\":false},\"capacity3\":{\"label\":\"Weight\",\"unit\":\"kg\",\"enable\":true,\"total\":true,\"required\":false,\"count\":false,\"average\":false},\"capacity4\":{\"label\":\"\",\"unit\":\"\",\"enable\":false,\"required\":false,\"total\":false,\"count\":false,\"average\":false},\"capacity5\":{\"label\":\"\",\"unit\":\"\",\"enable\":false,\"required\":false,\"total\":false,\"count\":false,\"average\":false}}",
"capacity_fields_enabled": "{\"capacity1\":{\"label\":\"Boxes\",\"unit\":\"counts\",\"enable\":true,\"required\":false,\"total\":false,\"count\":false,\"average\":false},\"capacity2\":{\"label\":\"Volume\",\"unit\":\"m³\",\"enable\":true,\"required\":false,\"total\":false,\"count\":false,\"average\":false},\"capacity3\":{\"label\":\"Weight\",\"unit\":\"kg\",\"enable\":true,\"total\":true,\"required\":false,\"count\":false,\"average\":false}}"
}
}As with custom fields, the update endpoint returns both capacity_fields and capacity_fields_enabled as JSON-encoded strings — capacity_fields holds all five slots, capacity_fields_enabled only the enabled ones. Parse the string to read the values.
Errors
These endpoints share the standard authentication errors:
- Missing token → HTTP 400
{ "code": 400, "message": "Token is required.", "data": [] } - Invalid or unknown token → HTTP 401
{ "message": "User not found." }
Validation failures (invalid JSON, unknown slot keys, unknown properties, invalid type or maxlength, or a missing required label/unit) return HTTP 400 with the standard { code, message, data } envelope and a message describing the problem.