Query carrier branches for a given carrier and country. Filters allow searching by zipcode, locality, state, geolocation, etc. type is the search type: 1, 2, or 3.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
When to use this endpoint
Use GET|POST /branches/{carrier}/{country_code} on the Queries API when you need a carrier’s service points (branches / drop-off and delivery locations) for a given country.
Typical uses:
- Let a shipper pick an origin or destination branch when the selected service requires drop-off or pick-up at a branch.
- Auto-select the nearest branch near an address (postal code, state, locality, and optionally street or coordinates).
- Populate branch pickers filtered by state and locality.
Call this before label creation when the chosen service requires a branch on origin and/or destination (for example when drop_off is 1 = origin, 2 = destination, or 3 = both). A missing branch_code can block label generation.
Base URLs (Queries API)
| Environment | Base URL |
|---|---|
| Sandbox | https://queries.test.envia.com/ |
| Production | https://queries.envia.com/ |
Authentication
Authorization: Bearer <ENVIA_TOKEN>Create or copy your token in the matching sandbox or production account. See Authentication.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
carrier | string | Yes | Carrier slug from GET /carrier?country_code={country_code} (name field, lowercase — not the marketing display name). |
country_code | string | Yes | ISO country code, 2–3 characters (e.g. MX, US, CO). |
Important: response shape
HTTP 200 returns a JSON array of branch objects.
This endpoint does not wrap results in { "data": [...] }. Parse the body as an array:
const branches = await response.json(); // array| Result | Meaning |
|---|---|
[...] | Matching branches (may include distance when geocoded). |
[] | No matching branches after the search cascade — not necessarily an error. |
Do not assume a { success, data, message } envelope for successful lookups on this path.
Using branch_code
branch_codeEach branch includes a branch_code. That value is the primary identifier to send when creating a label that requires a branch on origin and/or destination.
- Use
branch_codefrom the selected branch (often the nearest:branches[0]when results are distance-sorted). - On label / shipment payloads, send it on the corresponding address (commonly as
branchCode/branch_code, depending on the shipping API field). branch_idandreferenceare useful for catalogs and UI labels;branch_codeis what label generation expects.
Example (conceptual):
const nearest = branches[0];
const branchCode = nearest?.branch_code;
// Attach branchCode to the origin or destination address before creating the labelSearch behavior
Filters may be sent as a query string (GET) or a JSON body (POST). Field names are the same.
Nearby ranking (50 km)
- If
latitude/longitudeare present, or can be resolved from address fields (state,locality,zipcode,address), the API ranks active branches by Haversine distance and keeps those within 50 km, ordered nearest first. Adistancefield (km) is present on those rows. - If that yields no rows, it falls back to the same filters without distance ranking.
- If still empty and
zipcodehas more than one character, it retries with a shorter postal prefix. - Final fallback: active branches for that carrier and country with location filters removed.
Capability filter (type)
type)| Value | Meaning |
|---|---|
1 (default) | Admission / origin (drop-off) |
2 | Delivery / destination |
3 | Both |
Caching
- GET responses may be HTTP-cached up to 24 hours.
- POST is not cached the same way — prefer POST when filters or package rules must stay fresh.
There is no client-facing page cursor. Use limitBranches when you need to cap the number of rows.
Additional parameters
Common filters (zipcode, state, locality, address, latitude, longitude, type) work on both GET and POST. The following parameters are especially useful for UI pickers and rule-aware search.
| Parameter | Type | Method | Description |
|---|---|---|---|
branchType | string | GET or POST | Comma-separated branch categories: 1 Post Office, 2 Warehouse, 3 Third Party, 4 Lockers. |
limitBranches | number | GET or POST | Optional maximum number of branches returned. |
shipmentType | number | GET or POST | Filters by branch_rules.shipmentType (allowed values 0–9). |
packages | array | POST only | Package constraints evaluated against branch_rules (maxAmount, maxWeight, maxLength, maxHeight, maxWidth). |
carrierId | number | POST only | Carrier id from GET /carrier. Switches on live carrier lookup for carriers that support it. |
serviceName | string | POST only | Carrier service name. Required by live carrier lookup. |
packages item shape (POST)
packages item shape (POST)| Field | Type | Required | Description |
|---|---|---|---|
weight | number | Yes | Package weight. |
length | number | Yes | Length. |
height | number | Yes | Height. |
width | number | Yes | Width. |
amount | number | No | Quantity of this package. |
package_type | number | No | Package type id. |
POST vs GET
| Prefer | When |
|---|---|
| GET | Simple nearby or filter queries (zipcode, state/locality, lat/lng). Results may be cached up to 24 hours. |
| POST | Sending state/locality names, packages, or larger filter sets (avoids URL length limits; not cached like GET). |
If packages and/or shipmentType are present, branches may be filtered by branch_rules. Malformed branch_rules JSON on a row is ignored for that branch (the branch is still returned).
Live carrier lookup (POST with carrierId)
carrierId)Some carriers do not keep their branches in the Envia catalog. For those carriers, POST /branches/{carrier}/{country_code} can ask the carrier in real time for the points near an address, instead of reading the catalog.
When live lookup runs
All three conditions must be true:
- The request is a POST.
- The body includes
carrierId. - That carrier has the
return_branches_by_addressaction, andcarrierIdbelongs to the{carrier}in the path.
Otherwise the endpoint uses the catalog search described above. A GET always uses the catalog, even if you send carrierId.
Check that a carrier supports it
- Get the carrier
idfrom the carriers list. Match it byname.
curl --request GET \
--url "https://queries.test.envia.com/carrier?country_code={country_code}" \
--header "Authorization: Bearer $ENVIA_TOKEN"- List that carrier's actions and look for
return_branches_by_addressindata.
curl --request GET \
--url "https://queries.test.envia.com/carrier-action/{carrier_id}" \
--header "Authorization: Bearer $ENVIA_TOKEN"If the action is present, use live lookup. If not, use the catalog search above.
Required body fields
country_code comes from the path. Send these fields in the JSON body:
| Field | Type | Required | Description |
|---|---|---|---|
carrierId | number | Yes | Carrier id from GET /carrier. It turns live lookup on. |
zipcode | string | Yes | Postal code. |
address | string | Yes | Street address. |
locality | string | Yes | Locality or city. |
serviceName | string | Yes | Carrier service name. |
type | number | Yes | 1 origin (admission), 2 destination (delivery), 3 both. It has no default in live lookup. |
shipmentType | number | Yes | Shipment type, 0 to 9. |
packages | array | Yes | At least one package with weight, length, height and width. See packages item shape. |
state | string | No | State filter. |
latitude, longitude | number | No | Coordinates. Some carriers need them. |
Example
Live lookup for UPS in Spain (carrierId 172):
curl --request POST \
--url "https://queries.test.envia.com/branches/ups/ES" \
--header "Authorization: Bearer $ENVIA_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"carrierId": 172,
"zipcode": "45311",
"address": "Plaza De La Iglesia 2",
"locality": "Dos Barrios",
"serviceName": "<service_name>",
"type": 2,
"shipmentType": 1,
"packages": [
{ "weight": 1, "length": 10, "height": 10, "width": 10, "amount": 1 }
]
}'Response
The response is the same kind of array as the catalog search, with these differences:
- Each branch has
address.admissionandaddress.deliveryas booleans, and anhoursarray (empty when the carrier does not send hours). - The remaining fields come from the carrier, so they can vary between carriers.
[]means the carrier returned no points.- Use
branch_codeon the label, as with the catalog search.
Differences from the catalog search
| Topic | Catalog search (GET or POST) | Live lookup (POST with carrierId) |
|---|---|---|
| Data source | Envia branch catalog | The carrier, in real time |
| Caching | GET may be cached up to 24 hours | Not cached |
type | Optional, defaults to 1 | Required |
| Distance ranking | 50 km ranking and fallback cascade | Not applied. The carrier decides the order |
allBranch | Supported | Ignored |
| If nothing is found | Falls back to broader filters | Returns []. It does not fall back to the catalog |
Errors
| HTTP | When |
|---|---|
400 | A required field is missing. The message lists them, for example This carrier requires: zipcode, address, locality. |
400 | The carrier rejected the request. The carrier message is returned. For example, some carriers require coordinates or a specific service name. |
{ "statusCode": 400, "error": "Bad Request", "message": "This carrier requires: zipcode, address, locality" }Related endpoints
| Endpoint | Purpose |
|---|---|
GET /branches/{carrier}/{country_code}/catalog | States and localities for filter dropdowns (see below). |
GET /carrier?country_code={country_code} | Discover carrier slugs (name) for a country. |
GET /branches/{country_code} | Multi-carrier branches by country (different auth / filters). |
POST /branches/estafeta/oxxo | Estafeta OXXO branch lookup (carrier-specific payload with address + packages). |
GET /carrier-action/{carrier_id} | Actions enabled for a carrier. Look for return_branches_by_address to know if live lookup applies. |
POST {Shipping API}/ship/branchesbyaddress | The same live carrier lookup, called directly on the Shipping API instead of through POST /branches/.... |
Branch catalog helper
To drive state / locality filter dropdowns:
GET /branches/{carrier}/{country_code}/catalogOptional query parameters: zipcode, locality, state, type, carrierId.
Example response:
{
"states": ["State A", "State B"],
"localities": {
"State A": ["City 1", "City 2"],
"State B": ["City 3"]
}
}Typical flow:
- Call the catalog to list states and localities.
- Call
GET|POST /branches/{carrier}/{country_code}with the selected filters (and optional packages). - Use the returned
branch_codeon the label.
Which branch API should I call?
Use this decision tree to pick the right Branches endpoint:
Need branches for label / picker?
│
├─ Carrier is Estafeta OXXO (MX retail network)?
│ └─ POST /branches/estafeta/oxxo
│
├─ Carrier action includes return_branches_by_address?
│ └─ POST /branches/{carrier}/{country_code} with carrierId
│ (live carrier lookup, see "Live carrier lookup" on this page;
│ POST {Shipping API}/ship/branchesbyaddress is the same lookup
│ called directly on the Shipping API)
│
├─ Need only state / locality lists for dropdowns?
│ └─ GET /branches/{carrier}/{country_code}/catalog
│
├─ Need branches for one known carrier + country?
│ └─ GET|POST /branches/{carrier}/{country_code} ← this page
│ (optional: packages / shipmentType / branchType / limitBranches)
│
└─ Need multi-carrier branches for a country?
└─ GET /branches/{country_code}
(token_user auth; different filter set)Default for most integrations: GET|POST /branches/{carrier}/{country_code} plus the catalog helper when building filter UIs.
Examples
Replace {carrier} and {country_code} with values from GET /carrier?country_code={country_code} (use the carrier name slug).
GET — nearby branches by postal code
curl --request GET \
--url "https://queries.test.envia.com/branches/{carrier}/{country_code}?zipcode=00000&state=State%20Name&locality=City%20Name&type=1&limitBranches=10" \
--header "Authorization: Bearer $ENVIA_TOKEN"POST — filter with packages and shipment type
curl --request POST \
--url "https://queries.test.envia.com/branches/{carrier}/{country_code}" \
--header "Authorization: Bearer $ENVIA_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"type": 1,
"state": "State Name",
"locality": "City Name",
"zipcode": "00000",
"shipmentType": 1,
"packages": [
{
"weight": 2,
"length": 30,
"height": 20,
"width": 15,
"amount": 1
}
]
}'JavaScript (fetch)
const carrier = "your-carrier-slug"; // from GET /carrier?country_code=XX
const countryCode = "XX";
const response = await fetch(
`https://queries.test.envia.com/branches/${carrier}/${countryCode}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ENVIA_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: 1,
state: "State Name",
locality: "City Name",
zipcode: "00000",
}),
}
);
const branches = await response.json(); // raw array — not { data }
const nearest = branches[0];
const branchCode = nearest?.branch_code;When distance ranking succeeds, take branches[0] as the nearest branch within 50 km and use its branch_code on the label.
