Spring til indhold

Fejl og statuskoder

Alle fejl har samme form og en HTTP-status, der fortæller, om du skal rette kaldet, opgradere, vente eller prøve igen.

Fejlformatet

En fejl er altid et JSON-objekt med ét felt, error, der beskriver fejlen på engelsk. Forgren på HTTP-statussen, ikke på teksten, som kan blive præciseret over tid.

404
{ "error": "property not found" }

Hvert svar bærer desuden en X-Request-Id-header. Angiv den, hvis du kontakter support om et bestemt kald.

Statuskoder

Tabellen er dannet direkte fra API’ets eget fejlkatalog — den samme liste, som API’et er kontrolleret imod, så en ny fejlstatus ikke kan tages i brug uden at stå her. Kataloget kan også hentes maskinlæsbart og uden nøgle fra GET /v1/errors, med en stabil type pr. fejltype.

StatusBetydning i GrundfastPrøv igen?
400Ugyldig forespørgsel: forkert BFE- eller UUID-format, en manglende eller for kort parameter, et koordinat uden for Danmark, en ugyldig asOf, srid, cirkel eller polygon, eller et body, der ikke passer til skemaet.Nej — ret kaldet.
401Nøglen mangler, er ugyldig, udløbet eller tilbagekaldt. Svaret bærer en WWW-Authenticate-header, der beskriver formatet.Nej — ret kaldet.
402Funktionen er ikke med i din plan. Batch og webhooks kræver Pro; eksport og historik (asOf og /historik) kræver Scale. Beskeden nævner den plan, der skal til.Nej — ret kaldet.
403Kontoen er suspenderet, eller nøglen er en administrationsnøgle, der ikke gælder for data-endpoints. Et kald med cookie-session fra et andet site til et konto-endpoint (login, nøgler, betaling) afvises. Gælder ikke kald med API-nøgle.Nej — ret kaldet.
404Ressourcen findes ikke: ukendt BFE, UUID, CVR-nummer, kode eller sti.Nej — ret kaldet.
409Ressourcen er ikke i en tilstand, der tillader kaldet — typisk en eksport, der ikke er færdig endnu, når du henter filen.Ja, når forudsætningen er opfyldt.
413Request-body over 1 MB. Del kaldet op.Nej — ret kaldet.
415Et konto-endpoint fik et body, der ikke er application/json. Send Content-Type: application/json.Nej — ret kaldet.
422Jordstykket kunne findes, men bærer ingen ejerlavskode og intet matrikelnummer, så kortlægningen kan ikke slås op på matriklen. Slå op på koordinatet i stedet.Nej — ret kaldet.
429Burst-grænsen pr. minut for din plan er nået. Retry-After siger, hvornår vinduet åbner igen. Månedens kvote er brugt (eller sandbox-loftet for en testnøgle). Svaret bærer X-Quota-*-headere, og Retry-After peger på næste måned — prøv ikke igen automatisk. For mange forsøg med ugyldige nøgler fra samme IP-adresse. Ret nøglen og vent det antal sekunder, Retry-After angiver.rate_limited: Ja, efter Retry-After. quota_exceeded: Nej — ret kaldet. auth_throttled: Ja, efter Retry-After.
500En uventet fejl hos os. Den er logget med kaldets X-Request-Id; angiv det, hvis du kontakter support.Ja, med backoff.
502Kilden (fx Datafordeler) svarede med fejl, efter vi har prøvet igen, og der var ingen brugbar cachet kopi.Ja, med backoff.
503Kilden er ikke tilgængelig i øjeblikket, endpointet er ikke sat op i dette miljø (fx adresseindekset eller rumlige filtre), eller rate-limiteren er midlertidigt utilgængelig. Energimærke: ejendommen er ikke dækket endnu. Det er ikke det samme som "intet energimærke" — det ville være en 404.Ja, med backoff.
504Svaret tog længere end tidsgrænsen på ca. 20 sekunder. Arbejdet fortsætter i baggrunden, så et nyt kald er ofte hurtigt.Ja, med backoff.

Hvilke fejl tæller

  • 5xx og 504 tæller ikke. Et kald, der ender i en serverfejl eller tidsgrænsen, lægges tilbage i månedens kvote.
  • 4xx tæller med i kvoten. Et kald med en ugyldig BFE eller et ukendt nummer bruger en enhed, ligesom et vellykket kald.
  • Kun vellykkede svar faktureres. Overforbrug på betalte planer beregnes ud fra svar under 400.
  • 402 og 429 tæller ikke. Plan-tjekket og rate limits afviser kaldet, før det måles.

Hvornår du skal prøve igen

  • 429 fra burst-grænsen: vent det antal sekunder, Retry-After angiver, og prøv igen.
  • 429 fra månedens kvote: svaret bærer også X-Quota-*-headere, og Retry-After peger på næste måned. Prøv ikke igen automatisk.
  • 502, 503 og 504: prøv igen med eksponentiel backoff og jitter, fx 0,5 s, 1 s, 2 s. Stop efter nogle få forsøg.
  • 400, 401, 402, 403 og 404: prøv aldrig igen uden at ændre kaldet. Svaret bliver det samme.
grundfast-fetch.ts
const RETRYABLE = new Set([429, 502, 503, 504]);

export async function grundfastGet<T>(path: string, maxAttempts = 4): Promise<T> {
  for (let attempt = 1; ; attempt++) {
    const res = await fetch(`https://api.grundfast.dk${path}`, {
      headers: { Authorization: `Bearer ${process.env.GRUNDFAST_API_KEY}` },
    });
    if (res.ok) return (await res.json()) as T;

    // Månedens kvote er en 429 med X-Quota-*-headere: den forsvinder ikke ved at vente.
    const quotaExhausted = res.status === 429 && res.headers.has('X-Quota-Remaining');
    if (!RETRYABLE.has(res.status) || quotaExhausted || attempt >= maxAttempts) {
      const body = (await res.json().catch(() => ({}))) as { error?: string };
      throw new Error(`Grundfast ${res.status}: ${body.error ?? res.statusText}`);
    }

    const retryAfter = Number(res.headers.get('Retry-After'));
    const delayMs =
      retryAfter > 0 ? retryAfter * 1000 : 2 ** (attempt - 1) * 500 + Math.random() * 250;
    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }
}

// const ejendom = await grundfastGet('/v1/bbr/ejendom/5651067');

Fejl i SDK’et

TypeScript-SDK’et kaster en GrundfastError for ethvert svar uden for 2xx. Den har status (HTTP-statussen), message (teksten fra error) og retryAfter (sekunder fra Retry-After, når headeren findes). En timeout bliver til status 408.

fejl.ts
import { GrundfastClient, GrundfastError } from '@grundfast/sdk';

const gf = new GrundfastClient({ apiKey: 'gf_live_...' });

try {
  const ejendom = await gf.ejendom(5651067);
  console.log(ejendom.antal_bygninger);
} catch (err) {
  if (err instanceof GrundfastError && err.status === 404) {
    console.log('Ukendt BFE');
  } else if (err instanceof GrundfastError && err.status === 402) {
    console.log('Kræver en højere plan:', err.message);
  } else {
    throw err;
  }
}

SDK’et prøver selv igen ved 408, 500, 502 og 503 og ved burst-429, med backoff og op til to ekstra forsøg som standard (maxRetries). Det prøver aldrig igen ved månedens kvote-429, og en eksport oprettes aldrig to gange. 504 prøves ikke igen automatisk, så håndtér den selv, hvis du vil.