References API
Fetch the same regions, comunas and services you see in your panel, and check coverage and price before creating an order. Use this to build address selectors and shipping options in your checkout.
Regions and localities rarely change. Fetch them once and cache them for a day. Services and quotes are account-specific — see Caching.
Get regions
Get all Chilean regions for your address selector. Returns the full list, sorted by name — no pagination.
Response Fields
- Name
id- Type
- integer
- Description
Unique region identifier.
- Name
name- Type
- string
- Description
Region name.
- Name
slug- Type
- string
- Description
URL-friendly region identifier.
- Name
localities_count- Type
- integer
- Description
Number of localities in this region.
curl https://api.4nortes.app/api/v1/regions \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
Response
{
"success": true,
"message": "Regions retrieved successfully",
"data": [
{
"id": 1,
"name": "Arica y Parinacota",
"slug": "arica-y-parinacota",
"localities_count": 4
},
{
"id": 7,
"name": "Metropolitana de Santiago",
"slug": "metropolitana-de-santiago",
"localities_count": 52
},
{
"id": 2,
"name": "Tarapacá",
"slug": "tarapaca",
"localities_count": 7
},
{
"id": 6,
"name": "Valparaíso",
"slug": "valparaiso",
"localities_count": 38
}
],
"timestamp": "2025-02-03T10:00:00.000000Z"
}
Get comunas
Get all comunas (localities), sorted by name. Returns the full list — no pagination.
Response Fields
- Name
id- Type
- integer
- Description
Unique locality identifier. You can send it (as a string) in
destination_localitywhen creating orders.
- Name
name- Type
- string
- Description
Locality name (comuna). Also accepted in
destination_locality.
- Name
slug- Type
- string
- Description
URL-friendly locality identifier.
- Name
type- Type
- string
- Description
urban,ruralorboth.
- Name
region_id- Type
- integer
- Description
ID of the region this locality belongs to.
- Name
aliases- Type
- array
- Description
Alternative spellings for this locality. They are also matched when you send a name.
curl https://api.4nortes.app/api/v1/localities \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
Response
{
"success": true,
"message": "Localities retrieved successfully",
"data": [
{
"id": 3,
"name": "Las Condes",
"slug": "las-condes",
"type": "urban",
"region_id": 7,
"aliases": []
},
{
"id": 2,
"name": "Providencia",
"slug": "providencia",
"type": "urban",
"region_id": 7,
"aliases": []
},
{
"id": 1,
"name": "Santiago",
"slug": "santiago",
"type": "urban",
"region_id": 7,
"aliases": ["Santiago Centro"]
}
],
"timestamp": "2025-02-03T10:00:00.000000Z"
}
Get services
Get the delivery services configured for your account. Only active services are returned, sorted by name, with no pagination. Codes and names are set up per account by 4N NextDay, so they differ from one merchant to another.
Merchant token only: any other token gets a 401 with Authentication required..
Response Fields
- Name
id- Type
- integer
- Description
Unique service identifier. Use this as
service_idwhen creating orders.
- Name
code- Type
- string
- Description
Short code, specific to your account.
- Name
name- Type
- string
- Description
Service name, as shown in your panel.
- Name
type- Type
- string
- Description
b2b(deliveries to businesses),b2c(deliveries to consumers) orfield(cargo created by drivers on the road — never used for integration orders).
curl https://api.4nortes.app/api/v1/services \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
Response
{
"success": true,
"message": "Services retrieved successfully",
"data": [
{
"id": 31,
"code": "B2B-RM",
"name": "Distribución B2B Región Metropolitana",
"type": "b2b"
},
{
"id": 27,
"code": "ECOM-STGO",
"name": "E-commerce Santiago",
"type": "b2c"
}
],
"timestamp": "2025-02-03T10:00:00.000000Z"
}
Quote a rate
Check coverage and price before creating an order. The quote resolves the locality and applies your account's coverage rules exactly like POST /orders/create does, so a 200 here means the locality will be accepted at creation time. Use it in your checkout to show the shipping cost and to stop uncovered addresses early.
Request Body
- Name
destination_locality- Type
- string
- Description
The destination locality (comuna): its name, one of its aliases, or its numeric id as a string (
"2"). Name matching ignores case and accents. Max 100 characters. Required.
- Name
weight- Type
- number
- Description
Total weight in kilograms. Between
0.1and100. Required.
- Name
packages_count- Type
- integer
- Description
Number of packages. Between
1and50. Default1.
Response Fields
- Name
locality_id- Type
- integer
- Description
The locality that matched. Store it and send it back as
destination_localityto avoid any ambiguity.
- Name
locality_name- Type
- string
- Description
Its canonical name.
- Name
region_id- Type
- integer
- Description
Its region.
- Name
price- Type
- integer
- Description
Total price, in whole pesos.
- Name
currency- Type
- string
- Description
Always
CLP.
- Name
transit_days- Type
- integer
- Description
Estimated transit time to that locality, in days. At least
1.
- Name
breakdown- Type
- object
- Description
base_priceandweight_surcharge(both integers, in pesos). They add up toprice.
- Name
delivery_message- Type
- string|null
- Description
A note about deliveries to that locality for today's weekday (for example a cut-off or frequency notice), when one is configured.
nullotherwise. Show it to the customer as is.
Errors
- Name
404 Not Found- Description
Locality not found: {input}— nothing matched the name or id; order creation would fail the same way. OrNo tariff configured for locality: {name}— the locality exists and may well be covered, but has no price yet. This one only affects the quote:POST /orders/createdoesn't check tariffs, so don't block checkout on it; contact your account representative to get the price configured.
- Name
422 Unprocessable Entity- Description
Envelope with
Merchant {name} has no coverage for locality: {name}when your account doesn't deliver there. Or a raw validation body whendestination_locality,weightorpackages_countis missing or out of range.
curl -X POST https://api.4nortes.app/api/v1/rates/quote \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"destination_locality": "Providencia",
"weight": 3.0,
"packages_count": 1
}'
Response
{
"success": true,
"message": "Operation successful",
"data": {
"locality_id": 2,
"locality_name": "Providencia",
"region_id": 7,
"price": 5500,
"currency": "CLP",
"transit_days": 1,
"breakdown": {
"base_price": 4000,
"weight_surcharge": 1500
},
"delivery_message": null
},
"timestamp": "2025-02-03T10:00:00.000000Z"
}
422 — locality not covered
{
"success": false,
"message": "Merchant Acme Store has no coverage for locality: Putre",
"errors": null,
"timestamp": "2025-02-03T10:00:00.000000Z"
}
404 — locality not found
{
"success": false,
"message": "Locality not found: Providencai",
"errors": null,
"timestamp": "2025-02-03T10:00:00.000000Z"
}
Cache this data
| Data | Cache Duration | Notes |
|---|---|---|
| Regions | 1 day | Refresh on application startup |
| Localities | 1 day | Daily background job |
| Services | 1 hour | Account-specific; refresh when a service_id is rejected |
| Quotes | Don't cache across days | Tariffs and delivery_message can change; quote at checkout time |
Example: cache comunas in the browser
// Cache localities in memory or localStorage
const CACHE_KEY = 'nextday_localities'
const CACHE_DURATION = 24 * 60 * 60 * 1000 // 24 hours
async function getLocalities() {
const cached = localStorage.getItem(CACHE_KEY)
if (cached) {
const { data, timestamp } = JSON.parse(cached)
if (Date.now() - timestamp < CACHE_DURATION) {
return data
}
}
const response = await fetch('https://api.4nortes.app/api/v1/localities', {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json',
},
})
if (!response.ok) {
throw new Error(`Failed to load localities: HTTP ${response.status}`)
}
const { data } = await response.json()
localStorage.setItem(CACHE_KEY, JSON.stringify({
data,
timestamp: Date.now()
}))
return data
}