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:
| Lista | Qué cuenta como cambio |
|---|---|
GET /v1/cards, GET /v1/cards/count | updated_at de la tarjeta. |
GET /v1/groups | updated_at del grupo: su título o su configuración. |
GET /v1/webhooks | updated_at del webhook: su configuración y su secreto, no sus entregas. |
GET /v1/jobs | updated_at del trabajo: cada cambio de su estado. |
GET /v1/drafts | updated_at del borrador. |
GET /v1/cards/{card_id}/threads | La ú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}/folders | updated_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
- En la primera ejecución, lea la lista completa sin
updated_sincey recuerde el momento en que empezó la ejecución. - 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. - 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. - 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 devuelve400con el códigoapi.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.