The exact text to pseudonymise: non-blank, valid Unicode, without NUL. At most 750,000 UTF-16 code units, as in JavaScript and .NET; every offset in the response counts the same way.
- Længde
- 1 til 750.000
Pseudonymise text, find personal data and put the originals back. Send short texts synchronously and long documents as encrypted text jobs; PDF and Word files are in beta. Organisation integration keys and personal keys both work here.
https://api.komplai.dkPOST /v1/redact
Replaces personal data with labels such as [PERSON-1] and returns the pseudonymised text in redacted. Choose the layers in detectors: regex (rules for CPR numbers, phone numbers, e-mail addresses and more), ner (a model for names, organisations and addresses) and llm (a language model for what rules and NER miss, such as health data in free text). Without detectors, regex and ner run. Rules run on komplai's servers in Germany (EU), and NER at the place in nerDeployment or, without one, at the default place GET /v1/access marks. The language model runs on komplai's local infrastructure in Denmark by default; processing eu-cloud uses komplai's EU cloud, needs llm in detectors and EU processing approved for your organisation, and counts towards the organisation's monthly AI spending cap. Your organisation's own redaction rules always apply.
Use this call for short texts such as a letter or a note: at most 750,000 UTF-16 code units, and work that finishes within 300 seconds. Before anything runs, the call estimates the time from komplai's measured speeds with an empty queue; a run whose estimate exceeds the hold is refused with 413 use_job, its estimatedSeconds and holdSeconds, and nothing is processed or charged. The estimate cannot cover an EU language model, which has no measured speed yet, time spent waiting in the shared queue, or a text that takes longer than a typical one: such a run can still reach the hold and end with 504 processing_timeout and no result, and calls already sent to the EU cloud count towards the monthly AI spending cap. Send long texts and EU runs as a text job (POST /v1/redact/jobs), or send this call with the header Prefer: respond-async to get 202 and a job instead. Without that header the call never turns into a job. PDF and Word files go to POST /v1/redact/file. Ask for include reports only when you need them: they contain the originals. A failed call returns no partial result. engine agentic (preview) requires the organisation administrator's opt-in (403 when absent) and processing local; it reads up to 2,000,000 UTF-16 code units as a job, while a synchronous call takes what it can finish in time. External lookups require explicit per-run sources and the administrator's current source permission. No method guarantees anonymity; check the result.
Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.
{{$guid}} uuid The layers to run, in any non-empty combination. regex: rules for CPR numbers, phone numbers, e-mail addresses and more. ner: a model for names, organisations and addresses. llm: a language model for what rules and NER miss, such as health data in free text; it can take up to a minute. It reads the text in parts of at most 12,000 characters. When its answer for a part cannot be used, that answer is discarded and the part is asked again in two overlapping halves, down to halves of 1,500 characters: at most 14 extra calls for a part. If an answer still cannot be used, the call fails with 502 invalid_detection or incomplete_detection and returns no result. Default regex and ner. The older field mode is still accepted but is not listed here: leave it out, because if you send both, they must agree (400 unsupported_engine_mode). engine agentic needs regex and llm, with optional ner.
["regex", "ner"] regex ner llm Where the language model (llm) runs. local (default): komplai's local infrastructure in Denmark, with no AI charge. eu-cloud: komplai's EU cloud, which answers faster. It needs llm in detectors and EU processing approved for your organisation, and its usage counts towards the organisation's monthly AI spending cap (429 ai_credit_exhausted when the cap is reached). Every call to the model, including a part asked again in halves, is checked against the cap and counted on its own. Name the model in model, or leave it out for the default model there. Rules always run on komplai's servers in Germany (EU), and NER at the place in nerDeployment or, without one, at the default place GET /v1/access marks. GET /v1/access names where each layer processes text for your organisation, including eu-cloud, in services[].hosting.processing.layers. The API never switches between local and eu-cloud by itself.
local eu-cloud local Where the ner layer runs: eu-de (komplai's servers in Germany, EU) or local (komplai's local infrastructure in Denmark). Leave it out, or send null, for the default place: the one GET /v1/access marks with default true in the ner layer's places (services[].hosting.processing.layers), eu-de unless komplai has changed it. Each place there has available and a reason for the operations with detectors, and detect with the same for POST /v1/redact/detect and the operations without detectors, so check that the place you name is available for the operation you call. A place that cannot be used now answers 503 ner_location_unavailable and names the place in nerDeployment; NER never moves to another place. Needs ner in detectors (400 ner_deployment_without_ner); any other value answers 400 invalid_ner_deployment. The response names the place in configuration.nerDeployment (nerDeployment on POST /v1/redact/detect).
eu-de local null The NER model, by id from the ner layer's models in GET /v1/access. Leave it out, or send null, for the default model. An unknown id answers 400 ner_model_unknown, and a retired one or one that does not run at the place you name 400 ner_model_unavailable; a preview model needs your organisation's Redact preview, which an organisation integration key does not have (403 ner_model_preview_required). POST /v1/redact/detect, and the text operations without detectors, run only the default model (400 ner_model_unavailable for another). A model that is not set up at the default place on this server answers 503 ner_model_unconfigured; NER never runs another model. Needs ner in detectors (400 ner_model_without_ner). The response names the model in configuration.nerModel (nerModel on POST /v1/redact/detect).
null The language model for llm, by id from GET /v1/access: the models of the llm layer for the processing you choose. Leave it out, or send null, for the default model there. Only models validated for Redact at that processing are accepted (400 llm_model_not_validated): qwen3.8-27b-q8 for local and mistral-small-3.2-24b-instruct-2506 for eu-cloud. GET /v1/access also lists models with reason not_validated, which cannot be chosen. A local model that local infrastructure does not offer right now answers 503 local_model_unavailable, and an EU model your organisation's EU route does not have answers 409 model_not_enabled. Without model, the default must be validated too: on local the server's default model, on eu-cloud the EU model the person behind a personal key saved, else the model on your organisation's EU route (409 llm_model_not_validated). The API never picks another model. Needs llm in detectors and engine pipeline (400 llm_model_not_applicable). configuration.llmModel names the model that ran.
null Extra reports. Each contains originals: protect the response as personal information. mapping: label to original, for POST /v1/redact/restore. changes: exact positions in your text and in redacted. findings: everything the layers found. skipped: CPR-shaped numbers the regex layer left in redacted because their digits do not decode to a plausible birth date, with the reason. A skipped number can still identify a person, for example an erstatningspersonnummer with day + 60. skipped is filled only when regex runs.
[] mapping findings changes skipped Preview. Leave out. pipeline (default) runs the chosen detectors. agentic is an experimental method for organisations whose administrator has turned on the Redact Agentic preview (403 agentic_preview_not_enabled otherwise); an organisation integration key gets 403 integration_not_permitted. It needs processing local and detectors regex and llm, with optional ner. It reads the text in windows, so it takes the operation's own text limit; a long document belongs in a text job.
pipeline agentic pipeline Preview. Leave out. Lookup sources for engine agentic, chosen for each call. Each needs the administrator's approval and configured access; an unapproved or unavailable source refuses the call (403 agentic_lookup_not_allowed or 503 agentic_lookup_unavailable) and is never silently dropped. Default none.
[] cvr-official bbr web dar wikidata-local The pseudonymised text and what ran. The include reports you asked for contain originals.
The choices that took effect. llmModel names the language model when it is known, and llmReasoningEffort the reasoning effort it was sent: by the llm layer, and on eu-cloud by mode semantic without detectors too. nerModel and nerDeployment name the NER model and place when you chose them, and nerDeployment also when NER ran at another place than eu-de.
What actually ran: detectorsRun lists the layers, and the counts appear when they were measured. A missing count does not mean zero. llmOccurrenceRepairs counts llm findings whose quote occurs once in the text but whose occurrence number pointed past it; each was placed on that one match. llmResolvedFindings counts llm findings whose quote could not be placed exactly and that were placed on every span equal to the quote once spacing and line breaks, invisible characters, typographic quotes and dashes, and for quotes of two or more words or with a digit, letter case are ignored; each is an exact span of the text. llmWindows counts the language model's answers the result is made of. llmSplits counts answers that could not be used and were discarded; each made two more calls, one for each half of its part of the text.
Returned with mapping: one entry per label, with its type, original, confidence and source layer.
Everything the layers found, with offsets in your text and the layer that found each in source.
Each replacement with its offsets in your text (start, end) and in redacted (outputStart, outputEnd). Apply them in reverse order of outputStart to rebuild your exact text.
CPR-shaped numbers the regex layer declined and no final change covers, with a reason code and an English explanation. They remain in redacted and can still identify a person, for example an erstatningspersonnummer with day + 60 (reported as cpr_invalid_date). Empty when the regex layer did not run (NER- or LLM-only detectors, or engine agentic).
Only with Prefer: respond-async: the text is a job. Location points to its status; poll it, then read the result.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time The request was refused before processing.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.invalid_text_encoding text contains NUL or a lone UTF-16 surrogate.unsupported_redact_engine engine is not one of the documented values.engine_retired engine review, the separate LLM engine, is retired. Send engine pipeline, or leave engine out, with detectors ["regex", "llm"]; hint says the same. Nothing was reserved or processed.unsupported_redact_mode mode is not regex, ner or semantic.invalid_detectors detectors is empty, has an unknown or repeated value, or more than three values.unsupported_engine_mode mode disagrees with detectors. Leave mode out when you send detectors.invalid_processing processing is not local or eu-cloud.unsupported_processing processing eu-cloud needs llm in detectors (and engine pipeline). Add llm to detectors.unsupported_redact_policy policy is not all-detected.invalid_include include has an unknown or repeated value.invalid_ner_deployment nerDeployment is not eu-de or local.ner_deployment_without_ner nerDeployment was sent, but ner is not in detectors (or mode is regex).ner_model_without_ner nerModel was sent, but ner is not in detectors (or mode is regex).ner_model_unknown No NER model has the id in nerModel. GET /v1/access lists the models you may choose.ner_model_unavailable The NER model in nerModel is retired or does not run at the chosen place. A model other than the default also needs detectors.llm_model_not_applicable model was sent, but llm is not in detectors, or engine is not pipeline.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.unsupported_engine_detectors The detectors do not fit engine agentic: it needs regex and llm, with optional ner.invalid_sources sources has an unknown or repeated value.unsupported_engine_sources sources was sent without engine agentic.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_choice_not_allowed The organisation does not allow this processing (local infrastructure or EU cloud) through the API, or the connection is not made available through the API.processing_not_enabled The processing is not enabled for the app in the organisation: EU processing is not approved and enabled, or the agreement keeps processing on local infrastructure.processing_not_approved The organisation's processing approval for the app is missing or was withdrawn.app_not_assigned The key's person lost the app or their membership while the request was admitted.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.ai_credit_not_granted No monthly AI spending cap is set up for this month, so eu-cloud cannot run.ner_model_preview_required The NER model in nerModel is a preview. It needs your organisation's Redact preview, which an organisation integration key does not have.integration_not_permitted An organisation integration key cannot use this operation or this option.agentic_preview_not_enabled The organisation's administrator has not turned on the Redact Agentic preview.agentic_lookup_not_allowed A source in sources is not approved by the organisation's administrator.Conflict with the current state.
processing_policy_changed Your organisation's redaction rules changed while the request ran. Send it again.model_not_enabled The model is not one you may use at this processing, or it is not offered there right now.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.reasoning_effort_not_supported The reasoning effort komplai set for this EU language model in Redact is not one the model accepts on your organisation's EU route. Nothing was sent to the model, and the API does not send another effort.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.Too large.
text_too_large text is over the operation's limit in UTF-16 code units, or the body is over its byte limit.use_job The run cannot finish within the 300 seconds a synchronous call may take. estimatedSeconds is komplai's estimate from its measured speeds, with an empty queue; holdSeconds is the limit. Nothing was processed or charged. Send the same body as a text job (POST /v1/redact/jobs), or this call with Prefer: respond-async.processing_complexity_exceeded The text needs more work than its length allows: more candidate matches or matched characters than the per-character bounds in /v1/access, coreference matching work beyond its per-character bound (for example one name nested inside itself thousands of times), or more time for the organisation rules than their limit, which grows with the text and the number of rules. The bounds grow with the text, so splitting it rarely helps. Nothing partial is returned.result_too_large The result would be over 32 MiB. Ask for fewer include reports or split the text.context_limit The input and the requested output do not fit the model: max_tokens is over the model's limit, the input with max_tokens is over its context, or, in Redact, a part of the text does not fit even after it was asked again in halves down to 1,500 characters.The body has no Content-Type, or one the API does not read, such as XML or form data. Send application/json.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.ai_credit_exhausted The organisation's monthly AI spending cap for EU cloud is reached, or its own lower limit, or on a pilot the pilot's total allowance. Local processing keeps working.person_ai_credit_exhausted Your personal AI limit is reached (personal keys only).processing_capacity_busy All organisation-rule workers in this API process are busy. There is no queue: try again after Retry-After.A processing service failed. No partial result is returned.
incomplete_detection A detection layer did not finish the whole text. No partial result is returned.invalid_detection A detection layer returned output that failed validation. For llm: an answer that still could not be used after its part of the text was asked again in halves down to 1,500 characters.detection_service_unavailable The detection service could not be reached or failed.unsafe_placeholder A fixed replacement token from your organisation's rules occurs in the text or collides with a label.service_unavailable The model failed or could not be reached, or local infrastructure is not set up for this call right now.invalid_response The model's answer failed validation, so nothing was returned.agent_no_progress Redact Agentic stopped making progress: several rounds in a row read nothing new, found nothing and moved to no new step. No partial result is returned.Processing is not available right now.
ner_location_unavailable The NER place cannot be used now: komplai has not switched it on for the API, or it did not answer. nerDeployment names the place. NER never moves to another place; GET /v1/access shows which places are available.ner_model_unconfigured The NER model in nerModel is not set up at the default place on this server.local_model_unavailable The local language model in model is validated for Redact, but local infrastructure does not offer it right now. The API never picks another model.redact_runtime_unavailable A selected layer (NER or the language model) is not set up or not available right now.semantic_runtime_not_configured No local language model is set up for llm.detector_unavailable detectors includes ner, but NER is not set up.detection_service_unavailable The detection service could not be reached or failed.access_service_unavailable Keys and access could not be checked.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).chat_cloud_unavailable The organisation's EU cloud setup cannot be used right now.gateway_misconfigured The connection to the detection service or the language model is misconfigured.incoherent_redaction_policy Your organisation's redaction and allow rules conflict for this text.agentic_disabled engine agentic is switched off on this server.agentic_lookup_unavailable A source in sources is not available right now.model_busy The language model on local infrastructure cannot take this call right now: its shared queue is full, or no node can run the model (for example while it restarts). Wait Retry-After seconds; a text job waits by itself.service_unavailable The model failed or could not be reached, or local infrastructure is not set up for this call right now.The call timed out.
processing_timeout The call took more than 300 seconds, or the client disconnected. Send long texts as text jobs.model_stalled The language model stopped answering: its connection was silent, or it ran past the time its answer needs at the model's measured speed. No partial result is returned.model_queue_expired The language model's shared queue on local infrastructure did not reach this call before its deadline. Try again later, or send it as a text job, which waits for its turn./v1/redactcurl 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", "changes"]
}'$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$body = [ordered]@{
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', 'changes')
} | ConvertTo-Json -Depth 100
$request = @{
Method = 'Post'
Uri = 'https://api.komplai.dk/v1/redact'
Headers = $headers
ContentType = 'application/json; charset=utf-8'
Body = $body
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.post(
"https://api.komplai.dk/v1/redact",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
json={
"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", "changes"],
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
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", "changes"],
}),
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.komplai.dk/v1/redact");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
request.Content = new StringContent(@"{
""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"", ""changes""]
}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"redacted": "Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [EMAIL-1].",
"engine": "pipeline",
"mode": "ner",
"processing": "local",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 154,
"charsOut": 103,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "ner",
"detectors": ["regex", "ner"],
"sources": [],
"processing": "local"
},
"execution": {
"completed": true,
"detectorsRun": ["regex", "ner"],
"detectionPasses": 1,
"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"
},
"entries": [
{
"placeholder": "[PERSON-1]",
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "medium",
"source": "ner"
},
{
"placeholder": "[CPR-1]",
"type": "cpr",
"value": "120385-1234",
"confidence": "high",
"source": "regex"
},
{
"placeholder": "[ADRESSE-1]",
"type": "address",
"value": "Fiktivvej 12, 8000 Aarhus C",
"confidence": "high",
"source": "ner"
},
{
"placeholder": "[TLF-1]",
"type": "phone",
"value": "21 34 56 78",
"confidence": "medium",
"source": "regex"
},
{
"placeholder": "[EMAIL-1]",
"type": "email",
"value": "mette.holm@example.invalid",
"confidence": "high",
"source": "regex"
}
],
"changes": [
{
"start": 9,
"end": 29,
"outputStart": 9,
"outputEnd": 19,
"original": "Mette Kjærgaard Holm",
"replacement": "[PERSON-1]",
"type": "person"
},
{
"start": 39,
"end": 50,
"outputStart": 29,
"outputEnd": 36,
"original": "120385-1234",
"replacement": "[CPR-1]",
"type": "cpr"
},
{
"start": 59,
"end": 86,
"outputStart": 45,
"outputEnd": 56,
"original": "Fiktivvej 12, 8000 Aarhus C",
"replacement": "[ADRESSE-1]",
"type": "address"
},
{
"start": 109,
"end": 120,
"outputStart": 79,
"outputEnd": 86,
"original": "21 34 56 78",
"replacement": "[TLF-1]",
"type": "phone"
},
{
"start": 127,
"end": 153,
"outputStart": 93,
"outputEnd": 102,
"original": "mette.holm@example.invalid",
"replacement": "[EMAIL-1]",
"type": "email"
}
]
}{
"redacted": "Borgeren [PERSON-1] bor på [ADRESSE-1].",
"engine": "pipeline",
"mode": "ner",
"processing": "local",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 65,
"charsOut": 39,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "ner",
"detectors": ["ner"],
"sources": [],
"processing": "local",
"nerModel": "danish-pii-ner-v1.3.0",
"nerDeployment": "eu-de"
},
"execution": {
"completed": true,
"detectorsRun": ["ner"],
"detectionPasses": 1,
"nerCalls": 1,
"llmCalls": 0
}
}{
"redacted": "Sagsbehandleren talte med [PERSON-1] om hendes [HELBRED-1].",
"engine": "pipeline",
"mode": "semantic",
"processing": "local",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 66,
"charsOut": 59,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "semantic",
"detectors": ["regex", "ner", "llm"],
"sources": [],
"processing": "local",
"llmModel": "qwen3.8-27b-q8"
},
"execution": {
"completed": true,
"detectorsRun": ["regex", "ner", "llm"],
"detectionPasses": 1,
"nerCalls": 1,
"llmCalls": 1
},
"findings": [
{
"start": 26,
"end": 46,
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "medium",
"source": "ner",
"entityId": "person:Mette Kjærgaard Holm"
},
{
"start": 57,
"end": 65,
"type": "health",
"value": "diabetes",
"confidence": "medium",
"source": "llm"
}
]
}{
"redacted": "Sagsbehandleren talte med [PERSON-1] om hendes [HELBRED-1].",
"engine": "pipeline",
"mode": "semantic",
"processing": "eu-cloud",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 66,
"charsOut": 59,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "semantic",
"detectors": ["regex", "ner", "llm"],
"sources": [],
"processing": "eu-cloud",
"llmModel": "mistral-small-3.2-24b-instruct-2506"
},
"execution": {
"completed": true,
"detectorsRun": ["regex", "ner", "llm"],
"detectionPasses": 1,
"nerCalls": 1,
"llmCalls": 1
},
"mapping": {
"[PERSON-1]": "Mette Kjærgaard Holm",
"[HELBRED-1]": "diabetes"
},
"entries": [
{
"placeholder": "[PERSON-1]",
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "medium",
"source": "ner"
},
{
"placeholder": "[HELBRED-1]",
"type": "health",
"value": "diabetes",
"confidence": "medium",
"source": "llm"
}
]
}{
"redacted": "Gammelt nummer 150677-8642, erstatningspersonnummer 720385-1234 og cpr-nr. [CPR-1].",
"engine": "pipeline",
"mode": "regex",
"processing": "local",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 87,
"charsOut": 83,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "regex",
"detectors": ["regex"],
"sources": [],
"processing": "local"
},
"execution": {
"completed": true,
"detectorsRun": ["regex"],
"detectionPasses": 1,
"nerCalls": 0,
"llmCalls": 0
},
"skipped": [
{
"start": 15,
"end": 26,
"value": "150677-8642",
"type": "cpr",
"reason": "cpr_birth_year_out_of_range",
"detail": "Birth year 1877 is before 1880"
},
{
"start": 52,
"end": 63,
"value": "720385-1234",
"type": "cpr",
"reason": "cpr_invalid_date",
"detail": "Day 72 does not exist in month 03 of 1985"
}
]
}{
"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
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "processing_policy_changed",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/processing_policy_changed"
}{
"error": "text_too_large",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/text_too_large"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "incomplete_detection",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/incomplete_detection"
}{
"error": "ner_location_unavailable",
"nerDeployment": "local",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/ner_location_unavailable"
}{
"error": "processing_timeout",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/processing_timeout"
}POST /v1/redact/detect
Returns what regex and NER find, with UTF-16 offsets into your text, without changing it. At most 16,000 UTF-16 code units and 100,000 bytes per call; split longer texts or use POST /v1/redact. Rules run on komplai's servers in Germany (EU), and NER at the place you choose with nerDeployment or, without one, at the default place GET /v1/access marks (it lists the places). No language model runs here. Your organisation's own redaction rules apply, as on POST /v1/redact: a rule's match is returned with type and source custom and the rule's label in customLabel, and a finding that an allow rule covers is left out.
redact:detect Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
Where the ner layer runs: eu-de (komplai's servers in Germany, EU) or local (komplai's local infrastructure in Denmark). Leave it out, or send null, for the default place: the one GET /v1/access marks with default true in the ner layer's places (services[].hosting.processing.layers), eu-de unless komplai has changed it. Each place there has available and a reason for the operations with detectors, and detect with the same for POST /v1/redact/detect and the operations without detectors, so check that the place you name is available for the operation you call. A place that cannot be used now answers 503 ner_location_unavailable and names the place in nerDeployment; NER never moves to another place. Needs ner in detectors (400 ner_deployment_without_ner); any other value answers 400 invalid_ner_deployment. The response names the place in configuration.nerDeployment (nerDeployment on POST /v1/redact/detect).
eu-de local null The NER model, by id from the ner layer's models in GET /v1/access. Leave it out, or send null, for the default model. An unknown id answers 400 ner_model_unknown, and a retired one or one that does not run at the place you name 400 ner_model_unavailable; a preview model needs your organisation's Redact preview, which an organisation integration key does not have (403 ner_model_preview_required). POST /v1/redact/detect, and the text operations without detectors, run only the default model (400 ner_model_unavailable for another). A model that is not set up at the default place on this server answers 503 ner_model_unconfigured; NER never runs another model. Needs ner in detectors (400 ner_model_without_ner). The response names the model in configuration.nerModel (nerModel on POST /v1/redact/detect).
null What regex and NER found. The text itself is not changed or returned. When you named the NER place or model, nerDeployment and nerModel name what ran.
The request was refused before processing.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.unsupported_pilot_mode mode is not regex or ner, or semantic is true. No language model runs on this operation.invalid_ner_deployment nerDeployment is not eu-de or local.ner_deployment_without_ner nerDeployment was sent, but ner is not in detectors (or mode is regex).ner_model_without_ner nerModel was sent, but ner is not in detectors (or mode is regex).ner_model_unknown No NER model has the id in nerModel. GET /v1/access lists the models you may choose.ner_model_unavailable The NER model in nerModel is retired or does not run at the chosen place. A model other than the default also needs detectors.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_choice_not_allowed The organisation does not allow this processing (local infrastructure or EU cloud) through the API, or the connection is not made available through the API.processing_not_enabled The processing is not enabled for the app in the organisation: EU processing is not approved and enabled, or the agreement keeps processing on local infrastructure.processing_not_approved The organisation's processing approval for the app is missing or was withdrawn.app_not_assigned The key's person lost the app or their membership while the request was admitted.ner_model_preview_required The NER model in nerModel is a preview. It needs your organisation's Redact preview, which an organisation integration key does not have.Too large.
exceeds_ner_window text is over 16,000 UTF-16 code units, or the body is over 100,000 bytes. Use POST /v1/redact for longer texts.The body has no Content-Type, or one the API does not read, such as XML or form data. Send application/json.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.A processing service failed. No partial result is returned.
detection_service_unavailable The detection service could not be reached or failed.invalid_detection A detection layer returned output that failed validation. For llm: an answer that still could not be used after its part of the text was asked again in halves down to 1,500 characters.incomplete_detection A detection layer did not finish the whole text. No partial result is returned.Processing is not available right now.
ner_location_unavailable The NER place cannot be used now: komplai has not switched it on for the API, or it did not answer. nerDeployment names the place. NER never moves to another place; GET /v1/access shows which places are available.gateway_misconfigured The connection to the detection service or the language model is misconfigured.redact_runtime_unavailable A selected layer (NER or the language model) is not set up or not available right now.access_service_unavailable Keys and access could not be checked.detection_service_unavailable The detection service could not be reached or failed./v1/redact/detectcurl https://api.komplai.dk/v1/redact/detect \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"text": "Ring til Mette Kjærgaard Holm på 21 34 56 78.",
"mode": "ner"
}'$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$body = [ordered]@{
text = 'Ring til Mette Kjærgaard Holm på 21 34 56 78.'
mode = 'ner'
} | ConvertTo-Json -Depth 100
$request = @{
Method = 'Post'
Uri = 'https://api.komplai.dk/v1/redact/detect'
Headers = $headers
ContentType = 'application/json; charset=utf-8'
Body = $body
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.post(
"https://api.komplai.dk/v1/redact/detect",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
json={
"text": "Ring til Mette Kjærgaard Holm på 21 34 56 78.",
"mode": "ner",
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/detect", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "Ring til Mette Kjærgaard Holm på 21 34 56 78.",
mode: "ner",
}),
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.komplai.dk/v1/redact/detect");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
request.Content = new StringContent(@"{
""text"": ""Ring til Mette Kjærgaard Holm på 21 34 56 78."",
""mode"": ""ner""
}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"findings": [
{
"start": 9,
"end": 29,
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "high",
"source": "ner"
},
{
"start": 33,
"end": 44,
"type": "phone",
"value": "21 34 56 78",
"confidence": "medium",
"source": "regex"
}
],
"truncated": false,
"degraded": false
}{
"findings": [
{
"start": 9,
"end": 29,
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "high",
"source": "ner"
},
{
"start": 33,
"end": 44,
"type": "phone",
"value": "21 34 56 78",
"confidence": "medium",
"source": "regex"
}
],
"truncated": false,
"degraded": false,
"nerDeployment": "eu-de"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "exceeds_ner_window",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/exceeds_ner_window"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "detection_service_unavailable",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/detection_service_unavailable"
}{
"error": "ner_location_unavailable",
"nerDeployment": "local",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/ner_location_unavailable"
}POST /v1/redact/restore
Puts the originals back into text with labels such as [PERSON-1], for example an answer from your own model or workflow step. Send either the mapping from POST /v1/redact (asked for with include ["mapping"]) or the id of your own finished text job; with a job, komplai reads its retained result and you do not hold the mapping. Labels match regardless of case and spaces inside the brackets. Labels the mapping does not contain stay unchanged and are listed in unknownPlaceholders. Fixed replacement tokens from your organisation's redaction rules can stand for several originals, so they are never restored; those in the text are listed in fixedTokens. No model runs and the call has no AI charge; it counts against your request rate. The response contains originals: protect it as personal information.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
Body har en af disse former.
Label to original, as POST /v1/redact returns it with include ["mapping"]; send it unchanged. Keys in the exact [LABEL-N] form are restored. Any other key is a fixed replacement token from your organisation's redaction rules, such as [SAGSNR]: it can stand for several originals, so it is never restored and is listed in fixedTokens when the text contains it. Keys hold at most 128 UTF-16 code units without surrounding spaces, with at most 500 fixed tokens. Keys and values together may hold 2,000,000 UTF-16 code units. Send either mapping or job. At most 100,000 entries.
The text with the originals put back. It contains personal data; protect it like the source document.
Labels found in the text that the mapping does not contain, in [LABEL-N] form and sorted. They are left unchanged. A label that does not start with a letter, such as [2026_SAG-2], is listed only when the mapping uses that label, so ranges such as [1-3] are not.
The request was refused before processing.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.invalid_text_encoding text contains NUL or a lone UTF-16 surrogate.invalid_restore_source Send exactly one of mapping and job.invalid_job job is not a UUID.invalid_mapping mapping is not an object, or a value is empty, not a string, or contains NUL or a lone surrogate.invalid_placeholder A mapping key is empty, longer than 128 UTF-16 code units, has surrounding spaces, contains NUL or a lone surrogate, or is `__proto__`, `constructor` or `prototype`.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_access_withdrawn Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it.Not found.
not_found No job with this id for this key. A job is visible only to the key that created it, and it disappears when it expires.Conflict with the current state.
job_not_finished The job is still queued or running; state says which. Try again after Retry-After seconds.mapping_not_available The job kept neither mapping nor changes; hint says how to submit it again.The job ended without a result. error is the job's code (see GET /v1/redact/jobs/{id}) and state its state.
redact_job_cancelled The job was deleted or cancelled.redact_job_failed The job failed for a reason that is not passed on, for example a reached monthly AI spending cap or a failing EU cloud model.redact_job_unavailable The job ended without a result and without a stored reason.Too large.
text_too_large text is over the operation's limit in UTF-16 code units, or the body is over its byte limit.restore_too_large The body, the mapping (more than 100,000 entries, more than 2,000,000 UTF-16 code units or more than 500 fixed tokens) or the restored text (over 8,000,000 UTF-16 code units) is too large.The body has no Content-Type, or one the API does not read, such as XML or form data. Send application/json.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.Processing is not available right now.
redact_job_integrity_failed The job's encrypted data could not be read.redact_job_service_unavailable The job store failed.redact_restore_unavailable Unexpected failure while restoring.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).access_service_unavailable Keys and access could not be checked./v1/redact/restorecurl 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"
}
}'$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$body = [ordered]@{
text = 'Kære [PERSON-1]. Vi har modtaget din ansøgning og svarer på [EMAIL-1].'
mapping = [ordered]@{
'[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'
}
} | ConvertTo-Json -Depth 100
$request = @{
Method = 'Post'
Uri = 'https://api.komplai.dk/v1/redact/restore'
Headers = $headers
ContentType = 'application/json; charset=utf-8'
Body = $body
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.post(
"https://api.komplai.dk/v1/redact/restore",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
json={
"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",
},
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/restore", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
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",
},
}),
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.komplai.dk/v1/redact/restore");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
request.Content = new StringContent(@"{
""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""
}
}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"text": "Kære Mette Kjærgaard Holm. Vi har modtaget din ansøgning og svarer på mette.holm@example.invalid.",
"restored": 2,
"unknownPlaceholders": []
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "not_found",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/not_found"
}{
"error": "job_not_finished",
"state": "running",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/job_not_finished"
}{
"error": "redact_job_cancelled",
"state": "cancelled",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_job_cancelled"
}{
"error": "text_too_large",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/text_too_large"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "redact_job_integrity_failed",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_job_integrity_failed"
}POST /v1/redact/jobs
Stores the text encrypted and pseudonymises it in the background with the same options as POST /v1/redact, up to 2,000,000 UTF-16 code units (about 800 standard pages of 2,400 characters). Use it for long documents, also below the 300-second limit of a synchronous call. The answer is 202 with the job's id, and Location points to its status. Poll GET /v1/redact/jobs/{id}, at most every few seconds because reads count against the request limit, then read GET /v1/redact/jobs/{id}/result. Ask for include mapping or changes if you want to restore from the job with POST /v1/redact/restore. Personal data needs an approved storage policy for text jobs; the result stays encrypted until you delete the job or it expires, and the retention period counts from when the job ends. A job has no time limit of its own while it makes progress: it waits for the shared queue, every model call has a budget from the model's measured speed, and a job that makes no progress for 65 minutes fails with redact_job_stalled. A job belongs to the key that created it. A NER place or local language model the job names is checked against the settings when it is submitted, and whether it answers when the job runs; one that does not answer then fails the job with its code. A job that is interrupted (a restart or a lost worker) resumes from its encrypted checkpoint and sends at most the step that was in flight again: a call to the language model on local infrastructure gets its answer back from the queue when the queue finished it, and runs once more when the interruption cut it off, a call to the EU cloud is sent again once and counted towards the monthly AI spending cap like any call, and a register lookup is sent again; each is logged. After three interruptions the job ends with redact_job_attempts_exhausted. engine agentic (preview) requires the organisation administrator's opt-in (403 when absent) and processing local, and reads up to the same 2,000,000 UTF-16 code units in windows; external sources require explicit per-run selection and current administrator permission.
Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.
{{$guid}} uuid The layers to run, in any non-empty combination. regex: rules for CPR numbers, phone numbers, e-mail addresses and more. ner: a model for names, organisations and addresses. llm: a language model for what rules and NER miss, such as health data in free text; it can take up to a minute. It reads the text in parts of at most 12,000 characters. When its answer for a part cannot be used, that answer is discarded and the part is asked again in two overlapping halves, down to halves of 1,500 characters: at most 14 extra calls for a part. If an answer still cannot be used, the call fails with 502 invalid_detection or incomplete_detection and returns no result. Default regex and ner. The older field mode is still accepted but is not listed here: leave it out, because if you send both, they must agree (400 unsupported_engine_mode). engine agentic needs regex and llm, with optional ner.
["regex", "ner"] regex ner llm Where the language model (llm) runs. local (default): komplai's local infrastructure in Denmark, with no AI charge. eu-cloud: komplai's EU cloud, which answers faster. It needs llm in detectors and EU processing approved for your organisation, and its usage counts towards the organisation's monthly AI spending cap (429 ai_credit_exhausted when the cap is reached). Every call to the model, including a part asked again in halves, is checked against the cap and counted on its own. Name the model in model, or leave it out for the default model there. Rules always run on komplai's servers in Germany (EU), and NER at the place in nerDeployment or, without one, at the default place GET /v1/access marks. GET /v1/access names where each layer processes text for your organisation, including eu-cloud, in services[].hosting.processing.layers. The API never switches between local and eu-cloud by itself.
local eu-cloud local Where the ner layer runs: eu-de (komplai's servers in Germany, EU) or local (komplai's local infrastructure in Denmark). Leave it out, or send null, for the default place: the one GET /v1/access marks with default true in the ner layer's places (services[].hosting.processing.layers), eu-de unless komplai has changed it. Each place there has available and a reason for the operations with detectors, and detect with the same for POST /v1/redact/detect and the operations without detectors, so check that the place you name is available for the operation you call. A place that cannot be used now answers 503 ner_location_unavailable and names the place in nerDeployment; NER never moves to another place. Needs ner in detectors (400 ner_deployment_without_ner); any other value answers 400 invalid_ner_deployment. The response names the place in configuration.nerDeployment (nerDeployment on POST /v1/redact/detect).
eu-de local null The NER model, by id from the ner layer's models in GET /v1/access. Leave it out, or send null, for the default model. An unknown id answers 400 ner_model_unknown, and a retired one or one that does not run at the place you name 400 ner_model_unavailable; a preview model needs your organisation's Redact preview, which an organisation integration key does not have (403 ner_model_preview_required). POST /v1/redact/detect, and the text operations without detectors, run only the default model (400 ner_model_unavailable for another). A model that is not set up at the default place on this server answers 503 ner_model_unconfigured; NER never runs another model. Needs ner in detectors (400 ner_model_without_ner). The response names the model in configuration.nerModel (nerModel on POST /v1/redact/detect).
null The language model for llm, by id from GET /v1/access: the models of the llm layer for the processing you choose. Leave it out, or send null, for the default model there. Only models validated for Redact at that processing are accepted (400 llm_model_not_validated): qwen3.8-27b-q8 for local and mistral-small-3.2-24b-instruct-2506 for eu-cloud. GET /v1/access also lists models with reason not_validated, which cannot be chosen. A local model that local infrastructure does not offer right now answers 503 local_model_unavailable, and an EU model your organisation's EU route does not have answers 409 model_not_enabled. Without model, the default must be validated too: on local the server's default model, on eu-cloud the EU model the person behind a personal key saved, else the model on your organisation's EU route (409 llm_model_not_validated). The API never picks another model. Needs llm in detectors and engine pipeline (400 llm_model_not_applicable). configuration.llmModel names the model that ran.
null Extra reports. Each contains originals: protect the response as personal information. mapping: label to original, for POST /v1/redact/restore. changes: exact positions in your text and in redacted. findings: everything the layers found. skipped: CPR-shaped numbers the regex layer left in redacted because their digits do not decode to a plausible birth date, with the reason. A skipped number can still identify a person, for example an erstatningspersonnummer with day + 60. skipped is filled only when regex runs.
[] mapping findings changes skipped Preview. Leave out. pipeline (default) runs the chosen detectors. agentic is an experimental method for organisations whose administrator has turned on the Redact Agentic preview (403 agentic_preview_not_enabled otherwise); an organisation integration key gets 403 integration_not_permitted. It needs processing local and detectors regex and llm, with optional ner. It reads the text in windows, so it takes the operation's own text limit; a long document belongs in a text job.
pipeline agentic pipeline Preview. Leave out. Lookup sources for engine agentic, chosen for each call. Each needs the administrator's approval and configured access; an unapproved or unavailable source refuses the call (403 agentic_lookup_not_allowed or 503 agentic_lookup_unavailable) and is never silently dropped. Default none.
[] cvr-official bbr web dar wikidata-local The job is accepted. Location points to its status; poll it, then read the result.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time The request was refused before processing.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.invalid_text_encoding text contains NUL or a lone UTF-16 surrogate.unsupported_redact_engine engine is not one of the documented values.engine_retired engine review, the separate LLM engine, is retired. Send engine pipeline, or leave engine out, with detectors ["regex", "llm"]; hint says the same. Nothing was reserved or processed.unsupported_redact_mode mode is not regex, ner or semantic.invalid_detectors detectors is empty, has an unknown or repeated value, or more than three values.unsupported_engine_mode mode disagrees with detectors. Leave mode out when you send detectors.invalid_processing processing is not local or eu-cloud.unsupported_processing processing eu-cloud needs llm in detectors (and engine pipeline). Add llm to detectors.unsupported_redact_policy policy is not all-detected.invalid_include include has an unknown or repeated value.invalid_ner_deployment nerDeployment is not eu-de or local.ner_deployment_without_ner nerDeployment was sent, but ner is not in detectors (or mode is regex).ner_model_without_ner nerModel was sent, but ner is not in detectors (or mode is regex).ner_model_unknown No NER model has the id in nerModel. GET /v1/access lists the models you may choose.ner_model_unavailable The NER model in nerModel is retired or does not run at the chosen place. A model other than the default also needs detectors.llm_model_not_applicable model was sent, but llm is not in detectors, or engine is not pipeline.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.unsupported_engine_detectors The detectors do not fit engine agentic: it needs regex and llm, with optional ner.invalid_sources sources has an unknown or repeated value.unsupported_engine_sources sources was sent without engine agentic.invalid_idempotency_key Idempotency-Key is not a UUID, or it was sent more than once.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.approved_redact_storage_policy_required Your organisation processes personal data but has no approved storage policy for text jobs.processing_access_withdrawn Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it.processing_choice_not_allowed The organisation does not allow this processing (local infrastructure or EU cloud) through the API, or the connection is not made available through the API.processing_not_enabled The processing is not enabled for the app in the organisation: EU processing is not approved and enabled, or the agreement keeps processing on local infrastructure.processing_not_approved The organisation's processing approval for the app is missing or was withdrawn.app_not_assigned The key's person lost the app or their membership while the request was admitted.ner_model_preview_required The NER model in nerModel is a preview. It needs your organisation's Redact preview, which an organisation integration key does not have.integration_not_permitted An organisation integration key cannot use this operation or this option.agentic_preview_not_enabled The organisation's administrator has not turned on the Redact Agentic preview.agentic_lookup_not_allowed A source in sources is not approved by the organisation's administrator.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.Conflict with the current state.
idempotency_conflict This Idempotency-Key was used with a different body. Use a new UUID for a new job.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.model_not_enabled The model is not one you may use at this processing, or it is not offered there right now.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.reasoning_effort_not_supported The reasoning effort komplai set for this EU language model in Redact is not one the model accepts on your organisation's EU route. Nothing was sent to the model, and the API does not send another effort.Too large.
text_too_large text is over the operation's limit in UTF-16 code units, or the body is over its byte limit.The body has no Content-Type, or one the API does not read, such as XML or form data. Send application/json.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.Processing is not available right now.
redact_jobs_not_enabled Text jobs are not accepted right now; GET /v1/access shows text_contract.jobs_accepting_submissions.redact_job_service_unavailable The job store failed.redact_job_integrity_failed The job's encrypted data could not be read.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).chat_cloud_unavailable The organisation's EU cloud setup cannot be used right now.access_service_unavailable Keys and access could not be checked.ner_location_unavailable The NER place cannot be used now: komplai has not switched it on for the API, or it did not answer. nerDeployment names the place. NER never moves to another place; GET /v1/access shows which places are available.ner_model_unconfigured The NER model in nerModel is not set up at the default place on this server.redact_runtime_unavailable A selected layer (NER or the language model) is not set up or not available right now.agentic_disabled engine agentic is switched off on this server.agentic_lookup_unavailable A source in sources is not available right now./v1/redact/jobscurl https://api.komplai.dk/v1/redact/jobs \
-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", "changes"]
}'$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$body = [ordered]@{
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', 'changes')
} | ConvertTo-Json -Depth 100
$request = @{
Method = 'Post'
Uri = 'https://api.komplai.dk/v1/redact/jobs'
Headers = $headers
ContentType = 'application/json; charset=utf-8'
Body = $body
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.post(
"https://api.komplai.dk/v1/redact/jobs",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
json={
"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", "changes"],
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/jobs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
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", "changes"],
}),
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.komplai.dk/v1/redact/jobs");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
request.Content = new StringContent(@"{
""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"", ""changes""]
}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"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
}{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "succeeded",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 1,
"total": 1
},
"reused": true
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "idempotency_conflict",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/idempotency_conflict"
}{
"error": "text_too_large",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/text_too_large"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "redact_jobs_not_enabled",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_jobs_not_enabled"
}GET /v1/redact/jobs/{id}
state is queued, running, succeeded, failed, cancelled or invalidated. Read the result once it is succeeded. A failed, cancelled or invalidated job is final and carries error with the reason. Wait at least 2 seconds between reads: each read counts against the request limit.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
The job's status. A failed, cancelled or invalidated job carries error, for example redact_job_cancelled, processing_access_withdrawn, processing_outcome_uncertain, redact_job_attempts_exhausted, redact_job_stalled, redact_job_progress_failed, engine_retired, model_stalled, model_queue_expired, context_limit, agent_no_progress, rate_limited, ai_credit_exhausted, person_ai_credit_exhausted, redact_job_integrity_failed, incomplete_detection, invalid_detection, detection_service_unavailable, result_too_large, processing_complexity_exceeded, redact_runtime_unavailable, ner_location_unavailable, ner_model_unknown, ner_model_unavailable, ner_model_preview_required, ner_model_unconfigured, llm_model_not_validated, local_model_unavailable, reasoning_effort_not_supported, processing_choice_not_allowed, redact_job_failed. When access to the job was withdrawn, the read answers 403 processing_access_withdrawn instead; that is final too.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time The request was refused before processing.
Bad Request Fastify's reason phrase: a path parameter does not have the documented form, for example a job id that is not a UUID.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_access_withdrawn Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it.Not found.
not_found No job with this id for this key. A job is visible only to the key that created it, and it disappears when it expires.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.Processing is not available right now.
redact_job_service_unavailable The job store failed.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).access_service_unavailable Keys and access could not be checked./v1/redact/jobs/{id}curl https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c \
-H "Authorization: Bearer $KOMPLAI_TOKEN"$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$request = @{
Method = 'Get'
Uri = 'https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c'
Headers = $headers
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.get(
"https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c", {
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
},
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"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
}
}{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "running",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 0,
"total": 1
}
}{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "succeeded",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 1,
"total": 1
}
}{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "failed",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 0,
"total": 1
},
"error": "detection_service_unavailable"
}{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "invalidated",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 0,
"total": 1
},
"error": "redact_job_attempts_exhausted"
}{
"error": "Bad Request",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/bad-request"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "not_found",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/not_found"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "redact_job_service_unavailable",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_job_service_unavailable"
}DELETE /v1/redact/jobs/{id}
Cancels the job if it is still queued or running and deletes its encrypted text and result at once. Cancellation is final. Only the encrypted replay fingerprint for Idempotency-Key remains until the original expiry. Deleting a job that is already cancelled answers the same 200. Send no body. Deleting does not count against the request limit.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
The job is cancelled and its text and result are deleted.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time The request was refused before processing.
invalid_input The request is not what the operation documents, for example invalid JSON, a field that is not listed or a value out of range.Bad Request Fastify's reason phrase: a path parameter does not have the documented form, for example a job id that is not a UUID.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_access_withdrawn Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it.Not found.
not_found No job with this id for this key. A job is visible only to the key that created it, and it disappears when it expires.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.Processing is not available right now.
redact_job_service_unavailable The job store failed.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).access_service_unavailable Keys and access could not be checked./v1/redact/jobs/{id}curl -X DELETE https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c \
-H "Authorization: Bearer $KOMPLAI_TOKEN"$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$request = @{
Method = 'Delete'
Uri = 'https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c'
Headers = $headers
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.delete(
"https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
},
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Delete, "https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "cancelled",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 0,
"total": 1
},
"error": "redact_job_cancelled"
}{
"error": "Bad Request",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/bad-request"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "not_found",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/not_found"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "redact_job_service_unavailable",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_job_service_unavailable"
}GET /v1/redact/jobs/{id}/result
200 with the same result as POST /v1/redact once the job has succeeded. 202 with the job's status while it is queued or running; wait Retry-After seconds. 410 when it failed, was cancelled or was invalidated. Reading does not delete the encrypted result: DELETE removes text and result at once, and expiry removes the job and its replay fingerprint.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
The job's result, the same as POST /v1/redact returns for its body. Reading it does not delete it.
The choices that took effect. llmModel names the language model when it is known, and llmReasoningEffort the reasoning effort it was sent: by the llm layer, and on eu-cloud by mode semantic without detectors too. nerModel and nerDeployment name the NER model and place when you chose them, and nerDeployment also when NER ran at another place than eu-de.
What actually ran: detectorsRun lists the layers, and the counts appear when they were measured. A missing count does not mean zero. llmOccurrenceRepairs counts llm findings whose quote occurs once in the text but whose occurrence number pointed past it; each was placed on that one match. llmResolvedFindings counts llm findings whose quote could not be placed exactly and that were placed on every span equal to the quote once spacing and line breaks, invisible characters, typographic quotes and dashes, and for quotes of two or more words or with a digit, letter case are ignored; each is an exact span of the text. llmWindows counts the language model's answers the result is made of. llmSplits counts answers that could not be used and were discarded; each made two more calls, one for each half of its part of the text.
Returned with mapping: one entry per label, with its type, original, confidence and source layer.
Everything the layers found, with offsets in your text and the layer that found each in source.
Each replacement with its offsets in your text (start, end) and in redacted (outputStart, outputEnd). Apply them in reverse order of outputStart to rebuild your exact text.
CPR-shaped numbers the regex layer declined and no final change covers, with a reason code and an English explanation. They remain in redacted and can still identify a person, for example an erstatningspersonnummer with day + 60 (reported as cpr_invalid_date). Empty when the regex layer did not run (NER- or LLM-only detectors, or engine agentic).
The job is still queued or running. The body is its status.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time The request was refused before processing.
Bad Request Fastify's reason phrase: a path parameter does not have the documented form, for example a job id that is not a UUID.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_access_withdrawn Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it.Not found.
not_found No job with this id for this key. A job is visible only to the key that created it, and it disappears when it expires.The job ended without a result. error is the job's code (see GET /v1/redact/jobs/{id}) and state its state.
redact_job_cancelled The job was deleted or cancelled.redact_job_failed The job failed for a reason that is not passed on, for example a reached monthly AI spending cap or a failing EU cloud model.redact_job_attempts_exhausted The text job was interrupted three times, for example by restarts, and was stopped. No partial result is kept.Refused for now. Wait the seconds in Retry-After before you try again.
rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.Processing is not available right now.
redact_job_integrity_failed The job's encrypted data could not be read.redact_job_service_unavailable The job store failed.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).access_service_unavailable Keys and access could not be checked./v1/redact/jobs/{id}/resultcurl https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c/result \
-H "Authorization: Bearer $KOMPLAI_TOKEN"$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$request = @{
Method = 'Get'
Uri = 'https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c/result'
Headers = $headers
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.get(
"https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c/result",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c/result", {
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
},
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.komplai.dk/v1/redact/jobs/3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c/result");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"redacted": "Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [EMAIL-1].",
"engine": "pipeline",
"mode": "ner",
"processing": "local",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 154,
"charsOut": 103,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "ner",
"detectors": ["regex", "ner"],
"sources": [],
"processing": "local"
},
"execution": {
"completed": true,
"detectorsRun": ["regex", "ner"],
"detectionPasses": 1,
"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"
},
"entries": [
{
"placeholder": "[PERSON-1]",
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "medium",
"source": "ner"
},
{
"placeholder": "[CPR-1]",
"type": "cpr",
"value": "120385-1234",
"confidence": "high",
"source": "regex"
},
{
"placeholder": "[ADRESSE-1]",
"type": "address",
"value": "Fiktivvej 12, 8000 Aarhus C",
"confidence": "high",
"source": "ner"
},
{
"placeholder": "[TLF-1]",
"type": "phone",
"value": "21 34 56 78",
"confidence": "medium",
"source": "regex"
},
{
"placeholder": "[EMAIL-1]",
"type": "email",
"value": "mette.holm@example.invalid",
"confidence": "high",
"source": "regex"
}
],
"changes": [
{
"start": 9,
"end": 29,
"outputStart": 9,
"outputEnd": 19,
"original": "Mette Kjærgaard Holm",
"replacement": "[PERSON-1]",
"type": "person"
},
{
"start": 39,
"end": 50,
"outputStart": 29,
"outputEnd": 36,
"original": "120385-1234",
"replacement": "[CPR-1]",
"type": "cpr"
},
{
"start": 59,
"end": 86,
"outputStart": 45,
"outputEnd": 56,
"original": "Fiktivvej 12, 8000 Aarhus C",
"replacement": "[ADRESSE-1]",
"type": "address"
},
{
"start": 109,
"end": 120,
"outputStart": 79,
"outputEnd": 86,
"original": "21 34 56 78",
"replacement": "[TLF-1]",
"type": "phone"
},
{
"start": 127,
"end": 153,
"outputStart": 93,
"outputEnd": 102,
"original": "mette.holm@example.invalid",
"replacement": "[EMAIL-1]",
"type": "email"
}
]
}{
"id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
"state": "running",
"createdAt": "2026-10-20T08:00:00.000Z",
"expiresAt": "2026-10-20T09:00:00.000Z",
"progress": {
"completed": 0,
"total": 1
}
}{
"error": "Bad Request",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/bad-request"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "not_found",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/not_found"
}{
"error": "redact_job_cancelled",
"state": "cancelled",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_job_cancelled"
}{
"error": "rate_limited",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/rate_limited"
}{
"error": "redact_job_integrity_failed",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_job_integrity_failed"
}POST /v1/redact/file
Beta. Send a PDF with a text layer or a Word .docx as base64 in JSON; komplai extracts its text and runs the same Redact processing as for text, with the same options. The response is pseudonymised text, not a redacted file. No OCR runs: a scanned page is refused (422 scanned_pages_not_supported, with the page numbers) unless allowPagesWithoutText is true. The text is extracted on komplai's API servers (EU · Germany) in memory; the file is not stored. File problems: 400 unsupported_file_type, file_type_mismatch, invalid_file_encoding, empty_file; 413 file_too_large, too_many_pages, text_too_large, file_too_complex; 422 invalid_file, encrypted_file, no_text_found, scanned_pages_not_supported; 429 processing_capacity_busy while other files are being read. No method guarantees anonymity; check the result. At most 750,000 UTF-16 code units of extracted text, and work that finishes within 300 seconds: a run whose estimate exceeds that is refused with 413 use_job and its estimate before anything is processed, and one the estimate cannot cover (an EU language model, a wait in the shared queue) can still end with 504 processing_timeout, as on POST /v1/redact. Longer files go to POST /v1/redact/file/jobs, or send this call with Prefer: respond-async to get 202 and a job. pages gives each page's offsets in the extracted text and in redacted. Agentic processing has the same requirements as on POST /v1/redact.
Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.
{{$guid}} uuid The layers to run, in any non-empty combination. regex: rules for CPR numbers, phone numbers, e-mail addresses and more. ner: a model for names, organisations and addresses. llm: a language model for what rules and NER miss, such as health data in free text; it can take up to a minute. It reads the text in parts of at most 12,000 characters. When its answer for a part cannot be used, that answer is discarded and the part is asked again in two overlapping halves, down to halves of 1,500 characters: at most 14 extra calls for a part. If an answer still cannot be used, the call fails with 502 invalid_detection or incomplete_detection and returns no result. Default regex and ner. The older field mode is still accepted but is not listed here: leave it out, because if you send both, they must agree (400 unsupported_engine_mode). engine agentic needs regex and llm, with optional ner.
["regex", "ner"] regex ner llm Where the language model (llm) runs. local (default): komplai's local infrastructure in Denmark, with no AI charge. eu-cloud: komplai's EU cloud, which answers faster. It needs llm in detectors and EU processing approved for your organisation, and its usage counts towards the organisation's monthly AI spending cap (429 ai_credit_exhausted when the cap is reached). Every call to the model, including a part asked again in halves, is checked against the cap and counted on its own. Name the model in model, or leave it out for the default model there. Rules always run on komplai's servers in Germany (EU), and NER at the place in nerDeployment or, without one, at the default place GET /v1/access marks. GET /v1/access names where each layer processes text for your organisation, including eu-cloud, in services[].hosting.processing.layers. The API never switches between local and eu-cloud by itself.
local eu-cloud local Where the ner layer runs: eu-de (komplai's servers in Germany, EU) or local (komplai's local infrastructure in Denmark). Leave it out, or send null, for the default place: the one GET /v1/access marks with default true in the ner layer's places (services[].hosting.processing.layers), eu-de unless komplai has changed it. Each place there has available and a reason for the operations with detectors, and detect with the same for POST /v1/redact/detect and the operations without detectors, so check that the place you name is available for the operation you call. A place that cannot be used now answers 503 ner_location_unavailable and names the place in nerDeployment; NER never moves to another place. Needs ner in detectors (400 ner_deployment_without_ner); any other value answers 400 invalid_ner_deployment. The response names the place in configuration.nerDeployment (nerDeployment on POST /v1/redact/detect).
eu-de local null The NER model, by id from the ner layer's models in GET /v1/access. Leave it out, or send null, for the default model. An unknown id answers 400 ner_model_unknown, and a retired one or one that does not run at the place you name 400 ner_model_unavailable; a preview model needs your organisation's Redact preview, which an organisation integration key does not have (403 ner_model_preview_required). POST /v1/redact/detect, and the text operations without detectors, run only the default model (400 ner_model_unavailable for another). A model that is not set up at the default place on this server answers 503 ner_model_unconfigured; NER never runs another model. Needs ner in detectors (400 ner_model_without_ner). The response names the model in configuration.nerModel (nerModel on POST /v1/redact/detect).
null The language model for llm, by id from GET /v1/access: the models of the llm layer for the processing you choose. Leave it out, or send null, for the default model there. Only models validated for Redact at that processing are accepted (400 llm_model_not_validated): qwen3.8-27b-q8 for local and mistral-small-3.2-24b-instruct-2506 for eu-cloud. GET /v1/access also lists models with reason not_validated, which cannot be chosen. A local model that local infrastructure does not offer right now answers 503 local_model_unavailable, and an EU model your organisation's EU route does not have answers 409 model_not_enabled. Without model, the default must be validated too: on local the server's default model, on eu-cloud the EU model the person behind a personal key saved, else the model on your organisation's EU route (409 llm_model_not_validated). The API never picks another model. Needs llm in detectors and engine pipeline (400 llm_model_not_applicable). configuration.llmModel names the model that ran.
null Preview. Leave out. pipeline (default) runs the chosen detectors. agentic is an experimental method for organisations whose administrator has turned on the Redact Agentic preview (403 agentic_preview_not_enabled otherwise); an organisation integration key gets 403 integration_not_permitted. It needs processing local and detectors regex and llm, with optional ner. It reads the text in windows, so it takes the operation's own text limit; a long document belongs in a text job.
pipeline agentic pipeline Preview. Leave out. Lookup sources for engine agentic, chosen for each call. Each needs the administrator's approval and configured access; an unapproved or unavailable source refuses the call (403 agentic_lookup_not_allowed or 503 agentic_lookup_unavailable) and is never silently dropped. Default none.
[] cvr-official bbr web dar wikidata-local The pseudonymised text of the file, with each page's offsets in the extracted text and in redacted.
The choices that took effect. llmModel names the language model when it is known, and llmReasoningEffort the reasoning effort it was sent: by the llm layer, and on eu-cloud by mode semantic without detectors too. nerModel and nerDeployment name the NER model and place when you chose them, and nerDeployment also when NER ran at another place than eu-de.
What actually ran: detectorsRun lists the layers, and the counts appear when they were measured. A missing count does not mean zero. llmOccurrenceRepairs counts llm findings whose quote occurs once in the text but whose occurrence number pointed past it; each was placed on that one match. llmResolvedFindings counts llm findings whose quote could not be placed exactly and that were placed on every span equal to the quote once spacing and line breaks, invisible characters, typographic quotes and dashes, and for quotes of two or more words or with a digit, letter case are ignored; each is an exact span of the text. llmWindows counts the language model's answers the result is made of. llmSplits counts answers that could not be used and were discarded; each made two more calls, one for each half of its part of the text.
Returned with mapping: one entry per label, with its type, original, confidence and source layer.
Everything the layers found, with offsets in your text and the layer that found each in source.
Each replacement with its offsets in your text (start, end) and in redacted (outputStart, outputEnd). Apply them in reverse order of outputStart to rebuild your exact text.
CPR-shaped numbers the regex layer declined and no final change covers, with a reason code and an English explanation. They remain in redacted and can still identify a person, for example an erstatningspersonnummer with day + 60 (reported as cpr_invalid_date). Empty when the regex layer did not run (NER- or LLM-only detectors, or engine agentic).
Only with Prefer: respond-async: the file's text is a job, exactly as POST /v1/redact/file/jobs answers.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time Offsets in the extracted text, which is the job's source. Read the result from GET /v1/redact/jobs/{id}/result; with include changes, its changes map these offsets into redacted.
The request was refused before processing.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.invalid_file file is missing or malformed (filename missing, blank, longer than 255 characters or with control characters; data not a string; an unknown key), or the PDF or Word file itself is damaged or not a Word document.invalid_include include has an unknown or repeated value.unsupported_redact_engine engine is not one of the documented values.engine_retired engine review, the separate LLM engine, is retired. Send engine pipeline, or leave engine out, with detectors ["regex", "llm"]; hint says the same. Nothing was reserved or processed.unsupported_redact_mode mode is not regex, ner or semantic.invalid_detectors detectors is empty, has an unknown or repeated value, or more than three values.unsupported_engine_mode mode disagrees with detectors. Leave mode out when you send detectors.invalid_processing processing is not local or eu-cloud.unsupported_processing processing eu-cloud needs llm in detectors (and engine pipeline). Add llm to detectors.unsupported_redact_policy policy is not all-detected.invalid_ner_deployment nerDeployment is not eu-de or local.ner_deployment_without_ner nerDeployment was sent, but ner is not in detectors (or mode is regex).ner_model_without_ner nerModel was sent, but ner is not in detectors (or mode is regex).ner_model_unknown No NER model has the id in nerModel. GET /v1/access lists the models you may choose.ner_model_unavailable The NER model in nerModel is retired or does not run at the chosen place. A model other than the default also needs detectors.llm_model_not_applicable model was sent, but llm is not in detectors, or engine is not pipeline.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.unsupported_engine_detectors The detectors do not fit engine agentic: it needs regex and llm, with optional ner.invalid_sources sources has an unknown or repeated value.unsupported_engine_sources sources was sent without engine agentic.invalid_file_encoding file.data is empty or not base64.empty_file file.data decodes to nothing.unsupported_file_type The file is neither a PDF nor a Word .docx, by its content, its extension or its contentType.file_type_mismatch The extension or contentType disagrees with the file's content.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.processing_choice_not_allowed The organisation does not allow this processing (local infrastructure or EU cloud) through the API, or the connection is not made available through the API.processing_not_enabled The processing is not enabled for the app in the organisation: EU processing is not approved and enabled, or the agreement keeps processing on local infrastructure.processing_not_approved The organisation's processing approval for the app is missing or was withdrawn.app_not_assigned The key's person lost the app or their membership while the request was admitted.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.ai_credit_not_granted No monthly AI spending cap is set up for this month, so eu-cloud cannot run.ner_model_preview_required The NER model in nerModel is a preview. It needs your organisation's Redact preview, which an organisation integration key does not have.integration_not_permitted An organisation integration key cannot use this operation or this option.agentic_preview_not_enabled The organisation's administrator has not turned on the Redact Agentic preview.agentic_lookup_not_allowed A source in sources is not approved by the organisation's administrator.Conflict with the current state.
processing_policy_changed Your organisation's redaction rules changed while the request ran. Send it again.model_not_enabled The model is not one you may use at this processing, or it is not offered there right now.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.reasoning_effort_not_supported The reasoning effort komplai set for this EU language model in Redact is not one the model accepts on your organisation's EU route. Nothing was sent to the model, and the API does not send another effort.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.Too large.
file_too_large The file is over 50 MiB, or the body is over its byte limit.too_many_pages The PDF has more than 2,000 pages.file_too_complex Reading the file took more than 120 seconds or more resources than allowed (memory, ZIP entries, XML size or depth).text_too_large text is over the operation's limit in UTF-16 code units, or the body is over its byte limit.use_job The run cannot finish within the 300 seconds a synchronous call may take. estimatedSeconds is komplai's estimate from its measured speeds, with an empty queue; holdSeconds is the limit. Nothing was processed or charged. Send the same body as a text job (POST /v1/redact/jobs), or this call with Prefer: respond-async.processing_complexity_exceeded The text needs more work than its length allows: more candidate matches or matched characters than the per-character bounds in /v1/access, coreference matching work beyond its per-character bound (for example one name nested inside itself thousands of times), or more time for the organisation rules than their limit, which grows with the text and the number of rules. The bounds grow with the text, so splitting it rarely helps. Nothing partial is returned.result_too_large The result would be over 32 MiB. Ask for fewer include reports or split the text.context_limit The input and the requested output do not fit the model: max_tokens is over the model's limit, the input with max_tokens is over its context, or, in Redact, a part of the text does not fit even after it was asked again in halves down to 1,500 characters.The body has no Content-Type, or one the API does not read, such as XML or form data. Send application/json.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.The file cannot be read.
invalid_file file is missing or malformed (filename missing, blank, longer than 255 characters or with control characters; data not a string; an unknown key), or the PDF or Word file itself is damaged or not a Word document.encrypted_file The PDF is password protected.scanned_pages_not_supported A page has no text layer, for example a scan. No OCR runs. pages lists the pages; allowPagesWithoutText true processes the rest.no_text_found The file contains no text at all.Refused for now. Wait the seconds in Retry-After before you try again.
processing_capacity_busy All organisation-rule workers in this API process are busy. There is no queue: try again after Retry-After.rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.ai_credit_exhausted The organisation's monthly AI spending cap for EU cloud is reached, or its own lower limit, or on a pilot the pilot's total allowance. Local processing keeps working.person_ai_credit_exhausted Your personal AI limit is reached (personal keys only).A processing service failed. No partial result is returned.
incomplete_detection A detection layer did not finish the whole text. No partial result is returned.invalid_detection A detection layer returned output that failed validation. For llm: an answer that still could not be used after its part of the text was asked again in halves down to 1,500 characters.detection_service_unavailable The detection service could not be reached or failed.unsafe_placeholder A fixed replacement token from your organisation's rules occurs in the text or collides with a label.service_unavailable The model failed or could not be reached, or local infrastructure is not set up for this call right now.invalid_response The model's answer failed validation, so nothing was returned.agent_no_progress Redact Agentic stopped making progress: several rounds in a row read nothing new, found nothing and moved to no new step. No partial result is returned.Processing is not available right now.
redact_file_not_enabled File input is switched off on this server.file_extraction_unavailable The file reader could not start or stopped. This is not caused by the file.ner_location_unavailable The NER place cannot be used now: komplai has not switched it on for the API, or it did not answer. nerDeployment names the place. NER never moves to another place; GET /v1/access shows which places are available.ner_model_unconfigured The NER model in nerModel is not set up at the default place on this server.local_model_unavailable The local language model in model is validated for Redact, but local infrastructure does not offer it right now. The API never picks another model.redact_runtime_unavailable A selected layer (NER or the language model) is not set up or not available right now.semantic_runtime_not_configured No local language model is set up for llm.detector_unavailable detectors includes ner, but NER is not set up.detection_service_unavailable The detection service could not be reached or failed.access_service_unavailable Keys and access could not be checked.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).chat_cloud_unavailable The organisation's EU cloud setup cannot be used right now.gateway_misconfigured The connection to the detection service or the language model is misconfigured.incoherent_redaction_policy Your organisation's redaction and allow rules conflict for this text.agentic_disabled engine agentic is switched off on this server.agentic_lookup_unavailable A source in sources is not available right now.model_busy The language model on local infrastructure cannot take this call right now: its shared queue is full, or no node can run the model (for example while it restarts). Wait Retry-After seconds; a text job waits by itself.service_unavailable The model failed or could not be reached, or local infrastructure is not set up for this call right now.The call timed out.
processing_timeout The call took more than 300 seconds, or the client disconnected. Send long texts as text jobs.model_stalled The language model stopped answering: its connection was silent, or it ran past the time its answer needs at the model's measured speed. No partial result is returned.model_queue_expired The language model's shared queue on local infrastructure did not reach this call before its deadline. Try again later, or send it as a text job, which waits for its turn./v1/redact/filecurl https://api.komplai.dk/v1/redact/file \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"file": {
"filename": "afgoerelse.pdf",
"contentType": "application/pdf",
"data": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo="
},
"detectors": ["regex", "ner"],
"processing": "local",
"include": ["mapping"]
}'$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$body = [ordered]@{
file = [ordered]@{
filename = 'afgoerelse.pdf'
contentType = 'application/pdf'
data = 'JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo='
}
detectors = @('regex', 'ner')
processing = 'local'
include = @('mapping')
} | ConvertTo-Json -Depth 100
$request = @{
Method = 'Post'
Uri = 'https://api.komplai.dk/v1/redact/file'
Headers = $headers
ContentType = 'application/json; charset=utf-8'
Body = $body
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.post(
"https://api.komplai.dk/v1/redact/file",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
json={
"file": {
"filename": "afgoerelse.pdf",
"contentType": "application/pdf",
"data": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=",
},
"detectors": ["regex", "ner"],
"processing": "local",
"include": ["mapping"],
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/file", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
file: {
filename: "afgoerelse.pdf",
contentType: "application/pdf",
data: "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=",
},
detectors: ["regex", "ner"],
processing: "local",
include: ["mapping"],
}),
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.komplai.dk/v1/redact/file");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
request.Content = new StringContent(@"{
""file"": {
""filename"": ""afgoerelse.pdf"",
""contentType"": ""application/pdf"",
""data"": ""JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=""
},
""detectors"": [""regex"", ""ner""],
""processing"": ""local"",
""include"": [""mapping""]
}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"redacted": "Afgørelse til [PERSON-1]\ncpr-nr. [CPR-1], [ADRESSE-1]\n\nTelefon [TLF-1]\n[EMAIL-1]",
"engine": "pipeline",
"mode": "ner",
"processing": "local",
"policy": "all-detected",
"policyVersion": "redact-text-v1",
"offsetEncoding": "utf-16",
"charsIn": 131,
"charsOut": 80,
"truncated": false,
"degraded": false,
"configuration": {
"engine": "pipeline",
"mode": "ner",
"detectors": ["regex", "ner"],
"sources": [],
"processing": "local"
},
"execution": {
"completed": true,
"detectorsRun": ["regex", "ner"],
"detectionPasses": 1,
"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"
},
"entries": [
{
"placeholder": "[PERSON-1]",
"type": "person",
"value": "Mette Kjærgaard Holm",
"confidence": "medium",
"source": "ner"
},
{
"placeholder": "[CPR-1]",
"type": "cpr",
"value": "120385-1234",
"confidence": "high",
"source": "regex"
},
{
"placeholder": "[ADRESSE-1]",
"type": "address",
"value": "Fiktivvej 12, 8000 Aarhus C",
"confidence": "high",
"source": "ner"
},
{
"placeholder": "[TLF-1]",
"type": "phone",
"value": "21 34 56 78",
"confidence": "medium",
"source": "regex"
},
{
"placeholder": "[EMAIL-1]",
"type": "email",
"value": "mette.holm@example.invalid",
"confidence": "high",
"source": "regex"
}
],
"file": {
"type": "pdf",
"bytes": 1025,
"pageCount": 2
},
"pages": [
{
"number": 1,
"start": 0,
"end": 83,
"hasText": true,
"redactedStart": 0,
"redactedEnd": 53
},
{
"number": 2,
"start": 85,
"end": 131,
"hasText": true,
"redactedStart": 55,
"redactedEnd": 80
}
]
}{
"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,
"file": {
"type": "pdf",
"bytes": 1025,
"pageCount": 2
},
"pages": [
{
"number": 1,
"start": 0,
"end": 83,
"hasText": true
},
{
"number": 2,
"start": 85,
"end": 131,
"hasText": true
}
]
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "processing_policy_changed",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/processing_policy_changed"
}{
"error": "file_too_large",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/file_too_large"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "invalid_file",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_file"
}{
"error": "processing_capacity_busy",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/processing_capacity_busy"
}{
"error": "incomplete_detection",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/incomplete_detection"
}{
"error": "redact_file_not_enabled",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_file_not_enabled"
}{
"error": "processing_timeout",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/processing_timeout"
}POST /v1/redact/file/jobs
Beta. Send a PDF with a text layer or a Word .docx as base64 in JSON; komplai extracts its text and runs the same Redact processing as for text, with the same options. The response is pseudonymised text, not a redacted file. No OCR runs: a scanned page is refused (422 scanned_pages_not_supported, with the page numbers) unless allowPagesWithoutText is true. The text is extracted on komplai's API servers (EU · Germany) in memory; the file is not stored. File problems: 400 unsupported_file_type, file_type_mismatch, invalid_file_encoding, empty_file; 413 file_too_large, too_many_pages, text_too_large, file_too_complex; 422 invalid_file, encrypted_file, no_text_found, scanned_pages_not_supported; 429 processing_capacity_busy while other files are being read. No method guarantees anonymity; check the result. The text is extracted while you wait and submitted as a text job, exactly as POST /v1/redact/jobs, up to 2,000,000 UTF-16 code units. The 202 response adds the file's page offsets in the extracted text; poll and read the result, restore and delete with the /v1/redact/jobs/{id} operations.
Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.
redact:process Kaldene er rigtige: komplai behandler det, du sender, hvert kald tæller med i nøglens grænser, og behandling i EU-cloud tæller med i organisationens månedlige loft for AI-forbrug. Brug testdata.
En nøgle, der starter med kp_org_ eller kp_live_. Den bliver på denne side, til du forlader den, og sendes kun til api.komplai.dk.
Svar
Request-Id
Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.
{{$guid}} uuid The layers to run, in any non-empty combination. regex: rules for CPR numbers, phone numbers, e-mail addresses and more. ner: a model for names, organisations and addresses. llm: a language model for what rules and NER miss, such as health data in free text; it can take up to a minute. It reads the text in parts of at most 12,000 characters. When its answer for a part cannot be used, that answer is discarded and the part is asked again in two overlapping halves, down to halves of 1,500 characters: at most 14 extra calls for a part. If an answer still cannot be used, the call fails with 502 invalid_detection or incomplete_detection and returns no result. Default regex and ner. The older field mode is still accepted but is not listed here: leave it out, because if you send both, they must agree (400 unsupported_engine_mode). engine agentic needs regex and llm, with optional ner.
["regex", "ner"] regex ner llm Where the language model (llm) runs. local (default): komplai's local infrastructure in Denmark, with no AI charge. eu-cloud: komplai's EU cloud, which answers faster. It needs llm in detectors and EU processing approved for your organisation, and its usage counts towards the organisation's monthly AI spending cap (429 ai_credit_exhausted when the cap is reached). Every call to the model, including a part asked again in halves, is checked against the cap and counted on its own. Name the model in model, or leave it out for the default model there. Rules always run on komplai's servers in Germany (EU), and NER at the place in nerDeployment or, without one, at the default place GET /v1/access marks. GET /v1/access names where each layer processes text for your organisation, including eu-cloud, in services[].hosting.processing.layers. The API never switches between local and eu-cloud by itself.
local eu-cloud local Where the ner layer runs: eu-de (komplai's servers in Germany, EU) or local (komplai's local infrastructure in Denmark). Leave it out, or send null, for the default place: the one GET /v1/access marks with default true in the ner layer's places (services[].hosting.processing.layers), eu-de unless komplai has changed it. Each place there has available and a reason for the operations with detectors, and detect with the same for POST /v1/redact/detect and the operations without detectors, so check that the place you name is available for the operation you call. A place that cannot be used now answers 503 ner_location_unavailable and names the place in nerDeployment; NER never moves to another place. Needs ner in detectors (400 ner_deployment_without_ner); any other value answers 400 invalid_ner_deployment. The response names the place in configuration.nerDeployment (nerDeployment on POST /v1/redact/detect).
eu-de local null The NER model, by id from the ner layer's models in GET /v1/access. Leave it out, or send null, for the default model. An unknown id answers 400 ner_model_unknown, and a retired one or one that does not run at the place you name 400 ner_model_unavailable; a preview model needs your organisation's Redact preview, which an organisation integration key does not have (403 ner_model_preview_required). POST /v1/redact/detect, and the text operations without detectors, run only the default model (400 ner_model_unavailable for another). A model that is not set up at the default place on this server answers 503 ner_model_unconfigured; NER never runs another model. Needs ner in detectors (400 ner_model_without_ner). The response names the model in configuration.nerModel (nerModel on POST /v1/redact/detect).
null The language model for llm, by id from GET /v1/access: the models of the llm layer for the processing you choose. Leave it out, or send null, for the default model there. Only models validated for Redact at that processing are accepted (400 llm_model_not_validated): qwen3.8-27b-q8 for local and mistral-small-3.2-24b-instruct-2506 for eu-cloud. GET /v1/access also lists models with reason not_validated, which cannot be chosen. A local model that local infrastructure does not offer right now answers 503 local_model_unavailable, and an EU model your organisation's EU route does not have answers 409 model_not_enabled. Without model, the default must be validated too: on local the server's default model, on eu-cloud the EU model the person behind a personal key saved, else the model on your organisation's EU route (409 llm_model_not_validated). The API never picks another model. Needs llm in detectors and engine pipeline (400 llm_model_not_applicable). configuration.llmModel names the model that ran.
null Preview. Leave out. pipeline (default) runs the chosen detectors. agentic is an experimental method for organisations whose administrator has turned on the Redact Agentic preview (403 agentic_preview_not_enabled otherwise); an organisation integration key gets 403 integration_not_permitted. It needs processing local and detectors regex and llm, with optional ner. It reads the text in windows, so it takes the operation's own text limit; a long document belongs in a text job.
pipeline agentic pipeline Preview. Leave out. Lookup sources for engine agentic, chosen for each call. Each needs the administrator's approval and configured access; an unapproved or unavailable source refuses the call (403 agentic_lookup_not_allowed or 503 agentic_lookup_unavailable) and is never silently dropped. Default none.
[] cvr-official bbr web dar wikidata-local The file's text was extracted and submitted as a text job. Location points to its status.
Application retention deadline. A queued job expires this long after it was submitted; a running job is kept for as long as its worker is alive; when the job ends, the retention period counts from the end. Results remain encrypted until explicit deletion or expiry; reads do not consume them.
date-time Offsets in the extracted text, which is the job's source. Read the result from GET /v1/redact/jobs/{id}/result; with include changes, its changes map these offsets into redacted.
The request was refused before processing.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.invalid_file file is missing or malformed (filename missing, blank, longer than 255 characters or with control characters; data not a string; an unknown key), or the PDF or Word file itself is damaged or not a Word document.invalid_include include has an unknown or repeated value.unsupported_redact_engine engine is not one of the documented values.engine_retired engine review, the separate LLM engine, is retired. Send engine pipeline, or leave engine out, with detectors ["regex", "llm"]; hint says the same. Nothing was reserved or processed.unsupported_redact_mode mode is not regex, ner or semantic.invalid_detectors detectors is empty, has an unknown or repeated value, or more than three values.unsupported_engine_mode mode disagrees with detectors. Leave mode out when you send detectors.invalid_processing processing is not local or eu-cloud.unsupported_processing processing eu-cloud needs llm in detectors (and engine pipeline). Add llm to detectors.unsupported_redact_policy policy is not all-detected.invalid_ner_deployment nerDeployment is not eu-de or local.ner_deployment_without_ner nerDeployment was sent, but ner is not in detectors (or mode is regex).ner_model_without_ner nerModel was sent, but ner is not in detectors (or mode is regex).ner_model_unknown No NER model has the id in nerModel. GET /v1/access lists the models you may choose.ner_model_unavailable The NER model in nerModel is retired or does not run at the chosen place. A model other than the default also needs detectors.llm_model_not_applicable model was sent, but llm is not in detectors, or engine is not pipeline.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.unsupported_engine_detectors The detectors do not fit engine agentic: it needs regex and llm, with optional ner.invalid_sources sources has an unknown or repeated value.unsupported_engine_sources sources was sent without engine agentic.invalid_idempotency_key Idempotency-Key is not a UUID, or it was sent more than once.invalid_file_encoding file.data is empty or not base64.empty_file file.data decodes to nothing.unsupported_file_type The file is neither a PDF nor a Word .docx, by its content, its extension or its contentType.file_type_mismatch The extension or contentType disagrees with the file's content.The key is missing or not valid.
api_key_required No Authorization: Bearer header with a komplai key.invalid_api_key The key is unknown, expired, revoked or retired, the person behind a personal key is no longer a member or no longer assigned any app the key covers, or your organisation's API access for it is not set up or no longer active.invalid_token The key was revoked or expired, or its access ended, while the request was admitted or processed.The key may not do this, or the organisation's access does not cover it.
insufficient_scope The key lacks a scope the operation needs (x-komplai-scopes): it was not issued or created with it, its person is no longer assigned the app, or the organisation's processing approval no longer covers it.identity_retired The person behind a personal key has been removed from komplai.approved_redact_storage_policy_required Your organisation processes personal data but has no approved storage policy for text jobs.processing_access_withdrawn Access to the job was withdrawn after it was created: the agreement, the processing setup, the organisation's redaction rules or the storage policy for text jobs changed. The job is invalidated and its text and result are deleted. This is final: stop reading the job and do not reuse its Idempotency-Key; submit the text again as a new job when access allows it.processing_choice_not_allowed The organisation does not allow this processing (local infrastructure or EU cloud) through the API, or the connection is not made available through the API.processing_not_enabled The processing is not enabled for the app in the organisation: EU processing is not approved and enabled, or the agreement keeps processing on local infrastructure.processing_not_approved The organisation's processing approval for the app is missing or was withdrawn.app_not_assigned The key's person lost the app or their membership while the request was admitted.ner_model_preview_required The NER model in nerModel is a preview. It needs your organisation's Redact preview, which an organisation integration key does not have.integration_not_permitted An organisation integration key cannot use this operation or this option.agentic_preview_not_enabled The organisation's administrator has not turned on the Redact Agentic preview.agentic_lookup_not_allowed A source in sources is not approved by the organisation's administrator.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.Conflict with the current state.
idempotency_conflict This Idempotency-Key was used with a different body. Use a new UUID for a new job.processing_access_changed The organisation's processing setup changed while the request was handled. Send it again.model_not_enabled The model is not one you may use at this processing, or it is not offered there right now.llm_model_not_validated The language model in model is not validated for Redact at the processing you chose. GET /v1/access lists the models you may name.reasoning_effort_not_supported The reasoning effort komplai set for this EU language model in Redact is not one the model accepts on your organisation's EU route. Nothing was sent to the model, and the API does not send another effort.Too large.
file_too_large The file is over 50 MiB, or the body is over its byte limit.too_many_pages The PDF has more than 2,000 pages.file_too_complex Reading the file took more than 120 seconds or more resources than allowed (memory, ZIP entries, XML size or depth).text_too_large text is over the operation's limit in UTF-16 code units, or the body is over its byte limit.The body has no Content-Type, or one the API does not read, such as XML or form data. Send application/json.
invalid_body The body is not a JSON object with the documented fields: invalid JSON, Content-Type text/plain, an unknown field, a field of the wrong type, or a required field that is missing or blank.The file cannot be read.
invalid_file file is missing or malformed (filename missing, blank, longer than 255 characters or with control characters; data not a string; an unknown key), or the PDF or Word file itself is damaged or not a Word document.encrypted_file The PDF is password protected.scanned_pages_not_supported A page has no text layer, for example a scan. No OCR runs. pages lists the pages; allowPagesWithoutText true processes the rest.no_text_found The file contains no text at all.Refused for now. Wait the seconds in Retry-After before you try again.
processing_capacity_busy All organisation-rule workers in this API process are busy. There is no queue: try again after Retry-After.rate_limited Too many requests: the per-minute limit of the person behind a personal key (shared with that person's other keys and use of the hub) or of the integration behind an organisation integration key (shared by its keys), the organisation's (120), the API's (300) or the per-IP network limit. Wait Retry-After seconds.Processing is not available right now.
redact_file_not_enabled File input is switched off on this server.file_extraction_unavailable The file reader could not start or stopped. This is not caused by the file.redact_jobs_not_enabled Text jobs are not accepted right now; GET /v1/access shows text_contract.jobs_accepting_submissions.redact_job_service_unavailable The job store failed.redact_job_integrity_failed The job's encrypted data could not be read.invalid_organisation_policy Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule).chat_cloud_unavailable The organisation's EU cloud setup cannot be used right now.access_service_unavailable Keys and access could not be checked.ner_location_unavailable The NER place cannot be used now: komplai has not switched it on for the API, or it did not answer. nerDeployment names the place. NER never moves to another place; GET /v1/access shows which places are available.ner_model_unconfigured The NER model in nerModel is not set up at the default place on this server.redact_runtime_unavailable A selected layer (NER or the language model) is not set up or not available right now.agentic_disabled engine agentic is switched off on this server.agentic_lookup_unavailable A source in sources is not available right now./v1/redact/file/jobscurl https://api.komplai.dk/v1/redact/file/jobs \
-H "Authorization: Bearer $KOMPLAI_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"file": {
"filename": "afgoerelse.pdf",
"contentType": "application/pdf",
"data": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo="
},
"detectors": ["regex", "ner"],
"processing": "local",
"include": ["mapping"]
}'$headers = @{
Authorization = "Bearer $env:KOMPLAI_TOKEN"
}
$body = [ordered]@{
file = [ordered]@{
filename = 'afgoerelse.pdf'
contentType = 'application/pdf'
data = 'JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo='
}
detectors = @('regex', 'ner')
processing = 'local'
include = @('mapping')
} | ConvertTo-Json -Depth 100
$request = @{
Method = 'Post'
Uri = 'https://api.komplai.dk/v1/redact/file/jobs'
Headers = $headers
ContentType = 'application/json; charset=utf-8'
Body = $body
}
$response = Invoke-RestMethod @request
$response | ConvertTo-Json -Depth 100import os
import requests
response = requests.post(
"https://api.komplai.dk/v1/redact/file/jobs",
headers={
"Authorization": f"Bearer {os.environ['KOMPLAI_TOKEN']}",
},
json={
"file": {
"filename": "afgoerelse.pdf",
"contentType": "application/pdf",
"data": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=",
},
"detectors": ["regex", "ner"],
"processing": "local",
"include": ["mapping"],
},
timeout=330,
)
print(response.status_code, response.headers.get("Request-Id"))
print(response.json())const response = await fetch("https://api.komplai.dk/v1/redact/file/jobs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KOMPLAI_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
file: {
filename: "afgoerelse.pdf",
contentType: "application/pdf",
data: "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=",
},
detectors: ["regex", "ner"],
processing: "local",
include: ["mapping"],
}),
});
console.log(response.status, response.headers.get("Request-Id"));
console.log(await response.json());using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(330) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.komplai.dk/v1/redact/file/jobs");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("KOMPLAI_TOKEN"));
request.Content = new StringContent(@"{
""file"": {
""filename"": ""afgoerelse.pdf"",
""contentType"": ""application/pdf"",
""data"": ""JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=""
},
""detectors"": [""regex"", ""ner""],
""processing"": ""local"",
""include"": [""mapping""]
}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
if (response.Headers.TryGetValues("Request-Id", out var requestId))
{
Console.WriteLine(string.Join(", ", requestId));
}
Console.WriteLine(await response.Content.ReadAsStringAsync());Sæt først miljøvariablen KOMPLAI_TOKEN til din nøgle.
{
"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,
"file": {
"type": "pdf",
"bytes": 1025,
"pageCount": 2
},
"pages": [
{
"number": 1,
"start": 0,
"end": 83,
"hasText": true
},
{
"number": 2,
"start": 85,
"end": 131,
"hasText": true
}
]
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "api_key_required",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/api_key_required"
}{
"error": "insufficient_scope",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/insufficient_scope"
}{
"error": "idempotency_conflict",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/idempotency_conflict"
}{
"error": "file_too_large",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/file_too_large"
}{
"error": "invalid_body",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_body"
}{
"error": "invalid_file",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/invalid_file"
}{
"error": "processing_capacity_busy",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/processing_capacity_busy"
}{
"error": "redact_file_not_enabled",
"request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60",
"doc_url": "https://developers.komplai.dk/errors/redact_file_not_enabled"
}