Skip to main content
The ProductsService class (accessed via client.products) reads a store’s catalog: products and their variants, filtering and pagination across them, product specifications, and the collections products are grouped into.
Validation & Rate Limits: Product IDs must be valid UUIDs — malformed IDs return 400 immediately. All endpoints are rate-limited (publishable key: 1,000 requests/hr per IP; secret key: 10,000 requests/hr per key).
Product identifier: every product object exposes both id and product_id. They are the same value — use whichever fits your codebase.

Response Structure Tiers

To optimize performance across different device types, the service implements three response tiers:

Catalog Discovery

listProducts

Retrieve a paginated list of products. This method returns flat structures (no variants array) to keep payloads small.
  • ⚡ Performance: 50-70% smaller than detail endpoints.
  • 🖼️ Thumbnails: Use thumbnail_url for fast rendering in lists without iterating arrays.
  • 🛒 Quick Add: Includes default variant data (price, stock, sku) at root level.
  • 🔍 Intelligence: Use the has_variants flag to determine if the UI should show “View Options”.
  • ⏩ Pagination: Uses cursor-based navigation for stable, high-performance scrolling.
Lean by default. The list omits heavy fields a catalog grid rarely needs — the long-form description, the SEO block (seo_title / seo_description / seo_keywords), raw attributes / shipping_info, and the full media arrays — so grids stay fast. Get those on the detail calls (getProduct / getProductBySlug), request them explicitly with fields (e.g. fields: 'name,price,description,seo_title'), or pass full: true to return the complete object for every row. thumbnail_url, price, stock, has_variants and the taxonomy fields are always present.
Response

Personalized ordering

Pass personalize: true together with a signed-in customer’s session token (the x-auth-token header) and the page is ordered by how closely each product matches that shopper’s preferences, with the default order as the tiebreak. Without a customer session — or for a shopper who has no preference signal yet — the order is unchanged, so it is always safe to request.
Filter by brand. Pass brand (case-insensitive exact match) to build a brand landing page — pair it with listBrands below to render a “shop by brand” row, then list the chosen brand’s products:

Filter by category and subcategory

category_id and subcategory_id both match a whole branch of the taxonomy rather than a single node. A category matches products filed directly against it and products filed under any of its subcategories, at any depth; a subcategory matches products filed against it and every nested subcategory beneath it. A category page therefore returns the products of the branch as a shopper understands it — a “Computers” category includes everything under “Laptops” without listing each subcategory separately.
Each value must be a valid UUID. An id that matches nothing returns an empty products array with a 200, not an error. The two filters can be combined, in which case a product must match both. The subcategories of a category are available from GET /v1/subcategories?category_id=…. Several ids in one request. Both parameters accept multiple ids, in three forms: Passing several ids to one request keeps a single pagination cursor valid across the combined set. One request per category yields a separate cursor per response, and those cursors cannot be merged into a coherent page 2 — so a landing page spanning several categories is built from one multi-id request, not from several single-id requests stitched together.

listBrands

Return the catalog’s distinct brands, each with a product count, sorted by count (most products first). Use it to build brand navigation — for example a “featured brands” row after the hero — then pass a chosen brand to listProducts({ brand }).
Response
On a marketplace operator key the brands are aggregated across all active merchants; pass storeId to scope to one merchant.

getProduct

Retrieve complete details for a single item. This method handles Multi-Variant products by returning a hierarchical structure that eliminates data redundancy and supports variant-aware media.
  • Product-Level: Shared metadata at the root (name, brand, media gallery).
  • Aggregate Data: total_stock (sum of all variants) and price_range (min/max using selling_price).
  • Variants Array: Clean array containing variant-specific attributes (color, size, SKU) and isolated media for that specific variation.
A multi-variant detail response (here shown for the “Nebula Ceramic Mug”, a 3-variant product) — root metadata plus aggregate price_range / total_stock and a clean variants[] array, each with its own SKU, attributes, and isolated media:
Response

getProductBySlug

Retrieve a product using its SEO-friendly slug. Identical to getProduct in response structure but optimized for PDP routing.

SEO metadata

Every product carries optional SEO metadata for rendering search-engine-friendly product detail pages:
  • seo_title — the <title> for the product page.
  • seo_description — the meta description.
  • seo_keywords — an array of keywords.
These fields are also included in a store’s public catalog feed, so a catalog mirrored from one store into another preserves its SEO metadata.
The media system supports a fully-functional, variant-aware gallery.

Root-Level Media

  • thumbnail_url: Represents the primary image for the product. Perfect for simple grids.
  • media: An array of objects containing all base-level images and videos.

Variant Media

Each variant in the variants[] array can have its own media array. This allows you to show specific images when a user selects a particular variation (e.g., rotating the gallery to show the “Midnight Blue” model). Media Object Structure:

🎨 Advanced Field Filtering

Tybrite supports powerful field selection to minimize bandwidth.

Root-Level Filtering

Exclude large metadata objects by selecting only top-level fields.

Nested Array Filtering

Use dot notation to select specific fields within nested arrays.
Supported Fields for Filtering:
  • Core: product_id, name, sku, description, thumbnail_url, media
  • Pricing: price, selling_price, sale_price, price_range
  • Inventory: stock, total_stock, last_restocked (last_restocked is not returned by default — request it explicitly)
  • Variants: variants.sku, variants.selling_price, variants.media, variants.variant_attributes

Product Specifications

getProductSpecifications

Retrieve the latest published specifications for a single variant. Specifications are stored per variant, so pass a variant id (e.g. a variant_id from getProduct().variants[]) — not a product id. A product id returns 404.
Response
Returns 404 (“No specifications found for this product”) if the variant has no published specification — or if you passed a product id instead of a variant id. To browse all specs across the catalog (each tagged with its variant_id), use listProductSpecifications.

getProductCustomFields

Retrieve the merchant’s own custom fields for a product. A merchant can define fields Galactic Core does not — a care instruction, a country of origin, a fabric composition — and fill them per product. Only fields the merchant published are returned. A custom field can hold a cost or an internal reference, so a field is private unless it is explicitly marked public, and a private field is absent rather than empty. A product with no published fields returns an empty array.
Response
The merchant controls both the field names and how many exist, so render the array rather than reading fixed keys. See Custom Fields for the full picture — which records carry them, what each type looks like, and how to send values with an order. field_type tells you the shape of value: multiselect is an array of strings, json, dimensions and weight are objects, and the rest are scalars — a number field arrives as a number, not as text. field_label is what the merchant calls the field and is the string to show; field_name is stable across label edits and is the one to key off in code.
value is null when the merchant defined a field but has not filled it for this product, which is distinct from the field not existing.

listProductSpecifications

Browse specifications across the catalog rather than fetching one variant’s. Useful for building a spec-driven filter (every value of “storage_type” in stock, say) without a request per variant.
Response
Each entry carries its own variant_id, so a single pass over the list can be grouped by variant without further lookups.

Collections

Curated groups of products a merchant highlights on their storefront — a “Featured”, “New Arrivals”, or “Summer Edit” row. Each collection can carry a banner image, which makes it a natural building block for an image-led homepage.

listProductCollections

Response
image is the collection’s banner and the image to use on every viewport; image_mobile is an optional phone-sized crop. Render the mobile image on small screens when it is set and fall back to image otherwise — a <picture> element with a mobile <source> handles this cleanly. Either field is null when the merchant has not added artwork.

getProductCollection

Fetch a single collection by id — the same shape listProductCollections returns for that entry, so use it when you land directly on a collection page and have only the id from the URL. A collection the merchant built from rules rather than by hand also carries those rules.
Response
rules describes how an automated or smart collection selects its products, and is null for a collection the merchant curated by hand. Returns 404 when no collection matches the id.

getProductCollectionItems

Response
An empty collection returns { "items": [] }.

Response Codes

All product endpoints are GET and accept both publishable and secret keys.