Publish a product

Create a product, give it images, publish it to a channel and know when it's really live.

The whole loop is two writes and one wait.

1. Create the product

curl -X POST https://api.nembol.com/rest/v1/products \
  -H "Authorization: Bearer $NEMBOL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-VDJ-001" \
  -d '{
    "title": "Vintage denim jacket",
    "description": "<p>Classic 90s denim jacket.</p>",
    "brand": "Acme",
    "price": "49.90", "quantity": 3, "sku": "VDJ-M-001",
    "images": [{"url": "https://your-cdn.com/jacket.jpg"}]
  }'

The response is the product, synchronously. Grab id and the image ids.

2. Publish it

curl -X POST https://api.nembol.com/rest/v1/listings \
  -H "Authorization: Bearer $NEMBOL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: publish-VDJ-001-shopify" \
  -d '{"product_id": "prod_…", "channel_account_id": "chac_…"}'

202 with status: "ongoing". Publication runs through Nembol's channel workers. Get the channel_account_id from GET /channel_accounts.

3. Know when it's live

Subscribe to the listing.status_changed webhook (best), or poll GET /listings/{id} until status is listed. You'll get id_on_channel and url_on_channel. On a healthy channel this takes seconds, not minutes.

If the channel rejects it you get status: "error" and the channel's own message in issues[]. See Handle errors.

Gotchas

  • Images first. Channels reject imageless listings, so publishing without images fails upfront with photo_required_for_channel.
  • Image URLs must be public. Nembol downloads each url once and stores its own copy. If your images aren't reachable from the internet (a local ERP, a private bucket), send them as {"base64": "…"} instead (max 10 MB each). Point url at the image file itself, not at a page showing it: Nembol checks the bytes, so a URL that answers an HTML page gets 422 unsupported_file_type, and one it can't download gets 422 image_unreachable, each with the image in param. Nothing is created in either case.
  • Alt text. Give each image an alt (accessibility, SEO), up to 512 characters. It reaches Shopify, WooCommerce, Etsy, Wix, Squarespace and the Storefront when the images are pushed: on publish, and on an edit when the account's push updates switch is on. Etsy keeps the first 500 characters, Squarespace the first 200. Importing from those channels brings their alt text in. eBay, Amazon, TikTok Shop, Google Merchant Center and Meta have no image alt text, so they don't receive it. Change it later by sending the image back by id with a new alt ("" clears it); sellers can edit it in the dashboard too (Media tab, under each image).
  • Variants must be a full matrix. With options (e.g. Color × Size), every combination needs a variant. Channels generate the whole matrix, so a sparse set is rejected with 422 instead of publishing broken variants.
  • Currencies are not converted. Prices are in the store's currency (GET /store → currency) and Nembol publishes the number as it is: 19.90 on a EUR store is 19.90 USD on a US Shopify shop. Each channel account shows the currency it sells in (currency) and, when it differs from the store's, a currency_mismatch warning (on the account in warnings, on its listings in issues). Fix it with a price rule on that account (PATCH /channel_accounts/{id} with pricing), or connect a shop in the store's currency.
  • The channel price can differ from yours. Sellers can configure per-channel price rules in Nembol (percentage or fixed adjustment), so don't treat a different price on the channel as a bug.
  • WooCommerce may publish as draft. If the seller set product status: draft in their Nembol channel settings, the listing is listed but the product URL is not public until they publish it in WooCommerce.
  • Publishing is idempotent per (product_id, channel_account_id): re-POSTing returns the existing listing. If the listing errored, re-POST retries the publication.

After publishing

  • Price and text changes: PATCH /products/{id}. They reach the channel when the account's sync.product_edits switch is on (it starts off): see Edit a product.
  • Stock from your system: POST /inventory/batch by SKU, see Sync stock and prices in bulk.
  • Sales and shipping: order.created webhooks, then POST /orders/{id}/fulfillment, see Fulfill orders.

Last updated on October 16, 2026

Need help?

Email us and a human replies, usually within one business day.

On this page