Skip to content
Ingest Contract · v1

Bring Any Catalogue

Everything you need to send a catalogue to NitroSearch from a storefront we do not have a connector for — a headless build, a bespoke platform, or your own middleware. The same endpoint our four published connectors use.

This page is generated from the validation rules the endpoint actually enforces — not written by hand beside them. A test refuses a release where the two disagree.

What a merchant module must send to NitroSearch, and what NitroSearch will make of it.

This repository is generated. Do not edit it by hand — open an issue instead, or the next regeneration will silently revert your change.

What is here

  • kit/ — an optional, dependency-free PHP 7.4+ package for building payloads. Vendor it; do not Composer-require it. Its currency-exponent table is generated from the backend's own, so it cannot disagree with the system it sends to. See kit/README.md.

  • schema/ingest-batch.v1.schema.json — JSON Schema (2020-12) for the body of POST /v1/ingest/batch. Generated from the validation rules the endpoint enforces, not transcribed from a document, so it cannot describe an endpoint that does not exist.

  • fixtures/ — conformance cases. Each carries a wire payload and the expected_document NitroSearch produces from it. Every expected value was produced by running the real pipeline, so a case cannot assert behaviour the backend does not have. Run them in your own CI: no secrets, no network, no account required.

  • fixtures/product-usd-two-decimal-places.json

  • fixtures/product-jpy-zero-decimal-places.json

  • fixtures/product-kwd-three-decimal-places.json

  • fixtures/product-chf-two-decimal-places.json

  • fixtures/product-legacy-no-price-exponent.json

  • fixtures/product-legacy-sales-rank.json

  • fixtures/product-variants-fold-into-one-object.json

  • fixtures/product-attribute-spellings-merge.json

  • fixtures/product-visible-absent-fails-closed.json

  • fixtures/product-unsafe-url-is-dropped.json

  • fixtures/content-page-with-excerpt.json

  • fixtures/content-object-type-absent-means-product.json

The five things that catch adapter authors out

  1. Money is integer minor units, and you must declare the exponent. 19.99 is 1999 with price_exponent: 2. Yen is 1000 with price_exponent: 0. Omitting the exponent means "I scaled by 100 whatever the currency", which is what pre-1.x modules did, and it renders a ¥1,000 product as ¥100,000. A decimal or a float is rejected outright — money is never inferred.
  2. One product is one object, however many variations it has. Send variations nested in variants, never as separate top-level items. They fold into the parent: SKUs become searchable, attributes become facets, and the price becomes a range. Sending them separately also multiplies what the merchant is charged against their plan.
  3. visible fails closed. Anything not explicitly true is unreachable through the public search key. This is the most common cause of "my products are not appearing".
  4. version is your clock, and last write wins. An item whose version is not greater than the indexed one is skipped as stale. Milliseconds since epoch is the convention. A constant or absent version means out-of-order delivery silently overwrites newer data.
  5. A bad item is skipped, not fatal. One unmappable item is recorded with a reason and the rest of the batch still applies. You will not get a 4xx telling you which one — check the merchant's sync health panel.

What this contract does NOT cover

Stated explicitly, because a contract's silences are where integrations break:

  • Tax. There is one price field. Whether it includes tax is the merchant's own store setting; NitroSearch indexes and displays exactly what you send and performs no tax calculation of any kind.
  • Multi-currency and multi-storefront. One store sends one currency. A storefront serving several currencies is not supported yet.
  • Authentication, transport and rate limits. Request signing and endpoint behaviour are documented with the integration guide, not here. This repository describes the payload.
  • The search API. This is the ingest direction only.

Conformance fixtures

Every expected value below was produced by running the real pipeline, so a case cannot assert behaviour the backend does not have. No secrets, no network, no account.