> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cicini.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js example

> Fetch all customers with pagination using Node 18+ native fetch

# Node.js example

Works with Node **18+** (global `fetch`). Keep the API key in an environment variable.

```js theme={null}
// list-all-customers.mjs
const BASE = process.env.CICINI_BASE_URL ?? 'https://cicini.com';
const KEY = process.env.CICINI_API_KEY;

if (!KEY) {
  console.error('Set CICINI_API_KEY');
  process.exit(1);
}

async function listCustomersPage({ limit = 50, offset = 0 } = {}) {
  const url = new URL('/api/public/v1/customers', BASE);
  url.searchParams.set('limit', String(limit));
  url.searchParams.set('offset', String(offset));

  const res = await fetch(url, {
    headers: {
      Authorization: `Bearer ${KEY}`,
      Accept: 'application/json',
    },
  });

  const body = await res.json().catch(() => ({}));
  if (!res.ok) {
    const err = new Error(body.message || body.error || res.statusText);
    err.status = res.status;
    err.body = body;
    throw err;
  }
  return body;
}

async function listAllCustomers() {
  const all = [];
  let offset = 0;
  const limit = 50;

  for (;;) {
    const page = await listCustomersPage({ limit, offset });
    all.push(...page.data);
    if (!page.pagination?.hasMore) break;
    offset += limit;
  }
  return all;
}

const customers = await listAllCustomers();
console.log(`Fetched ${customers.length} customers`);
console.log(customers.slice(0, 3));
```

## Appointments with filters

```js theme={null}
async function listAppointments(params = {}) {
  const url = new URL('/api/public/v1/appointments', BASE);
  for (const [k, v] of Object.entries(params)) {
    if (v != null) url.searchParams.set(k, String(v));
  }
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${KEY}`, Accept: 'application/json' },
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

const week = await listAppointments({
  status: 'confirmed',
  startDate: '2026-07-14T00:00:00.000Z',
  endDate: '2026-07-21T00:00:00.000Z',
  limit: 100,
});
console.log(week.pagination, week.data.length);
```

## Notes

* Use this only on a **server** (never ship `CICINI_API_KEY` to browsers).
* Handle `401` / `400` separately from transport errors.
* For TypeScript, generate types from OpenAPI (`openapi-typescript` against `/openapi.json`) rather than hand-copying fields.
