CountertopData

API Reference

CountertopData exposes the same data shown on the search page as a small set of read-only JSON endpoints. There is no authentication — every endpoint below is a public, unauthenticatedGET request. There are no write endpoints.

Conventions

Base URL:

https://countertopdata.com/api/v1
ConventionDetail
FormatAll responses are JSON (Content-Type: application/json).
List envelopeList endpoints return { data, count }. Endpoints that paginate (/materials) also return limit and offset, andcount there is the number of items in this response (data.length) — not a total match count across all pages.
Single-resource envelope{ data: { ... } } — see /materials/{id} below.
ErrorsA non-2xx status with a JSON body of the shape { error: string }.
CachingResponses set Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600 — safe to cache at a shared/CDN layer.
TimestampsTimestamp fields (e.g. lastVerifiedAt, createdAt) serialize as ISO 8601 date-time strings, or null when unset.

GET /api/v1/materials

Search and list materials, each annotated with crystalline silica content, silica compliance tier, and per-market availability.

ParameterTypeNotes
material_typestringOne of Natural Stone, Quartz, Sintered Stone/Porcelain, Mineral Surface.
silica_compliance_tierstringOne of Zero-Silica, Low-Silica, Traditional.
brand_idstring (UUID)Exact match on the owning brand's id.
qstringCase-insensitive substring match against material name, brand name, and manufacturer code.
lifecycle_statusstringOne of Active, Discontinued. Filters the material's own rollup status directly.
marketstringOne of GB, IE, US, CA, AU. Restricts results to materials that have an availability row recorded for this market.
market_statusstringOne of Active, Discontinued. Only valid together withmarket — supplying market_status without marketreturns HTTP 400 with a JSON error body.
limitintegerDefault 50, maximum 100. Values above 100 return HTTP 400 rather than being silently capped.
offsetintegerDefault 0.

400 Bad Requestmarket_status supplied without market:

{"error":"market_status query param requires market to also be specified"}

400 Bad Requestlimit above 100:

{"error":"limit 500 exceeds the maximum of 100."}

Each item in data:

FieldNotes
idOpaque UUID string.
nameMaterial name.
slugURL-safe slug, unique per brand.
materialTypeOne of Natural Stone, Quartz, Sintered Stone/Porcelain, Mineral Surface.
colorGroupFree-text colour family; nullable.
crystallineSilicaPctMinMinimum crystalline silica content, percent (0–100); nullable.
crystallineSilicaPctMaxMaximum crystalline silica content, percent (0–100); nullable.
silicaComplianceTierOne of Zero-Silica, Low-Silica, Traditional; nullable — not every material has been tier-classified.
manufacturerCodeManufacturer's own SKU/code; nullable.
sdsDocumentUrlLink to the safety data sheet; nullable.
originCountryCountry of origin; nullable.
dataSourceOne of Manufacturer SDS, Brand Submission, Manual Entry, Third-Party Lab, Manufacturer Price List, Distributor Price List.
lastVerifiedAtISO 8601 timestamp of last verification; nullable.
brandIdUUID of the owning brand.
brandNameDenormalised brand name, joined in.
brandSlugDenormalised brand slug, joined in.
marketsArray of per-market availability rows — see below.

The markets array is the single most important field on this endpoint to read correctly. An empty markets array means no availability data has been recorded for that material — it is never a claim that the material is unavailable or discontinued. Coverage across GB/IE/US/CA/AU is, and will remain, incomplete. Absence of a market row is always "unknown," not "no." Any consumer of this API — human or automated — must not read a missing or empty markets entry as a negative signal.

Each entry in markets:

FieldNotes
marketOne of GB, IE, US, CA, AU.
statusActive or Discontinued, for that specific market only.
releasedAtNullable string: a bare year ("2024") or year-month ("2024-06"). Day-level precision is not represented.
discontinuedAtSame precision rules as releasedAt; nullable.

Worked example

Request:

curl "https://countertopdata.com/api/v1/materials?q=5141"

Response:

{
  "data": [
    {
      "id": "...",
      "name": "Frosty Carrina",
      "slug": "frosty-carrina",
      "materialType": "Mineral Surface",
      "crystallineSilicaPctMin": null,
      "crystallineSilicaPctMax": 1,
      "silicaComplianceTier": "Zero-Silica",
      "manufacturerCode": "5141",
      "dataSource": "Manufacturer Price List",
      "brandName": "Caesarstone",
      "brandSlug": "caesarstone",
      "markets": [
        { "market": "GB", "status": "Active", "releasedAt": null, "discontinuedAt": null }
      ]
    }
  ],
  "count": 1,
  "limit": 50,
  "offset": 0
}

q=5141 matches on manufacturer code here — q also matches material name and brand name. id is an opaque UUID, elided above.

GET /api/v1/materials/{id}

Fetch a single material by id. Same fields and markets-array semantics as the list endpoint above, returned as a single object rather than an array.

ParameterTypeNotes
idstring (UUID), path parameterRequired.

Response: { data: { ...same fields as /materials, markets } }.

404 Not Found when no material matches the id:

{"error":"Not found"}

GET /api/v1/brands

List and search brands (manufacturers).

ParameterTypeNotes
verification_statusstringOne of Verified, Unverified, Pending.
qstringCase-insensitive substring match against brand name.

Response: { data, count }. Each item is the full brand record —id, name, slug, website(nullable), verificationStatus, createdAt, updatedAt.

GET /api/v1/slab-specifications

List slab specification records — thickness, dimensions, weight, finish, and miter-edge compatibility. These describe individual slab batches; the same material/color can ship in multiple finishes as distinct batches, which is why this is a separate resource rather than columns on a material.

ParameterTypeNotes
material_idstring (UUID)Optional. Omit to list slab specification rows across all materials, unfiltered.

Response: { data, count }. Each item is the full record —id, materialId, thicknessMm, lengthMm,widthMm, weightKgSqm (all nullable numbers), finishType(nullable — one of Polished, Honed, Leathered,Matt, Concrete, Rough, Natural,Ultra-Rough, Stone, Silk, Antique,Soft Matt), miterEdgeCompatible(boolean), createdAt, updatedAt.

GET /api/v1/markets

The controlled list of market codes this API and dataset support. No query parameters.

Response: { data: [{ code, name }, ...] } — currentlyGB (United Kingdom), IE (Ireland), US (United States),CA (Canada), AU (Australia).

Terms and attribution

This API is free to use for any purpose. No key or account is required — everything above is open to anyone, right now.

Attribution ("data from countertopdata.com", linked back to this site) is appreciated but not required.

The rate limits described above exist to keep the service healthy for everyone, not to gate access. If you need sustained high volume, a bulk export, or help integrating this data into your own product, get in touch at api@countertopdata.com — that's also the address for corrections.

On provenance: every material in this registry carries its own dataSource andlastVerifiedAt, so you can always see where a figure came from and how current it is. If something looks wrong, the same contact address above is the way to flag it.