Prebit Developer Docs
Tutorials

Tutorial: Build a Product Sync App

Sync products from your own system into a Prebit store, safely retryable.

This builds on prebit-examples/product-sync — here we walk through why it's built the way it is, not just what it does.

The goal

You have products in your own system (a warehouse tool, a legacy catalog, whatever) and want them mirrored into a merchant's Prebit store, safely — meaning a network blip or a crashed process retrying the same sync doesn't create duplicates.

Step 1: get an access token

Assume you already completed OAuth and have an access_token with write_products granted.

import { PrebitPartnerClient } from "@prebit/sdk";

const client = new PrebitPartnerClient({ baseUrl: "https://admin.prebit.in", accessToken });

Step 2: pick a stable idempotency key per product

The key must be the same across retries of the same logical write, and different for a genuinely different write. A hash of your own system's stable identifier for that product (a SKU, an internal id) works well:

import crypto from "crypto";

function idempotencyKeyFor(sku: string): string {
  return crypto.createHash("sha256").update(`product-sync:${sku}`).digest("hex");
}

Don't use crypto.randomUUID() here. A fresh random key on every call means every retry is treated as a brand-new write — the exact thing idempotency exists to prevent. Derive it from something stable.

Step 3: create (or, on a real second run, decide create vs. update)

for (const product of myProducts) {
  const key = idempotencyKeyFor(product.sku);
  try {
    const { data } = await client.createProduct(
      { name: product.name, price: product.price, sku: product.sku, stock: product.stock },
      key,
    );
    console.log(`✓ ${product.name} → ${data.id}`);
  } catch (err) {
    console.error(`✗ ${product.name}:`, err);
  }
}

This tutorial's example always calls createProduct for simplicity. A real sync needs to track which of your products already have a Prebit id (store that mapping in your own database after the first successful create) so a second run calls updateProduct(id, ...) instead of trying to create the same product twice — the idempotency key protects against retrying the exact same request, not against sending a different request for a product you already created last week.

Step 4: handle partial failure

The loop above catches per-product errors so one bad product (e.g. a negative price, caught by validation) doesn't abort the whole sync. Log failures somewhere you'll actually see them — a sync that silently drops failed rows is worse than one that's slow.

Step 5 (optional): react to the merchant's own edits

If a merchant edits a product Prebit-side, you'll want to know — subscribe to product.updated in your manifest and see Webhooks. Note the loop-prevention behavior: your own writes never echo back to you, but the merchant's edits do.

Where to go from here

  • Inventory for keeping stock levels in sync separately (a different endpoint, different idempotency-key shape).
  • Collections if you also need to sync category/ collection membership.
  • Errors, Pagination & Idempotency for the full contract this tutorial builds on.

On this page