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
| Name | Type | Required | Description |
|---|---|---|---|
| address | string | Yes | Street address to geocode for the stop. |
| route_id | integer | No | Route to attach the stop to. Must belong to your team and not be active. If omitted, the stop is created as unscheduled. |
| city | string | No | City. Overrides the value derived from geocoding. |
| state | string | No | State/region. Overrides the value derived from geocoding. |
| zipcode | string | No | Postal code. Overrides the value derived from geocoding. |
| contact_name | string | No | Contact name for the stop. |
| phone | string | No | Contact phone number. Non-digit characters are stripped. |
| phone_country_code | string | No | Phone dialing code (e.g. 1) used to resolve the contact's country. Falls back to the address country. |
| string | No | Contact email. | |
| note | string | No | Free-text note for the stop. |
| company_name | string | No | Company name for the stop. |
| nick_name | string | No | Short label / nickname for the stop. |
| pin_color | string | No | Map pin color as a hex value. Defaults to #000000. |
| start_time | string | No | Earliest service time, HH:MM:SS or HH:MM (e.g. 09:00). Alias: earliest_time. |
| end_time | string | No | Latest service time, HH:MM:SS or HH:MM (e.g. 17:00). Alias: latest_time. |
| stop_duration | integer | No | Service duration in seconds. Must be a non-negative integer. |
| stop_type | string | No | Stop type. |
| stop_priority | string | No | Stop priority. |
| parcel_count | integer | No | Number of parcels at the stop. |
| customer_system_id | string | No | Your external/system identifier for the stop. |
| platform_id | integer | No | Platform identifier. |
| custom_fields | object | No | Key/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_fields | object | No | Key/value map of capacity values. Valid keys: capacity1–capacity5. 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
| Name | Type | Required | Description |
|---|---|---|---|
| stop_id | integer | Yes | ID of the stop to update. Must belong to your team. |
| address | string | No | New street address. Re-geocodes the stop and overrides city/state/zipcode. |
| city | string | No | City. Applied only when address is not sent. |
| state | string | No | State/region. Applied only when address is not sent. |
| zipcode | string | No | Postal code. Applied only when address is not sent. |
| contact_name | string | No | Contact name. |
| phone | string | No | Contact phone number. Non-digit characters are stripped. |
| phone_country_code | string | No | Phone dialing code used to resolve the contact's country. |
| string | No | Contact email. | |
| note | string | No | Free-text note. |
| company_name | string | No | Company name. |
| nick_name | string | No | Short label / nickname. |
| route_id | integer | No | Reassign the stop to a route. Setting it marks the stop as scheduled. |
| pin_color | string | No | Map pin color as a hex value. |
| start_time | string | No | Earliest service time, HH:MM:SS or HH:MM. Alias: earliest_time. |
| end_time | string | No | Latest service time, HH:MM:SS or HH:MM. Alias: latest_time. |
| stop_duration | integer | No | Service duration in seconds. Must be a non-negative integer. |
| stop_type | string | No | Stop type. |
| stop_priority | string | No | Stop priority. |
| parcel_count | integer | No | Number of parcels at the stop. |
| customer_system_id | string | No | Your external/system identifier for the stop. |
| platform_id | integer | No | Platform identifier. |
| custom_fields | object | No | Key/value map of custom fields to update. Only enabled fields are written, and only when the custom fields feature is in your plan. |
| capacity_fields | object | No | Key/value map of capacity values. Valid keys: capacity1–capacity5. |
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
| Name | Type | Required | Description |
|---|---|---|---|
| stop_id | integer | Yes | ID 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
| Name | Type | Required | Description |
|---|---|---|---|
| route_id | integer | No | Return only stops on this route. The route must belong to your team. |
| scheduled | boolean | No | Only valid with route_id. 1 returns scheduled stops, 0 returns unscheduled stops within that route. |
| unscheduled | boolean | No | When 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.
| Condition | HTTP status | Response |
|---|---|---|
Missing x-api-token header | 400 | { "code": 400, "message": "Token is required.", "data": [] } |
| Invalid or unknown token | 401 | { "message": "User not found." } |