Redact
Redact finder personoplysninger i en tekst og erstatter dem med betegnelser som [PERSON-1] og [CPR-1]. Du får den pseudonymiserede tekst tilbage og, hvis du beder om den, listen over betegnelser, så du senere kan sætte de oprindelige oplysninger tilbage, fx i et svar fra jeres egen sprogmodel.
Alle kald går til https://api.komplai.dk. Redact tager begge slags nøgler: en personlig API-nøgle (kp_live_...) og organisationens integrationsnøgle (kp_org_...), som komplai udsteder til et af jeres egne systemer, fx en robot eller en integrationsplatform.
Før du starter
- Jeres organisations aftale omfatter Redact via API'et, og du har fået adgang til Redact. Organisationens integrationsnøgle tilhører ingen person og skal ikke tildeles.
- Din nøgle har de scopes, som de kald, du bruger, kræver:
| Scope | Kald |
|---|---|
redact:detect | POST /v1/redact/detect |
redact:process | POST /v1/redact, tekstjobs, PDF- og Word-filer, POST /v1/redact/restore |
access:read | GET /v1/access |
Opret en personlig nøgle på hubbens side API-nøgler på hub.komplai.dk/api-access. API-nøgler og autentificering forklarer de to slags nøgler.
Brug kun testdata, indtil jeres organisation har en godkendt databehandleraftale. Eksemplerne på siden bruger fiktive personer.
Dit første kald
Send en kort tekst til POST /v1/redact med reglerne (regex) og navnemodellen (ner). De to lag kører også, når du udelader detectors.
curl https://api.komplai.dk/v1/redact \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "Borgeren Mette Kjærgaard Holm, cpr-nr. 120385-1234, bor på Fiktivvej 12, 8000 Aarhus C. Hun kan kontaktes på 21 34 56 78 eller mette.holm@example.invalid.",
"detectors": ["regex", "ner"],
"include": ["mapping"]
}'Svaret, hvor nogle felter er udeladt:
{
"redacted": "Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [EMAIL-1].",
"processing": "local",
"offsetEncoding": "utf-16",
"configuration": {
"engine": "pipeline",
"detectors": ["regex", "ner"],
"processing": "local"
},
"execution": {
"completed": true,
"detectorsRun": ["regex", "ner"],
"nerCalls": 1,
"llmCalls": 0
},
"mapping": {
"[PERSON-1]": "Mette Kjærgaard Holm",
"[CPR-1]": "120385-1234",
"[ADRESSE-1]": "Fiktivvej 12, 8000 Aarhus C",
"[TLF-1]": "21 34 56 78",
"[EMAIL-1]": "mette.holm@example.invalid"
}
}redacted er den pseudonymiserede tekst. mapping er listen over betegnelser. Gem den, hvis du vil sætte de oprindelige oplysninger tilbage, og beskyt den som kildeteksten, for den indeholder personoplysningerne.
include tilvælger ekstra rapporter. Alle indeholder de oprindelige oplysninger, så bed kun om det, du har brug for:
| Rapport | Indhold |
|---|---|
mapping | Listen over betegnelser, fra betegnelse til oprindelig oplysning, til POST /v1/redact/restore |
changes | Den præcise position for hver ændring i din tekst og i redacted |
findings | Alt, hvad lagene fandt, med positioner, type, sikkerhed og lag |
skipped | Tal, der ligner CPR-numre, som reglerne lod stå i teksten, med begrundelsen |
Kontrollér resultatet
Ingen metode kan garantere, at teksten ikke længere kan føres tilbage til en person. Kontrollér resultatet, før du bruger det, og behandl listen over betegnelser og de ekstra rapporter som personoplysninger.
Se jeres opsætning først
GET /v1/access viser, hvad din nøgle har adgang til, hvor hvert lag behandler tekst for jeres organisation, hvilke NER-steder og modeller et kald kan vælge, og hvilke grænser der gælder. Kaldet sender ingen tekst og kører ingen model.
curl https://api.komplai.dk/v1/access \
-H "Authorization: Bearer $KOMPLAI_TOKEN"Under services[].hosting.processing.layers står ét punkt pr. lag. Punktet for ner viser stederne og modellerne, og hvert punkt for llm viser sprogmodellerne til den behandling. En model med available: true kan vælges, og reason fortæller, hvorfor en anden ikke kan, fx not_validated for en model, der ikke er valideret til Redact. Punktet for ner, forkortet:
{
"detector": "ner",
"places": [
{ "id": "eu-de", "location": "EU · Germany", "available": true, "default": true },
{ "id": "local", "location": "Local infrastructure · Denmark", "available": false, "reason": "unconfigured" }
],
"models": [
{ "id": "danish-pii-ner-v1.3.0", "name": "Dansk NER 1.3.0", "status": "stable", "default": true, "places": ["eu-de", "local"] }
]
}text_contract.jobs_accepting_submissions viser, om tekstjobs tages imod lige nu.
Vælg lagene
detectors tager ét, to eller alle tre lag. Uden feltet kører regex og ner.
| Lag | Hvad det finder | Hvor det kører |
|---|---|---|
regex | Regler for CPR-numre, telefonnumre, mailadresser og mere | komplais servere i Tyskland (EU) |
ner | En model for navne, organisationer og adresser | NER-stedet: komplais servere i Tyskland eller lokal infrastruktur i Danmark |
llm | En sprogmodel for det, regler og NER overser, fx helbredsoplysninger i fritekst | Lokal infrastruktur i Danmark eller komplais EU-cloud |
Sprogmodellen læser teksten i dele på højst 12.000 tegn og kan bruge op til et minut. Kan svaret for en del ikke bruges, spørges der igen i to overlappende halvdele. Kan et svar stadig ikke bruges, fejler kaldet med incomplete_detection eller invalid_detection, og du får intet resultat.
Organisationens egne Redact-regler gælder altid i POST /v1/redact, POST /v1/redact/detect, tekstjobs og filer. En administrator skriver dem i hubben under Organisation › Redact › Regler; Regler i Redact viser hvordan.
Et tal, der ligner et CPR-nummer, men ikke svarer til en mulig fødselsdato, bliver stående i teksten. Bed om include: ["skipped"] for at få hvert tal med begrundelsen. Sådan et tal kan stadig identificere en person, fx et erstatningspersonnummer med dag plus 60.
NER-steder og -modeller
nerDeployment bestemmer, hvor laget ner kører:
eu-de: komplais servere i Tyskland (EU).local: komplais lokale infrastruktur i Danmark.
Udelad feltet for at bruge standardstedet, det sted GET /v1/access markerer med default: true. Angiv kun local, når GET /v1/access viser stedet som tilgængeligt for det kald, du bruger: stederne har available for kald med detectors og detect.available for POST /v1/redact/detect og kald uden detectors.
nerModel vælger en NER-model ud fra dens id i GET /v1/access. Udelad feltet for at bruge standardmodellen. POST /v1/redact/detect og kald uden detectors kører kun standardmodellen.
curl https://api.komplai.dk/v1/redact \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "Borgeren Mette Kjærgaard Holm bor på Fiktivvej 12, 8000 Aarhus C.",
"detectors": ["ner"],
"nerDeployment": "eu-de",
"nerModel": "danish-pii-ner-v1.3.0"
}'configuration.nerDeployment og configuration.nerModel i svaret viser, hvad der kørte. Et sted, der ikke kan bruges, giver ner_location_unavailable og nævner stedet. En ukendt eller utilgængelig model giver ner_model_unknown eller ner_model_unavailable. NER flytter aldrig til et andet sted eller en anden model.
Sprogmodeller og behandling
processing bestemmer, hvor laget llm kører:
local(standard): komplais lokale infrastruktur i Danmark. Den tæller ikke med i AI-forbruget, og køen deles med andre organisationer, uden prioritet.eu-cloud: komplais EU-cloud i Frankrig. Den svarer hurtigere, kræver, at EU-behandling er godkendt for jeres organisation, og forbruget tæller med i organisationens månedlige loft for AI-forbrug. Hvert kald til modellen tæller for sig, også en del, der spørges om igen i halvdele.
model vælger en sprogmodel, der er valideret til Redact til den behandling, ud fra dens id i laget llm i GET /v1/access. Udelad feltet for at bruge standardmodellen. En model, der ikke er valideret til Redact, giver llm_model_not_validated, og en lokal model, som den lokale infrastruktur ikke tilbyder lige nu, giver local_model_unavailable.
curl https://api.komplai.dk/v1/redact \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "Sagsbehandleren talte med Mette Kjærgaard Holm om hendes diabetes.",
"detectors": ["regex", "ner", "llm"],
"processing": "local",
"model": "qwen3.8-27b-q8",
"include": ["findings"]
}'Svaret erstatter også helbredsoplysningen, "Sagsbehandleren talte med [PERSON-1] om hendes [HELBRED-1].", og configuration.llmModel viser, hvilken model der kørte.
API'et skifter aldrig selv mellem local og eu-cloud og vælger aldrig en anden model. Når det månedlige loft for AI-forbrug er nået, stopper kald i EU-cloud med ai_credit_exhausted; lokal behandling virker stadig.
Korte tekster eller tekstjobs
| Kald | Tekstgrænse | Hvad du får |
|---|---|---|
| POST /v1/redact/detect | 16.000 | Fund med positioner i din tekst. Teksten ændres ikke, der kører ingen sprogmodel, og organisationens regler bruges. |
| POST /v1/redact | 750.000 | Den pseudonymiserede tekst i svaret, når arbejdet kan blive færdigt inden for 300 sekunder. |
| POST /v1/redact/jobs | 2.000.000 | Et tekstjob, der gemmes krypteret og behandles i baggrunden. |
Grænserne og alle positioner tæller UTF-16-tegn som i JavaScript og .NET. Et tekstjob på 2.000.000 tegn svarer til omkring 800 normalsider.
Før et synkront kald kører, beregner API'et tiden ud fra komplais målte hastigheder. Kan kørslen ikke blive færdig på 300 sekunder, afvises den med use_job, estimatedSeconds og holdSeconds, og intet behandles eller afregnes. Beregningen kan ikke tage højde for sprogmodellen i EU-cloud eller ventetid i den fælles kø, så sådan en kørsel kan stadig slutte med processing_timeout. Send lange tekster og kørsler i EU-cloud som tekstjobs.
Du kan også sende POST /v1/redact med headeren Prefer: respond-async. Så svarer kaldet 202 med et tekstjob, præcis som POST /v1/redact/jobs. Uden headeren bliver et kald aldrig til et job.
Kør et tekstjob
- Send teksten til POST /v1/redact/jobs med et nyt UUID i
Idempotency-Key. Svaret er 202 med jobbetsid, ogLocationpeger på dets status. - Læs GET /v1/redact/jobs/{id}, indtil
stateersucceeded. Vent mindst 2 sekunder mellem hver læsning, for hver læsning tæller med i din grænse for kald. - Hent resultatet på GET /v1/redact/jobs/{id}/result. Det er det samme, som POST /v1/redact returnerer.
- Slet jobbet med DELETE /v1/redact/jobs/{id}, når du har det, du skal bruge.
Byg body ud fra en tekstfil med jq, og send den:
jq -n --rawfile text sagsakt.txt \
'{text: $text, detectors: ["regex", "ner"], include: ["mapping"]}' > job.json
curl -i https://api.komplai.dk/v1/redact/jobs \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
--data @job.json{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "queued",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": { "completed": 0, "total": 0 },
"reused": false
}Sæt id'et i JOB_ID, og læs status, hent resultatet og slet jobbet:
curl "https://api.komplai.dk/v1/redact/jobs/$JOB_ID" \
-H "Authorization: Bearer $KOMPLAI_TOKEN"
curl "https://api.komplai.dk/v1/redact/jobs/$JOB_ID/result" \
-H "Authorization: Bearer $KOMPLAI_TOKEN"
curl -X DELETE "https://api.komplai.dk/v1/redact/jobs/$JOB_ID" \
-H "Authorization: Bearer $KOMPLAI_TOKEN"Det skal du vide om tekstjobs:
stateerqueued,running,succeeded,failed,cancelledellerinvalidated. De tre sidste er endelige og harerrormed årsagen. Resultatet svarer 202, mens jobbet kører, og 410, når det sluttede uden resultat.- Afbrydes forbindelsen, mens du sender, så send det samme kald igen med samme
Idempotency-Key. Så længe jobbet findes, får du det samme job tilbage (reused: true) i stedet for et nyt. Brug aldrig samme nøgle til en anden tekst; det giver idempotency_conflict. - Et job tilhører den nøgle, der oprettede det. En anden nøgle får 404, og når organisationens integrationsnøgle fornyes eller tilbagekaldes, kan dens jobs ikke længere læses.
- Et job har ingen tidsgrænse, så længe det kommer videre. Et job, der ikke kommer videre i 65 minutter, fejler med redact_job_stalled. Et job, der afbrydes, fx ved en genstart, fortsætter fra sit krypterede kontrolpunkt. Et kald til EU-cloud, der var i gang, sendes igen én gang og tæller med i det månedlige loft for AI-forbrug som alle andre kald.
- Tekstjobs med personoplysninger kræver en godkendt opbevaringspolitik for jeres organisation (approved_redact_storage_policy_required).
PDF- og Word-filer
Læsning af PDF- og Word-filer er i Beta. POST /v1/redact/file tager en PDF-fil med tekstlag eller en Word-fil i .docx som base64 i JSON, udtrækker teksten og kører den samme behandling som for tekst med de samme valg. Svaret er pseudonymiseret tekst, ikke en fil med maskeret indhold. pages giver hver sides positioner i den udtrukne tekst og i redacted. I en .docx er siderne brødteksten delt ved de sideskift, Word har gemt, og derefter sidehoveder, sidefødder, fodnoter og slutnoter som én del hver. Ud over rapporterne ovenfor tager include også source: den udtrukne tekst, som positionerne henviser til.
jq -n --rawfile data <(base64 < afgoerelse.pdf | tr -d '\n') \
'{file: {filename: "afgoerelse.pdf", data: $data}, detectors: ["regex", "ner"], include: ["mapping"]}' > file.json
curl https://api.komplai.dk/v1/redact/file \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H "Content-Type: application/json" \
--data @file.json- Højst 50 MiB, 2.000 PDF-sider og 750.000 UTF-16-tegn udtrukket tekst og de samme 300 sekunder som i POST /v1/redact. Længere filer sendes til POST /v1/redact/file/jobs, der udtrækker teksten, mens du venter, og sender den som et tekstjob. Læs, hent, sæt tilbage og slet det med kaldene under
/v1/redact/jobs/{id}. - Der kører ingen OCR. En side uden tekstlag, fx en scanning, afviser filen med scanned_pages_not_supported og sidenumrene. Med
allowPagesWithoutText: truebehandles de øvrige sider, og siderne uden tekst vises medhasText: false. - En adgangskodebeskyttet PDF giver encrypted_file. Word-filer i
.doclæses ikke; gem dem som.docx.
Sæt de oprindelige oplysninger tilbage
POST /v1/redact/restore sætter de oprindelige oplysninger tilbage i en tekst med betegnelser, fx et svar fra jeres egen model om den pseudonymiserede tekst. Send teksten og enten listen over betegnelser (mapping) præcis som POST /v1/redact returnerede den, eller job med id'et på dit eget færdige tekstjob, der blev sendt med include: ["mapping"] eller ["changes"]. Med et job læser komplai det gemte resultat, så du ikke selv skal opbevare listen.
curl https://api.komplai.dk/v1/redact/restore \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "Kære [PERSON-1]. Vi har modtaget din ansøgning og svarer på [EMAIL-1].",
"mapping": {
"[PERSON-1]": "Mette Kjærgaard Holm",
"[CPR-1]": "120385-1234",
"[ADRESSE-1]": "Fiktivvej 12, 8000 Aarhus C",
"[TLF-1]": "21 34 56 78",
"[EMAIL-1]": "mette.holm@example.invalid"
}
}'{
"text": "Kære Mette Kjærgaard Holm. Vi har modtaget din ansøgning og svarer på mette.holm@example.invalid.",
"restored": 2,
"unknownPlaceholders": []
}- Betegnelser genkendes uanset store og små bogstaver og mellemrum inden for parenteserne. En betegnelse, der ikke står på listen, bliver stående og vises i
unknownPlaceholders. - En fast erstatning fra organisationens regler, fx
[SAGSNR], kan stå for flere oprindelige oplysninger og sættes derfor aldrig tilbage. De faste erstatninger i teksten vises ifixedTokens. - Der kører ingen model, og kaldet tæller ikke med i AI-forbruget. Det tæller med i din grænse for kald.
- Svaret indeholder personoplysninger. Beskyt det som kildedokumentet.
Hvad der behandles hvor, og hvad der gemmes
- Regler kører på komplais servere i Tyskland (EU).
- NER kører i Tyskland (
eu-de) eller på lokal infrastruktur i Danmark (local). - Sprogmodellen kører på lokal infrastruktur i Danmark eller i komplais EU-cloud i Frankrig med
processing: "eu-cloud". Data forlader ikke EU. - Filer læses i hukommelsen på komplais API-servere i Tyskland og gemmes ikke. POST /v1/redact/file/jobs gemmer den udtrukne tekst krypteret som et tekstjob med jobbets opbevaringstid.
- Synkrone kald holder teksten i hukommelsen, mens kaldet kører. Resultatet findes kun i svaret.
- Tekstjobs holder teksten krypteret, mens jobbet venter eller kører, og resultatet krypteret, indtil du sletter jobbet, eller det udløber ved
expiresAt. Jobbet slettes ikke, når du henter resultatet. Opbevaringstiden følger organisationens opbevaringspolitik og regnes fra det tidspunkt, jobbet slutter. Uden en sådan politik gemmes et job med testdata i én time. - Forbrugs- og revisionsdata indeholder metadata, fx hvem der kaldte hvad og hvornår, ikke din tekst.
Hvor data behandles beskriver alle værktøjer.
Reference og fejl
- Redact-referencen: alle felter og svar med kodeeksempler og en konsol, hvor du kan prøve hvert kald.
- Konto-referencen: GET /v1/access.
- Fejl: alle koder, og hvad du kan gøre. Grænserne for kald står under Grænser.
- Redact i Word bruger den samme Redact direkte i et Word-dokument.