v2026-04 API. Both expose two surfaces: a public, unauthenticated catalog you read to render storefront pages, and a company, token-authenticated surface you use to manage every row regardless of whether it is live. This guide covers finding existing categories and collections on both surfaces and creating new ones.
Categories and collections share almost the same shape and the same operations. Examples below show categories in full and note where collections differ.
Base URLs and authentication
Public catalog reads resolve the company from the request subdomain, so call them against your company subdomain — for examplehttps://acme.fluid.app. They take no credentials.
Company operations require a Bearer token and are called against https://api.fluid.app. Read operations need the storefront.view scope; writes need storefront.update. Legacy per-resource grants (such as categories.update) are still accepted during the migration.
Public operations under
/api/v202604/categories, /api/v202604/categories/{slug}, and the collection equivalents are unauthenticated. Sending a token to them is unnecessary. Every /api/v202604/company/... operation requires the token.401 returns a bare {"message": ...} object, 403 returns a bare {"error": ...} or {"message": ...}, and only 404 and 422 use the wrapped error envelope ({"error": {"message": ...}, "status": ..., "meta": ...}). Don’t parse every error with one shape.
Browse the public catalog
GET /api/v202604/categories returns a page of live categories only — rows that are active, resolved-published, country-eligible, and language-eligible. Draft, scheduled, archived, and inactive rows never appear here.
categories array alongside a top-level status and a meta block:
Filter, search, and sort
The public catalog accepts these query parameters:string
Free-text search over the translation-aware
title and description fields.string
ISO-2 country code. Restricts results to categories available in that country. Unrestricted categories (those with no country list) match every country. See Control country availability.
string
ISO locale. Restricts results to categories translated in that locale.
string
One of
product, medium, page, library, or promotion. Categories only.string
A category id (as a string), or
"root" for top-level categories only. Categories only. See Work with the category hierarchy.string
One sort key:
position, title, or created_at. Prefix with - for descending (for example -created_at). Defaults to position then id.string
Response locale as an ISO code (for example
fr). Omit to use the company default. On the public surface, any field missing in the requested locale falls back to en.Paginate with cursors
Paging is cursor-based.meta.pagination.next_cursor and prev_cursor carry the cursor for the adjacent page; pass it back as page[cursor]. page[limit] sets the page size (default 25, max 100 — a larger value returns 422).
Collections
GET /api/v202604/collections mirrors the category catalog and accepts the same q, filter[country], filter[language], sort, lang, and pagination parameters. Collections have no hierarchy, so they do not accept filter[parent_id] or filter[source_type], and their rows omit parent_id, position, source_type, and has_children.
Look up one by slug
The slug is the canonical public identifier and matches the row’scanonical_url. Fetch a single category with GET /api/v202604/categories/{slug}:
category key inside the standard envelope.
Find any row as an admin
GET /api/v202604/company/categories returns every category for the calling company, in any lifecycle state (draft, scheduled, published, or archived), so you can manage rows that are not publicly visible.
q, filter[country], filter[language], sort, and lang parameters as the public catalog, plus two admin-only filters:
string
One of
draft, scheduled, published, or archived. Restricts to a single lifecycle state.string
"true" or "false" to restrict to active or inactive rows. A blank value (filter[active]=) means no filter.The company index accepts the same
filter[parent_id] and filter[source_type] filters as the public catalog — the two surfaces share one query contract. filter[parent_id] selects one level of the tree; filter[source_type] narrows to a single source type. You can also page through the index unfiltered and group client-side by each row’s parent_id. See Work with the category hierarchy.GET /api/v202604/company/categories/{id}. This returns the category in any lifecycle state:
/api/v202604/company/collections and /api/v202604/company/collections/{id}.
Create a category
POST /api/v202604/company/categories creates a category. The request body nests fields under a category key. title is the only required field.
201 with the new category under the category key.
A few things worth knowing at create time:
- Slug management. Send
slugtogether withcustom_slug: trueto pin a permanent, merchant-set slug. Withoutcustom_slug: true, the slug is auto-generated fromtitleand regenerates whenever the title changes. See Rename, publish, and schedule. - Lifecycle.
statusdefaults control whether the category is publicly visible. Settingstatus: "scheduled"with a futurepublish_atschedules it to go live. See Rename, publish, and schedule. - Country availability.
country_isosrestricts availability; an empty array means available everywhere the company sells. See Control country availability. - Nesting. Set
parent_idto nest a category under another. See Work with the category hierarchy. - Strict bodies. Write bodies are strict: a key the write schema doesn’t define is rejected with
422, not ignored. In particular, don’t echo a response object back into a write — read-only fields likecountriesandseoare not writable keys. - SEO keys differ between write and read. You write SEO as
search_engine_optimizer_attributes, but every response returns it underseo. Round-tripping a response’sseoobject into a PATCH won’t apply it.
Creating (and later updating) a category automatically queues fresh Lighthouse and compliance scans. Their results become available asynchronously on the company Lighthouse and compliance endpoints — the create response itself does not wait for them.
Create a collection
POST /api/v202604/company/collections mirrors category creation. The body nests under a collection key, and title is again the only required field. Because collections have no hierarchy, the body accepts no parent_id, position, or source_type.
Next steps
- Rename, publish, and schedule — change a title, control visibility, and schedule go-live.
- Control country availability — set and query which countries a row is available in.
- Work with the category hierarchy — nest categories and traverse parents and children.