FulfillbotDocs
Menu
MarkdownDownload

Incremental sync

To keep a copy of your orders without reading all of them every time, ask GET /v1/orders only for the orders that changed.

How it works

GET /v1/orders?updatedSince=<time> returns the orders whose updatedAt is at or after that time. The list is still sorted by creation time, newest first, and paged as usual. You can combine it with status.

updatedSince is an ISO 8601 date-time with a time zone, for example 2026-11-01T00:00:00Z. Encode + in an offset as %2B: 2026-11-01T08:00:00%2B08:00.

The recipe

  1. Note the current time before you request page 1. Call it started.
  2. Read every page with the same updatedSince. The first time, leave updatedSince out to read everything.
  3. Save each order by id, replacing the copy you had.
  4. Next time, use started minus a safety margin of a few minutes as updatedSince.

The margin covers clock differences and orders that changed while you were reading. You will see some orders again; that is expected: match them on id.

Things to know

  • Any edit through PATCH /v1/orders/{id}, including a change to the lines only, changes updatedAt, so the next updatedSince read picks it up.
  • Purchase orders, shipments, requests and quotes have no updatedSince. Use webhooks and fetch the resource with GET, or re-read the first pages of the list (newest first). Re-reading the first pages only finds new purchase orders, shipments and requests, because lists sort by creation time; for changes to older ones use webhooks plus GET.
  • Webhooks usually tell you about a change within a minute. Polling with updatedSince is a good safety net next to them: see Keep your orders in sync.

Example

import { readFile, writeFile } from "node:fs/promises";

const MARGIN_MS = 5 * 60 * 1000;
const state = JSON.parse(await readFile("sync-state.json", "utf8").catch(() => "{}"));
const started = new Date();
const orders = new Map(Object.entries(state.orders ?? {}));

for (let page = 1; ; page += 1) {
  const query = new URLSearchParams({ page: String(page), ...(state.updatedSince ? { updatedSince: state.updatedSince } : {}) });
  const response = await fetch(`https://api.rephut.com/v1/orders?${query}`, { headers: { Authorization: `Bearer ${process.env.FULFILLBOT_API_KEY}` } });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const { data, meta } = await response.json();
  for (const order of data) orders.set(order.id, order);
  if (data.length === 0 || page >= meta.pageCount) break;
}

const updatedSince = new Date(started.getTime() - MARGIN_MS).toISOString();
await writeFile("sync-state.json", JSON.stringify({ updatedSince, orders: Object.fromEntries(orders) }));
console.log(orders.size, "orders saved; next updatedSince:", updatedSince);

The list endpoint returns order summaries. Fetch GET /v1/orders/{id} for the full order, such as the recipient, fulfilment and charges.