Fortuna Compliance API

CPR Lookup and Validation

Use the CPR endpoints to retrieve a structured snapshot of an individual's CPR record, or to validate customer-provided data against official CPR records.

Prerequisites

  • Your account must have a broker with the Cpr capability enabled. Call GET /api/brokers to confirm. The {brokerId} path parameter is the id value from that response.
  • CPR numbers must be exactly 10 digits.

CPR lookup — `POST /api/cpr/

Retrieves the official CPR record for a person. Use this to get structured name, address, and status data.

Request body:

Field Type Required Description
audit.externalReference string Yes Your reference for this lookup (stored in audit log)
audit.context string No Optional context string
cpr string Yes 10-digit Danish CPR number

Response — person object:

Field Type Description
person.cprNumber string The CPR number looked up
person.name.givenName string First name
person.name.middleName string Middle name(s), if any
person.name.surname string Surname
person.address.streetName string Street name
person.address.streetNumber string House number
person.address.floor string Floor, if registered
person.address.unit string Door/side, if registered
person.address.careOfName string C/O name, if registered
person.address.zipCode string Postal code
person.address.zipName string Postal area name
person.address.cityName string City
person.personStatus string Current CPR status — see table below
person.isNameAddressProtected boolean true if the person has name/address protection (navne- og adressebeskyttelse)
person.retrievedAtUtc string (ISO 8601) When this snapshot was retrieved

Person status values:

Value Meaning
Active Normally registered person
ActiveWithHighRoadCode Active, with high road code
ActiveRegisteredResidenceInGreenlandicCpr Active, Greenlandic CPR
ActiveRegisteredResidenceInGreenlandicCprWithHighRoadCode Active, Greenlandic CPR with high road code
ActiveAdministrativeSocialSecurityNumber Administrative SSN, not a natural person
CancelledSocialSecurityNumber Cancelled
DeletedSocialSecurityNumber Deleted
ChangedSocialSecurityNumber Changed to another number
Missing Person missing
Emigrated Person emigrated
Deceased Person deceased

Note: If isNameAddressProtected is true, name and address fields may be withheld or redacted by the CPR authority. Do not display this information to end-users.

Error codes:

Status Meaning
400 Invalid CPR format, rate limit exceeded, or missing required fields
404 CPR number not found in the register
429 Too many requests — see Retry-After header for seconds to wait

CPR validation — `POST /api/cpr/

Validates customer-provided details against the official CPR record and returns a verdict with per-field scores. Use this for KYC customer validation.

Request body:

Field Type Required Description
audit.externalReference string Yes Your reference (stored in audit log)
audit.context string No Optional context string
cpr string Yes 10-digit Danish CPR number
firstNames string Yes Customer's first and middle names
lastName string Yes Customer's surname
street string Yes Street name
houseNumber string Yes House number
floor string No Floor (optional)
door string No Door/side designation (optional)
postalCode string Yes Postal code
city string Yes City
dateOfBirth string Yes Date of birth (YYYY-MM-DD)

Response:

Field Type Description
verdict string Overall match verdict — see table below
overallScore integer 0–100 composite score across all fields
name.score integer 0–100 name match score
name.match boolean Whether the name passed the match threshold
name.comment string Optional explanation
address.score integer 0–100 address match score
address.match boolean Whether the address passed the match threshold
address.comment string Optional explanation
dateOfBirth.score integer 0–100 date of birth match score
dateOfBirth.match boolean Whether the date of birth matched
dateOfBirth.comment string Optional explanation
risk.level string Risk level: Low, Medium, or High
risk.reasons string[] List of reasons contributing to the risk level
evidence.normalizedCprName string Normalized name from CPR record
evidence.normalizedCustomerName string Normalized name from your input
evidence.normalizedCprAddress string Normalized address from CPR record
evidence.normalizedCustomerAddress string Normalized address from your input
evidence.cprDateOfBirth string Date of birth from CPR record (YYYY-MM-DD)

Verdict values:

Verdict Meaning
Match All fields match — identity confirmed
PartialMatch Some fields match — further review recommended
NoMatch No significant match found
NotFound CPR number not found in the register
Error Lookup failed — retry or escalate

The evidence block shows the normalized values used for comparison, so you can understand exactly what was compared and why a partial match was returned.

Error codes:

Status Meaning
400 Invalid CPR format, rate limit exceeded, or missing required fields
429 Too many requests — see Retry-After header

Rate limiting

The CPR endpoints apply rate limiting to protect the upstream registry. If the rate limit is exceeded:

  • 400 is returned when too many failed lookups have occurred in a short period
  • 429 is returned when the request rate is too high — the Retry-After response header contains the number of seconds to wait before retrying

Test data (pre-production)

In the pre-production environment, use fictional CPR numbers from the official CPR test data repository:

https://cprservicedesk.atlassian.net/wiki/spaces/CPR/pages/11436127/Testdata

All data in the pre-production environment is fictional and for testing purposes only.