Integration docs

List your shop on turg.fitness.ee

Two ways to connect your catalogue: if your shop exposes a supported product API we onboard you from just your URL; otherwise you expose one JSON feed. This is the developer reference for both.

Overview

turg.fitness.ee is a multi-vendor marketplace. We read your catalogue automatically (about once an hour), show your products under your own vendor page, and link every product back to your shop for the sale. Catalogue data only — we never touch orders, customers, or payments.

Ready to start? You don't have to read all of this — just submit your URL and we'll tell you which path applies. This page is here for the developer who builds the feed (Path B).

Which path is mine?

It depends on whether your shop already exposes a machine-readable product API.

Path AWooCommerce with the Store API on/wp-json/wc/store/v1/products returns JSON → send us your URL, zero build.
Path AMagento 2 with public GraphQL/graphql answers without a token → send us your URL, zero build.
Path BEverything elseCustom shop, Shopify, or API turned off → expose one JSON feed (below).
On WooCommerce but not sure?Open https://your-shop.ee/wp-json/wc/store/v1/products?per_page=1. JSON list → Path A. A 404 / HTML page → the Store API is off (common) → Path B. The onboarding form detects this for you automatically.

Path A — supported platform

Nothing to build. Send us your shop URL, confirm the public API is reachable, and optionally your display name + brand colour. We pull your catalogue, map your categories into our browse tree, and put you live — then re-read hourly.

Path B — the JSON feed

Expose one HTTPS endpoint that returns your whole catalogue as JSON. Implement what's below and you go live with no further integration work.

01Endpoint

A single GET over HTTPS, at any URL you control.

GET https://your-shop.ee/api/marketplace/feed.json
Content-Type:     application/json; charset=utf-8
Content-Encoding: gzip           # whole catalogue, one document
200Fresh feed body.
304Return this (no body) when our If-None-Match matches your ETag — we skip the re-ingest.
401/403Auth failure. Don't echo the token in the error body.
503Planned maintenance, with Retry-After. We back off and retry.
5xxWe retry with backoff, up to 3 attempts.

02Auth

  • A shared secret in a request header: X-Feed-Token: <opaque string>.
  • We generate the token and share it out-of-band; we rotate it yearly or on request.
  • Reject any request without the correct header — don't leave the feed world-readable. Never put the token in the URL.

03Freshness

This is what keeps prices and stock from going stale.

  • Put generated_at (ISO-8601 UTC) inside the body.
  • Emit an ETag on every 200; honour If-None-Match and return 304 when nothing changed.
  • Each product's updated_at moves whenever that product's price, stock, or content changes.
  • Regenerate hourly or on change, whichever is cheaper. A cron-built cached snapshot is fine.

Size: one document up to 10 MB gzipped (~2,000 products). Bigger — tell us, we'll add sharding. Don't invent your own pagination.

04Body shape

feed.json — envelope
{
  "schema_version": "1.0",
  "generated_at": "2026-07-03T08:12:00Z",
  "vendor_id": "the-slug-we-assign-you",
  "currency": "EUR",
  "products": [ ... ]
}

schema_version must be "1.0". vendor_id is the stable slug we assign you. currency is ISO-4217 — we support EUR.

05Product object

Every field is required unless the table marks it optional.

one product
{
  "id": "31436",
  "sku": "ON-WHEY-2270-CHOC",
  "parent_id": "31430",
  "type": "variation",
  "permalink": "https://your-shop.ee/toode/whey-2270-sokolaad",
  "updated_at": "2026-07-01T09:00:00Z",
  "locales": {
    "et": {
      "name": "Gold Standard Whey 2270g šokolaad",
      "slug": "gold-standard-whey-2270-sokolaad",
      "short_description_html": "

Kvaliteetne vadakuvalk…

", "categories": [ { "id": "42", "slug": "valgud", "name": "Valgud" } ] } }, "price": "59.90", "regular_price": "69.90", "sale_price": "59.90", "stock_status": "instock", "stock_quantity": 17, "manage_stock": true, "brand": { "slug": "optimum-nutrition", "name": "Optimum Nutrition" }, "attributes": [ { "slug": "pa_maitse", "name": "Maitse", "value": "Šokolaad" } ], "tags": ["whey", "post-workout"], "images": ["https://your-shop.ee/img/whey-1.jpg"] }
FieldTypeReqNotes
idstringyesYour stable internal id. Never changes across feeds.
skustringyesStable across locales/feeds. Join key for variants + re-ingest.
parent_idstring · nullyesParent's id for a variation; explicit null otherwise.
typeenumyessimple · variable · variation · grouped · bundle.
permalinkURLyesYour product page — the buy button links here.
updated_atISO-8601yesMoves on any change to this product.
localesobjectyesKeyed by et/en/ru. Estonian required.
pricedecimal stryesCurrent price, VAT-inclusive, as a string.
regular_pricedecimal stryesPre-discount; equals price when not on sale.
sale_pricedecimal · nullyesSale price, or null.
stock_statusenumyesinstock · outofstock · onbackorder.
stock_quantityint · nullyesNumeric stock, or null when unmanaged.
manage_stockbooleanyesWhether stock_quantity is authoritative.
brandobjectyes{ slug, name } — slug lowercase, hyphenated, stable.
attributesarrayyesSee below. Empty allowed but discouraged.
tagsstring[]optLowercase, hyphenated labels.
imagesURL[]yes ≥1Full URLs only. First image is primary.

06Locales

locales is keyed by language code. Send what you support; we ingest et (required) and optionally en / ru. Per-locale: name (required), slug (required), categories (required, ordered breadcrumb using your own category slugs — we map them to our browse tree), and optional short_description_html / description_html (safe HTML subset: p, ul, li, strong, em, br). A product with no et locale is skipped.

07Attributes & variants

Attributes are labelled key/value pairs — never unlabeled positional columns. The slug is the contract: don't rename it once published. value is always a string.

attribute
{ "slug": "pa_suurus", "name": "Suurus", "value": "L" }

Useful slugs by category — send what applies:

  • Supplements: pa_maitse (flavour), pa_kogus-grammides (weight), pa_valjalaske-vorm (form), pa_servings.
  • Apparel & footwear: pa_suurus (size), pa_varv (colour), pa_sugu (gender), pa_spordiala (sport), pa_material.
Sizes & flavours with per-item stockModel a variable parent (parent_id:null, shared title/images/brand) plus one variation per option — each with its own sku and stock_status. That way a sold-out size shows as sold out. No per-option stock? A single simple product listing the options is accepted, but per-option stock is strongly preferred.

08Validation & operating rules

  • Validate against our JSON Schema on every regeneration. A failing feed is a hard error — we keep the last good ingest rather than publish a broken one.
  • Don't change a sku or brand.slug after first publication.
  • Removing a product — just drop it from the array; we diff and prune.
  • Tell us before any breaking change; we pin schema_version.
  • No customer, order, or payment data — catalogue only.

Schema & sample

Validate your feed against the JSON Schema on every build. Both files are stable, versioned URLs you can link your tooling at:

Ready to list your shop? Send us your URL and we'll take it from there.

Request onboarding →