> ## 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.

# Spresso integration

> Connect OmniCommerce catalog, commerce outcomes, and marketplace writes to Spresso end to end.

OmniCommerce is the marketplace adapter and system of record between Spresso
and Shopee, Lazada, TikTok Shop, Shopify, Zalora, Amazon, and future channels.
Spresso receives one provider-neutral catalog and outcome model; it does not
need to parse marketplace push payloads.

<Warning>
  Spresso's public [Catalog
  Sync](https://spresso.readme.io/docs/catalog-intake-copy) and [custom-platform
  installation](https://spresso.readme.io/docs/general) documentation currently
  describe catalog delivery by SFTP plus its storefront Web SDK. They do not
  publish a general-purpose webhook ingestion URL or custom-platform pricing
  API. Ask Spresso to provision the receiver, credentials, accepted event
  versions, and storefront price-token handoff before production activation. The
  APIs on this page are the OmniCommerce side of that adapter; do not invent a
  Spresso URL.
</Warning>

## End-to-end flow

```text theme={null}
Omni catalog export  ───────────────► Spresso product families and agents
Omni commerce webhooks ─────────────► Spresso outcomes and optimization
Spresso price decision ─────────────► Omni price API
Omni durable marketplace jobs ──────► Exact connected marketplace accounts
Omni job API and event recovery ────► Reconciliation and replay
```

The integration has four independent stages. Keeping them separate prevents a
late settlement or return from being mistaken for an order lifecycle update.

## 1. Bootstrap the catalog

Use `GET /api/v1/catalog/items` with `catalog:read`. The JSON response is
cursor-paged and includes both products and variants, product-family identity,
SKU and UPC, brand and category, tags, cost, list/sale/compare-at/MAP/MSRP
prices, currency, inventory, active promotion context, and exact marketplace
identifiers.

```bash theme={null}
curl "https://omnicommerce.sg/api/v1/catalog/items?limit=500" \
  -H "Authorization: Bearer $OMNI_API_KEY"
```

Follow `data.nextCursor` until `data.hasMore` is false. For incremental exports,
save a high-water timestamp and pass `updatedSince` with an overlap window.
Items are ordered by `updatedAt`, then ID.

If Spresso requests its documented flat-file intake, request CSV instead:

```bash theme={null}
curl "https://omnicommerce.sg/api/v1/catalog/items?format=csv&limit=500" \
  -H "Authorization: Bearer $OMNI_API_KEY" \
  --output omnicommerce-catalog.csv
```

For CSV pages, pagination is returned in `X-Has-More` and `X-Next-Cursor`.
The export includes Spresso's documented core columns such as Product Family
Name, Name, SKU Id, Product Id, UPC, Brand, Category, Cost, Price, MAP Price,
and MSRP Price. OmniCommerce can deliver that file to the SFTP location Spresso
provisions; SFTP credentials are not configured by this API.

## 2. Subscribe to incremental outcomes

Create a webhook subscription with `webhooks:manage`:

```bash theme={null}
curl -X POST "https://omnicommerce.sg/api/v1/webhooks" \
  -H "Authorization: Bearer $OMNI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://receiver.example.com/webhooks/omnicommerce",
    "description": "Spresso adapter",
    "events": [
      "product.created",
      "product.updated",
      "product.deleted",
      "product.price.changed",
      "product.inventory.changed",
      "order.created",
      "order.updated",
      "order.status.changed",
      "order.deleted",
      "return.created",
      "return.updated",
      "return.status.changed",
      "settlement.created",
      "settlement.updated",
      "settlement.status.changed"
    ]
  }'
```

Use the events for different facts:

| Resource   | What Spresso can learn                                                                    |
| ---------- | ----------------------------------------------------------------------------------------- |
| Product    | Catalog attributes, price, inventory, cost, MAP/MSRP, and promotion context               |
| Order      | PII-free SKU-level quantity, selling price, line total, and historical unit-cost outcomes |
| Return     | PII-free returned SKUs, quantities, refund amounts, and normalized return status          |
| Settlement | Late marketplace fees, subsidies, refunds, net settlement, and reconciliation status      |

Settlement and return events are separate from `order.updated`. They often
arrive hours or days later and can be corrected independently.

Verify `X-Omni-Signature` against the raw request body before parsing. Persist
the event ID in the same transaction as the snapshot and return `2xx` only
after durable acceptance. See [Webhooks](/webhooks/overview).

## 3. Apply a Spresso decision

Use the product or variant UUID from the catalog export. Both endpoints require
`catalog:write` and derive the organization from the bearer credential.

```bash theme={null}
curl -X PATCH \
  "https://omnicommerce.sg/api/v1/products/PRODUCT_OR_VARIANT_UUID/price" \
  -H "Authorization: Bearer $OMNI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "price": 29.90,
    "salePrice": 24.90,
    "currency": "SGD",
    "syncToMarketplaces": true,
    "targets": [
      { "platform": "shopee", "accountId": "shop-456" },
      { "platform": "lazada", "accountId": "seller-123" }
    ]
  }'
```

Inventory uses the same target model:

```http theme={null}
PATCH /api/v1/products/{productId}/inventory
```

Only exact enabled and published `{platform, accountId}` targets are accepted.
Omit `targets` to use all eligible listings, or set `syncToMarketplaces=false`
to change only the OmniCommerce catalog. Product source-ownership, active
promotion, and sale-price safeguards still apply.

## 4. Track and recover

Marketplace writes are asynchronous. A synchronized price or inventory update
returns `202`, job IDs, and immediate per-target queue status. Poll every job:

```http theme={null}
GET /api/v1/jobs/{jobId}
```

Do not treat the local catalog response as proof that every marketplace write
succeeded. Complete the integration transaction only after the returned jobs
reach a terminal state, and retain per-target errors for retry or operator
review.

If the webhook receiver is unavailable, recover immutable events with:

```bash theme={null}
curl "https://omnicommerce.sg/api/v1/webhook-events?occurredSince=2026-08-29T00:00:00Z&limit=250" \
  -H "Authorization: Bearer $OMNI_API_KEY"
```

Results are ordered oldest first. Continue with `data.nextCursor`. You can
repeat `eventType` or comma-separate event keys. Applying the same event twice
must be safe because webhook delivery is at least once.

For resource reconciliation, use the pull APIs:

| Endpoint                                 | Scope              | Purpose                                |
| ---------------------------------------- | ------------------ | -------------------------------------- |
| `GET /api/v1/catalog/items`              | `catalog:read`     | Full or incremental catalog export     |
| `GET /api/v1/orders`                     | `orders:read`      | Order bootstrap and reconciliation     |
| `GET /api/v1/orders/{orderId}`           | `orders:read`      | One complete order detail              |
| `GET /api/v1/returns`                    | `returns:read`     | Cursor-paged return outcomes           |
| `GET /api/v1/returns/{returnId}`         | `returns:read`     | One normalized return                  |
| `GET /api/v1/settlements`                | `settlements:read` | Latest normalized settlement snapshots |
| `GET /api/v1/settlements/{settlementId}` | `settlements:read` | One normalized settlement              |
| `GET /api/v1/webhook-events`             | `webhooks:manage`  | Missed-event recovery                  |

<Note>
  Settlement reads expose normalized snapshots created by the settlement event
  pipeline. Use them for ongoing integration and recovery; a historical finance
  backfill must run before expecting older orders to appear.
</Note>

## Activation checklist

* Obtain Spresso's provisioned SFTP and/or receiver contract and credentials.
* Agree on catalog cadence, timezone, currency handling, event schema versions,
  and the identifier Spresso returns with each price decision.
* Bootstrap and reconcile product-family/SKU counts before enabling writes.
* Test HMAC verification, duplicate delivery, out-of-order resource versions,
  and pull recovery.
* Start with `syncToMarketplaces=false`, then enable one exact test account.
* Verify MAP, min/max, rounding, promotion, and catalog source-ownership rules.
* Confirm storefront and cart surfaces use the same Spresso-selected price where
  the Spresso Web SDK or price token is required.
* Alert on terminal job failures and catalog/order/return/settlement lag.

## Why these fields exist

[Spresso agents](https://spresso.readme.io/docs/agent-configurations) are
configured around product families and use Standard Price, Cost, MAP,
Compare-at Price, optimization goals, bounds, and rounding rules. The catalog
export and product events preserve those values. Spresso's
[Pricing Intelligence](https://www.spresso.ai/products/pricing-intelligence)
is based on first-party SKU data; PII is excluded from OmniCommerce order and
return outcomes because pricing optimization needs SKU economics, not buyer
identity.

Continue with [Price and inventory updates](/guides/catalog-updates),
[Order webhooks](/webhooks/orders), [Return webhooks](/webhooks/returns), and
[Settlement webhooks](/webhooks/settlements).
