{✦} Stylumia Developers

API reference

Stylumia Catalog API · v0.2.0 · OpenAPI 3.1.0

All paths are relative to https://api.stylumia.com. Every request carries Authorization: Bearer <your API key> — see Authentication.

Read-only access to Stylumia's retailer product catalog crawl.

Every operation in this document is a draft (x-status: draft). Shapes, field names, and error codes may still change before general availability; treat this as a preview, not a stability guarantee.

One filter set, three operations

retailer, category, department, rcd, start_date, and end_date are the same six parameters on every operation below — narrow once and reuse the query anywhere:

  • GET /v1/sample — up to 100 rows, for judging the shape of the data.
  • GET /v1/catalog — the complete filtered set, cursor-paginated.
  • GET /v1/coverage — how much exists for those filters, before you pull any of it.

There is no discovery chain to walk. A guessed retailer, category, or department fails with valid_options naming the real values, which is the only vocabulary lookup an integrator needs. rcd is shorthand for a retailer:category:department combination — send one parameter instead of three, or several comma-separated to select more than one combination.

Every response echoes the filters the server actually resolved in meta.resolved, and carries a compact meta.coverage block, so one request answers both "what did I get" and "how much is there".

Error contract

Every non-2xx response is an RFC 9457 problem document (application/problem+json) shaped by the Problem schema, carrying code, retryable, recovery, and — on vocabulary errors — valid_options. retryable is the field to branch on: false means fix the request before resending, true means back off and retry. recovery is human-readable guidance that matches the public error catalogue byte-for-byte. Each operation below documents the exact set of codes it can emit via x-error-codes.

Credentials

Sign in to the developer portal, create a named API key, and copy it — the secret is shown exactly once. Send it as Authorization: Bearer <your API key>.

Keys do not expire; revoking is the only thing that ends one, and it takes effect on the very next request. Create as many as you need — one per service, script or agent — so a leak or a revocation never takes down more than the one integration.

GET /v1/sample

Sample rows

Up to 100 rows for the given filters. Uncursored — a sample is for judging the shape of the data before committing to a full GET /v1/catalog walk; anything larger belongs there instead.

Requires the catalog:sample scope, distinct from the catalog:read scope GET /v1/catalog and GET /v1/coverage need.

Parameters

NameTypeRequiredDescription
retailer string optional Restrict to this retailer's slug. An unrecognized value fails with unknown_retailer, whose valid_options names the closest real slugs. e.g. home_depot
category string optional Restrict to this category's slug, scoped by retailer if given. An unrecognized value fails with unknown_category, whose valid_options names the closest real slugs. e.g. power_tools
department string optional Restrict to this department's slug, scoped by retailer if given. An unrecognized value fails with unknown_department, whose valid_options names the closest real slugs. e.g. tools
rcd string optional One or more retailer:category:department triples, comma-separated. Shorthand for sending retailer, category, and department individually — send this instead when you already know the exact combination(s) you want. A malformed value fails with invalid_request. e.g. home_depot:power_tools:tools
start_date string (date) optional Only rows with crawl_date on or after this date, inclusive. ISO 8601 (YYYY-MM-DD). Malformed, or after end_date, fails with invalid_date_range. e.g. 2026-06-14
end_date string (date) optional Only rows with crawl_date on or before this date, inclusive. ISO 8601 (YYYY-MM-DD). Malformed, or before start_date, fails with invalid_date_range. e.g. 2026-08-14

Responses

StatusBodyDescription
200 ProductListResponse Up to 100 sample product rows matching the given filters.
400 Problem The request is malformed, or references an unrecognized retailer, category, department, date range, cursor, or `rcd` value.
401 Problem No credentials were presented, or the presented token is unknown, expired, or revoked.
403 Problem The token is valid but the team is not entitled to this operation.
429 Problem The published per-team rate limit was exceeded.
5XX Problem Something unforeseen failed on the server side, the service is down or degraded, or the server was too slow to answer. The request was not necessarily the problem — see `retryable`.

Errors this operation can return

Enumerated in the spec as x-error-codes. Branch on code, never on detail.

Example

curl "https://api.stylumia.com/v1/sample?retailer=home_depot" \
  -H "Authorization: Bearer $STYLUMIA_TOKEN"
GET /v1/catalog

Get catalog

The complete filtered set, walked with a cursor. Results are sorted by sku so a page's contents never shift under a caller mid-walk.

The cursor encodes position only — the same filters must be resent unchanged on every page. Continue with the cursor from pagination.next_cursor until pagination.has_more is false.

Requires the catalog:read scope.

Parameters

NameTypeRequiredDescription
retailer string optional Restrict to this retailer's slug. An unrecognized value fails with unknown_retailer, whose valid_options names the closest real slugs. e.g. home_depot
category string optional Restrict to this category's slug, scoped by retailer if given. An unrecognized value fails with unknown_category, whose valid_options names the closest real slugs. e.g. power_tools
department string optional Restrict to this department's slug, scoped by retailer if given. An unrecognized value fails with unknown_department, whose valid_options names the closest real slugs. e.g. tools
rcd string optional One or more retailer:category:department triples, comma-separated. Shorthand for sending retailer, category, and department individually — send this instead when you already know the exact combination(s) you want. A malformed value fails with invalid_request. e.g. home_depot:power_tools:tools
start_date string (date) optional Only rows with crawl_date on or after this date, inclusive. ISO 8601 (YYYY-MM-DD). Malformed, or after end_date, fails with invalid_date_range. e.g. 2026-06-14
end_date string (date) optional Only rows with crawl_date on or before this date, inclusive. ISO 8601 (YYYY-MM-DD). Malformed, or before start_date, fails with invalid_date_range. e.g. 2026-08-14
cursor string optional Opaque pagination cursor from a previous response's pagination.next_cursor. Omit for the first page. A cursor this server did not issue fails with invalid_cursor.
limit integer optional Maximum rows to return in this page.

Responses

StatusBodyDescription
200 ProductListResponse A page of product rows matching the given filters.
400 Problem The request is malformed, or references an unrecognized retailer, category, department, date range, cursor, or `rcd` value.
401 Problem No credentials were presented, or the presented token is unknown, expired, or revoked.
403 Problem The token is valid but the team is not entitled to this operation.
429 Problem The published per-team rate limit was exceeded.
5XX Problem Something unforeseen failed on the server side, the service is down or degraded, or the server was too slow to answer. The request was not necessarily the problem — see `retryable`.

Errors this operation can return

Enumerated in the spec as x-error-codes. Branch on code, never on detail.

Example

curl "https://api.stylumia.com/v1/catalog?retailer=home_depot" \
  -H "Authorization: Bearer $STYLUMIA_TOKEN"
GET /v1/coverage

Get coverage

Coverage metrics for each retailer/category/department combination matching the given filters: how many rows the full corpus holds, how many match this filter, and the crawl-date range they span. Use this to decide which start_date / end_date window on GET /v1/catalog will actually return rows before spending a call finding out.

Requires the catalog:read scope.

Parameters

NameTypeRequiredDescription
retailer string optional Restrict to this retailer's slug. An unrecognized value fails with unknown_retailer, whose valid_options names the closest real slugs. e.g. home_depot
category string optional Restrict to this category's slug, scoped by retailer if given. An unrecognized value fails with unknown_category, whose valid_options names the closest real slugs. e.g. power_tools
department string optional Restrict to this department's slug, scoped by retailer if given. An unrecognized value fails with unknown_department, whose valid_options names the closest real slugs. e.g. tools
rcd string optional One or more retailer:category:department triples, comma-separated. Shorthand for sending retailer, category, and department individually — send this instead when you already know the exact combination(s) you want. A malformed value fails with invalid_request. e.g. home_depot:power_tools:tools
start_date string (date) optional Only rows with crawl_date on or after this date, inclusive. ISO 8601 (YYYY-MM-DD). Malformed, or after end_date, fails with invalid_date_range. e.g. 2026-06-14
end_date string (date) optional Only rows with crawl_date on or before this date, inclusive. ISO 8601 (YYYY-MM-DD). Malformed, or before start_date, fails with invalid_date_range. e.g. 2026-08-14

Responses

StatusBodyDescription
200 CoverageListResponse Coverage metrics for every combination matching the given filters.
400 Problem The request is malformed, or references an unrecognized retailer, category, department, date range, cursor, or `rcd` value.
401 Problem No credentials were presented, or the presented token is unknown, expired, or revoked.
403 Problem The token is valid but the team is not entitled to this operation.
429 Problem The published per-team rate limit was exceeded.
5XX Problem Something unforeseen failed on the server side, the service is down or degraded, or the server was too slow to answer. The request was not necessarily the problem — see `retryable`.

Errors this operation can return

Enumerated in the spec as x-error-codes. Branch on code, never on detail.

Example

curl "https://api.stylumia.com/v1/coverage?retailer=home_depot" \
  -H "Authorization: Bearer $STYLUMIA_TOKEN"

Schemas

Every object the responses above refer to. Nullable means the field can be absent or null.

Product

A single crawled product row.

FieldTypeNullableDescription
product_id string no Stable id, a content hash of the row. Listings are re-crawled, not diffed against a permanent catalog: a product relisted under a new title mints a new product_id, it does not update the old one.
sku string no Retailer-specific product identifier. Format varies by retailer. Unique within a retailer only — the same sku string can appear under a different retailer for an unrelated product.
url string (uri) no Canonical URL of the product page as crawled.
domain string no Domain the product page was crawled from.
retailer string no Slug of the retailer this row was crawled from.
department string no Slug of the department this row belongs to.
category string no Slug of the category this row belongs to.
brand string no Brand name as listed on the retailer's page.
model_number string no Manufacturer model number as listed on the retailer's page.
title string no Product title as listed on the retailer's page.
mrp number no Manufacturer's listed (undiscounted) price, in currency.
selling_price number no Actual price charged at crawl time, in currency.
discount_pct number no Discount off mrp, as a percentage, at crawl time.
currency string no ISO 4217 currency code for mrp and selling_price.
color string yes Listed color, when the retailer publishes one for this product. null when not applicable or not listed.
image_url string (uri) no URL of the primary product image as crawled.
crawl_date string (date) no Date (YYYY-MM-DD) this row was crawled.

Coverage

Coverage metrics for one retailer/category/department combination.

FieldTypeNullableDescription
retailer string no Slug of the retailer.
department string no Slug of the department.
category string no Slug of the category.
rcd string no This combination as a retailer:category:department triple, ready to pass back as rcd.
corpus_rows integer no Total rows the full dataset holds for this combination, independent of any filter applied.
matching_rows integer no Rows within this combination that also satisfy the request's date filters, if any.
earliest_date string (date) no Earliest crawl_date (YYYY-MM-DD) among matching rows.
latest_date string (date) no Most recent crawl_date (YYYY-MM-DD) among matching rows.

CoverageSummary

The compact coverage block carried on every response, answering "how much exists" alongside "what did I get" — summed across every combination matching the request's filters.

FieldTypeNullableDescription
combinations integer no Number of retailer/category/department combinations matching the request's filters.
matching_rows integer no Total rows across those combinations that also satisfy the request's date filters, if any.
corpus_rows integer no Total rows the full dataset holds across those combinations, independent of any date filter.
earliest_date string (date) yes Earliest crawl_date (YYYY-MM-DD) among matching rows. null when no combination matches.
latest_date string (date) yes Most recent crawl_date (YYYY-MM-DD) among matching rows. null when no combination matches.

Pagination

Cursor pagination state for this response. `limit` and `total_matching` are present on `GET /v1/catalog`; `GET /v1/sample` and `GET /v1/coverage` are uncursored and omit them.

FieldTypeNullableDescription
limit integer yes Maximum rows requested for this page.
total_matching integer yes Total rows matching the request's filters, across every page.
next_cursor string yes Opaque cursor for the next page. Pass back as the cursor parameter to continue. null when there is no further page.
has_more boolean no Whether a further page exists beyond this one.

Meta

Response metadata.

FieldTypeNullableDescription
request_id string no Unique id for this request. Quote it when reporting a problem, especially a 5xx.
resolved object no Every filter the server actually applied, including omitted ones as null, so a response is never ambiguous about what was queried.
coverage CoverageSummary no

ProductListResponse

Response envelope for `GET /v1/sample` and `GET /v1/catalog`.

FieldTypeNullableDescription
data array<Product> no The matching product rows for this page.
pagination Pagination no
meta Meta no

CoverageListResponse

Response envelope for `GET /v1/coverage`.

FieldTypeNullableDescription
data array<Coverage> no Coverage metrics, one entry per matching retailer/category/department combination.
pagination Pagination no
meta Meta no

Problem

RFC 9457 problem details, extended for programmatic handling. Every non-2xx response has this shape, served as `application/problem+json`.

FieldTypeNullableDescription
type string (uri) no Stable URI identifying this error type; resolves to its entry in the public error catalogue ({base}/errors#{code}).
title string no Short, human-readable summary of the error type. Constant per code.
status integer no HTTP status code, repeated from the response line for convenience.
detail string no Human-readable explanation specific to this occurrence of the problem.
code string no Stable machine-readable error code. Append-only — safe to branch on in code.
retryable boolean no false means fix the request before resending; true means back off and retry — the request itself was not the problem.
recovery string no What to do about this error, byte-identical to the public error catalogue.
request_id string no Unique id for the request that produced this error. Quote it when reporting a problem.
field string yes Name of the request parameter at fault. Present only on errors tied to one parameter.
valid_options array<string> yes On vocabulary errors, the closest real values to what was sent (or the first few valid values), so a failed call can self-correct without a documentation round trip.

Want to run these? The Explorer builds a request and executes it against the live API. This page has a .md twin.