Hướng dẫn
Trên trang này
TL;DR — Kéo các creative quảng cáo đã duyệt theo kiểu tăng dần: truyền checkpoint gần nhất của bạn vào
updated_since, đi theonext_cursortới hết, ghi đè bản ghi theocreative_id, và chỉ dời checkpoint khi cả lượt chạy đã thành công. Kiểm lại một creative đã lưu bằngGET /creatives/{id}; ngừng dùng nó sau ngày UTC củarights.ends_at.
Trước khi bắt đầu
- Một key có
creatives:exportcho job, đặt trongWANDURA_API_KEY. Job marketing không bao giờ cầnplayback. - Bản ghi và lớp vỏ response: Creative.
Quy trình
- Lần chạy đầu:
GET /creatives?limit=100không cóupdated_since; khidata.next_cursorcòn khácnull, gọi lại vớicursor=<next_cursor>. - Upsert mọi bản ghi theo
creative_id. Một bản ghi có thể đến hai lần (updated_atđược làm tròn xuống tới giây, vàupdated_sincelà so sánh nghiêm ngặt): cứ ghi đè. - Checkpoint: sau khi lượt chạy hoàn tất, lưu
updated_atlớn nhất bạn đã nhận. - Các lần chạy sau: làm như trên, với
updated_since=<checkpoint>ở mọi trang của lượt chạy. - Khi lỗi (kể cả
4224222, cursor không còn hợp lệ): giữ checkpoint cũ; lần chạy sau bắt đầu lại từ đó. Không bỏ sót gì. - Creative bị gỡ không được thông báo. Trước khi dùng một creative đã lưu, hoặc mỗi ngày một lần, gọi
GET /creatives/{id}:4044040nghĩa là ngừng dùng nó. - Bản quyền: dùng được tới hết ngày UTC mà
rights.ends_attrỏ tới (ends_at + 86400).
Vài lần chạy mỗi giờ vẫn nằm thoải mái trong rate limit của creative.
Code
export async function syncCreatives(store: CreativeStore, o: CallOptions = {}): Promise<boolean> {
const since = await store.checkpoint();
let cursor: string | null = null;
let max = since ?? 0;
try {
do {
const qs = new URLSearchParams({ limit: '100' });
if (since !== null) qs.set('updated_since', String(since)); // the same value on every page of a run
if (cursor) qs.set('cursor', cursor);
const { data }: { data: Envelope } = await call<Envelope>('GET', `/api/delivery/v1/creatives?${qs}`, { policy: BACKGROUND, ...o });
for (const c of data.data.items) { await store.upsert(c); max = Math.max(max, c.updated_at); }
cursor = data.data.next_cursor;
} while (cursor);
} catch (e) {
// 422 / code 4222 (cursor no longer valid) or anything else: the next run restarts from the old checkpoint.
log('creatives_sync_failed', { status: (e as { status?: number }).status, code: (e as { errorCode?: string }).errorCode });
return false;
}
await store.saveCheckpoint(max); // only after the whole run: nothing is ever skipped
return true;
}Xong khi
- Lần chạy thứ hai khi phía Wandura không có thay đổi thì không trả về gì mới.
- Lượt chạy bị ngắt giữa chừng không dời checkpoint.
- Creative đã quá ngày bản quyền không còn được dùng.
Liên quan
Cập nhật 02/10/2026 · Lịch sử thay đổi (1)