Store Hugs Developers

AdminClient

Your ERP, warehouse, CRM or app on a shop's products, stock, orders, customers, marketing, reviews, quotations, keys and webhooks, through the Admin API. Use it on your server only.

Get started

  1. Make a key. In the Store Hugs panel, open Shop Settings → Integration API and add an Admin key (sa_live_…). Choose its scopes and, optionally, the IP addresses your servers call from. The key is shown once; keep it in your server's secrets.

  2. Install the SDK:

    npm install @storehugs/integration
    
  3. Make a client and a first call:

    import { AdminClient } from '@storehugs/integration';
    
    const admin = new AdminClient({ apiKey: process.env.STOREHUGS_ADMIN_KEY! });
    
    const shop = await admin.shop();
    console.log(shop.name, shop.plan, shop.currency);
    
  4. Sync. Read every record changed since your last run, oldest change first, and keep the last updatedAt you saw:

    for await (const product of admin.products.all({
        updatedSince: lastSyncedAt,
    })) {
        await saveToErp(product);
        lastSyncedAt = product.updatedAt ?? lastSyncedAt;
    }
    
  5. Write safely. Every write is retried with the same Idempotency-Key (see retries). Pass the updatedAt you read with a change, so a newer edit is never overwritten (409 edit_conflict):

    const product = await admin.products.get(12);
    await admin.products.update(
        12,
        { price: 19.5 },
        { unmodifiedSince: product.updatedAt ?? undefined },
    );
    

The key names the shop; there's no shop id to pass. A request from a browser (with an Origin header) is refused.

Options

Option Type
apiKey string Required. An Admin key, made in the panel or issued to your app.
baseUrl string The panel's origin. Default https://my.storehugs.com (ADMIN_API_URL).
fetch FetchLike Your own fetch (see custom fetch).
maxRetries number Retries after 429, 503 and network errors. Default 2.
inProgressTimeoutMs number How long to wait while a retried write still runs. Default 30000.

Scopes

Each method needs the scope it names. A key without it gets 403 insufficient_scope.

Scope Allows
shop:read The shop's details.
keys:read, keys:write Storefront keys.
products:read, products:write Products.
inventory:write Stock levels.
orders:read, orders:write Orders, their status and shipments.
customers:read, customers:write Customers and wholesale memberships.
marketing:read, marketing:write Coupons and offers.
reviews:read, reviews:write Reviews and the shop's replies.
quotations:read, quotations:write B2B quotations.
webhooks:read, webhooks:write Webhook endpoints.

Lists and sync

Every resource with a list has two methods:

They take these query fields, and the resource's filters below:

Query Type
limit number Records per page, up to 100.
cursor string The page to read, from meta.nextCursor.
updatedSince string ISO 8601. Only records changed since then, oldest change first.
const page = await admin.orders.list({ status: 'processing', limit: 50 });
const next = page.meta.nextCursor
    ? await admin.orders.list({
          status: 'processing',
          limit: 50,
          cursor: page.meta.nextCursor,
      })
    : null;

Changes with UpdateOptions

Methods that change a record (update, setMembership) take UpdateOptions last:

Option Type
unmodifiedSince string The record's updatedAt as you read it. If it has changed since, the change is refused with 409 edit_conflict.
idempotencyKey string Your own Idempotency-Key.

Other writes take RequestOptions (idempotencyKey, signal, headers).

Models and methods

Each page describes every method in full: its parameters, the fields it sends and gets back, its refusals and an example.