Upper Help
API

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 (custom1custom5) and five capacity field slots (capacity1capacity5).

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 (custom1custom5); 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:

NameTypeRequiredDescription
(slot key)objectYesOne of custom1, custom2, custom3, custom4, custom5. Any other key is rejected.
typestringNoField input type. One of text, boolean, number.
namestringNoInternal field name.
valuemixedNoStored value(s) for the field.
requiredbooleanNoWhether the field is mandatory on a stop.
maxlengthnumberNoMaximum length; must be numeric.
labelstringNoDisplay label. Required (non-empty) when enable is true.
enablebooleanNoWhether the field is active. When true, label must be provided.
totalbooleanNoShow a total of this field across the route.
countbooleanNoShow a count of this field across the route.
averagebooleanNoShow 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 (capacity1capacity5); 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:

NameTypeRequiredDescription
(slot key)objectYesOne of capacity1, capacity2, capacity3, capacity4, capacity5. Any other key is rejected.
labelstringNoDisplay label. Required (non-empty) when enable is true.
unitstringNoUnit of measure (for example kg, counts, ). Required (non-empty) when enable is true.
enablebooleanNoWhether the field is active. When true, both label and unit must be provided.
requiredbooleanNoWhether the field is mandatory on a stop.
totalbooleanNoShow a total of this field across the route.
countbooleanNoShow a count of this field across the route.
averagebooleanNoShow 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\":\"\",\"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\":\"\",\"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 stringscapacity_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.

On this page