Blu Pantheon
Référence API

Paginazione

Paginazione a cursore delle API Blu Pantheon: parametri, struttura della risposta, filtri, ordinamento e cicli completi.

Tutti gli endpoint che restituiscono collezioni usano una paginazione a cursore. Il client non richiede un numero di pagina ma un puntatore opaco alla posizione successiva, restituito dalla chiamata precedente. Questo garantisce risultati coerenti anche quando la collezione cambia durante la lettura.

Parametri di query

Parametri di paginazione

ParametroTipoObblig.DefaultDescrizione
limitnumberNo50Numero di elementi per pagina. Valori ammessi da 1 a 200. Un valore fuori intervallo produce VALIDATION_ERROR.
cursorstringNo—Puntatore opaco alla pagina successiva, copiato da pagination.nextCursor. Omettilo per la prima pagina.
sortstringNocreatedAtCampo di ordinamento. I valori ammessi variano per risorsa e sono indicati nel riferimento di ogni endpoint.
orderstringNodescDirezione dell’ordinamento: asc oppure desc.

Il cursore incorpora l'ordinamento

Un cursore è valido solo per la combinazione di sort, order e filtri con cui è stato generato. Se cambi uno di questi parametri devi ripartire dalla prima pagina, altrimenti la risposta è 400 con codice INVALID_CURSOR.

Struttura della risposta

Ogni risposta paginata ha la stessa forma: un array data e un oggetto pagination.

GET /console/v1/sessions?limit=2
{
  "data": [
    {
      "id": "sess_9f2c8d41",
      "projectId": "bp_proj_7f3a9c21",
      "clientId": "cli_5e1a7b30",
      "channel": "web",
      "status": "open",
      "messageCount": 14,
      "startedAt": "2026-09-04T09:12:44.006Z",
      "lastActivityAt": "2026-09-04T09:41:02.884Z",
      "createdAt": "2026-09-04T09:12:44.006Z"
    },
    {
      "id": "sess_3b7e0c58",
      "projectId": "bp_proj_7f3a9c21",
      "clientId": "cli_9d4f2a17",
      "channel": "whatsapp",
      "status": "closed",
      "messageCount": 6,
      "startedAt": "2026-09-04T08:55:10.412Z",
      "lastActivityAt": "2026-09-04T09:03:37.221Z",
      "createdAt": "2026-09-04T08:55:10.412Z"
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6InNlc3NfM2I3ZTBjNTgiLCJ0cyI6MTc4ODUxNTUzNX0",
    "hasMore": true,
    "total": 1234
  }
}

Oggetto pagination

ParametroTipoObblig.DefaultDescrizione
nextCursorstring | nullSì—Cursore da passare alla chiamata successiva. Vale null quando non ci sono altre pagine.
hasMorebooleanSì—True se esistono altri elementi oltre quelli restituiti. È la condizione di uscita del ciclo.
totalnumberNo—Numero totale di elementi che soddisfano i filtri. Può essere assente o approssimato su collezioni molto grandi.

Usa hasMore, non total

Il campo total è una stima calcolata al momento della prima chiamata e può essere omesso quando il conteggio esatto sarebbe troppo costoso. La condizione corretta per continuare il ciclo è hasMore uguale a true, oppure nextCursor diverso da null.

Ciclo di paginazione completo

paginate.ts
const BASE_URL = 'https://api.blupantheon.com';
const API_KEY = process.env.BP_API_KEY!;

interface Page<T> {
  data: T[];
  pagination: { nextCursor: string | null; hasMore: boolean; total?: number };
}

export async function* paginate<T>(
  path: string,
  query: Record<string, string | number> = {},
): AsyncGenerator<T, void, undefined> {
  let cursor: string | null = null;

  do {
    const params = new URLSearchParams({
      limit: '200',
      ...Object.fromEntries(Object.entries(query).map(([k, v]) => [k, String(v)])),
    });
    if (cursor) params.set('cursor', cursor);

    const res = await fetch(`${BASE_URL}${path}?${params}`, {
      headers: { Authorization: `Bearer ${API_KEY}` },
    });

    if (!res.ok) {
      const err = await res.json();
      throw new Error(`${err.code}: ${err.message} (traceId ${err.traceId})`);
    }

    const page = (await res.json()) as Page<T>;
    for (const item of page.data) yield item;

    cursor = page.pagination.nextCursor;
  } while (cursor);
}

// Uso: scorre tutte le sessioni aperte del progetto senza caricarle tutte in memoria.
for await (const session of paginate('/console/v1/sessions', {
  projectId: 'bp_proj_7f3a9c21',
  status: 'open',
})) {
  console.log(session);
}

Filtri comuni

I filtri si combinano liberamente con la paginazione e si applicano prima dell'ordinamento. I filtri non riconosciuti vengono ignorati silenziosamente: verifica sempre di aver scritto correttamente il nome.

Filtri disponibili sulla maggior parte delle collezioni

ParametroTipoObblig.DefaultDescrizione
createdAfterstringNo—Data ISO 8601. Include solo gli elementi creati dopo l’istante indicato, estremo escluso.
createdBeforestringNo—Data ISO 8601. Include solo gli elementi creati prima dell’istante indicato, estremo escluso.
updatedAfterstringNo—Data ISO 8601. Utile per le sincronizzazioni incrementali basate sull’ultima modifica.
statusstringNo—Filtra per stato della risorsa. Accetta più valori separati da virgola, ad esempio open,pending.
projectIdstringNo—Limita i risultati a un singolo progetto, ad esempio bp_proj_7f3a9c21.
clientIdstringNo—Limita i risultati alle risorse associate a uno specifico cliente.
channelstringNo—Canale di origine: web, whatsapp, email, telegram, api.
qstringNo—Ricerca testuale libera sui campi indicizzati della risorsa. Minimo 2 caratteri.

Esempio di combinazione tipica per una sincronizzazione incrementale notturna:

curl -sS -G "https://api.blupantheon.com/console/v1/clients" \
  -H "Authorization: Bearer bp_live_xxxxxxxxxxxxxxxx" \
  --data-urlencode "updatedAfter=2026-09-03T00:00:00Z" \
  --data-urlencode "status=active" \
  --data-urlencode "sort=updatedAt" \
  --data-urlencode "order=asc" \
  --data-urlencode "limit=200"

Sincronizzazioni incrementali

Per le sincronizzazioni usa updatedAfter con sort=updatedAt e order=asc: leggi in avanti nel tempo e memorizza l'updatedAt dell'ultimo elemento elaborato come punto di ripartenza. Sottrai un margine di 60 secondi al valore memorizzato per non perdere record scritti a cavallo della finestra.

Ordinamento

ParametroValoriComportamento
sortcreatedAt, updatedAt, name, lastActivityAtIl set di valori ammessi dipende dalla risorsa
orderasc, descPredefinito desc

L'ordinamento è sempre totale e deterministico: a parità di valore del campo scelto viene applicato un criterio secondario sull'identificativo della risorsa. Questo garantisce che nessun elemento venga saltato o restituito due volte durante la paginazione.

Un valore di sort non supportato produce 400 con codice VALIDATION_ERROR e l'elenco dei campi ammessi in details.

Limiti massimi

VincoloValoreComportamento oltre il limite
limit massimo200400 VALIDATION_ERROR
limit minimo1400 VALIDATION_ERROR
Validità del cursore15 minuti400 INVALID_CURSOR
Profondità di scorrimentoNessun limite—
Lunghezza minima di q2 caratteri400 VALIDATION_ERROR

Stabilità del cursore

Il cursore è opaco e temporaneo

Il valore di nextCursor è una stringa codificata il cui formato interno può cambiare senza preavviso. Non decodificarlo, non modificarlo, non costruirlo manualmente e non salvarlo in modo persistente per riprendere una lettura il giorno successivo: dopo 15 minuti scade e restituisce INVALID_CURSOR. Per riprendere una lettura interrotta usa un filtro temporale (createdAfter o updatedAfter).

Durante una paginazione la collezione sottostante può cambiare. Il comportamento è il seguente:

  • Gli elementi creati dopo l'inizio del ciclo non compaiono se l'ordinamento è discendente su createdAt; compaiono in coda se l'ordinamento è ascendente.
  • Gli elementi eliminati durante il ciclo semplicemente non vengono restituiti: la pagina può contenere meno elementi di limit pur avendo hasMore a true.
  • Gli elementi modificati durante il ciclo possono essere restituiti due volte se ordini per updatedAt in ordine ascendente. Deduplica sempre in base all'id quando elabori grandi volumi.

Una pagina corta non significa fine dei risultati

Non interrompere il ciclo perché una pagina contiene meno elementi di limit. L'unica condizione di uscita corretta è hasMore uguale a false oppure nextCursor uguale a null.

Errori frequenti

Sur cette page