Upper Help
API

Stops

Create, update, delete, and list stops in Upper Route Planner using the external API.

The Stops endpoints let you manage individual stops in Upper Route Planner — geocoding addresses, attaching contact and scheduling details, and reading them back. You can create stops on their own or attach them to a route by passing a route_id.

Every endpoint on this page requires the x-api-token header. You'll find your token in the app under Settings → Webhooks (the API Token field, with a copy button). See Authentication for details.

When a stop belongs to a route, edits and deletions trigger re-optimization: if the route was already optimized, it is reset to upcoming and flagged to be optimized again. Stops cannot be created, updated, or deleted on a route that is currently active (in progress).

Create a stop

POST /api/v1/ext-create-stop

Header: x-api-token: <your token>

Creates a new stop. The address is geocoded with Google Maps to derive latitude/longitude, formatted address, city, state, and zipcode (any values you pass for those fields take precedence). Pass route_id to attach the stop to a route; omit it to create an unscheduled stop.

Parameters

NameTypeRequiredDescription
addressstringYesStreet address to geocode for the stop.
route_idintegerNoRoute to attach the stop to. Must belong to your team and not be active. If omitted, the stop is created as unscheduled.
citystringNoCity. Overrides the value derived from geocoding.
statestringNoState/region. Overrides the value derived from geocoding.
zipcodestringNoPostal code. Overrides the value derived from geocoding.
contact_namestringNoContact name for the stop.
phonestringNoContact phone number. Non-digit characters are stripped.
phone_country_codestringNoPhone dialing code (e.g. 1) used to resolve the contact's country. Falls back to the address country.
emailstringNoContact email.
notestringNoFree-text note for the stop.
company_namestringNoCompany name for the stop.
nick_namestringNoShort label / nickname for the stop.
pin_colorstringNoMap pin color as a hex value. Defaults to #000000.
start_timestringNoEarliest service time, HH:MM:SS or HH:MM (e.g. 09:00). Alias: earliest_time.
end_timestringNoLatest service time, HH:MM:SS or HH:MM (e.g. 17:00). Alias: latest_time.
stop_durationintegerNoService duration in seconds. Must be a non-negative integer.
stop_typestringNoStop type.
stop_prioritystringNoStop priority.
parcel_countintegerNoNumber of parcels at the stop.
customer_system_idstringNoYour external/system identifier for the stop.
platform_idintegerNoPlatform identifier.
custom_fieldsobjectNoKey/value map of custom fields. Only fields enabled for your account are stored, and only when the custom fields feature is included in your plan.
capacity_fieldsobjectNoKey/value map of capacity values. Valid keys: capacity1capacity5. Values are stored as integers.

Example request

curl -X POST "https://teamapi.upperinc.com/api/v1/ext-create-stop" \
  -H "x-api-token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "route_id": 502,
    "address": "1600 Amphitheatre Parkway, Mountain View, CA",
    "contact_name": "Jane Doe",
    "phone": "+1 415-555-0142",
    "phone_country_code": "1",
    "email": "jane@example.com",
    "note": "Leave at front desk",
    "company_name": "Acme Co",
    "pin_color": "#FF6600",
    "start_time": "09:00",
    "end_time": "17:00",
    "stop_duration": 300,
    "parcel_count": 2,
    "customer_system_id": "EXT-1001"
  }'

Example response

{
  "code": 200,
  "message": "Stop created successfully.",
  "data": {
    "stop_id": 84213,
    "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
    "route_id": 502,
    "latitude": 37.4220656,
    "longitude": -122.0840897
  }
}

If your plan limits stops per route and adding this stop would exceed it, the request fails with a message such as Stop limit exceeded. Your plan allows N stops per route.

Update a stop

POST /api/v1/ext-update-stop

Header: x-api-token: <your token>

Updates an existing stop. Only the fields you send are changed. If you send a new address, it is re-geocoded and the latitude/longitude, formatted address, city, state, zipcode, and verification flags are recalculated — and any city/state/zipcode you also pass are ignored in favor of the geocoded values. Changing the address marks an optimized route for re-optimization.

Parameters

NameTypeRequiredDescription
stop_idintegerYesID of the stop to update. Must belong to your team.
addressstringNoNew street address. Re-geocodes the stop and overrides city/state/zipcode.
citystringNoCity. Applied only when address is not sent.
statestringNoState/region. Applied only when address is not sent.
zipcodestringNoPostal code. Applied only when address is not sent.
contact_namestringNoContact name.
phonestringNoContact phone number. Non-digit characters are stripped.
phone_country_codestringNoPhone dialing code used to resolve the contact's country.
emailstringNoContact email.
notestringNoFree-text note.
company_namestringNoCompany name.
nick_namestringNoShort label / nickname.
route_idintegerNoReassign the stop to a route. Setting it marks the stop as scheduled.
pin_colorstringNoMap pin color as a hex value.
start_timestringNoEarliest service time, HH:MM:SS or HH:MM. Alias: earliest_time.
end_timestringNoLatest service time, HH:MM:SS or HH:MM. Alias: latest_time.
stop_durationintegerNoService duration in seconds. Must be a non-negative integer.
stop_typestringNoStop type.
stop_prioritystringNoStop priority.
parcel_countintegerNoNumber of parcels at the stop.
customer_system_idstringNoYour external/system identifier for the stop.
platform_idintegerNoPlatform identifier.
custom_fieldsobjectNoKey/value map of custom fields to update. Only enabled fields are written, and only when the custom fields feature is in your plan.
capacity_fieldsobjectNoKey/value map of capacity values. Valid keys: capacity1capacity5.

Example request

curl -X POST "https://teamapi.upperinc.com/api/v1/ext-update-stop" \
  -H "x-api-token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stop_id": 84213,
    "contact_name": "Jane D.",
    "phone": "+1 415-555-0199",
    "note": "Ring the bell twice",
    "end_time": "18:00"
  }'

Example response

{
  "code": 200,
  "message": "Stop updated successfully.",
  "data": {
    "stop_id": 84213,
    "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
    "route_id": 502,
    "latitude": "37.4220656",
    "longitude": "-122.0840897",
    "contact_name": "Jane D.",
    "phone": "14155550199",
    "phone_country_id": 38,
    "email": "jane@example.com",
    "needs_optimization": false
  }
}

Delete a stop

POST /api/v1/ext-delete-stop

Header: x-api-token: <your token>

Deletes a stop (soft delete). If the stop belongs to a route, the route's stop count is updated and, if the route was optimized, it is flagged for re-optimization. Stops on an active route cannot be deleted.

Parameters

NameTypeRequiredDescription
stop_idintegerYesID of the stop to delete. Must belong to your team.

Example request

curl -X POST "https://teamapi.upperinc.com/api/v1/ext-delete-stop" \
  -H "x-api-token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "stop_id": 84213 }'

Example response

{
  "code": 200,
  "message": "Stop deleted successfully.",
  "data": {
    "stop_id": 84213,
    "route_id": 502,
    "needs_optimization": true
  }
}

Get stops

GET /api/v1/ext-get-stops

Header: x-api-token: <your token>

Returns stops belonging to your team, ordered by their optimized order index. Use route_id to fetch the stops on a specific route, optionally filtered by scheduled. Use unscheduled=1 to fetch unscheduled stops across all routes. With no filter, all of your team's active stops are returned.

Parameters

NameTypeRequiredDescription
route_idintegerNoReturn only stops on this route. The route must belong to your team.
scheduledbooleanNoOnly valid with route_id. 1 returns scheduled stops, 0 returns unscheduled stops within that route.
unscheduledbooleanNoWhen 1 (and route_id is not set), returns unscheduled stops across all routes.

Example request

curl -X GET "https://teamapi.upperinc.com/api/v1/ext-get-stops?route_id=502" \
  -H "x-api-token: YOUR_API_TOKEN"

Example response

{
  "code": 200,
  "message": "Stops fetched successfully.",
  "data": [
    {
      "stop_id": 84213,
      "route_id": 502,
      "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
      "latitude": "37.4220656",
      "longitude": "-122.0840897",
      "contact_name": "Jane Doe",
      "phone": "14155550142",
      "phone_country_id": 38,
      "email": "jane@example.com",
      "note": "Leave at front desk",
      "company_name": "Acme Co",
      "city": "Mountain View",
      "state": "California",
      "zipcode": "94043",
      "status": "None",
      "start_time": "09:00:00",
      "end_time": "17:00:00",
      "stop_duration": 300,
      "order_index": 1,
      "customer_system_id": "EXT-1001",
      "stop_type": null,
      "stop_priority": "Medium",
      "parcel_count": 2,
      "is_scheduled": "Y",
      "created_at": "2026-06-24 10:15:00"
    }
  ],
  "total": 1
}

ext-get-stops adds a total field alongside the standard envelope, containing the number of stops returned in data.

Authentication errors

These apply to every endpoint on this page.

ConditionHTTP statusResponse
Missing x-api-token header400{ "code": 400, "message": "Token is required.", "data": [] }
Invalid or unknown token401{ "message": "User not found." }

On this page