Skip to content
NEXTOREx

Guides

Code examples

Copyable cURL, JavaScript and PHP examples for requests, POST with idempotency, pagination and retries.

Small, copyable examples for common environments. Replace the placeholder key with your own, and read it from an environment variable or secret store: never paste a real key into source code.

Set these once in your shell:

export NEXTOREX_API_BASE="https://api.nextorex.com/api/public/v1"
export NEXTOREX_API_KEY="nx_live_xxxxxxxxxxxx_YOUR_SECRET_HERE"

cURL

GET

curl "$NEXTOREX_API_BASE/erp/customers?limit=10&sort=name" \
  -H "Authorization: Bearer $NEXTOREX_API_KEY" \
  -H "Accept: application/json"

POST with an Idempotency-Key

curl -X POST "$NEXTOREX_API_BASE/erp/customers" \
  -H "Authorization: Bearer $NEXTOREX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: customer-import-row-1042" \
  -d '{"name": "Example Traders", "email": "[email protected]", "phone": "+923001234567"}'

Public catalog (no key)

curl "$NEXTOREX_API_BASE/catalog?app=crm"

JavaScript (Node.js 18 or newer)

const BASE = process.env.NEXTOREX_API_BASE
const KEY = process.env.NEXTOREX_API_KEY

async function nextorex(path, { method = 'GET', body, idempotencyKey } = {}) {
  const headers = { Authorization: `Bearer ${KEY}`, Accept: 'application/json' }
  if (body) headers['Content-Type'] = 'application/json'
  if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey

  const res = await fetch(`${BASE}${path}`, { method, headers, body: body ? JSON.stringify(body) : undefined })
  const json = await res.json().catch(() => null)
  if (!res.ok) {
    const e = json?.error ?? {}
    throw Object.assign(new Error(e.message ?? `HTTP ${res.status}`), { status: res.status, code: e.code, requestId: e.request_id, retryAfter: res.headers.get('Retry-After') })
  }
  return json
}

// GET
const me = await nextorex('/me')
console.log(me.data.key.scopes)

// POST with an Idempotency-Key: safe to retry with the same key
import { randomUUID } from 'node:crypto'
const key = `lead-${randomUUID()}`
const lead = await nextorex('/crm/leads', {
  method: 'POST',
  idempotencyKey: key,
  body: { first_name: 'Ayesha', last_name: 'Khan', email: '[email protected]', phone: '+923001234567', source: 'Website' },
})
console.log(lead.data.id)

// Pagination: follow next_cursor until has_more is false
async function* allLeads(filter = '') {
  let cursor = null
  do {
    const qs = `limit=100${filter}${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ''}`
    const page = await nextorex(`/crm/leads?${qs}`)
    yield* page.data
    cursor = page.pagination.has_more ? page.pagination.next_cursor : null
  } while (cursor)
}

for await (const l of allLeads('&filter[priority]=high')) console.log(l.id, l.email)

Generate the idempotency key once per operation and keep it with your own record, so that a retry after a crash reuses the same key.

PHP

<?php
$base = getenv('NEXTOREX_API_BASE');
$key  = getenv('NEXTOREX_API_KEY');

function nextorex(string $method, string $path, ?array $body = null, ?string $idempotencyKey = null): array
{
    global $base, $key;
    $headers = ['Authorization: Bearer ' . $key, 'Accept: application/json'];
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    if ($idempotencyKey !== null) {
        $headers[] = 'Idempotency-Key: ' . $idempotencyKey;
    }
    $ch = curl_init($base . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_HTTPHEADER     => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 20,
        CURLOPT_POSTFIELDS     => $body !== null ? json_encode($body) : null,
    ]);
    $raw = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    $json = json_decode((string) $raw, true) ?? [];
    if ($status >= 400) {
        $e = $json['error'] ?? [];
        throw new RuntimeException(($e['code'] ?? 'http_' . $status) . ' (request ' . ($e['request_id'] ?? 'unknown') . ')');
    }
    return $json;
}

// GET
$customers = nextorex('GET', '/erp/customers?limit=10');

// POST with an Idempotency-Key
$created = nextorex('POST', '/erp/customers', ['name' => 'Example Traders'], 'customer-import-row-1042');

// Pagination
$cursor = null;
do {
    $query = '/erp/customers?limit=100' . ($cursor ? '&cursor=' . urlencode($cursor) : '');
    $page = nextorex('GET', $query);
    foreach ($page['data'] as $customer) {
        echo $customer['id'], ' ', $customer['name'], PHP_EOL;
    }
    $cursor = $page['pagination']['has_more'] ? $page['pagination']['next_cursor'] : null;
} while ($cursor);

Webhook verification

Ready-to-use verification functions for Node.js and PHP are on the Webhooks page.

Retrying safely

async function withRetry(fn, attempts = 5) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn()
    } catch (e) {
      const retryable = e.status === 429 || e.status >= 500 || e.status === undefined || e.code === 'idempotency_request_in_progress'
      if (!retryable || i === attempts - 1) throw e
      const wait = e.retryAfter ? Number(e.retryAfter) * 1000 : 2 ** i * 500
      await new Promise((r) => setTimeout(r, wait + Math.random() * 250))
    }
  }
}

Retry only network failures, 429 and 5xx (and idempotency_request_in_progress), always with the same Idempotency-Key. Do not retry other 4xx errors unchanged.