Catalog REST API
The REST Catalog API is the primary integration surface for product sync, cart creation, and order completion.
Base URL:
https://merchant.thyris.cloud/api/v1/catalog
All requests require an API key.
Authorization: Bearer tr_live_your_key_here
For a complete required/optional field matrix for each request, see 05-request-field-requirements.md.
Endpoint Summary
| Method | Endpoint | Purpose |
|---|---|---|
GET | /stores | List stores available to the API key. |
GET | /products | List or search products. |
GET | /product-details?catalogId={catalogId} | Get complete authorized product details directly, without ACP Runtime or Flow execution. |
POST | /products | Create or upsert a product. |
GET | /products/{productId} | Get one product by Thyris product UUID. |
PATCH | /products/{productId} | Update one product. |
DELETE | /products/{productId} | Delete one product. |
GET | /carts | List carts. Defaults to non-archived carts. Use status=archived for archived carts. |
POST | /carts | Create a checkout-ready cart. |
POST / PATCH / DELETE | /carts/items | Add, update, or remove one or more cart items after cart creation. Supports bundle payloads. |
POST | /carts/clear?cartId={cartId} | Clear a cart if no checkout was created. |
POST | /carts/archive?cartId={cartId} | Permanently archive a cart. Archived carts cannot be reopened. |
GET | /orders | List orders. |
POST | /orders | Complete an order from a checkout ID. |
GET | /orders/{orderId} | Get an order by Thyris order UUID, public order ID, or checkout ID. |
PATCH | /orders/{orderId} | Update order details or status. |
List Stores
GET /api/v1/catalog/stores
Optional query:
GET /api/v1/catalog/stores?q=STORE_NAME_OR_ID
List Products
GET /api/v1/catalog/products?storeId=STORE_UUID&q=hoodie
Query parameters:
| Name | Required | Notes |
|---|---|---|
storeId | No | Limits results to one store. Store-scoped keys default to their bound store. |
q | No | Searches name, SKU, external ID, and catalog ID. |
Every returned product carries its own scope: { merchantId, storeId } and public merchant profile. The collection does not publish one root store ID, because merchant-, network-, and custom-scoped keys can return products from multiple stores.
The public merchant profile contains id, name, slug, description, logoUrl, websiteUrl, industry, and language. It intentionally excludes contact details, ownership data, plan, company size, timezone, internal status, and other operational fields. List, search, legacy product lookup, and product-detail responses use the same profile shape.
For the storefront UI profile, every renderable product must have non-empty catalogId, name, price, currency, and primary imageUrl, and its public merchant profile must have non-empty name and logoUrl. websiteUrl is returned when configured but may be null; a merchant website cannot be guaranteed for every merchant. Products or merchants missing an storefront UI-required field must be rejected during onboarding/synchronization or excluded from storefront render results.
Example:
curl "https://merchant.thyris.cloud/api/v1/catalog/products?storeId=STORE_UUID&q=hoodie" \
-H "Authorization: Bearer tr_live_your_key_here"
Create Or Upsert Product
POST /api/v1/catalog/products
Content-Type: application/json
Required fields:
storeIdnameprice
The general Catalog API keeps image fields optional for backward compatibility. Merchants enabled for the storefront UI profile must additionally supply a valid primary imageUrl (directly or as the first imageUrls entry), and the merchant account must have a valid logoUrl.
Recommended idempotency fields:
skuexternalId
When sku or externalId matches an existing product in the same store, the product is updated. Otherwise a new product is created.
{
"storeId": "STORE_UUID",
"sku": "HOODIE-BLK",
"externalId": "shopify_product_123",
"name": "Black Hoodie",
"description": "A heavyweight black hoodie.",
"price": 49.9,
"currency": "USD",
"status": "active",
"inStock": true,
"inventoryQuantity": 12,
"imageUrl": "https://cdn.example.com/hoodie.png",
"imageUrls": [
"https://cdn.example.com/hoodie.png",
"https://cdn.example.com/hoodie-back.png"
],
"productUrl": "https://store.example.com/products/hoodie",
"metadata": {
"sourceSystem": "shopify"
},
"otherDetails": {
"brand": "Acme",
"category": "Apparel",
"tags": ["hoodie", "black"]
},
"variants": [
{
"sku": "HOODIE-BLK-M",
"externalId": "shopify_variant_123",
"name": "Black Hoodie / Medium",
"price": 49.9,
"currency": "USD",
"status": "active",
"inStock": true,
"inventoryQuantity": 8,
"imageUrl": "https://cdn.example.com/hoodie-black-m.png",
"productUrl": "https://store.example.com/products/hoodie?variant=black-m",
"otherDetails": {
"color": "black",
"size": "M"
}
}
]
}
imageUrls is optional and accepts at most 20 valid URLs in display order. Its first value is the primary image and is synchronized to the legacy imageUrl field. Sending only imageUrl remains supported.
Response:
{
"success": true,
"mode": "created",
"data": {
"id": "product_uuid",
"catalogId": "1234567890"
}
}
Get Product
GET /api/v1/catalog/products/PRODUCT_UUID
Get Product Details Without A Flow
GET /api/v1/catalog/product-details?catalogId=1234567890
Use this read-only endpoint when a client already has a product identifier and needs the complete authorized product record without invoking ACP Runtime or selecting a Flow. Prefer the ten-digit catalogId returned by product search. productId, sku, and externalId are also accepted; storeId is recommended with SKU or external-ID lookup.
{
"success": true,
"data": {
"id": "PRODUCT_UUID",
"catalogId": "1234567890",
"name": "Black Hoodie",
"description": "A heavyweight black hoodie.",
"price": "49.90",
"currency": "USD",
"inStock": true,
"imageUrl": "https://cdn.example.com/hoodie.png",
"imageUrls": ["https://cdn.example.com/hoodie.png"],
"store": { "id": "STORE_UUID", "name": "Acme Downtown", "slug": "acme-downtown" },
"merchant": {
"id": "MERCHANT_UUID",
"name": "Acme",
"slug": "acme",
"description": "Apparel and accessories.",
"logoUrl": "https://cdn.example.com/acme-logo.png",
"websiteUrl": "https://acme.example",
"industry": "Retail",
"language": "en"
}
}
}
Update Product
PATCH /api/v1/catalog/products/PRODUCT_UUID
Content-Type: application/json
Example:
{
"price": 44.9,
"inStock": true,
"inventoryQuantity": 24,
"imageUrls": [
"https://cdn.example.com/hoodie-v2.png",
"https://cdn.example.com/hoodie-v2-back.png"
]
}
If the request only changes price, outbound event subscribers receive product.price.updated. If it changes stock fields, subscribers receive product.inventory.updated. Other product changes emit product.updated.
Delete Product
DELETE /api/v1/catalog/products/PRODUCT_UUID
Successful response:
{
"success": true
}
List Carts
GET /api/v1/catalog/carts?storeId=STORE_UUID
GET /api/v1/catalog/carts?storeId=STORE_UUID&status=archived
GET /api/v1/catalog/carts?storeId=STORE_UUID&includeArchived=true
Carts include line items and store summary fields. The default list excludes archived carts so operational cart views do not mix active and archived records. Archived carts are read-only history records.
Create Cart
POST /api/v1/catalog/carts
Content-Type: application/json
Use the product's 10 digit catalogId, not the product UUID.
{
"storeId": "STORE_UUID",
"items": [
{
"catalogId": "1234567890",
"quantity": 2,
"otherDetails": {
"giftWrap": true
}
}
],
"metadata": {
"conversationId": "conv_123"
},
"otherDetails": {
"channel": "agent"
}
}
Response:
{
"success": true,
"data": {
"id": "cart_uuid",
"scope": {
"merchantId": "MERCHANT_UUID",
"storeId": "STORE_UUID"
},
"checkout": {
"id": "chk_1234567890abcdef12345678"
},
"status": "checkout_created",
"totalQuantity": 2,
"totalAmount": "99.80",
"currency": "USD",
"items": []
}
}
Cart creation fails atomically if a product is inactive, out of stock, has zero inventory, or the requested quantity exceeds stock.
Mutate Cart Items After Creation
POST /api/v1/catalog/carts/items
PATCH /api/v1/catalog/carts/items
DELETE /api/v1/catalog/carts/items
Content-Type: application/json
Idempotency-Key: merchant-cart-op-001
Single-item payloads remain supported:
{
"cartId": "CART_UUID",
"catalogId": "1234567890",
"quantity": 1
}
Bundle payloads use items[] and apply atomically within one cart mutation. Use POST to add, PATCH to replace quantities, and DELETE to remove lines. Update/remove operations accept either itemId or catalogId for each item.
{
"cartId": "CART_UUID",
"items": [
{ "catalogId": "1234567890", "quantity": 1 },
{ "catalogId": "9876543210", "quantity": 2 }
]
}
Successful mutations return the refreshed cart and emit the specific item or bundle webhook event plus the compatibility cart.updated event. Mutations are rejected when the cart is archived, closed, completed, checkout-locked, outside the key scope, or when inventory is insufficient.
Archive Cart
POST /api/v1/catalog/carts/archive?cartId=CART_UUID
Archive is irreversible. Archived carts stay available through GET /carts?status=archived and are excluded from the default cart list. Archived carts cannot be changed, cleared, closed, prepared for checkout, or returned to normal cart flow.
Cart And Order Operation Settings
Merchant Dashboard exposes store-scoped operation settings under Catalog:
- Cart Settings: open-cart TTL, checkout TTL, abandoned-cart threshold, automatic archive rule set, empty-cart archive threshold, closed/cancelled-checkout archive windows, irreversible archive posture, item/bundle mutation switches, bundle limits, inventory-hold settings, cart export format/schedule/PII inclusion, and cart webhook retry/event toggles.
- Order Settings: completion mode, manual completion, cancellation/refund windows, dedupe/idempotency policy, stock decrement mode, inventory webhook dispatch, invoice/export format and schedule, retention days, webhook retry/event toggles, and acknowledgement/fulfillment SLA targets.
These settings are stored on the store configuration and are the operational control plane for cart/order behavior. Runtime enforcement depends on the deployed catalog-service version; integration teams should treat dashboard values as authoritative policy and verify enforcement in staging before go-live.
Clear Cart
POST /api/v1/catalog/carts/clear?cartId=CART_UUID
Carts with an existing checkoutId cannot be cleared.
List Orders
GET /api/v1/catalog/orders?storeId=STORE_UUID&q=ord_
q searches order ID, checkout ID, and payment ID.
Complete Order
POST /api/v1/catalog/orders
Content-Type: application/json
{
"checkoutId": "chk_1234567890abcdef12345678",
"payment": {
"id": "pay_1234567890abcdef12345678",
"provider": "manual",
"status": "paid"
},
"customer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"phone": "+15551112233"
},
"shippingAddress": {
"line1": "Example Street 1",
"city": "New York",
"country": "US",
"postalCode": "10001"
},
"billingAddress": {
"line1": "Example Street 1",
"city": "New York",
"country": "US",
"postalCode": "10001"
},
"otherDetails": {
"deliveryNote": "Leave with reception"
}
}
payment is optional. When payment.id is supplied, the order preserves it for reconciliation; otherwise Catalog generates an internal payment reference. The response contains the newly generated orderId on the order object and returns related IDs as cart.id, checkout.id, and payment.id.
Get Order
GET /api/v1/catalog/orders/ORDER_ID_OR_CHECKOUT_ID
The path value may be the Thyris order UUID, generated public orderId, or checkoutId.
Update Order
PATCH /api/v1/catalog/orders/ORDER_ID_OR_CHECKOUT_ID
Content-Type: application/json
Allowed fields:
status:completedorcancelledcustomershippingAddressbillingAddresspaymentDetailsmetadataotherDetails
Example:
{
"status": "cancelled",
"paymentDetails": {
"status": "refunded",
"provider": "manual"
}
}
Common Status Codes
| Status | Meaning |
|---|---|
200 | Successful read or update. |
201 | Created successfully. |
400 | Invalid payload or missing required parameter. |
401 | Missing or invalid API key. |
403 | API key is not allowed to access the requested store or record. |
404 | Product, cart, or order not found. |
409 | Conflict, such as SKU/external ID identity mismatch or invalid cart/order state. |
500 | Unexpected server error. |
For retry guidance, outbound receiver responses, and integration checks, see Testing and Troubleshooting and Catalog Webhooks.