{"openapi":"3.1.0","info":{"title":"Danadresse API — DAWA drop-in replacement","summary":"Drop-in REST replacement for dawa.aws.dk · Free tier 1000/day","description":"**Drop-in replacement for the Danish Address Web API (DAWA).** DAWA closes on 17 August 2026 — Danadresse takes over with the exact same endpoints, query parameters, JSON shapes and UUIDs.\n\n### Migration in 30 seconds\n1. Replace your base URL `https://dawa.aws.dk` → `https://api.danadresse.dk`.\n2. Add an `X-Api-Key: dawa_live_…` header to every request (get one free at <https://danadresse.dk/dashboard/signup>).\n3. Ship. Your DAR/DAGI IDs still resolve.\n\nFree tier: 1 000 calls/day per IP (no key needed). Paid tiers: Hobby/Basic/Pro/Enterprise — see <https://danadresse.dk/#pricing>.\n\n### Auth\nPublic DAWA endpoints (`/adresser`, `/autocomplete`, …) accept the key as either `X-Api-Key` header or `?api_key=` query — either is fine. Dashboard endpoints under `/api/v1/auth`, `/api/v1/keys`, `/api/v1/billing` require a JWT Bearer token from `POST /api/v1/auth/login`.\n\nBuilt by [LynBro ApS](https://lynbro.dk).","contact":{"name":"Danadresse Support","url":"https://danadresse.dk/dashboard","email":"support@danadresse.dk"},"license":{"name":"Data: CC BY 4.0 (Klimadatastyrelsen) · API: proprietary","url":"https://danadresse.dk/terms"},"version":"1.0.0"},"servers":[{"url":"https://api.danadresse.dk","description":"Production"},{"url":"https://danadresse.dk","description":"Same host (CORS-friendly)"}],"paths":{"/autocomplete":{"get":{"tags":["dawa:autocomplete"],"summary":"Autocomplete","description":"DAWA-сумісний autocomplete endpoint.\n\nNB: DAWA повертає JSON array (не obj). Те саме робимо.\nJSONP callback обгортка робиться у middleware (TODO).","operationId":"autocomplete_autocomplete_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search query (DAWA: required)","default":"","title":"Q"},"description":"Search query (DAWA: required)"},{"name":"struktur","in":"query","required":false,"schema":{"enum":["mini","full"],"type":"string","default":"mini","title":"Struktur"}},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","default":4326,"title":"Srid"}},{"name":"fuzzy","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Fuzzy"}},{"name":"adgangsadresserOnly","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Adgangsadresseronly"}},{"name":"params","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"JSON-encoded filter object, e.g. {\"kommunekode\":\"101\"}","title":"Params"},"description":"JSON-encoded filter object, e.g. {\"kommunekode\":\"101\"}"},{"name":"callback","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"JSONP callback function name","title":"Callback"},"description":"JSONP callback function name"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response Autocomplete Autocomplete Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/postnumre":{"get":{"tags":["dawa:postnumre"],"summary":"List Postnumre","operationId":"list_postnumre_postnumre_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"nr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nr"}},{"name":"navn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navn"}},{"name":"side","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Side"}},{"name":"per_side","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Per Side"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Postnumre Postnumre Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/postnumre/{nr}":{"get":{"tags":["dawa:postnumre"],"summary":"Get Postnummer","operationId":"get_postnummer_postnumre__nr__get","parameters":[{"name":"nr","in":"path","required":true,"schema":{"type":"string","title":"Nr"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Postnummer Postnumre  Nr  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kommuner":{"get":{"tags":["dawa:kommuner"],"summary":"List Kommuner","operationId":"list_kommuner_kommuner_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"navn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navn"}},{"name":"kode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kode"}},{"name":"regionskode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Regionskode"}},{"name":"side","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Side"}},{"name":"per_side","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Per Side"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Kommuner Kommuner Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kommuner/{kode}":{"get":{"tags":["dawa:kommuner"],"summary":"Get Kommune","operationId":"get_kommune_kommuner__kode__get","parameters":[{"name":"kode","in":"path","required":true,"schema":{"type":"string","title":"Kode"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Kommune Kommuner  Kode  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/vejnavne":{"get":{"tags":["dawa:vejnavne"],"summary":"List Vejnavne","operationId":"list_vejnavne_vejnavne_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"navn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navn"}},{"name":"side","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Side"}},{"name":"per_side","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Per Side"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Vejnavne Vejnavne Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/vejnavne/{id}":{"get":{"tags":["dawa:vejnavne"],"summary":"Get Vejnavn","operationId":"get_vejnavn_vejnavne__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Vejnavn Vejnavne  Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/adgangsadresser":{"get":{"tags":["dawa:adgangsadresser"],"summary":"List Adgangsadresser","operationId":"list_adgangsadresser_adgangsadresser_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"vejnavn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vejnavn"}},{"name":"husnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Husnr"}},{"name":"postnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr"}},{"name":"kommunekode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kommunekode"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status"}},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","default":4326,"title":"Srid"}},{"name":"side","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Side"}},{"name":"per_side","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Per Side"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Adgangsadresser Adgangsadresser Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/adgangsadresser/{id}":{"get":{"tags":["dawa:adgangsadresser"],"summary":"Get Adgangsadresse","operationId":"get_adgangsadresse_adgangsadresser__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","default":4326,"title":"Srid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Adgangsadresse Adgangsadresser  Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/adgangsadresser/reverse":{"get":{"tags":["dawa:adgangsadresser"],"summary":"Reverse Geocode","description":"Знаходить найближчу adgangsadresse до точки (x, y).","operationId":"reverse_geocode_adgangsadresser_reverse_get","parameters":[{"name":"x","in":"query","required":true,"schema":{"type":"number","description":"Longitude (4326) або East (25832)","title":"X"},"description":"Longitude (4326) або East (25832)"},{"name":"y","in":"query","required":true,"schema":{"type":"number","description":"Latitude (4326) або North (25832)","title":"Y"},"description":"Latitude (4326) або North (25832)"},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","default":4326,"title":"Srid"}},{"name":"struktur","in":"query","required":false,"schema":{"enum":["mini","full"],"type":"string","default":"full","title":"Struktur"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reverse Geocode Adgangsadresser Reverse Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/adresser":{"get":{"tags":["dawa:adresser"],"summary":"Søg adresser (DAWA-kompatibel)","description":"Søger danske adresser. 1:1 DAWA-kompatibel.\n\nReturnerer JSON som standard. `?format=csv` giver DAWA-CSV-eksport.","operationId":"list_adresser_adresser_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Fritekstsøgning på vejnavn","title":"Q"},"description":"Fritekstsøgning på vejnavn"},{"name":"vejnavn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vejnavn"}},{"name":"husnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Husnr"}},{"name":"etage","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Etage"}},{"name":"dør","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dør"}},{"name":"postnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr"}},{"name":"kommunekode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kommunekode"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"1=aktiv (default), 2=nedlagt","title":"Status"},"description":"1=aktiv (default), 2=nedlagt"},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","description":"4326=WGS84, 25832=ETRS89/UTM32","default":4326,"title":"Srid"},"description":"4326=WGS84, 25832=ETRS89/UTM32"},{"name":"format","in":"query","required":false,"schema":{"enum":["json","csv"],"type":"string","description":"Response format","default":"json","title":"Format"},"description":"Response format"},{"name":"side","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Side"}},{"name":"per_side","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Per Side"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/adresser/reverse":{"get":{"tags":["dawa:adresser"],"summary":"Reverse geocode → adresse","description":"Find nærmeste fulde adresse til en koordinat. DAWA-kompatibel.","operationId":"adresser_reverse_adresser_reverse_get","parameters":[{"name":"x","in":"query","required":true,"schema":{"type":"number","description":"Longitude (4326) / East (25832)","title":"X"},"description":"Longitude (4326) / East (25832)"},{"name":"y","in":"query","required":true,"schema":{"type":"number","description":"Latitude (4326) / North (25832)","title":"Y"},"description":"Latitude (4326) / North (25832)"},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","default":4326,"title":"Srid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Adresser Reverse Adresser Reverse Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/adresser/{id}":{"get":{"tags":["dawa:adresser"],"summary":"Hent én adresse","operationId":"get_adresse_adresser__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"srid","in":"query","required":false,"schema":{"enum":[4326,25832],"type":"integer","default":4326,"title":"Srid"}},{"name":"format","in":"query","required":false,"schema":{"enum":["json","csv"],"type":"string","default":"json","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/datavask/adgangsadresser":{"post":{"tags":["dawa:datavask"],"summary":"Datavask Adgangsadresser","description":"Очищення/валідація adgangsadresse. Повертає top матч + кутегорію.","operationId":"datavask_adgangsadresser_datavask_adgangsadresser_post","parameters":[{"name":"struktur","in":"query","required":false,"schema":{"enum":["mini","full"],"type":"string","default":"mini","title":"Struktur"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaskInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Datavask Adgangsadresser Datavask Adgangsadresser Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["dawa:datavask"],"summary":"Datavask af adgangsadresse (DAWA-kompatibel GET)","description":"GET-version af datavask. Tager parametre direkte i query og kalder POST-handleren.\n\nHvis `betegnelse` er udfyldt parser vi den til vejnavn/husnr/postnr (best-effort).","operationId":"datavask_adgangsadresser_get_datavask_adgangsadresser_get","parameters":[{"name":"vejnavn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vejnavn"}},{"name":"husnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Husnr"}},{"name":"postnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr"}},{"name":"supplerendebynavn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplerendebynavn"}},{"name":"betegnelse","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Hel adresse-streng, parses","title":"Betegnelse"},"description":"Hel adresse-streng, parses"},{"name":"struktur","in":"query","required":false,"schema":{"enum":["mini","full"],"type":"string","default":"mini","title":"Struktur"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Datavask Adgangsadresser Get Datavask Adgangsadresser Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/datavask/adresser":{"post":{"tags":["dawa:datavask"],"summary":"Datavask Adresser","description":"Datavask на повну адресу (з etage/dør).","operationId":"datavask_adresser_datavask_adresser_post","parameters":[{"name":"struktur","in":"query","required":false,"schema":{"enum":["mini","full"],"type":"string","default":"mini","title":"Struktur"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaskInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Datavask Adresser Datavask Adresser Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["dawa:datavask"],"summary":"Datavask af adresse (DAWA-kompatibel GET)","description":"GET-version af datavask for fulde adresser.","operationId":"datavask_adresser_get_datavask_adresser_get","parameters":[{"name":"vejnavn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vejnavn"}},{"name":"husnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Husnr"}},{"name":"etage","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Etage"}},{"name":"dør","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dør"}},{"name":"postnr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr"}},{"name":"supplerendebynavn","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplerendebynavn"}},{"name":"betegnelse","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Betegnelse"}},{"name":"struktur","in":"query","required":false,"schema":{"enum":["mini","full"],"type":"string","default":"mini","title":"Struktur"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Datavask Adresser Get Datavask Adresser Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/healthz":{"get":{"tags":["health"],"summary":"Healthz","operationId":"healthz_api_v1_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/readyz":{"get":{"tags":["health"],"summary":"Readyz","operationId":"readyz_api_v1_readyz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/auth/signup":{"post":{"tags":["auth"],"summary":"Signup","operationId":"signup_api_v1_auth_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/login":{"post":{"tags":["auth"],"summary":"Login","operationId":"login_api_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/me":{"get":{"tags":["auth"],"summary":"Me","operationId":"me_api_v1_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Me Api V1 Auth Me Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"JWT stateless — клієнт сам видаляє token. Для blacklist можна додати Redis.","operationId":"logout_api_v1_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Logout Api V1 Auth Logout Post"}}}}}}},"/api/v1/auth/magic":{"post":{"tags":["auth"],"summary":"Request Magic","description":"Запит magic-link на email. Якщо юзера нема — створюємо.","operationId":"request_magic_api_v1_auth_magic_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MagicRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Request Magic Api V1 Auth Magic Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/otp/signup":{"post":{"tags":["auth"],"summary":"Otp Signup","description":"Stage 1 of signup: stash credentials, email a 6-digit code.\n\nNo user row is created until the code is verified — this prevents the table\nfrom filling with abandoned half-signups and lets people retry with the\nsame email.","operationId":"otp_signup_api_v1_auth_otp_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpSignupBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Otp Signup Api V1 Auth Otp Signup Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/otp/verify":{"post":{"tags":["auth"],"summary":"Otp Verify","description":"Stage 2 of signup: consume code, create user, return JWT.","operationId":"otp_verify_api_v1_auth_otp_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpVerifyBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/otp/forgot":{"post":{"tags":["auth"],"summary":"Otp Forgot","description":"Request a password-reset code. Always returns 200 — we don't leak\nwhether an email exists in our system (prevents user enumeration).","operationId":"otp_forgot_api_v1_auth_otp_forgot_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpForgotBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Otp Forgot Api V1 Auth Otp Forgot Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/otp/reset":{"post":{"tags":["auth"],"summary":"Otp Reset","description":"Verify reset code, set new password, return JWT (auto-login).","operationId":"otp_reset_api_v1_auth_otp_reset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpResetBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/otp/resend":{"post":{"tags":["auth"],"summary":"Otp Resend","description":"Re-issue a code. Rate-limit: max 1 resend per 60 sec per email+purpose.","operationId":"otp_resend_api_v1_auth_otp_resend_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpResendBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Otp Resend Api V1 Auth Otp Resend Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/magic/{token}":{"get":{"tags":["auth"],"summary":"Confirm Magic","operationId":"confirm_magic_api_v1_auth_magic__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/keys":{"get":{"tags":["keys"],"summary":"List Keys","operationId":"list_keys_api_v1_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Keys Api V1 Keys Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["keys"],"summary":"Create Key","description":"Створити ключ. Plaintext key повертається ТІЛЬКИ ЗАРАЗ і ніколи знов.","operationId":"create_key_api_v1_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Key Api V1 Keys Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/keys/{key_id}":{"delete":{"tags":["keys"],"summary":"Revoke Key","operationId":"revoke_key_api_v1_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Key Api V1 Keys  Key Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout","description":"Створити Stripe Checkout Session. Якщо у юзера ще немає customer_id — створюємо.","operationId":"create_checkout_api_v1_billing_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Checkout Api V1 Billing Checkout Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/portal":{"post":{"tags":["billing"],"summary":"Create Portal","description":"Stripe Customer Portal — користувач керує підпискою, методами оплати, інвойсами.","operationId":"create_portal_api_v1_billing_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Portal Api V1 Billing Portal Post"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/status":{"get":{"tags":["billing"],"summary":"Billing Status","operationId":"billing_status_api_v1_billing_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Status Api V1 Billing Status Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/webhook/stripe":{"post":{"tags":["billing"],"summary":"Stripe Webhook","description":"Stripe webhook. Підтримує ОБИДВА формати payload:\n\n1. **Snapshot** (`Payload style: Snapshot`, API v2026-03-25.dahlia):\n   Повний event object з усіма даними. `event.type` = \"customer.subscription.created\" etc.\n\n2. **Thin payload** (`Payload style: Thin`, Unversioned):\n   Тільки `event.type` + `event.related_object.id`. Треба fetch повного об'єкта через API.\n\nОбидва — одна функція. Розрізняємо по `payload_style` у тілі.","operationId":"stripe_webhook_api_v1_billing_webhook_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Stripe Webhook Api V1 Billing Webhook Stripe Post"}}}}}}},"/api/v1/enrich/adresser/{id}/dagi":{"get":{"tags":["enrich"],"summary":"Dagi Tags","description":"Все 8 адміністративних рівнів за one call.\n\nEquivalent to Smarty's FIPS/congressional district feature but free.","operationId":"dagi_tags_api_v1_enrich_adresser__id__dagi_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"Adgangsadresse UUID","title":"Id"},"description":"Adgangsadresse UUID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Dagi Tags Api V1 Enrich Adresser  Id  Dagi Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/adresser/{id}/bbr":{"get":{"tags":["enrich"],"summary":"Bbr Data","description":"BBR building data — construction year, area, energy label, etc.\n\nSTUB: returns shape that mirrors final structure. Real data when BBR ETL\nvia Datafordeler completes (~ post-cutover).","operationId":"bbr_data_api_v1_enrich_adresser__id__bbr_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Bbr Data Api V1 Enrich Adresser  Id  Bbr Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/adresser/{id}/virksomheder":{"get":{"tags":["enrich"],"summary":"Companies At Address","description":"CVR companies registered at this address.\n\nStub: would call CVR API or pre-loaded virk_at_address table.\nFor now points to soge.dk for direct lookup.","operationId":"companies_at_address_api_v1_enrich_adresser__id__virksomheder_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Companies At Address Api V1 Enrich Adresser  Id  Virksomheder Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/adresser/{id}/climate":{"get":{"tags":["enrich"],"summary":"Climate Risk","description":"Flood + storm-surge + groundwater rise risk for 2050.\n\nStub for DMI Klimaatlas integration — unique DK value-add no global\ncompetitor offers.","operationId":"climate_risk_api_v1_enrich_adresser__id__climate_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Climate Risk Api V1 Enrich Adresser  Id  Climate Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/adresser/{id}/property":{"get":{"tags":["enrich"],"summary":"Property Valuation","description":"Tax-assessed property valuation (Vurderingsstyrelsen).\n\nStub for SVUR ETL.","operationId":"property_valuation_api_v1_enrich_adresser__id__property_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Property Valuation Api V1 Enrich Adresser  Id  Property Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/adresser/{id}/all":{"get":{"tags":["enrich"],"summary":"All Enrichment","description":"Composite call — DAGI + BBR + Companies + Climate + Property in one.\n\nCost-efficient for clients — 5 enrichments in single HTTP roundtrip.","operationId":"all_enrichment_api_v1_enrich_adresser__id__all_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response All Enrichment Api V1 Enrich Adresser  Id  All Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/distance":{"get":{"tags":["enrich"],"summary":"Distance Between Addresses","description":"Straight-line distance + bearing between two DAWA addresses.\n\nUseful for delivery zone checks, last-mile costing, postnummer-radius queries\nwithout spinning up a routing engine.","operationId":"distance_between_addresses_api_v1_enrich_distance_get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"Source adgangsadresse UUID","default":"","title":"From"},"description":"Source adgangsadresse UUID"},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"Destination adgangsadresse UUID","default":"","title":"To"},"description":"Destination adgangsadresse UUID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Distance Between Addresses Api V1 Enrich Distance Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/quality/score":{"post":{"tags":["enrich"],"summary":"Quality Score","description":"Score the completeness + plausibility of an address record.\n\nUseful for data-cleansing pipelines that need a numeric confidence\nbefore triggering a more expensive datavask call. 0 = unusable, 100 = perfect.","operationId":"quality_score_api_v1_enrich_quality_score_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QualityInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Quality Score Api V1 Enrich Quality Score Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/enrich/validate/iban":{"post":{"tags":["enrich"],"summary":"Validate Iban","description":"IBAN mod-97 validation + DK bank code lookup.","operationId":"validate_iban_api_v1_enrich_validate_iban_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IBANInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Validate Iban Api V1 Enrich Validate Iban Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/validate/cvr":{"post":{"tags":["enrich"],"summary":"Validate Cvr","description":"Danish CVR 8-digit validation.","operationId":"validate_cvr_api_v1_enrich_validate_cvr_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CVRInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Validate Cvr Api V1 Enrich Validate Cvr Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/validate/phone":{"post":{"tags":["enrich"],"summary":"Validate Phone","description":"Danish phone normalization (+45) + line type hint.","operationId":"validate_phone_api_v1_enrich_validate_phone_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Validate Phone Api V1 Enrich Validate Phone Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/enrich/validate/ean":{"post":{"tags":["enrich"],"summary":"Validate Ean","description":"EAN/GLN 13-digit mod-10 (Luhn-variant) check.","operationId":"validate_ean_api_v1_enrich_validate_ean_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EANInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Validate Ean Api V1 Enrich Validate Ean Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bulk/cleanse":{"post":{"tags":["bulk"],"summary":"Bulk Cleanse","description":"Submit CSV for bulk address cleansing.","operationId":"bulk_cleanse_api_v1_bulk_cleanse_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_bulk_cleanse_api_v1_bulk_cleanse_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Bulk Cleanse Api V1 Bulk Cleanse Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bulk/jobs/{job_id}":{"get":{"tags":["bulk"],"summary":"Job Status","operationId":"job_status_api_v1_bulk_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Job Status Api V1 Bulk Jobs  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bulk/jobs":{"get":{"tags":["bulk"],"summary":"List Jobs","description":"List the caller's most recent bulk jobs (best-effort scan of Redis).","operationId":"list_jobs_api_v1_bulk_jobs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Jobs Api V1 Bulk Jobs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bulk/jobs/{job_id}/download":{"get":{"tags":["bulk"],"summary":"Job Download","operationId":"job_download_api_v1_bulk_jobs__job_id__download_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/":{"get":{"tags":["dashboard"],"summary":"Home","operationId":"home_dashboard__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/dashboard/login":{"get":{"tags":["dashboard"],"summary":"Login Page","operationId":"login_page_dashboard_login_get","parameters":[{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["dashboard"],"summary":"Login Post","operationId":"login_post_dashboard_login_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_post_dashboard_login_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/signup":{"get":{"tags":["dashboard"],"summary":"Signup Page","operationId":"signup_page_dashboard_signup_get","parameters":[{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["dashboard"],"summary":"Signup Post","description":"Stage 1: validate + email a 6-digit code. No user row created yet.","operationId":"signup_post_dashboard_signup_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_signup_post_dashboard_signup_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/signup/verify":{"post":{"tags":["dashboard"],"summary":"Signup Verify","description":"Stage 2: consume code → create user → cookie session → /dashboard/keys.","operationId":"signup_verify_dashboard_signup_verify_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_signup_verify_dashboard_signup_verify_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/signup/resend":{"post":{"tags":["dashboard"],"summary":"Signup Resend","operationId":"signup_resend_dashboard_signup_resend_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_signup_resend_dashboard_signup_resend_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/forgot":{"get":{"tags":["dashboard"],"summary":"Forgot Page","operationId":"forgot_page_dashboard_forgot_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["dashboard"],"summary":"Forgot Post","description":"Always go to reset step — don't leak whether email exists.","operationId":"forgot_post_dashboard_forgot_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_forgot_post_dashboard_forgot_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/forgot/reset":{"post":{"tags":["dashboard"],"summary":"Forgot Reset","operationId":"forgot_reset_dashboard_forgot_reset_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_forgot_reset_dashboard_forgot_reset_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/forgot/resend":{"post":{"tags":["dashboard"],"summary":"Forgot Resend","operationId":"forgot_resend_dashboard_forgot_resend_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_forgot_resend_dashboard_forgot_resend_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/logout":{"get":{"tags":["dashboard"],"summary":"Logout","operationId":"logout_dashboard_logout_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/dashboard/keys":{"get":{"tags":["dashboard"],"summary":"Keys Page","operationId":"keys_page_dashboard_keys_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["dashboard"],"summary":"Keys Create","operationId":"keys_create_dashboard_keys_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_keys_create_dashboard_keys_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/keys/{key_id}/revoke":{"post":{"tags":["dashboard"],"summary":"Keys Revoke","operationId":"keys_revoke_dashboard_keys__key_id__revoke_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/usage":{"get":{"tags":["dashboard"],"summary":"Usage Page","operationId":"usage_page_dashboard_usage_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/dashboard/billing":{"get":{"tags":["dashboard"],"summary":"Billing Page","operationId":"billing_page_dashboard_billing_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/dashboard/bulk":{"get":{"tags":["dashboard"],"summary":"Bulk Page","operationId":"bulk_page_dashboard_bulk_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/uk":{"get":{"tags":["landing"],"summary":"Index","operationId":"index_uk_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/en":{"get":{"tags":["landing"],"summary":"Index","operationId":"index_en_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/":{"get":{"tags":["landing"],"summary":"Index","operationId":"index__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"Body_bulk_cleanse_api_v1_bulk_cleanse_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"vejnavn_col":{"type":"string","title":"Vejnavn Col","default":"vejnavn"},"husnr_col":{"type":"string","title":"Husnr Col","default":"husnr"},"postnr_col":{"type":"string","title":"Postnr Col","default":"postnr"}},"type":"object","required":["file"],"title":"Body_bulk_cleanse_api_v1_bulk_cleanse_post"},"Body_forgot_post_dashboard_forgot_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_forgot_post_dashboard_forgot_post"},"Body_forgot_resend_dashboard_forgot_resend_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_forgot_resend_dashboard_forgot_resend_post"},"Body_forgot_reset_dashboard_forgot_reset_post":{"properties":{"email":{"type":"string","title":"Email"},"code":{"type":"string","title":"Code"},"new_password":{"type":"string","title":"New Password"}},"type":"object","required":["email","code","new_password"],"title":"Body_forgot_reset_dashboard_forgot_reset_post"},"Body_keys_create_dashboard_keys_post":{"properties":{"name":{"type":"string","title":"Name"},"mode":{"type":"string","title":"Mode"}},"type":"object","required":["name","mode"],"title":"Body_keys_create_dashboard_keys_post"},"Body_login_post_dashboard_login_post":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"Body_login_post_dashboard_login_post"},"Body_signup_post_dashboard_signup_post":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"name":{"type":"string","title":"Name","default":""}},"type":"object","required":["email","password"],"title":"Body_signup_post_dashboard_signup_post"},"Body_signup_resend_dashboard_signup_resend_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_signup_resend_dashboard_signup_resend_post"},"Body_signup_verify_dashboard_signup_verify_post":{"properties":{"email":{"type":"string","title":"Email"},"code":{"type":"string","title":"Code"}},"type":"object","required":["email","code"],"title":"Body_signup_verify_dashboard_signup_verify_post"},"CVRInput":{"properties":{"cvr":{"type":"string","title":"Cvr"}},"type":"object","required":["cvr"],"title":"CVRInput"},"CheckoutRequest":{"properties":{"success_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Success Url"},"cancel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cancel Url"}},"type":"object","title":"CheckoutRequest"},"CreateKeyBody":{"properties":{"name":{"type":"string","title":"Name"},"mode":{"type":"string","title":"Mode","default":"live"},"scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scopes"}},"type":"object","required":["name"],"title":"CreateKeyBody"},"EANInput":{"properties":{"ean":{"type":"string","title":"Ean"}},"type":"object","required":["ean"],"title":"EANInput"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IBANInput":{"properties":{"iban":{"type":"string","title":"Iban"}},"type":"object","required":["iban"],"title":"IBANInput"},"LoginBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginBody"},"MagicRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"MagicRequest"},"OtpForgotBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"OtpForgotBody"},"OtpResendBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"purpose":{"type":"string","enum":["signup","reset"],"title":"Purpose"}},"type":"object","required":["email","purpose"],"title":"OtpResendBody"},"OtpResetBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","pattern":"^\\d{6}$","title":"Code"},"new_password":{"type":"string","maxLength":200,"minLength":8,"title":"New Password"}},"type":"object","required":["email","code","new_password"],"title":"OtpResetBody"},"OtpSignupBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":200,"minLength":8,"title":"Password"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"lang":{"type":"string","title":"Lang","default":"da"}},"type":"object","required":["email","password"],"title":"OtpSignupBody"},"OtpVerifyBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","pattern":"^\\d{6}$","title":"Code"}},"type":"object","required":["email","code"],"title":"OtpVerifyBody"},"PhoneInput":{"properties":{"phone":{"type":"string","title":"Phone"},"country":{"type":"string","title":"Country","default":"DK"}},"type":"object","required":["phone"],"title":"PhoneInput"},"QualityInput":{"properties":{"vejnavn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vejnavn"},"husnr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Husnr"},"etage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Etage"},"door":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Door"},"postnr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr"},"postnr_navn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr Navn"},"kommunekode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kommunekode"}},"type":"object","title":"QualityInput"},"SignupBody":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":200,"minLength":8,"title":"Password"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"cvr":{"anyOf":[{"type":"string","pattern":"^\\d{8}$"},{"type":"null"}],"title":"Cvr"},"lang":{"type":"string","title":"Lang","default":"da"}},"type":"object","required":["email","password"],"title":"SignupBody"},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"Bearer"},"user":{"additionalProperties":true,"type":"object","title":"User"}},"type":"object","required":["access_token","user"],"title":"TokenResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VaskInput":{"properties":{"vejnavn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vejnavn"},"husnr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Husnr"},"etage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Etage"},"dør":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dør"},"postnr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postnr"},"supplerendebynavn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplerendebynavn"}},"type":"object","title":"VaskInput"}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"JWT issued from /api/v1/auth/login (dashboard sessions).","scheme":"bearer"},"APIKeyHeader":{"type":"apiKey","description":"API key issued from /dashboard/keys. Free tier (1000/day per IP) works without a key.","in":"header","name":"X-Api-Key"},"APIKeyQuery":{"type":"apiKey","description":"API key as query parameter (DAWA-compat fallback).","in":"query","name":"api_key"}}},"tags":[{"name":"dawa:adresser","description":"DAWA-compat: full addresses with etage/dør"},{"name":"dawa:adgangsadresser","description":"DAWA-compat: entry addresses (building-level)"},{"name":"dawa:autocomplete","description":"DAWA-compat: typo-tolerant search-as-you-type"},{"name":"dawa:postnumre","description":"DAWA-compat: postal codes"},{"name":"dawa:kommuner","description":"DAWA-compat: municipalities"},{"name":"dawa:vejnavne","description":"DAWA-compat: street names"},{"name":"dawa:datavask","description":"DAWA-compat: address cleansing (kategori A/B/C)"},{"name":"enrich","description":"Beyond DAWA: DAGI, BBR, climate, distance, quality"},{"name":"bulk","description":"Bulk CSV cleansing (async jobs)"},{"name":"auth","description":"Dashboard auth: signup, login, OTP, password reset"},{"name":"keys","description":"Dashboard: manage API keys"},{"name":"billing","description":"Dashboard: subscription + invoicing"}]}