API base URLhttps://query.datapublica.dk

Errors and freshness

The API uses HTTP status codes and JSON response bodies. Inspect both the status and body before deciding whether to retry.

Standard error body

Validation, authentication, authorization, not-found, and dataset-availability failures use this base shape:

type ErrorResponse = {
  error: string;
};

Example:

{
  "error": "Company not found"
}

Status codes

StatusMeaningClient action
400A query parameter, JSON body, identifier, cursor, or SQL statement is invalid.Correct the request before retrying.
401The bearer token is missing, malformed, unknown, or revoked.Supply or replace the token.
403A paid plan is required, the account is suspended, an operation is unavailable to the owner, or a usage limit is exhausted.Inspect code and usage fields; upgrade when code is paid_plan_required; otherwise do not immediately retry.
404The requested entity was not found in the active dataset.Check the identifier or search for the entity.
422Natural-language translation needs clarification or requests unsupported behavior.Inspect the structured translation body and change the question.
429Requests are arriving too quickly.Respect retry-after or resetAt when present, then retry with backoff.
500An unexpected server error prevented the request from completing.Retry with backoff; report a persistent failure with the x-request-id.
503No active dataset is loaded, or a required usage-decision service is unavailable.Retry with backoff and report a persistent failure.

Usage and quota errors

A plan/capability block, exhausted quota, or rate limit adds a stable code and usage window fields:

type UsageErrorResponse = {
  error: string;
  code: "paid_plan_required" | "quota_exceeded" | "plan_limit_exceeded" | "rate_limit_exceeded" | string;
  planKey?: string;
  quotaBucket?: string | null;
  limit?: number | null;
  used?: number;
  remaining?: number | null;
  windowStart?: string | null;
  windowEnd?: string | null;
  resetAt?: string | null;
};

When available, the response also includes X-Usage-Bucket, X-Usage-Limit, X-Usage-Remaining, and X-Usage-Reset headers. Treat the response values as authoritative. Datapublica does not publish plan prices or fixed quota amounts in the API docs.

A Free-plan API request returns 403 with code: "paid_plan_required"; the public API requires a paid plan. Quota exhaustion can return 403 with code: "quota_exceeded". A short-term request-rate decision can return 429 with code: "rate_limit_exceeded". Both use the same usage field names.

Natural-language translation 422

POST /api/sql/translate returns a structured body when no safe SQL should be produced:

{
  "status": "unsupported",
  "sql": null,
  "description": "Deleting inactive companies is a mutating and unsafe operation, which is not supported.",
  "notes": ["Only read-only SQL queries can be generated."],
  "assumptions": [],
  "warnings": ["No data was deleted."],
  "metadata": {
    "provider": "openai",
    "model": "model-name",
    "buildId": "build_...",
    "schemaVersion": "sha256:...",
    "referencedTables": []
  },
  "error": {
    "code": "unsafe_request"
  }
}

The other translation outcome is status: "needs_clarification" with error.code: "needs_clarification". Treat both as handled outcomes: revise the question instead of executing SQL.

Dataset unavailable 503

Entity, search, timeline, portfolio, SQL, and translation endpoints require an active CVR dataset:

{
  "error": "No active dataset loaded"
}

Retry with exponential backoff. A persistent 503 should be reported through support with the x-request-id header.

Freshness and build_id

Entity detail and ownership portfolio responses include a build_id, for example build_.... Translation metadata exposes the same concept as metadata.buildId.

Use the build identifier as the freshness cue:

  • Store it with derived results when reproducibility matters.
  • Compare it across related responses to determine whether they came from the same published dataset build.
  • Refresh cached derived data after observing a new build identifier.

Timeline and search responses do not always include a build identifier in their body. Fetch the related detail or portfolio resource when an explicit freshness cue is required.

Request IDs

Responses include an x-request-id header. Record it with the URL, method, status, and timestamp when diagnosing a failure. Do not record the bearer token.