Madpris API Dokumentation

Madpris stiller en offentlig JSON API til rådighed, så du kan hente priser, produkter og statistik direkte fra vores database. Læse-endpoints er læse-adgang (GET), mens præcise batch-opslag bruger POST, og kræver ingen autentifikation.

Base URL: https://madpris.gratis.dk

Endpoints:

Bemærk: Alle svar er i JSON-format med Content-Type: application/json og CORS-headeren Access-Control-Allow-Origin: * — du kan derfor kalde API’et direkte fra browser-JavaScript.

Daglige kaldgrænser

Alle /api/...-kald tælles i en UTC-kalenderdag. Uden en gyldig nøgle er grænsen 500 kald pr. IP-adresse pr. dag. En aktiv registreret privilegeret nøgle sendes i headeren X-API-Key og bruger sin egen konfigurerede daglige grænse (som standard 300000 kald pr. dag).

curl "https://madpris.gratis.dk/api/products?q=kaffe" \
  -H 'X-API-Key: YOUR_API_KEY'

Hvert API-svar indeholder X-RateLimit-Limit, X-RateLimit-Remaining og X-RateLimit-Reset (Unix-tidspunktet for næste reset ved midnat UTC). Hvis grænsen er nået, returneres 429 med Retry-After og et JSON-svar med error, limit, remaining og reset. En manglende nøgle er tilladt på det offentlige niveau; kun en medsendt, ugyldig nøgle giver 401. Ugyldige nøgleforsøg tæller stadig i IP-grænsen. Nøgler oprettes, listes, tilbagekaldes og roteres af operatøren; en tilbagekaldt eller udløbet nøgle kan ikke bruge sin tidligere kvote. Nøgler deles ikke kvote med hinanden.

API-svar indeholder også X-Madpris-Publication-Run, X-Madpris-Published-At og X-Madpris-Publication-Status, når en vellykket post-merge publication er registreret. De identificerer den database-publication, som live-servingens friskhedsstatus refererer til.

/api/filters

GET /api/filters

Returnerer alle tilgængelige filtermuligheder: butikker, kategorier, mærker, underkategorier, nationale oprindelser og prisinterval.

Parametre

Ingen.

Eksempel

curl "https://madpris.gratis.dk/api/filters"

Respons

{
    "stores": [
      {"id": "rema1000", "name": "Rema 1000"},
      {"id": "netto",    "name": "Netto"},
      ...
    ],
    "categories": [
      "Mejeri", "Kød", "Grønt", ...
    ],
    "brands": [
      "Arla", "Thise", "Naturmælk", ...
    ],
    "subcategories": {
      "Mejeri": ["Mælk", "Ost", "Yoghurt", ...],
      ...
    },
    "nationalities": [
      "Dansk", "Italiensk", "Tysk", ...
    ],
    "price_range": {"min": 0.0, "max": 999.0}
  }

/api/stats

GET /api/stats

Overordnet statistik over databasen: antal produkter, butikker, kategorier, seneste opdatering, samt fordeling på butikker.

Parametre

Ingen.

Eksempel

curl "https://madpris.gratis.dk/api/stats"

Respons

{
    "total_products": 45231,
    "total_stores": 19,
    "total_categories": 48,
    "last_updated": "2026-07-22T23:05:00Z",
    "stores": {
      "rema1000": 5230,
      "netto": 4891,
      ...
    }
  }

/api/price-drops

GET /api/price-drops

Returnerer produkter med de største prisfald i databasen. Et prisfald beregnes som forskellen mellem den aktuelle pris og en tidligere højere pris. Resultaterne indeholder også price_last_seen_at, price_observed_at og price_status for produktet og hver butikspost.

Parametre

ParameterTypeStandardBeskrivelse
sort string "drop_pct" Sortering: drop_pct (procentvist fald) eller drop_abs (absolut fald i kroner)
page integer 1 Sidenummer (50 produkter per side)

Eksempel

curl "https://madpris.gratis.dk/api/price-drops?sort=drop_pct&page=1"

Respons

{
    "total": 872,
    "page": 1,
    "page_size": 50,
    "total_pages": 18,
    "products": [
      {
        "group_id": 1423,
        "name": "Økologisk hakket oksekød 8-12%",
        "store": "rema1000",
        "current_price": 28.0,
        "previous_price": 42.0,
        "drop_pct": 33.3,
        "drop_abs": 14.0,
        "price_last_seen_at": "2026-07-22",
        "category": "Kød",
        ...
      },
      ...
    ]
  }

/api/price-history

GET /api/price-history

Henter prishistorik for et bestemt produkt over tid. Du kan slå op enten via group_id (anbefalet) eller via kombinationen store + name.

Parametre

ParameterTypeStandardBeskrivelse
group_id påkrævet* integer — Gruppe-ID for produktet (foretrækkes)
store påkrævet* string — Butik-id (f.eks. "netto", "rema1000"). Kun hvis group_id ikke angives
name påkrævet* string — Produktnavn. Kun hvis group_id ikke angives

* Enten group_id alene, eller både store og name sammen.

Eksempel

curl "https://madpris.gratis.dk/api/price-history?group_id=1423"

Respons

{
    "group_id": 1423,
    "name": "Økologisk hakket oksekød 8-12%",
    "store": "rema1000",
    "history": [
      {"date": "2026-07-01", "price": 42.0},
      {"date": "2026-07-08", "price": 38.0},
      {"date": "2026-07-15", "price": 35.0},
      {"date": "2026-07-22", "price": 28.0}
    ]
  }

/api/product-by-ean

GET /api/product-by-ean

Slår et produkt op via dets EAN-stregkode (GTIN). Returnerer produktdetaljer på tværs af alle butikker hvis tilgængeligt. Hver butikspost har price_last_seen_at, price_observed_at og price_status (eller null), og produktets felt beskriver den billigste butikspost.

Parametre

ParameterTypeStandardBeskrivelse
ean påkrævet string — EAN-stregkode, minimum 8 cifre (f.eks. 5701234567890)

Eksempel

curl "https://madpris.gratis.dk/api/product-by-ean?ean=5711952000123"

Respons

{
    "ean": "5711952000123",
    "name": "Arla Letmælk 1L",
    "brand": "Arla",
    "category": "Mejeri",
    "stores": [
      {
        "store": "netto",
        "price": 14.95,
        "price_last_seen_at": "2026-07-22",
        "store_product_name": "Arla Letmælk 1 liter",
        "url": null
      },
      {
        "store": "rema1000",
        "price": 14.50,
        "price_last_seen_at": "2026-07-22",
        "store_product_name": "Arla Letmælk 1L",
        "url": null
      }
    ]
  }

/api/merged-products

GET /api/merged-products

Søger efter produkter på tværs af butikker og returnerer sammenlagte resultater — identiske produkter fra forskellige butikker slås sammen til én post med priser fra hver butik. Dette er det primære søge-endpoint som hjemmesiden selv bruger.

Hvert produkt og hver post i stores indeholder price_last_seen_at, price_observed_at og price_status. Datoen er den seneste faktiske observation af den viste pris for den pågældende butik. Hvis en sammenlagt post ikke kan knyttes sikkert til en underliggende observation, er felterne null. price_status er observed, reverted_to_normal eller historical; en tilbageført pris må ikke læses som observeret på overgangstidspunktet.

Parametre

ParameterTypeStandardBeskrivelse
qstring""Søgeord (fritekst)
storesstring""Komma-separerede butik-id’er (f.eks. "netto,rema1000")
categorystring""Kategorinavn (f.eks. "Mejeri")
subcategorystring""Underkategori (f.eks. "Mælk")
brandstring""Mærkenavn
sortstring"unit_price"Sortering: unit_price, name, price, store
orderstring"asc"Rækkefølge: asc eller desc
min_pricenumber—Minimumspris (f.eks. 10)
max_pricenumber—Maksimumspris (f.eks. 50)
on_salestring""Kun tilbudsvarer: "1" for ja
organicstring""Kun økologisk: "1" for ja
sugarfreestring""Kun sukkerfri: "1" for ja
lactosefreestring""Kun laktosefri: "1" for ja
glutenfreestring""Kun glutenfri: "1" for ja
brand_groupingstring"1"Gruppér efter mærke: "0" for slået fra
size_groupingstring"1"Gruppér efter størrelse: "0" for slået fra
nationality_groupingstring"1"Gruppér efter oprindelse: "0" for slået fra
multi_storestring"0"Kun produkter med flere butikker: "1"
pageinteger1Sidenummer (50 produkter per side)

Eksempel

curl "https://madpris.gratis.dk/api/merged-products?q=m%C3%A6lk&category=Mejeri&sort=unit_price&order=asc&page=1"

Respons

{
    "total": 342,
    "page": 1,
    "page_size": 50,
    "total_pages": 7,
    "products": [
      {
        "group_id": 1423,
        "name": "Sødmælk",
        "brand": "Arla",
        "category": "Mejeri",
        "unit": "L",
        "unit_size": 1.0,
        "unit_price": 14.95,
        "price_last_seen_at": "2026-07-22",
        "nationality": "Dansk",
        "ean": "5711952000123",
        "organic": true,
        "store_products": [
          {
            "store": "netto",
            "store_product_name": "Arla Sødmælk 1L",
            "price": 14.95,
            "price_last_seen_at": "2026-07-22",
            "unit_price": 14.95,
            "on_sale": false,
            "url": null
          },
          {
            "store": "rema1000",
            "store_product_name": "Arla Sødmælk 1 liter",
            "price": 14.50,
            "price_last_seen_at": "2026-07-22",
            "unit_price": 14.50,
            "on_sale": false,
            "url": null
          }
        ]
      },
      ...
    ]
  }

/api/products

GET /api/products

Søger efter rå produkter — hver butiks variant returneres som en selvstændig post. Brug /api/merged-products hvis du vil have produkter slået sammen på tværs af butikker. Hvert produkt indeholder price_last_seen_at, price_observed_at og price_status. Status og dato kommer fra den faktiske prisobservation; reverted_to_normal og historical er ikke nye observationer.

Parametre

ParameterTypeStandardBeskrivelse
qstring""Søgeord (fritekst)
storesstring""Komma-separerede butik-id’er
categorystring""Kategorinavn
brandstring""Mærkenavn
sortstring"unit_price"Sortering: unit_price, name, price, store
orderstring"asc"Rækkefølge: asc eller desc
min_pricenumber—Minimumspris
max_pricenumber—Maksimumspris
on_salestring""Kun tilbudsvarer: "1"
organicstring""Kun økologisk: "1"
sugarfreestring""Kun sukkerfri: "1"
lactosefreestring""Kun laktosefri: "1"
glutenfreestring""Kun glutenfri: "1"
pageinteger1Sidenummer (50 produkter per side)

Eksempel

curl "https://madpris.gratis.dk/api/products?q=hakket+okse&sort=price&order=asc"

Respons

{
    "total": 28,
    "page": 1,
    "page_size": 50,
    "total_pages": 1,
    "products": [
      {
        "product_id": 18932,
        "store": "netto",
        "name": "Hakket oksekød 8-12%",
        "brand": "Danish Crown",
        "category": "Kød",
        "price": 28.0,
        "price_last_seen_at": "2026-07-22",
        "unit": "g",
        "unit_size": 500,
        "unit_price": 56.0,
        "ean": "5711952123456",
        "organic": false,
        "on_sale": true,
        "url": null
      },
      ...
    ]
  }

/api/products/batch

POST /api/products/batch

Slår præcist de angivne rå produkt-ID'er op i ét databasekald. Resultaterne returneres i samme rækkefølge som første forekomst af ID'erne. ID'er, der ikke længere findes, returneres i missing_product_ids.

Send et JSON-objekt med et ikke-tomt product_ids-array af positive heltal. Gentagne ID'er deduplikeres. Højst 500 ID'er og 64 KiB request-body accepteres. Svaret bruger samme rå produktfelter som /api/products, inklusive product_id, price_last_seen_at, price_observed_at og price_status.

curl -X POST "https://madpris.gratis.dk/api/products/batch" \
  -H 'Content-Type: application/json' \
  -d '{"product_ids":[18932,18933,999999999]}'
{
    "products": [{"product_id": 18932, "store": "Netto", "price": 28.0, "size": "500 g", "price_last_seen_at": "2026-09-04"}],
    "missing_product_ids": [18933, 999999999]
  }

Ugyldig JSON, tomme arrays, forkerte ID-typer eller for store requests giver 4xx. Endpointet er omfattet af de daglige API-kaldgrænser.

Madpris API — madpris.gratis.dk