# Quickstart

> Connect your first order to 4N NextDay. Learn how to sync orders from your system automatically.

Source: https://api-doc.4nortes.app/quickstart

Get your system connected in minutes. This guide shows you how to sync an order with 4N NextDay - the same as clicking "Create Order" in your panel, but automated.

> **Note:**
>
> You'll need an API token for your merchant account. Tokens are issued by your 4N NextDay administrator from the admin panel — there is no login step. See the [Authentication](https://api-doc.4nortes.app/authentication.md) guide for details.

## Base URL

All API requests should be made to the following base URL:

```bash
https://api.4nortes.app/api/v1
```

## Authentication

The 4N NextDay API uses bearer tokens for authentication. Your token is issued by your 4N NextDay administrator and may carry an expiry date — once it passes, requests return `401` until you get a new one.

Include the token in the `Authorization` header of all requests:

```bash
Authorization: Bearer {token}
```

## Sync your first order

This is the same as filling out the order form in your panel. Instead of typing the details manually, your system sends them automatically:

```bash
curl -X POST https://api.4nortes.app/api/v1/orders/create \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "sender_name": "John Store",
    "sender_phone": "+56912345678",
    "sender_email": "store@example.com",
    "recipient_name": "Jane Doe",
    "recipient_phone": "+56987654321",
    "recipient_email": "jane@example.com",
    "destination_address": "Calle Secundaria 456",
    "destination_locality": "Providencia",
    "destination_reference": "Near the plaza",
    "weight": 2.5,
    "external_reference": "ORDER-001",
    "service_id": 1,
    "packages_count": 1
  }'
```

```js
const response = await fetch('https://api.4nortes.app/api/v1/orders/create', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    sender_name: 'John Store',
    sender_phone: '+56912345678',
    sender_email: 'store@example.com',
    recipient_name: 'Jane Doe',
    recipient_phone: '+56987654321',
    recipient_email: 'jane@example.com',
    destination_address: 'Calle Secundaria 456',
    destination_locality: 'Providencia',
    destination_reference: 'Near the plaza',
    weight: 2.5,
    external_reference: 'ORDER-001',
    service_id: 1,
    packages_count: 1,
  }),
})

const data = await response.json()
console.log(data)
```

```python
import requests

response = requests.post(
    'https://api.4nortes.app/api/v1/orders/create',
    headers={
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json',
    },
    json={
        'sender_name': 'John Store',
        'sender_phone': '+56912345678',
        'sender_email': 'store@example.com',
        'recipient_name': 'Jane Doe',
        'recipient_phone': '+56987654321',
        'recipient_email': 'jane@example.com',
        'destination_address': 'Calle Secundaria 456',
        'destination_locality': 'Providencia',
        'destination_reference': 'Near the plaza',
        'weight': 2.5,
        'external_reference': 'ORDER-001',
        'service_id': 1,
        'packages_count': 1,
    }
)

print(response.json())
```

```php
$client = new \GuzzleHttp\Client();

$response = $client->post('https://api.4nortes.app/api/v1/orders/create', [
    'headers' => [
        'Authorization' => 'Bearer ' . $token,
        'Content-Type' => 'application/json',
    ],
    'json' => [
        'sender_name' => 'John Store',
        'sender_phone' => '+56912345678',
        'sender_email' => 'store@example.com',
        'recipient_name' => 'Jane Doe',
        'recipient_phone' => '+56987654321',
        'recipient_email' => 'jane@example.com',
        'destination_address' => 'Calle Secundaria 456',
        'destination_locality' => 'Providencia',
        'destination_reference' => 'Near the plaza',
        'weight' => 2.5,
        'external_reference' => 'ORDER-001',
        'service_id' => 1,
        'packages_count' => 1,
    ],
]);

echo $response->getBody();
```

A few things about the payload:

- `destination_locality` accepts the locality (comuna) name or its numeric id. The id must be sent as a string (`"2"`, not `2`). See [Localities](https://api-doc.4nortes.app/localities.md).
- `service_id` must be one of **your** services — get the ids from `GET /services`. Omit it to use your account's default active service. Replace the `1` in the example with a real id.
- `external_reference` is your own order code. It must be unique within your account.

You'll get back `201 Created` with the order details and the tracking number - just like when you create an order in your panel:

```json
{
  "success": true,
  "message": "Order created successfully",
  "data": {
    "id": 12345,
    "tracking_number": "4N202502030001",
    "external_reference": "ORDER-001",
    "cost_center": null,
    "purchase_order": null,
    "bill_of_lading": null,
    "merchant_id": 42,
    "service_id": 1,
    "destination": {
      "address_line": "Calle Secundaria 456",
      "locality_id": 2,
      "locality_name": "Providencia",
      "reference": "Near the plaza"
    },
    "recipient": {
      "name": "Jane Doe",
      "phone": "+56987654321",
      "email": "jane@example.com"
    },
    "sender": {
      "name": "John Store",
      "phone": "+56912345678",
      "email": "store@example.com"
    },
    "delivery_state": "pending",
    "packages_count": 1,
    "weight": 2.5,
    "valuation": 0,
    "created_at": "2025-02-03T10:30:00.000000Z"
  },
  "timestamp": "2025-02-03T10:30:00.000000Z"
}
```

`cost_center`, `purchase_order` and `bill_of_lading` echo the optional request fields of the same name and are `null` when you don't send them; `valuation` defaults to `0`.

> **Note:**
>
> Not sure whether you deliver to a locality? Call [`POST /rates/quote`](https://api-doc.4nortes.app/api/references.md#quote-rates) first. It runs the same locality and coverage checks as order creation and returns the price, so a successful quote means the locality will be accepted.

## What's next?

Your first order is synced. Here's what else you can automate:

- [Understand order states](https://api-doc.4nortes.app/orders.md) - See how orders flow through the system
- [Sync orders automatically](https://api-doc.4nortes.app/api/orders.md) - Full orders reference
- [Check coverage and price](https://api-doc.4nortes.app/api/references.md#quote-rates) - Quote before you create
- [Track the order](https://api-doc.4nortes.app/api/tracking.md) - Timeline, proofs and per-package progress
- [Get notified of updates](https://api-doc.4nortes.app/webhooks.md) - Receive tracking updates automatically
- [Handle errors](https://api-doc.4nortes.app/errors.md) - What to do when something goes wrong

<a id="ai-agent"></a>

## Build it with your AI agent

Using Claude Code, Cursor, Copilot or ChatGPT? These docs are published in formats agents read directly:

- [`/llms-full.txt`](https://api-doc.4nortes.app/llms-full.txt) — the whole documentation in one Markdown file.
- [`/llms.txt`](https://api-doc.4nortes.app/llms.txt) — an index of every page, following the [llms.txt](https://llmstxt.org) convention.
- Any page as Markdown: add `.md` to its URL (for example [`/api/orders.md`](https://api-doc.4nortes.app/api/orders.md)), or use **Copy page** at the top of each page.

Paste this prompt into your agent, fill in the last line, and let it scaffold the integration:

```text
You are integrating our system with the 4N NextDay shipping API (4 Nortes, Chile).

1. Read the full documentation first: https://api-doc.4nortes.app/llms-full.txt
   Every page is also available as Markdown, e.g. https://api-doc.4nortes.app/api/orders.md
2. Base URL: https://api.4nortes.app/api/v1
   Authenticate every request with "Authorization: Bearer $NEXTDAY_API_TOKEN".
   Read the token from an environment variable; never hard-code or log it.
3. Build:
   - A typed client for the endpoints we need. Start with POST /rates/quote,
     POST /orders/create, GET /orders/{tracking_number} and GET /tracking/{tracking_number}.
   - Error handling that branches on the HTTP status, not on the response body:
     401, 404, 422 (field errors), 429 (honour Retry-After).
   - If we receive webhooks: an endpoint that verifies X-4Nortes-Signature
     (HMAC-SHA256 of the raw request body) before parsing, answers 2xx quickly,
     and deduplicates on (event, data.tracking_number, timestamp).
4. Use only fields and values documented there. Ignore unknown fields and
   unknown event names so new ones never break us.
5. Ask me before assuming anything the docs don't state.

Our stack: <language, framework, and where our orders live>
```
