# SDKs & Libraries

> Code examples and helpers to connect your system to 4N NextDay faster.

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

We don't have official SDKs yet, but connecting is simple with standard HTTP libraries. Here's how to get started in your language.

## Making requests

Use these libraries to call the API:

### JavaScript / Node.js

```js
// Using native fetch (Node.js 18+)
const response = await fetch('https://api.4nortes.app/api/v1/orders', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Accept': 'application/json',
  },
})

// Using axios
import axios from 'axios'

const client = axios.create({
  baseURL: 'https://api.4nortes.app/api/v1',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Accept': 'application/json',
  },
})

const response = await client.get('/orders')
```

### Python

```python
import requests

# Using requests library
headers = {
    'Authorization': f'Bearer {token}',
    'Accept': 'application/json',
}

response = requests.get(
    'https://api.4nortes.app/api/v1/orders',
    headers=headers
)

data = response.json()
```

### PHP

```php
// Using Guzzle
use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://api.4nortes.app/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer ' . $token,
        'Accept' => 'application/json',
    ],
]);

$response = $client->get('orders');
$data = json_decode($response->getBody(), true);
```

### Ruby

```ruby
require 'net/http'
require 'json'

uri = URI('https://api.4nortes.app/api/v1/orders')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{token}"
request['Accept'] = 'application/json'

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

data = JSON.parse(response.body)
```

## Build a simple wrapper

Here's a JavaScript helper class you can copy into your project. It branches on the HTTP status code rather than on a `success` flag, because authentication, validation and rate-limit errors don't carry one (see [Error Handling](https://api-doc.4nortes.app/errors.md)):

```js
class NextDayAPI {
  constructor(token) {
    this.token = token
    this.baseUrl = 'https://api.4nortes.app/api/v1'
  }

  async request(method, endpoint, data = null) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      method,
      headers: {
        'Authorization': `Bearer ${this.token}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
      body: data ? JSON.stringify(data) : undefined,
    })

    const body = await response.json().catch(() => ({}))

    if (!response.ok) {
      const error = new Error(body.message ?? `HTTP ${response.status}`)
      error.status = response.status
      // Only validation errors (422) carry `errors`; keys are the failing fields
      error.fields = body.errors ? Object.keys(body.errors) : []
      error.retryAfter = Number(response.headers.get('Retry-After')) || null
      throw error
    }

    return body.data
  }

  // Orders
  createOrder(orderData) {
    return this.request('POST', '/orders/create', orderData)
  }

  getOrder(trackingNumber) {
    return this.request('GET', `/orders/${trackingNumber}`)
  }

  listOrders(params = {}) {
    const query = new URLSearchParams(params).toString()
    return this.request('GET', `/orders${query ? `?${query}` : ''}`)
  }

  cancelOrder(trackingNumber) {
    return this.request('POST', `/orders/${trackingNumber}/cancel`)
  }

  // Tracking
  track(trackingNumber) {
    return this.request('GET', `/tracking/${trackingNumber}`)
  }

  // Coverage and price check
  quote(destinationLocality, weight, packagesCount = 1) {
    return this.request('POST', '/rates/quote', {
      destination_locality: destinationLocality,
      weight,
      packages_count: packagesCount,
    })
  }

  // Reference data
  getRegions() {
    return this.request('GET', '/regions')
  }

  getLocalities() {
    return this.request('GET', '/localities')
  }

  getServices() {
    return this.request('GET', '/services')
  }
}

// Usage - use the token issued for your merchant account
const api = new NextDayAPI(process.env.NEXTDAY_TOKEN)

const order = await api.createOrder({
  sender_name: 'My Store',
  sender_phone: '+56912345678',
  recipient_name: 'Jane Doe',
  recipient_phone: '+56987654321',
  destination_address: 'Calle Principal 123',
  destination_locality: 'Providencia',
  weight: 1.2,
})

console.log(`Created order: ${order.tracking_number}`)
```

> **Note:**
>
> The example above omits `service_id`, so the order is created with your account's default active service. If your account has no active service, the call fails with `422` and the message `There are no active services available for this merchant.` — pass a `service_id` from `GET /services` to be explicit. See [Services](https://api-doc.4nortes.app/services.md).

## Community libraries

Built something for 4N NextDay? Let us know and we'll list it here.

> **Note:**
>
> Check that any third-party library is up to date before using it.

## Full API docs

For all the details:

- [Orders API](https://api-doc.4nortes.app/api/orders.md) - Sync orders and download labels
- [Tracking API](https://api-doc.4nortes.app/api/tracking.md) - Fetch tracking for customers
- [References API](https://api-doc.4nortes.app/api/references.md) - Get regions, comunas, services and rate quotes
