factsource.ai
Sign in

api

One GET per product.

JSON over HTTPS. The demo dataset is open; everything else takes a key you create in your account, and every call is metered against one balance.

This is the reading API. Publishing your own facts — if you make the products, or look after them for whoever does — goes the other way and is described for brands.

open

The demo dataset. No key, no account, cached for a minute.

GET/api/v1/products/:gtinopen

One record. Any GTIN form resolves to GTIN-14, and the canonical URL comes back in Content-Location.

metered

A key, and one credit per record returned. A lookup that finds nothing is not charged.

GET/api/v1/products/:gtinapi key

The same shape as the demo endpoint, over the whole catalogue. One credit per record.

soon

Working, not settled. Neither is on by default and neither shape is fixed — ask if you want either turned on.

POST/api/v1/validateapi keysoon

Send us what you hold and we answer field by field: matches, differs, disputed, uncertain, or we have nothing. Staff-facing today at a different address; the metered client route under this one is the remaining work.

GET/api/v1/brands/:slugapi keysoon

A brand's own record — country, segment, site, and the sub-brands and twins we have resolved. The graph behind it is thin and the relations are not yet ones we would sell. The brand name on a product needs none of this and always ships.

versioning

The major version is in the path and the exact shape is in the body. A field may be added without warning; a field never changes meaning, and nothing is removed inside a major. When that has to happen, /api/v2 appears and /api/v1 keeps answering.

# the shape you get is stated in every response
"$schema": ".../product-1.1.json"

# the path carries the major
GET /api/v1/products/:gtin

a response, trimmed

{
  "$schema": "/api/v1/schema/product-1.1.json",
  "gtin": "00000000000017",
  "identity": {
    "brand": [
      { "value": "Aurora",       "confidence": 77, "sources": 2, "contested": true },
      { "value": "Aurora Paris", "confidence": 14, "sources": 1, "contested": true }
    ]
  },
  "measures": {
    "volume": [
      { "value": 50, "unit": "ml", "printed_as": ["1.7 fl oz"],
        "confidence": 98, "sources": 2, "contested": false }
    ]
  }

  // and classification, composition, origin, content, related, extras,
  // gtin_alts, sources_count, last_updated — every one of them always
  // present. The full shape is the $schema above, which is served.
}

Note what is not here: a single winning brand. Two sources say Aurora, one says Aurora Paris, and the response says so. Picking is your policy, not ours. The volume shows the same idea for measurements — 50 ml is the value, and printed_as keeps what the label actually said.

the shape of a call

Every call carries a key, and answers from the whole catalogue:

curl -H "Authorization: Bearer fsk_production_…" \
  https://app.factsource.ai/api/v1/products/$GTIN