> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnicommerce.sg/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript SDK

> Typed JavaScript/TypeScript client for every OmniCommerce REST endpoint.

The TypeScript SDK (`@omni-commerce/sdk`) is generated from the public OpenAPI spec, so every documented REST operation is a typed resource method. The command-line client uses the same spec — see [Omni CLI](https://docs.omnicommerce.sg/cli/omni-cli.md).

The unscoped npm name `omnicommerce` is reserved. The public org is `@omni-commerce`.

## Install

```bash theme={null}
npm install @omni-commerce/sdk
```

Requires Node 18+ (global `fetch`). Named export only:

```ts theme={null}
import { OmniClient } from "@omni-commerce/sdk";
```

## Authenticate

Use an organization API key (`omni_sk_...`) as a bearer token. Do not send `organizationId` on API-key requests.

```ts theme={null}
const client = new OmniClient({
  apiKey: process.env.OMNI_API_KEY,
});
```

Omit `apiKey` to read `OMNI_API_KEY`. Override the host with `baseUrl` or `environment` (`https://omnicommerce.sg` by default). See [Authentication](https://docs.omnicommerce.sg/authentication.md).

```ts theme={null}
const client = new OmniClient({
  apiKey: process.env.OMNI_API_KEY,
  environment: "http://localhost:3000",
  timeoutInSeconds: 60,
  maxRetries: 2,
});
```

## Resource clients

Each call takes one request object (path params, query, and JSON body together), then optional request options:

```ts theme={null}
const products = await client.products.list({ q: "lamp" });

const job = await client.products.create({
  product: {
    sku: "SKU-100",
    title: "Sample product",
    price: 29.9,
    currency: "SGD",
    images: ["https://cdn.example.com/product.jpg"],
  },
});

await client.jobs.wait({ jobId: job.jobId });

await client.products.publish({
  productId: "prod_123",
  marketplaces: ["shopee"],
});

const delist = await client.products.delist({
  productId: "prod_123",
  marketplaces: ["shopee", "lazada"],
});
await client.jobs.wait({ jobId: delist.jobId });
```

Per-request overrides:

```ts theme={null}
await client.orders.get(
  { orderId: "ord_123" },
  { timeoutInSeconds: 15, abortSignal: controller.signal },
);
```

`await request.withRawResponse()` returns `{ data, rawResponse }` with status and headers.

## Publish selected fields

Pass `marketplaces` to choose where to publish/update. Omit it to use every enabled or already listed marketplace. Pass `updateFields` to publish only those saved product fields, matching the publish popover. Selected-field updates require an existing listing and assigned store; other fields and listing visibility stay unchanged. Omit fields for a full publish.

```ts theme={null}
const publish = await client.products.publish({
  productId: "prod_123",
  marketplaces: ["shopee", "lazada"],
  updateFields: ["name", "description", "images"],
});
for (const target of publish.data?.results ?? []) {
  if (target.jobId) await client.jobs.wait({ jobId: target.jobId });
  for (const correlation of target.correlations ?? []) {
    await client.jobs.wait({ jobId: correlation.id });
  }
}
```

Check `ok` and every target result: valid marketplaces can queue while another fails. Price and inventory selections return their durable jobs in the same results. Queued work is not proof of a live marketplace change. See the [API reference](https://docs.omnicommerce.sg/api-reference.md) for supported fields and marketplace capability limits.

## Product inventory

`products.list()` returns rows in `page.items`. Read catalog stock from `stockQuantity`, matching the Products page. Parent rows already aggregate their variants; virtual bundles already account for component stock and any manual cap. The list response does not embed a `variants` array: a row with `variantCount` above 0 has variants, and `products.get()` returns them in `variants`.

```ts theme={null}
const page = await client.products.list({ q: "lamp" });
for (const product of page.items ?? []) {
  const quantity = product.stockQuantity;
  console.log(product.id, quantity == null ? "Unknown stock" : quantity);
}
```

Only `0` means zero stock. Preserve null or missing values as unknown; do not default them to zero. `inventoryQuantity` and `inventory.quantity` are not product-list fields. `stockQuantity` is catalog stock, not a sum of marketplace inventory mirrors or a per-location available-to-promise balance.

## Market price comparison

Compare up to 50 OmniCommerce simple product or variant IDs using the shopping APIs behind pricing strategy. This read-only operation requires `catalog:read` and returns a durable job.

```ts theme={null}
const queued = await client.products.comparePrices({
  productIds: ["cc87d195-097a-4a5a-8229-cd989ce98d0f"],
});

await client.jobs.wait({ jobId: queued.jobId }, { timeoutInSeconds: 1800 });
const completed = await client.products.getPriceComparison({
  jobId: queued.jobId,
});
for (const result of completed.result?.results ?? []) {
  for (const market of result.markets) {
    console.log(
      result.productId,
      market.country,
      market.currency,
      market.currentPrice,
      market.comparison,
      market.error,
    );
  }
}
```

Omit `gl` to compare every recorded listing market; pass `gl: "sg"` to restrict research to Singapore. Global Zalora uses each recorded country price and currency, including Hong Kong and Taiwan. A Shopify store based in India but selling in SGD is researched in Singapore. Use variant IDs for products with variants.

Inspect `completed.result.success`, each market's `success`, `priceSource`, `priceAsOf`, and errors. Marketplace snapshots and acknowledged writes are persisted evidence, not a live listing refresh. Missing published prices produce explicit failures, with catalog research where available. Unlisted products use catalog pricing. Currencies stay separate; verify shopping variants and pack sizes before using results. A client wait timeout leaves the durable job running. See the [API reference](https://docs.omnicommerce.sg/api-reference.md) for the canonical contract.

## Coverage

| Client | Examples |
| - | - |
| `client.brandsgateway` | `importProducts` |
| `client.products` | `list`, `create`, `get`, `update`, `delete`, `publish`, `getListings`, `delist`, `bulkImport`, `enrich`, `uploadImage` |
| `client.orders` | `list`, `create`, `get`, `update`, `getActionOptions`, `queueAction`, `listActions` |
| `client.documents` | `upload`, `get` |
| `client.reviews` | `list`, `get`, `reply` |
| `client.analytics` | `getOverview`, `getTraffic`, `getProducts`, `getPricing`, `getAds`, `getOrders`, `getContent`, `getProfit`, `getAiTraffic`, `getStores`, `getReports` |
| `client.promotions` | `list`, `create`, `get`, `update`, `delete`, `retry` |
| `client.priceBooks` | `list`, `create`, `get`, `update`, `delete`, `preview` |
| `client.aop` | `create`, `execute`, `getConfig`, `updateConfig`, `retry` |
| `client.agents.general` | `invoke`, `start`, `getRun` |
| `client.jobs` | `get`, `cancel`, `wait` |
| `client.webhooks` | `list`, `create` |
| `client.checkoutSessions` | `create`, `get`, `update`, `complete`, `cancel` |
| `client.ucp` | `checkoutSessions`, `orders` |
| `client.oauth` | `token`, `revoke` |

Looks, returns, settlements, marketplaces, search, evaluate, monitor, sync, Zalora, and the remaining documented tags follow the same pattern. The generator covers every REST operation in the [API reference](https://docs.omnicommerce.sg/api-reference.md).

`client.agents.general.invoke` waits for the Omni agent. Pass `{ timeoutInSeconds: 780 }` on that call. `start` returns immediately and `getRun({ runId })` polls the run. See [Omni agent API](https://docs.omnicommerce.sg/guides/agent.md).

## File uploads

Upload methods (`documents.upload`, `products.uploadImage`) send multipart/form-data. Pass the file as a `File` (or `Blob` with a type); the other fields are sent as form fields.

```ts theme={null}
import { readFile } from "node:fs/promises";

await client.documents.upload({
  file: new File([await readFile("manual.pdf")], "manual.pdf", {
    type: "application/pdf",
  }),
  documentType: "manual",
});
```

## Errors

Non-2xx responses throw `OmniError` subclasses. See [SDK errors](https://docs.omnicommerce.sg/sdk/errors.md).

GET/HEAD/OPTIONS/PUT/DELETE retry on 5xx and network failures. 408 and 429 retry for every method. POST/PATCH are not retried on 5xx.

## Webhooks

```ts theme={null}
import { constructEvent } from "@omni-commerce/sdk";

const event = await constructEvent(
  rawBody,
  request.headers,
  process.env.OMNI_WEBHOOK_SECRET,
);
```

HMAC-SHA256 over `{timestamp}.{rawBody}` compared to `X-Omni-Signature`. See [Webhooks](https://docs.omnicommerce.sg/webhooks/overview.md).

## Regenerate

From this repository:

```bash theme={null}
yarn sdk:generate
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.