Инкрементална синхронизация с updated_since
За да поддържате копие на данните от Sursa в собствената си система, не е нужно всеки път да четете всичко.
Списъците на обекти, които имат updated_at, приемат updated_since и връщат само обектите, променени в този
момент или след него.
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"С updated_since списъкът е подреден по updated_at във възходящ ред, после по id, и курсорът
продължава в същия ред. Така четете промените в реда, в който са станали, и границата между страниците никога не ги
разделя така, че някоя да се изгуби.
updated_since се приема от тези списъци:
| Списък | Какво се смята за промяна |
|---|---|
GET /v1/cards, GET /v1/cards/count | updated_at на картата. |
GET /v1/groups | updated_at на групата: заглавието или настройките ѝ. |
GET /v1/webhooks | updated_at на уебхука: настройките и тайната му, но не и доставките му. |
GET /v1/jobs | updated_at на заданието: всяка промяна на статуса му. |
GET /v1/drafts | updated_at на черновата. |
GET /v1/cards/{card_id}/threads | Последното създаване или редактиране на основния коментар или на някой от отговорите. Нишката идва цялата. |
GET /v1/folders, GET /v1/collections/{name}/folders | updated_at на папката. Съвпадащите папки идват като плосък списък, вж. по-долу. |
Колекциите, потребителите и съобщенията нямат updated_at, затова списъците им не се филтрират по него: те са
кратки, така че ги четете целите при всяко изпълнение. Времето трябва да съдържа отместване на часовата зона,
например Z или +02:00; всяка друга стойност се отказва, както при GET /v1/cards.
С updated_since дървото на папките вече не е дърво: folders на всяка колекция съдържа променените папки като
плосък списък с празен children, а parent_id показва къде се намира всяка от тях.
GET /v1/folders тогава пропуска колекциите без променени папки.
Цикъл на синхронизация
- При първото изпълнение прочетете целия списък без
updated_sinceи запомнете момента, в който изпълнението е започнало. - При всяко следващо изпълнение подайте запомнения момент като
updated_since, минус малък резерв, например една минута, и запомнете новото начално време. - Записвайте всеки обект в хранилището си по неговото
id, като заменяте предишното копие. Обектите, които се появяват два пъти заради резерва, просто се записват отново. - Изисквайте всяка следваща страница с курсора и със същия
updated_since. Курсорът работи само с филтрите на първата страница: без тях заявката връща400с кодаapi.cursor_invalid.
Когато използвате началното време на изпълнението, а не времето на завършването му, промяна, направена докато изпълнението тече, със сигурност ще бъде взета при следващото.
GET /v1/cards връща JSON масив, затова следващата му страница идва в заглавката X-Next-Cursor
(вж. Списъци, които връщат масив):
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
}Изтривания
Списъкът връща само обекти, които съществуват, затова не може да ви каже, че нещо е изтрито. Вземайте изтриванията от лентата със събития:
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"За четенето на лентата е нужен ключ с ролята admin и обхвата webhooks:manage. Събитията се пазят 30 дни. Ако
синхронизацията ви не е стартирала по-дълго от това, прочетете отново пълния списък и премахнете от хранилището си
всеки обект, който вече не е в него.
Експорт в хранилище за данни събира списъците, updated_since и лентата със
събития в едно задание.