Ir al contenido
Sursa Developers

Sincronización incremental con updated_since

Para mantener una copia de los datos de Sursa en su propio sistema, no necesita leerlo todo cada vez. Las listas de objetos que tienen updated_at aceptan updated_since y devuelven solo los objetos que cambiaron en ese momento o después.

curl -G https://api.sursa.com/v1/cards \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  --data-urlencode "updated_since=2026-10-23T00:00:00Z" \
  --data-urlencode "limit=200"

Con updated_since, la lista se ordena por updated_at en orden ascendente y después por id, y el cursor continúa en ese orden. Así, lee los cambios en el orden en que ocurrieron, y el límite entre páginas nunca los divide de forma que se pierda alguno.

Aceptan updated_since estas listas:

ListaQué cuenta como cambio
GET /v1/cards, GET /v1/cards/countupdated_at de la tarjeta.
GET /v1/groupsupdated_at del grupo: su título o su configuración.
GET /v1/webhooksupdated_at del webhook: su configuración y su secreto, no sus entregas.
GET /v1/jobsupdated_at del trabajo: cada cambio de su estado.
GET /v1/draftsupdated_at del borrador.
GET /v1/cards/{card_id}/threadsLa última creación o edición del comentario raíz o de cualquier respuesta. El hilo llega completo.
GET /v1/folders, GET /v1/collections/{name}/foldersupdated_at de la carpeta. Las carpetas que coinciden llegan como una lista plana; consulte más abajo.

Las colecciones, los usuarios y los avisos no tienen updated_at, así que sus listas no filtran por él: son cortas, de modo que léalas completas en cada ejecución. La hora debe tener un desfase de zona horaria, como Z o +02:00; cualquier otro valor se rechaza, igual que en GET /v1/cards.

Con updated_since, un árbol de carpetas deja de ser un árbol: folders de cada colección contiene las carpetas cambiadas como una lista plana, con children vacío, y parent_id indica dónde está cada una. GET /v1/folders omite entonces las colecciones sin carpetas cambiadas.

Un bucle de sincronización

  1. En la primera ejecución, lea la lista completa sin updated_since y recuerde el momento en que empezó la ejecución.
  2. En cada ejecución siguiente, pase ese momento recordado como updated_since, menos un pequeño margen, como un minuto, y recuerde la nueva hora de inicio.
  3. Escriba cada objeto en su almacén por su id, sustituyendo la copia anterior. Los objetos que aparecen dos veces por el margen simplemente se vuelven a escribir.
  4. Pida cada página siguiente con el cursor y el mismo updated_since. Un cursor solo funciona con los filtros de la primera página: sin ellos, la solicitud devuelve 400 con el código api.cursor_invalid.

Usar la hora de inicio de la ejecución, y no la hora en que terminó, garantiza que la ejecución siguiente recoja un cambio hecho mientras la ejecución estaba en curso.

GET /v1/cards devuelve un array JSON, así que su página siguiente llega en el encabezado X-Next-Cursor (consulte Listas que devuelven un array):

const BASE = "https://api.sursa.com";
const headers = { Authorization: `Bearer ${process.env.SURSA_API_KEY}` };

async function syncCards(since, saveCard) {
  const startedAt = new Date();
  const params = new URLSearchParams({ limit: "200" });
  if (since) params.set("updated_since", new Date(since.getTime() - 60_000).toISOString());
  let query = params.toString();
  while (query) {
    const response = await fetch(`${BASE}/v1/cards?${query}`, { headers });
    if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
    for (const card of await response.json()) await saveCard(card); // write into your store by card.id
    const cursor = response.headers.get("X-Next-Cursor");
    if (cursor) params.set("cursor", cursor); // keep updated_since: the cursor needs the same filters
    query = cursor ? params.toString() : "";
  }
  return startedAt; // pass it as `since` next time
}

Eliminaciones

Una lista solo devuelve objetos que existen, así que no puede indicarle que algo se eliminó. Recoja las eliminaciones del feed de eventos:

curl -G https://api.sursa.com/v1/webhook-events \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  --data-urlencode "type=card.deleted" \
  --data-urlencode "created_since=2026-10-23T00:00:00Z"

Para leer el feed hace falta una clave con el rol admin y el ámbito webhooks:manage. Los eventos se conservan durante 30 días. Si su sincronización lleva más tiempo sin ejecutarse, vuelva a leer la lista completa y elimine de su almacén todos los objetos que ya no estén en ella.

Exportar a un almacén de datos reúne las listas, updated_since y el feed de eventos en un solo trabajo.