Hopp til innhold
skribbskribb

Utviklere

Hold lageret i sync

Et annet system eier beholdningen, og skribb følger etter.
Alle sidene

Nøkkelen trenger

products:readproducts:write

Lag en nøkkel →

Oppsettet

To ting må stemme før noe av dette virker. Produktet må være fysisk: digitale produkter har ikke lager, og et forsøk svarer 409 not-a-physical-product. Og produktet må ha lagerstyring i det hele tatt. Et produkt med inventory: null selges uten å telle ned, og et forsøk på å justere det svarer 409 inventory-not-tracked. Du slår det på ved å sette et tall.

Slå på lagerstyring for et produkt
curl -X PATCH https://api.skribb.no/v1/products/prod_8kQ2vX/stock \
  -H "Authorization: Bearer skribb_sk_…" \
  -H "Content-Type: application/json" \
  -d '{"set": 42}'

Bruk delta, ikke set

set skriver et absolutt tall. delta flytter beholdningen relativt til det den er nå.

Selger butikken tre krus i samme øyeblikk som lagersystemet ditt melder at det kom inn ti, kommer to oppdateringer inn nesten samtidig. Med delta blir begge med, og beholdningen ender riktig uansett hvilken rekkefølge de lander i. Med set vinner den siste, og den andre forsvinner uten et ord.

Bruk set bare når du mener «uansett hva som står der nå skal det være dette»: ved en opptelling, eller når du kobler et produkt til for første gang. {"set": null} slår lagerstyringen av igjen.

Avvik i lageret

Et trekk som ville gjort beholdningen negativ, blir avvist med 409. Det er ikke en feil du skal prøve igjen på, for den kan aldri gå. Det er de to systemene som er uenige om hva som står på hylla.

Svaret har inventory med beholdningen slik den faktisk er hos oss, så du kan avstemme uten et ekstra kall. Som regel er det riktige å skrive ditt eget tall med set og logge at de var i utakt.

Svaret du får
{
  "error": "would-go-negative",
  "message": "Trekket ville gjort beholdningen negativ. Svaret sier hva den faktisk er, så du kan avstemme.",
  "docs": "https://skribb.no/utviklere/referanse/produkter",
  "inventory": 2
}

Hent bare det som er endret

Den andre veien, altså å oppdage at noe er solgt i butikken, hører du om med stock.changed som webhook. Runden under er den som tar igjen etterpå: vi lover ikke at en webhook kommer fram, så et system som bare lytter driver sakte fra oss.

Du trenger ikke hente alle produktene hver gang: updated_since gir deg bare de endrede, og updated_at på hvert produkt er verdien du tar vare på til neste runde.

Lista er paginert. Er has_more sann, sender du next_cursor som ?cursor= for å få neste side.

En full runde
const KEY = process.env.SKRIBB_KEY;
const base = "https://api.skribb.no/v1";

async function api(path, init) {
  const res = await fetch(base + path, {
    ...init,
    headers: {
      Authorization: `Bearer ${KEY}`,
      ...(init?.body ? { "Content-Type": "application/json" } : {}),
      ...init?.headers,
    },
  });
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body.message), { body, status: res.status });
  return body;
}

// 1. Hva har endret seg hos oss siden sist?
async function* changedSince(iso) {
  let cursor = null;
  do {
    const qs = new URLSearchParams({ updated_since: iso, limit: "200" });
    if (cursor) qs.set("cursor", cursor);
    const page = await api(`/products?${qs}`);
    yield* page.products;
    cursor = page.has_more ? page.next_cursor : null;
  } while (cursor);
}

// 2. Flytt en endring fra ditt system til skribb.
async function move(productId, delta) {
  try {
    return await api(`/products/${productId}/stock`, {
      method: "PATCH",
      body: JSON.stringify({ delta }),
    });
  } catch (err) {
    if (err.body?.error !== "would-go-negative") throw err;
    // Vi er i utakt. Vårt tall er fasiten, så skriv det og logg avviket.
    console.warn("i utakt", { productId, skribb: err.body.inventory });
    return await api(`/products/${productId}/stock`, {
      method: "PATCH",
      body: JSON.stringify({ set: yourStockFor(productId) }),
    });
  }
}

Inaktive produkter, rategrensa og hvilken hendelse du lytter på

Et produkt du har tatt ut av butikken er fortsatt i lista, med is_active: false. Vi lar raden stå, for tidligere bestillinger skal fortsatt vise hva som ble kjøpt. Filtrer det bort hvis synkroniseringen din bare bryr seg om det som er til salgs.

Grensa er rundt 120 forespørsler i minuttet per nøkkel. En runde som henter 200 av gangen og bare skriver det som er endret, kommer ingen steder i nærheten. En runde som skriver hvert produkt hver gang, gjør det fort.

stock.changed kommer uansett hva som flyttet tallet: et salg, et varemottak, en opptelling eller en import fra et annet system. order.paid dekker bare salgene og gir deg varelinjene, så den er riktig når du skal plukke en pakke og ikke når du skal holde et lagertall i takt.

Videre