Get Branches

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.

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…

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)

EnvironmentBase URL
Sandboxhttps://queries.test.envia.com/
Productionhttps://queries.envia.com/

Authentication

Authorization: Bearer <ENVIA_TOKEN>

Create or copy your token in the matching sandbox or production account. See Authentication.

Path parameters

ParameterTypeRequiredDescription
carrierstringYesCarrier slug from GET /carrier?country_code={country_code} (name field, lowercase — not the marketing display name).
country_codestringYesISO 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
ResultMeaning
[...]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

Each 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_code from 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_id and reference are useful for catalogs and UI labels; branch_code is 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 label

Search behavior

Filters may be sent as a query string (GET) or a JSON body (POST). Field names are the same.

Nearby ranking (50 km)

  1. If latitude / longitude are 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. A distance field (km) is present on those rows.
  2. If that yields no rows, it falls back to the same filters without distance ranking.
  3. If still empty and zipcode has more than one character, it retries with a shorter postal prefix.
  4. Final fallback: active branches for that carrier and country with location filters removed.

Capability filter (type)

ValueMeaning
1 (default)Admission / origin (drop-off)
2Delivery / destination
3Both

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.

ParameterTypeMethodDescription
branchTypestringGET or POSTComma-separated branch categories: 1 Post Office, 2 Warehouse, 3 Third Party, 4 Lockers.
limitBranchesnumberGET or POSTOptional maximum number of branches returned.
shipmentTypenumberGET or POSTFilters by branch_rules.shipmentType (allowed values 0–9).
packagesarrayPOST onlyPackage constraints evaluated against branch_rules (maxAmount, maxWeight, maxLength, maxHeight, maxWidth).
carrierIdnumberPOST onlyCarrier id from GET /carrier. Switches on live carrier lookup for carriers that support it.
serviceNamestringPOST onlyCarrier service name. Required by live carrier lookup.

packages item shape (POST)

FieldTypeRequiredDescription
weightnumberYesPackage weight.
lengthnumberYesLength.
heightnumberYesHeight.
widthnumberYesWidth.
amountnumberNoQuantity of this package.
package_typenumberNoPackage type id.

POST vs GET

PreferWhen
GETSimple nearby or filter queries (zipcode, state/locality, lat/lng). Results may be cached up to 24 hours.
POSTSending 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)

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:

  1. The request is a POST.
  2. The body includes carrierId.
  3. That carrier has the return_branches_by_address action, and carrierId belongs 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

  1. Get the carrier id from the carriers list. Match it by name.
curl --request GET \
  --url "https://queries.test.envia.com/carrier?country_code={country_code}" \
  --header "Authorization: Bearer $ENVIA_TOKEN"
  1. List that carrier's actions and look for return_branches_by_address in data.
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:

FieldTypeRequiredDescription
carrierIdnumberYesCarrier id from GET /carrier. It turns live lookup on.
zipcodestringYesPostal code.
addressstringYesStreet address.
localitystringYesLocality or city.
serviceNamestringYesCarrier service name.
typenumberYes1 origin (admission), 2 destination (delivery), 3 both. It has no default in live lookup.
shipmentTypenumberYesShipment type, 0 to 9.
packagesarrayYesAt least one package with weight, length, height and width. See packages item shape.
statestringNoState filter.
latitude, longitudenumberNoCoordinates. 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.admission and address.delivery as booleans, and an hours array (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_code on the label, as with the catalog search.

Differences from the catalog search

TopicCatalog search (GET or POST)Live lookup (POST with carrierId)
Data sourceEnvia branch catalogThe carrier, in real time
CachingGET may be cached up to 24 hoursNot cached
typeOptional, defaults to 1Required
Distance ranking50 km ranking and fallback cascadeNot applied. The carrier decides the order
allBranchSupportedIgnored
If nothing is foundFalls back to broader filtersReturns []. It does not fall back to the catalog

Errors

HTTPWhen
400A required field is missing. The message lists them, for example This carrier requires: zipcode, address, locality.
400The 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

EndpointPurpose
GET /branches/{carrier}/{country_code}/catalogStates 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/oxxoEstafeta 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/branchesbyaddressThe 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}/catalog

Optional 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:

  1. Call the catalog to list states and localities.
  2. Call GET|POST /branches/{carrier}/{country_code} with the selected filters (and optional packages).
  3. Use the returned branch_code on 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.


Path Params
string
required

Carrier name.

string
required

Two-digit country code.

Query Params
string

Zipcode value to filter.

number
enum

Branch type filter (By default returns all branch types).

IDBranch type
1Post Office
2Warehouse
3Third Party
4Lockers
Allowed:
string

Locality filter.

string

State filter.

number
enum
Defaults to 1

Available branches by location (origin/destination)

IDLocation
1Origin
2Destination
3Origin and Destination
Allowed:
float

Latitude for geolocation search.

float

Longitude for geolocation search.

string

Full address filter.

boolean

If true, returns all branches.

integer
0 to 9

Filters by branch_rules.shipmentType (allowed values 0 to 9).

number

Maximum number of branches returned.

Response

Language
Credentials
Bearer
JWT
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json