Changelog

Every change to the Nembol API, newest first.

/v1 changes additively only: new endpoints, new fields and new enum values can appear; nothing existing is renamed, removed or re-typed. Breaking changes would ship as /v2 with at least 6 months of deprecation notice.

Release of 2026-10-20

The entries from 2026-10-07 to 2026-10-19 ship together in the release of 2026-10-20 and are not in production before that day. They describe the final form of each feature; the additive-only promise applies from the release on.

2026-10-22: Partner prepaid credit, deleting a product while its delist is running

Added

  • GET /partner/billing: credit_balance, the prepaid credit left. When you pay Nembol in advance (e.g. a bank transfer), it becomes credit that each invoice uses first; only the rest is charged to your card or invoiced.

Changed

  • DELETE /products/{id}: while a listing of the product still has an operation running (ongoing, usually the delist you just asked for), it answers 409 listing_operation_in_progress instead of 422 product_still_listed. Wait for operation.completed (or poll the listing until delisted), then delete. Both errors now list the listings in error.details.listing_ids.

2026-10-21: API access during the trial

Changed

  • During the free trial, on any plan, a store can call the API with test keys (nbl_test_) and add one webhook endpoint. Live keys and the partner program still need Enterprise+; a live key on a trial answers 403 plan_not_eligible.

2026-10-19: Exports, notifications, catalog and promotions fixes

Changed

  • Imports: items are linked to existing products by SKU on every plan (the Basic plan used to create every item as a new product). The import.warnings note about it is gone.
  • GET /exports/orders: the standard file ends with a Status column (the order's status, as in GET /orders); quickbooks leaves out canceled and refunded orders, so they never become invoices.
  • POST /notifications/read: ids are echoed exactly as sent; an id that isn't one of the company's notifications answers 404 notification_not_found (param = ids[n], nothing is marked); an empty ids array is a 422.
  • POST /products/merge: a real merge answers object: "merge" (it said merge_preview).
  • PUT /products/{id}/variants: a confirmed removal is recorded in the action log (with Nembol-Action-Id) and can be undone; sending variants without options keeps the product's option names (rebuilt from the variants it keeps) instead of clearing them.
  • PUT /products/{id}/variants: an entry matched by id or sku without options keeps its own options (it was read as "no options" and refused as a duplicate combination). Undoing a variant removal restores the option values too, with no false changed_since conflict on options.
  • Imports: re-importing items that an earlier undo removed creates them anew and leaves the removed ones removed (they came back as well), so the undo of the new import removes everything it reports.
  • CSV imports: one per company at a time, as documented. A second POST /imports with csv while one runs answers 409 import_already_running (the check never matched before).
  • GET /listings?updated_after= filters on the listing's updated_at; an invalid timestamp is a 422.
  • POST /listings/batch results: listing_id is null when the product has no listing on that account and the request didn't start one.
  • POST /imports with filters.collection_id: takes the col_ id from GET /channel_accounts/{id}/collections (it imported nothing); an id the account doesn't have is a 422.
  • Promotions: a promotion that isn't a draft needs every channel connected (422 channel_not_connected) and at least one product listed there (422 promotion_reaches_nothing); GET /promotions?status= refuses an unknown value (422).
  • Storefront bundles: name over 140 characters is a 422.

2026-10-17: Promotions and storefront validation

Changed

  • Promotions: starts_at is optional (omitted = starts now; a draft keeps it until armed). Every invalid field answers 422 with its own message and param (discount.value, product_ids[2], variant_ids.prod_…). New codes: unknown_channel, discount_exceeds_price (names the product, variant, channel and price), variant_not_found; state errors are 409 promotion_running, promotion_not_running, promotion_reverting instead of a generic 422.
  • PATCH /storefront: every value is checked before anything is written, with its param; an unknown key inside announcement, return_policy or shipping is a 422 (it used to overwrite the saved value); announcement and return_policy merge partial updates; contact_email must be an email; an unknown theme is a 422 before the plan check. return_policy and shipping are snake_case and documented (who_pays; worldwide_free or zones[] with free_over, heavier_than…).
  • Discount codes: an invalid code is a 422 (param: code), never rewritten; PATCH changes only the fields sent ({value: 15} keeps the type); every error names its field.
  • Bundles: item errors name the item (items, items[1].product_id, 404 product_not_found / variant_not_found); bundle ids are bndl_<8> (the old bndl_bnd_… ids still work); pricing.type is percentage or fixed, like every other discount.
  • Storefront orders read like /orders: cursor pagination (limit, cursor, next_cursor), money as 2-decimal strings (total: "20.90", no more _cents), prod_ / var_ ids on lines, id = the order_… number. ?status= outside the list is a 422. An unknown order is 404 order_not_found on get, status and refund. A refund takes amount (decimal) and is checked (already_refunded, order_not_paid, amount above what's left) before the confirmation is asked.

Fixed

  • Nembol-Action-Id is now on every write, including shipping an order, disconnecting, delisting batches and closing a company; an idempotent replay no longer records the action twice.

  • PATCH /products/{id}/variants/{variant_id}: a malformed variant id on an existing product is 404 variant_not_found; "msrp": null removes the compare-at price (like "0.00").

  • Product edits on a single-channel product: a text sent with the same value isn't an edit (a full-product save keeps the channel's own title), and an empty channel text keeps following the product (no copy).

  • The action of PUT /products/{id}/variants lists its changes like every other action: variants.var_….price with 2-decimal strings, added or removed variants in the API's variant shape, options as [{name, values}].

  • A listing's operation_id keeps pointing at its last operation after it settles (it went back to null), in GET /listings, GET /listings/{id} and listing.status_changed.

  • A product with a variant at 0 that isn't on any channel is ready, not listed (also in ?status=listed / ready). Each product status is documented, with the order they apply in.

  • GET /products (and ?sku=) leaves archived products (deleted or merged) out unless status=archived; they stay readable by id.

  • Test webhook deliveries (API and dashboard) carry every data field of the real event, with valid values (order.status_changed has status, inventory.updated the sale fields, channel_account.* their ids).

  • Security: redirect URLs must be on a public host (loopback, private, link-local and *.localhost addresses are refused); webhook deliveries and image URLs are refused when the name resolves to a non-public address (redirects included).

  • An invalid cursor answers 422 validation_failed (param: cursor) on every list; it used to return the first page.

  • 409 sandbox_limit points to Settings → Partner → Go live.

  • GET /partner/statement: days_in_month added; days, amount and monthly_price documented (days to month end for open companies).

  • A request body that isn't valid JSON answers 400 invalid_json in the usual error envelope (with request_id); too large is 413 payload_too_large. It used to be an HTML error page.

  • GET /partner/statement and GET /partner/billing: money is a 2-decimal string like everywhere else (total, accounts[].monthly_price, accounts[].amount, rates), with the invoice currency (USD, Nembol's price list, whatever currency a company sells in).

  • POST /inventory/batch, POST /products/batch and the price adjustment could lose a channel job when several products were pushed to the same channel at once: the operation's results for those products stayed pending forever. The products are now queued together, one job batch per channel.

  • Security: the Nembol-Account header on a key without accounts:manage now answers 403 insufficient_scope before anything is read. Before, a read-only partner key could read inside every company (products, orders, customers, channel accounts).

Documentation

  • Every operation states its required scope (x-required-scopes in the spec, generated from the API itself), for least-privilege keys.
  • Shipping an order never asks for a confirmation (no Nembol-Confirmation, no 409 on fulfillment); connecting through the API imports only what is asked; a reconnected account gets a new chac_ id and its listings carry it; data.object is the resource as it is at delivery; the pagination exceptions; subscription_inactive is a 402; the unused image upload quota code removed; channel_account.connected / disconnected and listing.status_changed payloads match the catalog.
  • /llms-full.txt is plain Markdown (no site components), shows both shapes of POST /imports, and has one copy of each page; the Exports guide is in the sidebar and /llms.txt.
  • Closed companies stay readable (reads only), to export their data.
  • Rate limits: X-RateLimit-Reset is when the bucket is full again (not the next free slot, which is Retry-After); a partner company's bucket is sized by that company's plan (Enterprise+ 80 / 4 per s, every other plan 40 / 2 per s).

2026-10-16: Orders sync, reconnect, documentation

Added

  • GET /orders?updated_after= and the order's updated_at, to fetch only the orders placed or changed since your last sync.
  • Every order line has an id and a variant_id.
  • POST /channel_accounts/{id}/enable_business_policies (eBay): enroll the account in eBay Business Policies explicitly, with the two-step confirmation, so it can publish. Connecting never enrolls.
  • Companies: GET /accounts is cursor-paginated (limit, cursor, has_more, next_cursor); the Account carries country and currency.
  • New channel accounts get the channel's default settings when they connect (Squarespace, OnBuy, Kaufland, Google Merchant Center, PrestaShop and Temu now too), through the API exactly as in the dashboard.
  • POST /channel_connections: import_products and import_orders (both off by default): through the API a new connection imports nothing unless asked; a requested product import is a regular operation (import_operation_id, undoable). The dashboard keeps importing both.
  • Connecting a channel whose account was disconnected brings it back (reconnects_shop on the connection; same place and listings); new_account: true adds a different shop instead.
  • Reconnect an existing channel account after its login expired: POST /channel_connections with channel_account_id. The account keeps its id and listings. See Connect a channel.

Fixed

  • The two-step confirmation is asked only after the request is checked: closing a company, undoing an import and delisting answer their own error first (account_not_found, import_already_undone, listing_not_delistable…) instead of confirmation_required.
  • A batch delist confirms only the listings that would really end; with none, it answers the per-item outcomes. Closing an already closed company is idempotent (200, no confirmation).
  • Batch results keep the order of items and repeat the ids you sent, also for an unknown product or account (they came back null).
  • One product text: description is what the dashboard shows and every channel publishes. short_description is a deprecated alias that always returns the same value; when both are sent, description wins.
  • Listings of removed products (deleted, or removed by an import undo) leave GET /listings and answer 404 by id. A listing's created_at / updated_at are now its own, not the product's.
  • Partners go live by themselves: Go live in Settings → Partner (card first on card terms). One way; back to the sandbox through developer@nembol.com.
  • Image alt text is stored (it was dropped), editable in the dashboard, sent to Shopify, WooCommerce, Etsy, Wix, Squarespace and the Storefront, and read back on import from them. A kept image can change its alt.
  • An image URL that can't be downloaded answers 422 image_unreachable (with the image in param) instead of a 500.
  • Image URLs are checked like base64 and POST /files: a URL that doesn't answer a JPEG, PNG, WebP or GIF (e.g. an HTML page) gets 422 unsupported_file_type instead of being stored as an image.
  • Stored images keep their real type: the url ends in .jpg, .png, .webp or .gif and is served with the matching Content-Type (it was always .png / image/png). POST /files accepts the same four formats.
  • Stock and price changes (POST /inventory/batch, POST /inventory/price_adjustment) report one result per SKU and per live channel, with channel_account_id and listing_id, settled by that channel's own answer: a failure on one shop is no longer hidden.
  • POST /inventory/batch: rejected SKUs are also failed results (the operation ends partial); a batch where nothing applies answers 422 no_items_applied instead of a succeeded operation.
  • A listing's created_at is fixed at creation (it moved on every status change).
  • PATCH /listings/{id} with own texts returns the operation_id of the push, settled by the channel's answer; with the account's sync.product_edits off nothing is sent and push_skipped_reason says so (it claimed pushed).
  • A stock / price / text push that fails on the channel ends failed in its operation (it could end succeeded when a later push on the same product worked). Shopify's "currently being modified" is retried first.
  • listing.status_changed fires once per real status change, with data.previous_status; data.object is documented as the state at delivery.
  • Product objects in events carry the company's own currency (they said USD).
  • listing.status_changed notifies settled statuses only (ongoing isn't notified); previous_status is the last notified one, so events always chain.
  • Delist, disconnect and close confirmations name the product, shop or company.
  • Webhook deliveries of a company's events always carry account_id (some came without it), and identify themselves with User-Agent: Nembol-Webhooks/1.0.
  • Test webhook deliveries carry a sample data.object of the real shape (it was null); an unknown type answers 422.
  • One order.created per channel order (a multi-line order could send two).
  • inventory.updated now also fires for sales (data.source: "order").
  • Channel accounts show the currency their shop sells in and a currency_mismatch warning when it differs from the store's (prices are never converted); listings carry the same warning in issues.
  • Accounts connected before learn their currency at their first read (the read waits); currency_unknown when it can't be read. Sale inventory.updated events say which variant and by how much (variant_id, sku, quantity_change).
  • Orders carry number (the channel's display number) and the channel's money breakdown (subtotal, shipping, discount, tax, tax_remitted_by); total is the channel's order total.
  • Exports: ids as in the API (prod_…, ord_…), 2-decimal prices, every format documented (new Exports guide); the Google feed fills brand.
  • limit outside 1–100 answers 422 on every list (it was clamped); /customers validates sort / dir and gives country as ISO 3166-1 alpha-2; unknown values are null, never "".
  • A store billed by Nembol (billing_source: "manual") gets 409 billing_managed_by_nembol on every billing link (it got a 502 or Stripe links).
  • preferences.currency defaults to the store's currency; notification ids are ntf_….
  • Promotions: starts_at in the past answers 422; the plan limit is limits.running_promotions in GET /billing (Basic and trial 1, Pro and above unlimited). Idempotency: stored 4xx responses are documented.
  • /products/batch: a SKU on more than one variant fails with sku_ambiguous (it updated one of them); a batch where nothing applies answers 422 no_items_applied, like /inventory/batch. OperationResult.error.details.
  • Undo: a dry run (or a test key) answers status: "simulated" with outcome and per-product items, merge undos included; variant paths use var_… ids; prices have 2 decimals; a merge 404 lists the missing products.
  • POST /imports (CSV): a file without price and quantity (or sku-code) answers 422 with the missing columns; re-imported rows update their product, identical rows are counted as unchanged (new counter).
  • Generated SKUs (variants created without one) are 10 letters and digits.
  • POST /orders/{id}/fulfillment no longer asks for a two-step confirmation: shipping runs unattended from a WMS or label run; the marketplace is still notified at most once per order.
  • Fulfillment: tracking.url must be an http(s) URL (422); fields not sent keep their value; resending a tracking already notified answers attempted: false with already_notified_same_tracking (it said delivered). order.status_changed carries data.status, and is sent only when the status changes (not for a tracking or source_status-only update).
  • Webhooks: every event is now delivered whichever part of Nembol produced it; a missing delivery is queued within minutes (24 h window). Events from the order sync of partner sub-accounts weren't reaching partner endpoints.
  • A channel order canceled before shipping gives its units back to Nembol's stock and the other channels, once per line, with inventory.updated (reason: "order_canceled"), unless the channel's quantity edits already sync into Nembol.
  • Listing variants no longer carry status (it was always null): a variant's state is the listing's status.

Documentation

  • /llms-full.txt holds the full reference: every operation with its parameters and responses, in the same order as the sidebar.
  • Every operation in the reference documents its response schema.
  • The error code list is complete.
  • Closing a company (POST /accounts/{id}/close) is documented with its two-step confirmation. See Partner program.

Added

  • A connect link that can't be used (expired, already used, or refused by the store's plan, subscription or free slots) now sends the seller back to return_url with status and error (link_expired, link_already_used, plan_not_eligible, subscription_inactive, slot_no_longer_available, channel_login_failed). Without return_url the Nembol page is unchanged.
  • Partner sandbox: GET /partner/billing answers sandbox and sandbox_max_accounts; a 4th open company in sandbox answers 409 sandbox_limit. See Test your integration.

Fixed (documentation)

  • GET /channel_accounts/{id}/categories and GET /channel_accounts/{id}/categories/{category_id}/attribute_schema were listed in the reference but were never available (they answered 404). They are no longer listed; discovery.categories and discovery.attribute_schema stay false.

2026-10-14: Partner program, choose the account to connect

Added

  • Partner program: POST /accounts, GET /accounts, GET /accounts/{id}, PATCH /accounts/{id}, POST /accounts/{id}/close, GET /partner/statement, GET /partner/billing, and the Nembol-Account header to work inside a company. New permission accounts:manage.
  • Events of a partner's companies carry account_id and reach the partner's webhook endpoints.
  • Amazon, Google Merchant Center and Facebook Catalog can be connected with a connection link. When the channel asks which account to connect, the connection is needs_choice with choices: POST /channel_connections/{id}/choose.
  • Amazon connection params: country and optional marketplace.
  • GET /events with a partner key: all companies' events in one feed (account_id), account to narrow.

Added

  • POST /products/merge accepts variant_maps (variants matched by hand, for products live only on Etsy, Shopify or WooCommerce with the same number of variants). A 422 variants_differ now carries details.matching with both variant lists and a suggestion.
  • GET /ignored_listings and DELETE /ignored_listings/{id}: the channel listings ignored from "Requires attention", and how to bring one back (the next import of that channel brings it in again).
  • Product.merged_into on products absorbed by a merge.
  • Events: a merge emits product.updated for the survivor (data.merged) and product.deleted for each absorbed product (data.merged_into); POST /products/{id}/resolve emits product.updated (product.deleted for ignore); per-listing text edits emit product.updated.
  • Error.details documented, with the merge error codes.

Changed

  • keep_independent on a product whose reason is an Etsy setting now answers 409 resolution_not_applicable (it used to answer 200 doing nothing).
  • PATCH /listings/{id} texts on a to_verify product answer 409 product_requires_attention, like every other listing write.
  • A merge on an unknown product answers product_not_found (was not_found).

2026-10-13: Requires attention

Added

  • New product status to_verify ("Requires attention") and the requires_attention field (reason, channel, conflicting_product_ids): channel imports no longer discard items in conflict (several products with the same SKU, variants that don't match, a barcode conflict, an Etsy listing with one quantity for all variants…). They come in paused and are not published, synced or linked until resolved.
  • POST /products/{id}/resolve: keep_independent (with with), made_to_order, recheck, ignore (deleted from Nembol; every future import skips its channel listing). Merging it with POST /products/merge also resolves it.
  • 409 product_requires_attention on listing writes for such products; inventory and batch writes by SKU skip them.
  • Imports report requires_attention alongside created and linked.

Changed

  • One linking rule for every channel import: normalized SKU (case and spaces ignored), barcode as a helper when valid and not reused.

2026-10-13: Same product (merge)

Added

  • POST /products/merge: several products become one. Listings move to the survivor, the others are archived with merged_into, one stock per variant is shared by all channels. Per-field choices, dry_run preview, undoable for 30 days. Refused when two products are on the same channel account or their variants don't correspond.
  • /sales/products counts the sales of merged products for the survivor.

2026-10-12: Per-channel titles and descriptions

Added

  • PATCH /listings/{id} now accepts overrides.title and overrides.description: the channel's own texts (null = back to the product's). Pushed to the channel when the listing is live; logged and undoable. category_id and attributes still return 422.
  • Listing.content: what the channel actually receives (override or product text); ListingSummary.overrides on products.
  • Imported listings now start with the channel's own title and description. A leader channel's edits (content sync from a channel) replace the texts of every listing.

2026-10-08: Storefront, customers, notifications, exports

Added

  • /storefront: settings (read; write limited to storefront fields, never payment keys), discount codes and bundles (new scope storefront:write), storefront orders with refund (two-step confirmation) and status changes.
  • GET /customers; GET /notifications + POST /notifications/read; GET /preferences; GET /error_fixes (how to fix a channel error).
  • Channel extras: google_categories (GMC), certification_requirements, manufacturers, responsible_persons (TikTok Shop), pull_updates (eBay/Etsy), stop_bulk.
  • GET /exports/products (standard / inventory / google) and GET /exports/orders (standard / quickbooks) as text/csv.

2026-10-08: Promotions, variants, duplicate

Added

  • /promotions: list, create, update, stop, retry failed channels, delete (new scope promotions:write); conflicts and plan limits as explicit errors; logged in the action log.
  • PUT /products/{id}/variants: set the complete variant set (ids kept, only sent fields change, missing variants removed, with the two-step confirmation when the product is live); undoable.
  • POST /products/{id}/duplicate with optional sku_suffix / title.

2026-10-08: Search, sales and catalog diagnostics

Added

  • GET /products search: q (free text), barcode, tag, category, channel_account_id + listing_status (incl. none = not on that channel), price_min/max, quantity_min/max (total stock), issue, sold_since / not_sold_since, product_ids, created_after/before, updated_before, sort (updated_at / created_at).
  • GET /sales: totals, day/week/month series and per-channel split, per currency (canceled/refunded excluded). GET /sales/products: best sellers or chosen products with last_sold_at.
  • GET /catalog/diagnostics: products per issue + duplicated SKUs and barcodes.

2026-10-08: Action log, undo and confirmations

Added

  • The action log: GET /actions (filter by product_id, type…) and GET /actions/{id}: every change with who made it (key, agent via MCP, dashboard user for channel settings) and field-level before/after values. Writes answer with a Nembol-Action-Id header.
  • POST /actions/{id}/undo (with dry_run preview): undo within 30 days; values changed since are reported as conflicts and never overwritten; quantities are reversed as a delta. Imports and channel settings too.
  • POST /products/{id}/restore: bring back a deleted product.
  • Two-step confirmation (409 confirmation_required + Nembol-Confirmation header) for delist, marking an order shipped and disconnecting, on keys created from today and on every MCP call. Existing keys keep their behavior.
  • Guide: Undo and confirmations.

Changed

  • Deleting a product (or removing an image) keeps the images for 30 days so they can be restored; they are removed afterwards.

2026-10-08: Imports

Added

  • POST /imports: import a connected channel account's catalog or a CSV, in the background, using the dashboard's import with its rules (only new items, linking by SKU, plan limit). filters override the account's import settings for one import. Plan notes in import.warnings.
  • Operations of type import.channel / import.csv carry an import block: live processed, then created, updated, linked, not_imported.
  • POST /imports/{id}/undo: remove from Nembol what an import added (created products and SKU links). Nothing on the channel is touched.
  • Guide: Import products.

2026-10-08: Billing

Added

  • GET /billing: plan, status, renewal date, payment method, usage, invoices, and whether the store can switch to each plan and interval now (and, if not, why).
  • Links to the payment provider's own page, where the person confirms: POST /billing/plan_change_link (subscribe, reactivate, upgrade, downgrade, monthly ↔ annual; refused with plan_limits_exceeded when usage doesn't fit), /billing/payment_method_link, /billing/cancel_link, /billing/manage_link (renew, invoices). No money moves through the API.
  • POST /billing/restart_trial for eligible canceled stores.
  • New scopes billing:read and billing:manage. The billing endpoints stay reachable when the store is no longer on an API plan.
  • Guide: Manage the subscription.

2026-10-07: Writable channel settings, bulk operations, connect channels

Added

  • Connect channels from your app or agent: POST /channel_connections (new channels:connect scope): single-use OAuth links for eBay, Etsy, Shopify, WooCommerce, TikTok Shop, Temu and more, immediate connection for API-key channels (Kaufland, OnBuy, PrestaShop, Subito); GET /channel_connections/{id} for the outcome. See the guide Connect a channel.

  • /redirect_urls: the allowlist your return_url must match (also in Settings → Developers → Redirect URLs).

  • POST /channel_accounts/{id}/disconnect, with the two-step confirmation (409 confirmation_required, then the same request with Nembol-Confirmation).

  • Events channel_account.connected and channel_account.disconnected.

  • POST /listings/batch: publish, delist, resync or retry up to 100 (product, channel account) pairs in one call, tracked as one operation with a result per pair (skipped when already in the requested state).

  • POST /inventory/price_adjustment: raise or lower all variant prices of up to 100 products by a percentage or an amount (optional .99 rounding); per-variant previous_price / price in the operation for undo.

  • GET /listings?error_contains=: listings whose current error message contains a text. This is the precise filter for targeted retries. error_code=channel_error now works (it was rejected before).

  • Operation results: product_id, a real listing_id (was always null), variant_id / previous_price / price on price adjustments, and the result status skipped.

  • PATCH /channel_accounts/{id}: change sync rules, price rule, quantity cap and channel defaults (new channels:write scope). Same switches and effects as the dashboard.

  • GET /channel_accounts/{id}/policies (eBay business policies, Etsy shipping profiles and return policies; ?type= filter) and GET /channel_accounts/{id}/collections (Shopify), read live from the channel. discovery.policies / discovery.collections flag support.

  • Channel account fields: sync.transfer_orders, pricing.rounding, defaults, policy_validation (eBay) and writable (the paths PATCH accepts on that account).

  • Event channel_account.updated with source and previous_attributes. PATCH previous_attributes back to undo a change.

Fixed

  • Publishing through the API now applies the trial limit the dashboard applies: a store on a trial can have at most 10 listings per channel account (403 trial_publish_limit on POST /listings, per-pair trial_publish_limit in POST /listings/batch).
  • POST /inventory/batch on products not live on any channel: the operation now completes immediately (succeeded) instead of staying pending forever, since there is no channel to confirm.
  • pricing.mode now always returns the documented absolute (some accounts returned the internal value amount).
  • inventory is documented correctly: on quantity channels threshold is a cap on the units shown; on Google Merchant Center it is the minimum stock to show as in stock.

2026-08-27: General availability

Changed

  • The API is out of invite-only beta. It is now included in the Enterprise+ plan: create your keys in Settings → Developers, no request form, no waiting list. Beta keys keep working unchanged.
  • Rate limits are unchanged for paid Enterprise+ stores (80 burst, 4 req/s). A store still on an Enterprise+ trial gets 40 burst, 2 req/s; it moves to the full tier when the subscription starts.
  • A subscription that is no longer live (canceled or lapsed) now stops answering with 403 plan_not_eligible instead of continuing to serve.

2026-07-30: Orders write, richer products, batch

Added

  • POST /orders/{id}/fulfillment: mark shipped, attach tracking and notify the source marketplace (new orders:write scope). Applies to the whole channel order; marketplace notification is once-per-order.
  • Order.buyer.address: full ship-to address (behind orders:read).
  • POST /products/batch: create or update up to 100 products, matched by variant SKU, with per-item outcomes.
  • PATCH /listings/{id}: empty body re-syncs the listing to its channel.
  • Product fields: category, short_description, vat_rate, mpn, weight, dimensions. Variant fields: msrp (strikethrough price on supported channels), grams (per-variant shipping weight), asin, images (variant-specific photos, assigned from the product's images).
  • GET /rest/v1/status: aggregated uptime/latency, monitored every minute from Nembol's infrastructure (powers the Status page).
  • Models section in these docs: every object, field by field.

Changed

  • The daily image-upload cap is gone. Upload entire catalogs freely (products still hold up to 20 images each).
  • Channel errors in issues[] and operation results are plain text now.
  • Variants with options must cover every option combination (dense matrix). Sparse sets are rejected with 422 instead of publishing phantom variants.

2026-07-24: Initial beta

Added

  • First release of the Nembol API (invite-only beta): products CRUD, images, per-channel publish/delist, inventory single + batch by SKU, orders (read-only), operations, events, webhook endpoints.
  • Webhook events: order.created, order.status_changed, product.updated, product.deleted, inventory.updated, listing.status_changed, operation.completed.
  • Test mode (nbl_test_ keys): validated, simulated, never persisted.

Last updated on October 22, 2026

Need help?

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

On this page