# API reference > Base URLs, versions, the OpenAPI document, JSON conventions, request ids and retries, and every endpoint of komplai's API with a console to try it. komplai's API takes JSON and answers with JSON over HTTPS. Every call sends your key in the `Authorization` header: ```bash curl https://api.komplai.dk/v1/access \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` GET /v1/access shows what your key can reach, where each Redact layer processes text and which limits apply. [API keys and authentication](https://developers.komplai.dk/authentication) explains the two kinds of key. ## Endpoints Each endpoint lists the scopes and keys it needs, its fields and its responses, with code samples in curl, PowerShell, Python, JavaScript and C#. The samples read your key from the environment variable `KOMPLAI_TOKEN`. Signed in to the hub, **APIs and integrations › API reference** shows the operations your own access covers. ## Base URLs | Environment | API | Keys from | | --- | --- | --- | | Production | `https://api.komplai.dk` | `https://hub.komplai.dk` | | Test | `https://api.test.komplai.dk` | `https://hub.test.komplai.dk` | Create the key in the hub of the environment you call. Each environment serves the OpenAPI document for the version it runs at `/v1/openapi.json`. ## Versions and stability Every path starts with `/v1`. The OpenAPI document's `info.version` is the version of the contract, 1.3.0 in the document this reference is built from. The [changelog](https://developers.komplai.dk/changelog) lists what each version changed. Each operation has `x-komplai-stability`: - `stable` keeps its contract. - `beta` may still change, and komplai gives notice before it does. Decide, Coding and Redact's PDF and Word input are in beta. - `alpha` is early and may change without notice. A request field marked `preview` is an early option inside an operation and may change without notice: Redact's `engine` and `sources`. Leave them out unless your organisation's administrator has turned on the Redact Agentic preview. ## The OpenAPI document [/openapi.json](https://developers.komplai.dk/openapi.json) on this site is OpenAPI 3.1, a copy of the document the production API serves at `https://api.komplai.dk/v1/openapi.json`. This reference is built from it. GET /v1/openapi.json needs no key and ignores any `Authorization` header, so a tool that always sends a key still gets it. Besides standard OpenAPI, the document has: | Extension | Contents | | --- | --- | | `x-komplai-scopes` | The scopes an operation needs. | | `x-komplai-principals` | The kinds of key an operation accepts: `person` for a personal API key, `integration` for an organisation integration key. | | `x-komplai-stability` | `stable`, `beta` or `alpha` on each operation and tag, `preview` on a request field. | | `x-komplai-error-codes` | At the root: every error code with its statuses, its meaning, what to do, its page and the operations that return it. | ### Import into Postman - [OpenAPI document](https://developers.komplai.dk/openapi.json): OpenAPI 3.1. - [Postman collection](https://developers.komplai.dk/downloads/komplai-api.postman_collection.json): every endpoint, with example bodies, grouped like this reference, with bearer authentication from the variable `token`. - [Postman environment](https://developers.komplai.dk/downloads/komplai-api.postman_environment.json): the variables `baseUrl` (`https://api.komplai.dk`) and `token`, a secret that starts empty. 1. In Postman, import the collection and the environment and select the environment. For another tool, use the OpenAPI document. 2. Put your key in `token`. For the test environment, set `baseUrl` to `https://api.test.komplai.dk`. 3. Send GET /v1/access to check that the key works. Optional headers, such as `Idempotency-Key` and `Prefer`, are in the requests that take them but switched off. `Idempotency-Key` holds Postman's `{{$guid}}`, a new UUID on each send. In other tools, generate a UUID for each job or leave the header out. ## Requests and answers - Send a body as JSON with `Content-Type: application/json`. Another content type answers 400 or 415. - Redact, Chat and Coding refuse a field they do not document, with 400 [`invalid_body`](https://developers.komplai.dk/errors/invalid_body), [`invalid_input`](https://developers.komplai.dk/errors/invalid_input) or [`invalid_coding_input`](https://developers.komplai.dk/errors/invalid_coding_input). Decide ignores fields it does not list. - Chat and Coding use OpenAI's chat completion format. - Text lengths and offsets count UTF-16 code units, as string length does in JavaScript and .NET. In Python, `len(text.encode("utf-16-le")) // 2` gives the same count. - Ids such as a text job's `id` and `organisation_id` are UUIDs; a Chat answer's `id` starts with `chatcmpl-`. Times such as `createdAt` and `expiresAt` are ISO 8601 in UTC. `created` in Chat and Coding answers is seconds since 1970 (UTC). - A call that succeeds answers 200, or 202 when it has created a text job or when you ask for the result of a job that is still queued or running. - Answers to calls with a key carry `Cache-Control: private, no-store`. - A call that fails answers with a status and an error body. See [Errors](https://developers.komplai.dk/errors). ## Request-Id Every response to a call the API handles carries a `Request-Id` header with a UUID, and an error body repeats it as `request_id`. Log it with each call and quote it when you ask komplai about one. To have your own id used, send it in `X-Request-Id`. It must be one valid UUID; on other values the API makes a new one. The exception is POST /v1/coding/chat/completions, which requires `X-Request-Id` and answers 400 [`invalid_request_id`](https://developers.komplai.dk/errors/invalid_request_id) without it: a new version 4 UUID for each operation, and the same one again only to retry an operation whose outcome you do not know. komplai then answers 409 [`duplicate_request`](https://developers.komplai.dk/errors/duplicate_request) instead of calling the model a second time. A response without `Request-Id` was answered before the API handled the call, for example by the gateway while the API restarts. Treat it by its status. ## Retries and idempotency Whether you can send a call again depends on whether it may already have reached a model. - **Text jobs.** Send `Idempotency-Key` with a new UUID for each job on POST /v1/redact/jobs and POST /v1/redact/file/jobs, and on POST /v1/redact and POST /v1/redact/file with `Prefer: respond-async`. If the connection drops, send the same request with the same `Idempotency-Key`: within the job's lifetime you get the same job back, with `reused` `true`, instead of a second job. The same `Idempotency-Key` with another body answers 409 [`idempotency_conflict`](https://developers.komplai.dk/errors/idempotency_conflict). An `Idempotency-Key` is bound to your organisation, the owner of the API key (a person or an integration) and the API key itself. - **Coding.** `X-Request-Id`, as above. - **Chat and synchronous Redact** have no idempotency. A call that timed out or lost its connection may already have reached the model, and calls in EU cloud count towards the monthly AI spending cap. Do not send them again automatically, and switch off automatic retries of POST in your HTTP client or SDK. - **Calls without AI charge that change nothing,** such as GET operations, POST /v1/redact/detect and POST /v1/redact/restore, can be sent again. Each one counts against your request limit. - **After 429,** wait the seconds in `Retry-After`. [Errors](https://developers.komplai.dk/errors) says when trying again helps. Poll a text job at most every 2 seconds. While the job is queued or running, GET /v1/redact/jobs/{id}/result answers 202 with `Retry-After: 2`. ## Calling from a browser The API accepts browser calls only from komplai's own sites, including the consoles on this site. Call it from a server, a script or an integration platform: a key in a web page is visible to everyone who opens it. ## Try a call Each endpoint has a console that sends the call from your browser to the API with a key you paste. The key stays in the page's memory and is forgotten when you leave the page; the console never stores it in the browser. On developers.test.komplai.dk, the console calls the test environment. Calls are real: komplai processes what you send, each call counts towards your key's limits, and processing in EU cloud counts towards your organisation's monthly AI spending cap. Use test data. --- https://developers.komplai.dk/api # API keys and authentication > The two kinds of komplai API key, how you get, renew and revoke them, the scopes that limit them and what GET /v1/access tells you. Every call to an operation sends a key as a bearer token in the `Authorization` header. The only call without a key is GET /v1/openapi.json, which is public. ```bash curl https://api.komplai.dk/v1/access \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` Send the whole key. The API reads it only from this header, so it never belongs in a URL. Answers to calls with a key carry `Cache-Control: private, no-store`. ## Two kinds of key | | Personal API key | Organisation integration key | | --- | --- | --- | | Starts with | `kp_live_` | `kp_org_` | | Belongs to | You, in one organisation | One of your organisation's own systems, not a person | | Created by | You, in the hub | komplai, when your organisation asks | | Reaches | The tools assigned to you: Redact, Chat, Decide, Coding and Register lookup, within the key's scopes | Redact and GET /v1/access only | | Valid for | 7, 30, 90 or 365 days, as you choose | Up to 365 days, set by komplai | | Request limit | Yours, shared with your other keys and your use of the hub | The integration's own, kept when komplai issues a new key | | Managed under | **APIs and integrations › API keys** | **Organisation › Sign-in and security › Integration keys** | komplai stores only a hash of each key and its first characters, so a key cannot be shown again after it was issued. Keep it in a secret store, never in code, a URL or an e-mail. ## Scopes A scope allows a group of operations. Each operation's page in the [API reference](https://developers.komplai.dk/api) lists the scopes and the kinds of key it accepts. | Scope | Operations | Keys | | --- | --- | --- | | `access:read` | GET /v1/access | Both | | `redact:detect` | POST /v1/redact/detect | Both | | `redact:process` | POST /v1/redact, POST /v1/redact/restore, the text job operations under /v1/redact/jobs, and POST /v1/redact/file and /v1/redact/file/jobs (Beta) | Both | | `chat:complete` | GET /v1/models, POST /v1/chat/completions | Personal | | `decide:process` | POST /v1/decide, POST /v1/decide/batch (Beta) | Personal | | `coding:read` | GET /v1/coding/account, GET /v1/coding/models (Beta) | Personal | | `coding:complete` | POST /v1/coding/chat/completions (Beta) | Personal | | `mcp:read` | Register lookup from an MCP client (Beta) | Personal | You can give a personal API key only scopes for tools that are assigned to you. Give it only the scopes the system needs. The API checks the scopes against your current access on every call: when your assignment or your organisation's processing approval no longer covers a tool, the call answers 403 [`insufficient_scope`](https://developers.komplai.dk/errors/insufficient_scope) or 401 [`invalid_api_key`](https://developers.komplai.dk/errors/invalid_api_key). An organisation integration key on an operation it does not reach gets 403 [`integration_not_permitted`](https://developers.komplai.dk/errors/integration_not_permitted), before its scopes are checked. ## Personal API keys ### Create a key [Get started](https://developers.komplai.dk/get-started) walks you through it: **APIs and integrations › API keys › Create API key**, then the purpose, a name, the validity and the permissions. - The key belongs to you and the organisation you have selected in the hub. If you belong to several organisations, switch to the right one before you create the key. - You can have up to 20 active keys in each organisation. - After the hub has shown the key once, the list shows its name, the first characters of the key, its scopes, status, expiry date and when it was last used. ### Renew a key Renewing creates a new key and revokes the old one in the same step. 1. Under **APIs and integrations › API keys**, choose **Renew** next to the key. 2. Choose the **Validity** and check the permissions. 3. Choose **Renew key** and copy the new key. The old key stops working at once, so put the new key in your system straight away. A text job is visible only to the key that created it: read or delete its result before you renew. Only you can renew your own keys. ### Revoke a key Choose **Revoke** next to the key and then **Revoke key**. Access with the key stops immediately. Your organisation's administrator sees the members' keys on the same page and can revoke them too. ### When a key stops working - It reaches its expiry date, shown under **Expires**. - You or your administrator revoke it, or you renew it. - You leave the organisation, or no tool the key covers is assigned to you any longer. - Your organisation's API access for the tool ends. A call with such a key answers 401 [`invalid_api_key`](https://developers.komplai.dk/errors/invalid_api_key). If the key stops while a call is running, the call answers 401 [`invalid_token`](https://developers.komplai.dk/errors/invalid_token). ## Organisation integration keys An organisation integration key lets one of your organisation's own systems, such as a robot or an integration platform, call Redact without a person. Calls with it are recorded under the integration's name, never under a person. - **Getting a key.** [Contact us](https://en.komplai.dk/#kontakt) with the system's name, what it will do and a contact person at your organisation. komplai issues the key and delivers it once to the contact person through Secret. The contact person gets no access with the key and needs no account. - **What it reaches.** GET /v1/access and Redact: detection, pseudonymisation, restore, text jobs and PDF and Word input. Chat, Decide, Coding, Register lookup and `engine` `agentic` answer 403 [`integration_not_permitted`](https://developers.komplai.dk/errors/integration_not_permitted). Redact in Word and the Coding client accept personal API keys only. - **Requirements.** The key works while it is active, your organisation's agreement includes Redact through the API and the processing is approved. The API checks this on every call and during every text job. If one of them ends, every integration key in the organisation stops at once. - **Usage.** Calls count towards your organisation's request limits and its monthly AI spending cap. An integration has no personal limit. Its request limit belongs to the integration, so a new key does not reset it. - **A new key.** komplai issues the next key for the same integration. The old key stops the moment the new one is issued, with no overlap, and its queued, running and finished text jobs are invalidated. Replace keys between your system's batches. - **Revoking.** Your organisation's administrator opens **Organisation › Sign-in and security › Integration keys**, chooses **Revoke** and then **Revoke key**. The system loses access at once, queued and running jobs stop and results can no longer be fetched. The integration stays, so komplai can issue a new key for it. The **Integration keys** page shows each integration's name, contact person, key, status, expiry and last use. Its statuses: | Status | Meaning | | --- | --- | | Active | The key works. | | No access to Redact | The key is valid, but your organisation cannot use Redact through the API at the moment. | | Expired | The key has passed its expiry date. komplai can issue a new key. | | Stopped | Your organisation can no longer use Redact through the API, so the key stopped. komplai can issue a new key. | | Revoked by your administrator, Revoked by komplai | The key was revoked. The integration still exists, so komplai can issue a new key. | | Closed | komplai has closed the integration. It cannot get a new key. | ## What GET /v1/access returns GET /v1/access counts as one request, sends no text and runs no model. Call it when your system starts, and before a run where the processing matters. The full example is in the [reference](https://developers.komplai.dk/reference/account#readAccess). | Field | Contents | | --- | --- | | `organisation_id` | Your organisation's id. | | `principal` | Only for an organisation integration key: `type` `integration`, `integration_id` and `name`. A personal API key's answer has no `principal`. | | `scopes` | Every scope the key has. | | `services[]` | One entry per tool the key reaches, with `service`, the key's `scopes` for it, `hosting`, `processing` and `limits`. | | `services[].hosting.processing.layers` | For Redact: one entry per layer (`regex`, `ner`, `llm`) and processing choice, with where it processes text, whether it is set up, the NER places and the models a call may name. | | `services[].processing` | What your organisation's agreement allows: `data_mode` (`synthetic` for test data only, `personal` for personal data under `agreement_reference`), `storage` with what is stored and for how long, and for Redact `text_contract` with its options and limits. | | `services[].limits.requests_per_minute` | Calls per minute for the tool: per person for a personal API key, per integration for an organisation integration key. | | `limits` | `organisation_requests_per_minute` and `shared_requests_per_minute`, and `requests_per_minute` when the key reaches one tool. | | `hosting`, `processing` | A summary, when the key reaches one tool. | `services[].edition` is deprecated and always `custom`. Read `scopes` and `processing` instead. --- https://developers.komplai.dk/authentication # Changelog > Changes to komplai's API, newest first, by version of the OpenAPI document. Changes to komplai's API, newest first. The version is `info.version` in the [OpenAPI document](https://developers.komplai.dk/openapi.json). ## 1.3.0 The version this documentation describes. - Complete request and response schemas, with examples, for Chat (GET /v1/models, POST /v1/chat/completions), Decide (POST /v1/decide, POST /v1/decide/batch) and Coding (GET /v1/coding/account, GET /v1/coding/models, POST /v1/coding/chat/completions). Before this version, the document listed these operations and referred to the hub for their requests and responses. - Every response to a call the API handles carries a `Request-Id` header. Send `X-Request-Id` with a UUID to have your own id used. - Every JSON error body has `request_id` and `doc_url` besides `error`. The document describes the body as `components.schemas.Error` and lists every code with its statuses, meaning and what to do in `x-komplai-error-codes`. An error event in the Coding stream carries the same two fields. - Every operation and tag has `x-komplai-stability`: `stable`, `beta` or `alpha`. Redact's `engine` and `sources` are marked `preview`. - POST /v1/chat/completions documents [`eu_cloud_refused`](https://developers.komplai.dk/errors/eu_cloud_refused) (502): komplai's EU cloud refused the call, so the model did not answer it. - The API accepts browser calls from developers.komplai.dk, so the consoles on this site can send calls, and lets the browser read `Request-Id`, `Retry-After`, `Location`, `Preference-Applied` and the `X-RateLimit-*` headers. - The document links to this site and to the hub's API area, where a member creates a personal API key. ## 20 October 2026 Changes to Redact while the document was at version 1.2.0. - `Prefer: respond-async` on POST /v1/redact and POST /v1/redact/file answers 202 with a text job instead of holding the connection. The text may then be as long as a text job allows. - A synchronous run that komplai estimates cannot finish within 300 seconds is refused before anything runs, with 413 [`use_job`](https://developers.komplai.dk/errors/use_job), `estimatedSeconds` and `holdSeconds`. - An interrupted text job resumes from its encrypted checkpoint. A job that makes no progress for 65 minutes ends with [`redact_job_stalled`](https://developers.komplai.dk/errors/redact_job_stalled). - `engine` `review` is retired. A request that names it answers 400 [`engine_retired`](https://developers.komplai.dk/errors/engine_retired), with `hint` naming what to send instead. ## 1.2.0 Released on 19 October 2026. - Redact calls can name the NER place (`nerDeployment`: `eu-de` or `local`), the NER model (`nerModel`) and the language model (`model`). A place or model that cannot be used is refused by name and never replaced by another. - GET /v1/access lists the NER places and the models a call may name, with whether each can be used now. ## 1.1.0 Released on 19 October 2026. - Organisation integration keys (`kp_org_`) for Redact and GET /v1/access. - POST /v1/redact/restore puts the originals back into a text with labels such as `[PERSON-1]`. - PDF and Word input (Beta): POST /v1/redact/file and POST /v1/redact/file/jobs. - The per-IP limit answers 429 [`rate_limited`](https://developers.komplai.dk/errors/rate_limited) with `Retry-After` and `x-ratelimit-*` on every route. - The OpenAPI document gained readable `operationId`s, a security scheme for each kind of key, the error codes for each status with an example, and examples for every Redact operation. GET /v1/openapi.json ignores the `Authorization` header, so import tools that always send a key still get it. ## 1.0.0 The version before 19 October 2026: personal API keys (`kp_live_`) for Redact (pseudonymisation, detection and text jobs), GET /v1/access, Chat, Decide and Coding. --- https://developers.komplai.dk/changelog # Where data is processed > Where each tool and API call processes data, who runs it, whether data leaves the EU, and what is stored for how long. Data you send to komplai is processed in one of four places. Which one a call uses depends on the tool, on what your organisation's agreement approves and on the processing the call asks for. A call is never moved to another place: a place or model that cannot be used is refused with an error that names it. ## The four places | Place | Run by | Where | Data leaves the EU | | --- | --- | --- | --- | | komplai's servers | komplai, at Hetzner | Falkenstein, Germany | No | | Local infrastructure | komplai | Denmark | No | | EU cloud | komplai, through its EU model provider | France | No | | Your own AI connections | Your organisation or its provider | Where the provider or your administrator states | Depends on the connection | - **komplai's servers** run the hub, the API, Redact's rules, NER at the place `eu-de`, Register lookup and the databases. They are shared with other organisations. - **Local infrastructure** runs language models, Decide's decision models and NER at the place `local`. The queue is shared with other organisations, without priority. Processing on local infrastructure has no AI charge and does not count towards the monthly AI spending cap. - **EU cloud** runs language models for the tools your organisation has EU processing approved for, such as Chat, Coding and Redact's language model. Usage is metered at the provider's price and counts towards your organisation's monthly AI spending cap. - **Your own AI connections** are added by your organisation's administrator in the hub. The agreement with the provider is your organisation's own, the provider is not a komplai subprocessor, and the usage does not count towards the monthly AI spending cap. Chat, the Chat API and drafting in Documents, templates and Word can use them. [Your own AI connections](https://developers.komplai.dk/guides/ai-connections) shows how. ## Tool by tool ### Redact Redact processes the text you send in layers, and each layer has its own place: - **Rules** (`regex`) run on komplai's servers in Germany. - **NER** (`ner`) runs at the place in `nerDeployment`: `eu-de` is komplai's servers in Germany, and `local` is local infrastructure in Denmark when GET /v1/access lists it as available. Without `nerDeployment`, NER runs at the default place GET /v1/access marks. - **The language model** (`llm`) runs on local infrastructure in Denmark, unless the call asks for `processing: "eu-cloud"`. POST /v1/redact/detect runs rules and NER only. POST /v1/redact/restore runs no model. File input (Beta) extracts the text of a PDF or Word file in memory on komplai's servers in Germany and does not store the file. Then the text is processed like any other. POST /v1/redact/file/jobs stores the extracted text encrypted as a text job. Redact in Word scans up to 16,000 characters of the document's main text through POST /v1/redact/detect, so it uses rules and NER at the same places. Headers, footers, footnotes, text boxes, comments, metadata and images are not scanned. ### Chat POST /v1/chat/completions sends the messages to the place in `processing`: - `komplai-local`: local infrastructure in Denmark. - `eu-cloud`: komplai's EU cloud, when your organisation has EU processing approved for Chat. - `connection:`: one of your organisation's own connections that its administrator has made available through the API. Without `processing`, the call runs where your organisation's Chat runs. The [Chat reference](https://developers.komplai.dk/reference/chat) has the fields and the errors. ### Decide Decide (Beta) sends the text and the questions to a decision model on local infrastructure in Denmark. On the way, the text is held in the encrypted queue described below; it is not stored after that. ### Coding Coding (Beta) sends what the coding client sends, messages and the results of tools the client ran, to a model in komplai's EU cloud on your organisation's approved route. komplai never runs a tool itself. ### Register lookup Register lookup (Beta) runs lookups in CVR, Retsinformation, Statistics Denmark and Folketinget on komplai's servers in Germany. The register you query receives the lookup parameters and has its own operating locations. No AI is used. ### Run Apps published with Run run in the visitor's browser, and Run runs no server code. The app files are stored on komplai's server at Hetzner in the EU; the hub's Data protection page names the place. An app that an administrator has approved for AI sends text to komplai's EU cloud or an approved AI connection, never to local infrastructure. Data an app saves in komplai is encrypted in komplai's database at Hetzner in Germany. [Publish with Run](https://developers.komplai.dk/guides/run) has the details. Tools without an API, such as Lens, Secret and Index, are listed with their processing on the hub's Data protection page. ## What is stored, and for how long | What | Stored | For how long | | --- | --- | --- | | Synchronous calls: Redact, detect, restore, file input, Chat completions and Decide | Nothing after the response, apart from the queue on local infrastructure | Not stored | | Text sent to local infrastructure | Encrypted in the queue until it is processed, and the result encrypted in the queue after that | The result for 1 hour, then deleted by periodic cleanup, possibly later during an outage | | Redact text jobs | The text, encrypted while the job is queued or running and cleared when the job ends, and the result, encrypted | Until you delete the job or it reaches `expiresAt` | | Coding | No prompts, answers or tool results | Not stored | | Chat conversations in the hub | The conversation, encrypted on komplai's servers in Germany and visible only to the person who had it | Until the person deletes it | | Usage and audit records | Who, when, the tool, the model and token or character counts, without content | As your organisation's agreement states | | Backups | A daily copy of komplai's databases, encrypted (AES-256) and kept at Hetzner in the EU, without files outside the databases | As agreed separately | A text job's retention counts from when the job ends. With test data and no storage policy, the result is kept for 1 hour. Personal data in text jobs needs a storage policy that your organisation agrees with komplai. It sets the retention, at most 30 days, and without it the job is refused with [approved_redact_storage_policy_required](https://developers.komplai.dk/errors/approved_redact_storage_policy_required). DELETE /v1/redact/jobs/{id} removes the text and the result at once. Reading a result does not delete it. ### The model service in EU cloud These are the terms of the model service behind komplai's EU cloud, as komplai last checked them on 13 October 2026. GET /v1/coding/account returns them, in Danish, in `data`. - The model service does not use input, prompts or answers to train, retrain or improve the base models. - Prompts and answers are not stored by default. A temporary, project-isolated cache of intermediate results is automatic and cannot be turned off. - During specific debugging or security incidents, including investigations of HTTP 500 errors, the whole request can be stored for up to two weeks. - Aggregated, anonymised usage data can be stored for up to six months. Processing and retention also follow your organisation's agreement with komplai. ## Check it for your organisation GET /v1/access shows the processing for your key. For Redact, `services[].hosting.processing.layers` names where each layer runs, and the `ner` layer lists every place NER can run, each with `available` and a `reason`. `services[].processing.data_mode` says whether you may send personal data; [Test data](https://developers.komplai.dk/test-data) explains it. ```bash curl https://api.komplai.dk/v1/access \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` In the hub, **Data protection** (`/governance`) lists your tools, or every tool in the agreement for an administrator, each with its processing, location and status. Each row says what is sent and stored, which data is permitted and which data processing agreement applies. When your organisation has data processing agreements, the page has them as PDF files, and administrators also see the platform backup. On **Organisation › AI and processing › Processing** (`/settings/processing`), an administrator chooses which of the approved places each tool may use. [Processing approval](https://developers.komplai.dk/guides/processing-approval) explains both pages. ## When a place cannot be used A call names its place, or uses the default your organisation set, and it runs there or not at all. The API never switches to another place or model, also not when the chosen one fails or a cap is reached. These are the errors you meet most often: - [processing_not_enabled](https://developers.komplai.dk/errors/processing_not_enabled): EU processing is not approved for the tool in your organisation. - [processing_choice_not_allowed](https://developers.komplai.dk/errors/processing_choice_not_allowed): your administrator does not allow this place through the API, or has not made the connection available through the API. - [ner_location_unavailable](https://developers.komplai.dk/errors/ner_location_unavailable): the NER place you named cannot be used right now. - [eu_cloud_refused](https://developers.komplai.dk/errors/eu_cloud_refused): komplai's EU cloud refused the call. - [ai_credit_exhausted](https://developers.komplai.dk/errors/ai_credit_exhausted): your organisation's monthly AI spending cap or its own lower limit is reached. Local infrastructure keeps working. - [connection_failed](https://developers.komplai.dk/errors/connection_failed): the provider behind your own connection could not be reached. --- https://developers.komplai.dk/data-processing # Errors > How komplai's API reports an error, how to handle each status and when to try again, with every error code and what to do. A failed call answers with an HTTP status and a JSON body: ```json { "error": "invalid_body", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_body" } ``` | Field | Contents | | --- | --- | | `error` | The code. Each code has its own page, listed [below](#codes). | | `request_id` | The same id as the response's `Request-Id` header. Quote it when you ask komplai about a call. | | `doc_url` | The page for the code, with what happened and what to do. | The OpenAPI document describes this body as `components.schemas.Error`. Some codes add fields that help you act: `hint` with [`engine_retired`](https://developers.komplai.dk/errors/engine_retired) and [`mapping_not_available`](https://developers.komplai.dk/errors/mapping_not_available), `state` with [`job_not_finished`](https://developers.komplai.dk/errors/job_not_finished), `nerDeployment` with [`ner_location_unavailable`](https://developers.komplai.dk/errors/ner_location_unavailable), `estimatedSeconds` and `holdSeconds` with [`use_job`](https://developers.komplai.dk/errors/use_job), and `pages` with [`scanned_pages_not_supported`](https://developers.komplai.dk/errors/scanned_pages_not_supported). The example on each code's page shows them. Apart from a Coding stream that has already begun, a failed call returns no partial result. A few codes are the web server's own reason phrases, such as `Not Found` or `Payload Too Large`. Their bodies also carry the server's `message` and `statusCode`. ## Handle errors by status Branch on the HTTP status first and the code second, and treat a code you do not know by its status. | Status | What it means | What to do | | --- | --- | --- | | 400, 413, 415, 422 | The request, the text or the file cannot be processed as sent. | Correct it. The same request gets the same answer. | | 401 | The key is missing, unknown, expired or revoked. | Check that you send the whole key, or create a new one. | | 403 | The key may not do this: a scope is missing, the tool is not assigned to you, the processing is not approved, or an organisation integration key cannot use the operation. | Use a key with the right access, or ask your organisation's administrator. | | 404 | No text job with that id for this key, a model or connection you named is not available to you, or no operation has that method and path. | Check the id, the key, the model or connection and the path. | | 409 | The request conflicts with the current state. | Read the code: some ask you to send the request again, some to wait, and others need a change. | | 410 | A text job ended without a result. | Submit the text again as a new job. | | 429 | A limit is reached. | For a request limit, wait the seconds in `Retry-After`, then try again. For an AI spending limit, see below. | | 500, 502, 503 | komplai or a service behind it failed or is unavailable. | Try again later. If the call may have reached a model, do not send it again automatically. | | 504 | The time ran out. | After [`processing_timeout`](https://developers.komplai.dk/errors/processing_timeout), send the text as a text job. After [`timeout`](https://developers.komplai.dk/errors/timeout), the outcome is unknown. | A response without a `Request-Id` header was answered before the API handled the call, for example by the gateway while the API restarts. Treat it by its status. ## When to try again - **429 with `Retry-After`.** [`rate_limited`](https://developers.komplai.dk/errors/rate_limited) and [`processing_capacity_busy`](https://developers.komplai.dk/errors/processing_capacity_busy) say how many seconds to wait in `Retry-After`, at most 60. A 429 from the per-IP limit also has `x-ratelimit-limit`, `x-ratelimit-remaining` and `x-ratelimit-reset`. [Limits](https://developers.komplai.dk/limits) lists the limits. - **429 for AI spending.** After [`ai_credit_exhausted`](https://developers.komplai.dk/errors/ai_credit_exhausted) and [`person_ai_credit_exhausted`](https://developers.komplai.dk/errors/person_ai_credit_exhausted), waiting does not help: a monthly cap starts again next month. Choose local processing, or ask your organisation's administrator about the limit. - **A model may have answered.** After a 502, 503 or 504 on a call that reaches a model, such as Chat or a synchronous Redact call with `llm`, the model may already have worked and EU cloud usage may already count towards the cap. Do not resend such calls automatically. Text jobs and Coding have their own protection against duplicates: see [Retries and idempotency](https://developers.komplai.dk/api#retries-and-idempotency). - **Busy local infrastructure.** [`model_busy`](https://developers.komplai.dk/errors/model_busy) (503) on POST /v1/redact also sends `Retry-After`. A text job waits for its turn by itself. - **Other 4xx answers** do not change by trying again. Correct the request, the key or the access first, unless the code's page tells you to send the request again, as [`processing_access_changed`](https://developers.komplai.dk/errors/processing_access_changed) does. ## Text jobs A text job that fails ends in state `failed`, `cancelled` or `invalidated`, and GET /v1/redact/jobs/{id} names the reason in `error`. GET /v1/redact/jobs/{id}/result then answers 410. Codes that only end a text job, such as [`redact_job_stalled`](https://developers.komplai.dk/errors/redact_job_stalled), have no HTTP status of their own and are listed under **Text jobs** at the end of the index. ## Errors in the Coding stream When POST /v1/coding/chat/completions fails after the stream has begun, the last event is `data: {"error": {"message": "…", "code": "…", "request_id": "…", "doc_url": "…"}}` without `data: [DONE]`. Treat the outcome as unknown. ## Codes --- https://developers.komplai.dk/errors # Get started > Create a personal API key in the hub, check it with GET /v1/access and send your first text to Redact. This guide takes you from a personal API key to your first call to Redact, with a call to Chat as the alternative. You need a terminal with curl. ## Before you start - You have an account in an organisation that has API access with komplai, and your administrator has assigned you the tool you want to call (in the hub: **Organisation › People › Tool access**). When you can create a key, the hub's menu shows **APIs and integrations**. If it does not, ask your administrator. - A system that runs without a person, such as a robot, uses an organisation integration key that komplai issues instead. With that key, start at step 2. [Organisation integration keys](https://developers.komplai.dk/authentication#organisation-integration-keys) explains how you get one. - Use test data until your organisation's processing of personal data is approved. Step 2 shows which applies to your key. See [Test data](https://developers.komplai.dk/test-data). ## 1. Create a personal API key 1. [Sign in](https://hub.komplai.dk/login) to the hub, open **APIs and integrations** in the menu and choose **API keys**. 2. Choose **Create API key**. 3. Under **What will the key be used for?**, choose **Redact** and then **Continue**. This selects the scopes `access:read`, `redact:detect` and `redact:process`. 4. Under **Name the key**, enter the name of the system that will use it, choose a **Validity** of 7, 30, 90 or 365 days and choose **Continue**. 5. Under **Review access**, check the **Permissions** and choose **Create API key**. 6. Copy the key. The hub shows it only this once. For Chat, choose **Chat and text** in step 3, and under **Review access** also tick `access:read` under **Account access**, so the key can make the call in step 2. > **Treat the key as a password** > > Anyone who has the key can call the API as you, within its scopes. Keep it in a secret store, never in code, a URL, a ticket or an e-mail. If it leaks, revoke it under **API keys** at once. The examples read the key from the environment variable `KOMPLAI_TOKEN`. This command reads it in a terminal without showing it or saving it in your shell history. Paste the key and press Enter: ```bash read -rs KOMPLAI_TOKEN && export KOMPLAI_TOKEN ``` ## 2. Check the key GET /v1/access shows what the key reaches. It sends no text and runs no model. ```bash curl https://api.komplai.dk/v1/access \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` A 200 answer means the key works. These fields tell you what you can do with it: | Field | What it tells you | | --- | --- | | `scopes` | The scopes the key has. | | `services[].service` | Each tool the key reaches, such as `redact` or `chat`. | | `services[].processing.data_mode` | `synthetic`: use test data only. `personal`: personal data under the agreement in `agreement_reference`. | | `services[].hosting.processing.layers` | For Redact: where each layer processes text. | | `services[].limits.requests_per_minute` | Your request limit per minute for calls to the tool. | [API keys and authentication](https://developers.komplai.dk/authentication) describes the whole answer. If the call fails: - 401 [`api_key_required`](https://developers.komplai.dk/errors/api_key_required): the header is missing, often because `KOMPLAI_TOKEN` is empty. - 401 [`invalid_api_key`](https://developers.komplai.dk/errors/invalid_api_key): the key is incomplete, expired or revoked, or you are no longer assigned the tool. - 403 [`insufficient_scope`](https://developers.komplai.dk/errors/insufficient_scope): the key does not have `access:read`. Create a key that has it. ## 3. Make your first call **Redact** POST /v1/redact/detect finds personal data in a text without changing it. `mode` `ner` runs the rules and the NER model. Send a test text: ```bash curl 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"}' ``` ```json { "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 } ``` The NER model found the name and the rules found the phone number. `start` and `end` count UTF-16 code units in your text. The rules run on komplai's servers in Germany (EU), and NER at the default place GET /v1/access marks, which is komplai's servers in Germany unless komplai has changed it. The text is held in memory while the call runs and is not stored. Your organisation's own redaction rules apply: a rule's match comes back with `source` and `type` set to `custom`. **Chat** POST /v1/chat/completions sends messages to a model and returns the whole answer. `processing` `komplai-local` runs the model on komplai's local infrastructure in Denmark, with no AI charge. The answer can take up to a minute while the shared queue is busy. ```bash curl https://api.komplai.dk/v1/chat/completions \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{"processing": "komplai-local", "messages": [{"role": "user", "content": "Hvor lang tid har jeg til at klage over en afgørelse om boligstøtte?"}], "max_tokens": 256}' ``` ```json { "id": "chatcmpl-8c1d5e3a-2f7b-4a9c-b6e0-3d4f5a6b7c8d", "object": "chat.completion", "created": 1792483200, "model": "qwen3.8-27b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Du har normalt 4 uger til at klage, regnet fra den dag du fik afgørelsen. Fristen står i afgørelsens klagevejledning." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 27, "completion_tokens": 33 } } ``` The answer is in `choices[0].message.content`, and `model` names the model that answered. Without `model` in the request, the call uses the model you chose in the hub, else your organisation's default. GET /v1/models?processing=komplai-local lists the models you can name. If your organisation does not allow local infrastructure through the API, the call answers 403 [`processing_choice_not_allowed`](https://developers.komplai.dk/errors/processing_choice_not_allowed). ## Next steps - [Redact](https://developers.komplai.dk/tools/redact): pseudonymise text with POST /v1/redact, put the originals back and send long documents as text jobs. - [API keys and authentication](https://developers.komplai.dk/authentication): scopes, renewal and revocation, and organisation integration keys. - [Errors](https://developers.komplai.dk/errors) and [Limits](https://developers.komplai.dk/limits): what to do when a call fails or reaches a limit. - [API reference](https://developers.komplai.dk/api): every operation, with samples in curl, PowerShell, Python, JavaScript and C#, and a console to try each call. --- https://developers.komplai.dk/get-started # Your own AI connections > Add your organisation's own AI infrastructure or provider account in the hub, choose whether Chat and the API may use it, and call it with processing connection:. Your organisation can run Chat on its own AI: its own infrastructure, such as Azure OpenAI, its own hardware or another OpenAI-compatible endpoint, or its own account with a provider such as Anthropic, OpenAI, Mistral AI or OpenRouter. An administrator adds each connection in the hub and decides whether people can pick it in Chat and whether it can be used through the API. The agreement with the provider is your organisation's own. The provider is not a komplai subprocessor, your organisation pays it directly, and the usage does not count towards the monthly AI spending cap. Decide, Redact's detection, Index and search in Documents always use komplai's validated models, so connections do not apply to them. ## Add a connection You need to be an administrator of the organisation. The page is there when your organisation has Chat or Documents. 1. [Sign in](https://hub.komplai.dk/login) and open **Organisation › AI and processing › Connections** (`/settings/ai`). The page is called **AI connections**. 2. Under **Your connections**, open **Add a connection**. 3. Choose the **Type**. **Your account with a provider** takes a **Provider**: Anthropic, OpenAI, Mistral AI, OpenRouter, or **Another provider (OpenAI-compatible)**. **Your own infrastructure** is an OpenAI-compatible endpoint, for example Azure OpenAI or your own hardware. 4. Enter a **Name**. People see it in Chat, for example *Azure Sweden*. 5. For your own infrastructure or another provider, enter the **API address**, **Where is data processed?** and **Does data stay in the EU/EEA?** (*Yes*, *No* or *Don't know*). For another provider, also enter the **Provider's name**. The address must use https and be reachable from the internet. 6. Enter the **Model** as the provider writes it. On Azure, it is the deployment's name. On OpenRouter, `openrouter/free` picks among OpenRouter's free models, or you can name one model. 7. Paste the **API key**. It is stored encrypted, and afterwards only its last four characters are shown. 8. Choose **Can be chosen in Chat** and **Can be used through the API**. A new connection starts with Chat ticked and the API not ticked. 9. Select **Add connection**. The page checks the connection straight away, without sending a message, and says whether the provider accepted the key and lists the model. ## What people see about a connection Every connection states where it processes data, who runs it and whether data leaves the EU/EEA, on the page and next to the choice in Chat: | Provider | Processed in | Data leaves the EU/EEA | | --- | --- | --- | | Anthropic | The United States | Yes | | OpenAI | The United States | Yes | | Mistral AI | France | No | | OpenRouter | The United States; OpenRouter forwards each request to the model's provider, which may be in another country | Yes | | Your own infrastructure or another provider | Where your administrator states | As your administrator states | For your own infrastructure and another provider, these are your administrator's statements, and the hub shows them as yours. - **Free models.** OpenRouter's models that end in `:free`, and the `openrouter/free` router, carry a notice next to the choice: the provider may store and use what is sent. Use them for testing, synthetic data and ideas. - **Routers.** A router such as `openrouter/free` picks a model for each request. The model that answered is shown in Chat and in the usage log, and the API returns it in `model`. ## Check, change or delete a connection - **Check the connection** tests the key and the model without sending a message. A connection that does not answer within 15 seconds is reported as not answering. - **Edit** changes any field. Leave **API key** empty to keep the key; if you change provider, enter a new key. - **Delete connection** deletes the key too, and the connection can no longer be chosen in Chat or used through the API. A connection that drafting uses cannot be deleted until you choose other processing for drafting. The same page has **Drafting in Documents, templates and Word**: where text is sent when someone asks for a draft or a suggestion. Choose **Local infrastructure** or one of your connections and select **Save choice**. ## How keys and addresses are protected - An administrator types the key once. It is stored encrypted and never sent back to a browser. komplai's staff never receive or handle it. - komplai's operators see your connections read-only, with the host of your own address, but never the key, its last characters or the full address. - The address is checked when it is saved and again before every call. It must use https, may not point to an internal or private network address and may not redirect. - Creating, changing and deleting a connection, and changing the drafting choice, are written to the organisation's **Audit log**, without the key. - Only the organisation's administrators can open the page. komplai's read-only support access cannot. ## Use a connection through the API A call can run on a connection when: - it uses a personal API key (`kp_live_...`) with `chat:complete`. An organisation integration key (`kp_org_...`) is refused with [integration_not_permitted](https://developers.komplai.dk/errors/integration_not_permitted); - the person behind the key has access to Chat, and your organisation's Chat processing is approved; - the connection has **Can be used through the API** ticked. The connection then shows **Value for processing in the API**, such as `connection:6d3f9a2e-1b4c-4e7d-8a5f-0c2b9e4d7a31`. The choices under **AI and processing › Processing** cover komplai's own processing; a connection follows its own two switches. 1. Copy the connection's value from the Connections page. 2. List its model with GET /v1/models. The list has one entry: the model or router the connection names. ```bash curl "https://api.komplai.dk/v1/models?processing=connection:6d3f9a2e-1b4c-4e7d-8a5f-0c2b9e4d7a31" \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` ```json { "object": "list", "data": [ { "id": "openrouter/free", "object": "model", "owned_by": "openrouter", "name": "OpenRouter, gratis modeller", "processing": "connection:6d3f9a2e-1b4c-4e7d-8a5f-0c2b9e4d7a31" } ] } ``` 3. Send POST /v1/chat/completions with the value in `processing`. Leave `model` out, or send the model the connection names. ```bash curl https://api.komplai.dk/v1/chat/completions \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{"processing": "connection:6d3f9a2e-1b4c-4e7d-8a5f-0c2b9e4d7a31", "messages": [{"role": "user", "content": "Hvor lang tid har jeg til at klage over en afgørelse om boligstøtte?"}], "max_tokens": 256}' ``` 4. Read the answer. `model` is the model that answered, which a router chooses per request; `requested_model` is the model or router the connection names, and `processing` repeats the connection. ```json { "object": "chat.completion", "model": "meta-llama/llama-3.3-70b-instruct:free", "requested_model": "openrouter/free", "processing": "connection:6d3f9a2e-1b4c-4e7d-8a5f-0c2b9e4d7a31", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Du har normalt 4 uger til at klage, regnet fra den dag du fik afgørelsen. Fristen står i afgørelsens klagevejledning." }, "finish_reason": "stop" } ] } ``` A call on a connection follows the same rules as other Chat calls: text only, the whole answer at once, at most 32 messages and 80,000 UTF-16 code units, and 120 seconds for the model to answer. komplai stores the call's metadata and the model that answered, not the messages. In addition: - `reasoning_effort` can only be `none`; any other value is refused with [reasoning_not_enabled](https://developers.komplai.dk/errors/reasoning_not_enabled). - A connection to Anthropic takes a `temperature` of at most 1, only text as `response_format`, and at least one message that is not a system message. Anything else is refused with [invalid_input](https://developers.komplai.dk/errors/invalid_input). - A `model` other than the connection's own is refused with [model_not_enabled](https://developers.komplai.dk/errors/model_not_enabled). The API never moves a call from a connection to komplai's processing or to another connection, also not when the connection fails. The [Chat reference](https://developers.komplai.dk/reference/chat#createChatCompletion) has every field. A call on a connection can also stop with these errors: | Code | Status | What happened | | --- | --- | --- | | [connection_not_found](https://developers.komplai.dk/errors/connection_not_found) | 404 | No connection with this id is available to you through the API. | | [processing_choice_not_allowed](https://developers.komplai.dk/errors/processing_choice_not_allowed) | 403 | The connection is not made available through the API. | | [connection_model_unavailable](https://developers.komplai.dk/errors/connection_model_unavailable) | 409 | The provider does not know the model the connection names. | | [connection_rate_limited](https://developers.komplai.dk/errors/connection_rate_limited) | 429 | The provider refused the call for now. Wait the seconds in `Retry-After`. | | [connection_unauthorized](https://developers.komplai.dk/errors/connection_unauthorized) | 502 | The provider refused the connection's key. | | [connection_payment_required](https://developers.komplai.dk/errors/connection_payment_required) | 502 | The provider wants payment on your organisation's account. | | [connection_request_refused](https://developers.komplai.dk/errors/connection_request_refused) | 502 | The provider refused the request, for example a value it does not take. | | [connection_failed](https://developers.komplai.dk/errors/connection_failed) | 502 | The provider could not be reached or failed. | | [connection_unavailable](https://developers.komplai.dk/errors/connection_unavailable) | 503 | The connection's key cannot be read, or its address is refused. | | [timeout](https://developers.komplai.dk/errors/timeout) | 504 | The model did not answer within 120 seconds. | --- https://developers.komplai.dk/guides/ai-connections # Sign-in with Entra ID and AD FS > Let people sign in to komplai with their Microsoft work account. You prepare Entra ID or AD FS, and komplai sets up the connection with your IT team. People in your organisation can sign in to komplai with their Microsoft work account, through Microsoft Entra ID or AD FS. komplai sets up the connection together with your IT team: you prepare an app registration in Entra ID or a relying party trust in AD FS, send komplai a few values, and komplai connects it to your organisation. The hub says the same under **Organisation › Sign-in and security › Sign-in** (`/settings/sso`). ## How sign-in works - People sign in at hub.komplai.dk with their work email address. komplai's sign-in service at `auth.komplai.dk` sends them on to Microsoft and takes them back once they have signed in there. The sign-in service runs on komplai's servers in Germany. - Your own Microsoft policies, such as Conditional Access and Microsoft's MFA, apply while people sign in at Microsoft. - Only people you invite get access. A Microsoft sign-in on its own gives no access to your organisation in komplai. [Invitations](https://developers.komplai.dk/guides/invitations) explains how people join. ## Before you start Agree with komplai: - whether you connect Entra ID or AD FS - whether people may still sign in with a password alongside the Microsoft sign-in, or only through Microsoft - who in your IT team komplai works with Then open `/settings/sso`, expand **Technical details** and copy **Organisation short name** and **ID in the sign-in system**. komplai uses them to connect the right organisation. ## Microsoft Entra ID You create a single-tenant app registration. komplai's sign-in service uses it to send people to Microsoft and to read their basic profile. 1. In the Microsoft Entra admin center, go to **App registrations** and choose **New registration**. 2. Give it a name people recognise, such as `komplai`. 3. Under **Supported account types**, choose **Accounts in this organizational directory only**. 4. Under **Redirect URI**, choose **Web** and enter the redirect URI komplai gives you for your organisation. Choose **Register**. 5. Under **API permissions**, check that Microsoft Graph has the delegated permissions `openid`, `profile`, `email` and `User.Read`. If your users may not consent to apps themselves, choose **Grant admin consent**. 6. Under **Certificates & secrets**, create a new client secret. Copy its **Value** straight away, because Entra shows it only once, and note when it expires. 7. On **Overview**, copy the **Directory (tenant) ID** and the **Application (client) ID**. Send komplai these values: | Value | Where you find it | | --- | --- | | Directory (tenant) ID | Overview | | Application (client) ID | Overview | | Client secret value | Certificates & secrets | | The secret's expiry date | Certificates & secrets | Send the client secret as a one-time link, for example from [secret](https://secret.komplai.dk), never in the email itself. The tenant ID and client ID are not secret. komplai's sign-in service stores the client secret encrypted. > **The client secret expires** > > Sign-in through Entra ID stops working on the day the client secret expires. Create a new secret in good time before that date and send it to komplai the same way. Delete the old secret once komplai has confirmed that the new one is in use. The connection asks Microsoft for `openid`, `profile`, `email` and `User.Read`: the person's basic profile, such as name and email address. It never creates accounts, and it does not link a Microsoft account to a komplai account just because the email addresses match. ## AD FS AD FS connects over SAML, with komplai as a relying party trust. komplai creates its side first, because your relying party trust is built from komplai's metadata. 1. Send komplai the address of your AD FS federation metadata, normally `https:///FederationMetadata/2007-06/FederationMetadata.xml`. If the address cannot be reached from the internet, send the metadata file instead. 2. komplai creates the connection and sends you the address of its metadata. 3. In AD FS Management, choose **Add Relying Party Trust**, select **Claims aware** and import the data from komplai's metadata address. Name the trust `komplai`. 4. Choose an access control policy. **Permit everyone** lets everyone in your directory continue to komplai, where only invited people get in. A policy for a group limits the Microsoft sign-in to that group. 5. Add claim issuance rules that send the claims komplai names with its metadata. They are usually the ones in the table below. 6. Tell komplai that the trust is ready. | Claim | What to send | | --- | --- | | Name ID | A value that stays the same for the person, such as the user principal name, in the Name ID format that komplai's metadata names | | E-Mail Address | The person's work email address (`E-Mail-Addresses`) | | Given Name | `Given-Name` | | Surname | `Surname` | > **Token-signing certificates** > > komplai keeps a copy of your federation metadata, including the token-signing certificate. When AD FS creates a new token-signing certificate, tell komplai before it becomes the primary certificate, so sign-in keeps working. ## Test before you invite people Test the connection with one person before you invite others with it. 1. Wait until komplai tells you that the connection is in place. 2. On **Members** (`/team`), open **Invite a colleague** and enter the address of one colleague, for example from IT. 3. Open the **Sign-in** line above **Send invitation** (it shows your current default), choose **Organisation sign-in (SSO)** as **Sign-in method**, and choose **Send invitation**. 4. Your colleague opens the invitation email, enters their name, chooses **Sign in** and signs in with their Microsoft work account. 5. The test has worked when your colleague lands in komplai. Then make it the default for new invitations: on `/settings/sso`, under **Default invitation method**, choose **Organisation sign-in (SSO)** and then **Save sign-in method**. You can still choose another method for each invitation. Members who already have an account keep the sign-in method they have. ## Two-factor authentication Under **Two-factor authentication** on `/settings/sso` you choose who must use it: - **Require two-factor authentication for administrators** - **Require two-factor authentication for members and guests** The requirement follows the person's role, whatever sign-in method they use. A person it covers who signs in with Microsoft is asked for their komplai second factor after the Microsoft sign-in, in addition to what your Microsoft policies ask for. People set up an authenticator app or a security key at their next sign-in. A person who belongs to more than one organisation in komplai follows the strictest requirement. Saving a change needs a recent sign-in: if yours is more than five minutes old, the hub asks you to confirm it. To turn a requirement off while administrators must use two-factor authentication, you confirm with two-factor authentication. ## Get it set up To connect Entra ID or AD FS, [contact us](https://en.komplai.dk/#kontakt) or use **Contact us about SSO** on `/settings/sso`. Include the two values from **Technical details**. --- https://developers.komplai.dk/guides/entra-id-ad-fs # Invitations > Invite colleagues to your organisation in komplai, choose their role, tools and sign-in method, and follow each invitation until it is accepted. People join your organisation in komplai only by invitation. komplai invites your first administrator when your organisation is set up. After that, your administrators invite colleagues from the hub. ## Invite a colleague 1. Open **Organisation › People › Members** (`/team`) and choose **Invite a colleague**. 2. Enter the colleague's **Email address**. 3. Choose a **Role**. 4. Under **Access when the invitation is accepted**, tick the tools the person gets. All the tools your organisation has are ticked to start with. A guest gets no tools, so the list is hidden for guests. 5. To use another sign-in method than your organisation's default, open the **Sign-in** line above **Send invitation** and choose a **Sign-in method**. 6. Choose **Send invitation**. ### Roles | Role | What the person can do | | --- | --- | | Member | Use the tools you give them access to. | | Admin | Invite colleagues and change the organisation's settings. | | Guest | Gets no access to tools or the API. | ### Who you can invite - If komplai has registered your organisation's email domains, members and admins need an address on one of them. Guests can have any address. [Contact us](https://en.komplai.dk/#kontakt) if a domain should be added. - An email address can have one pending invitation at a time. - Your organisation can send 20 invitations per hour. ### Sign-in methods | Method | What the invited person does | | --- | --- | | Password | Chooses a password when accepting. | | Passkey | Asks komplai's sign-in to email a setup link, registers a passkey from that email, then signs in and accepts. | | Organisation sign-in (SSO) | Signs in with your organisation's own account. The connection must be set up first; see [Sign-in with Entra ID and AD FS](https://developers.komplai.dk/guides/entra-id-ad-fs). | You set the default under **Default invitation method** on **Organisation › Sign-in and security › Sign-in** (`/settings/sso`). People who already have an account keep the sign-in method they have. ## What the person receives An email from komplai, in Danish, saying that you have invited them to your organisation in komplai. It names the tools the invitation gives, and its link works for 7 days. Replies go to your email address. ## Accepting The link opens a page that welcomes the person to your organisation. What happens next depends on the sign-in method: - **Password**: the person enters their first name, last name and a password that meets the rules listed under the field, and komplai signs them in. If two-factor authentication is required for their role, they first scan a QR code with an authenticator app on their phone and enter the six-digit code. They can choose **Use a security key instead** and set up the key at their first sign-in. - **Passkey**: the person enters their name and chooses **Send passkey setup**. They open the link in the email from komplai's sign-in, register a passkey, then sign in and accept the invitation. - **Organisation sign-in (SSO)**: the person enters their name, chooses **Sign in** and signs in with your organisation's account. - **An existing account**: someone who already has a komplai account, for example in another organisation, chooses **Accept invitation** and signs in as usual. When the invitation is accepted, the person becomes a member with the role you chose and gets the tools you ticked. A ticked tool outside your agreement is assigned when the agreement covers it. Signing in then opens your organisation, even for someone who belongs to other organisations. A link that has expired, been revoked or already been used shows **This invitation isn't valid**. The person then asks you for a new invitation. ## Follow up on invitations **Organisation › People › Invitations** (`/team/invitations`) lists every invitation with **Email address**, **Role**, **Method**, **Invited by**, **Status** and **Expires**. Search by address, or filter by status. | Status | Meaning | | --- | --- | | Pending | Sent and not accepted. The link works until the date under **Expires**. | | Accepted | The person has joined. | | Expired | The person opened the link after the date under **Expires**. | | Revoked | Withdrawn by an administrator. | For a pending invitation: - **Resend** emails a new link that works for 7 days, also when the date under **Expires** has passed. The link in the earlier email stops working, and the new email says so. - **Revoke** stops the link at once. An expired or revoked invitation cannot be resent: invite the person again from **Members**. If the hub says an invitation was created but its email could not be sent, choose **Resend** here. Invitations that komplai sent show komplai under **Invited by**. ## After someone has joined - Change a person's role, or remove them, on **Members** (`/team`). A person who becomes a guest, or is removed, loses their tools, and their API keys for your organisation stop working. Your organisation always keeps at least one administrator. - Give or take away tools later on **Tool access** (`/settings/apps`). - A member who uses a tool through the API creates their own personal API key (`kp_live_...`) under **APIs and integrations** (`/api-access`). The key is bound to the person and your organisation. See [API keys and authentication](https://developers.komplai.dk/authentication). --- https://developers.komplai.dk/guides/invitations # MCP clients > Connect VS Code or another MCP client to Register lookup over Streamable HTTP with a personal API key, without the key ending up in a file. Register lookup (Beta) lets an MCP client look up CVR, Retsinformation, Statistics Denmark and Folketinget. The client connects to `https://mcp.komplai.dk/mcp` over Streamable HTTP and sends your personal API key as a Bearer header on every request. [Register lookup](https://developers.komplai.dk/tools/register-lookup) describes the tools. ## Before you start - Your organisation's agreement includes Register lookup, and an administrator has given you access to it. - API access to Register lookup is turned on for your account, so you can create a key with `mcp:read`. If it is not, Register lookup in the hub says so. - Register lookup is approved for test data only. ## Create a key 1. In the hub, open **Register lookup** (`/modules/mcp`). The page shows the address and the configuration for your environment. 2. Choose **Create a key for Register lookup**. It opens **API keys** with Register lookup chosen. 3. Name the key, for example after the client and the computer, and choose how long it lasts. 4. Under **Review access**, check that `mcp:read` is selected and choose **Create API key**. 5. Copy the key. It is shown only once. The key starts with `kp_live_` and is bound to you and your organisation. It reaches only what you have access to. ## Connect VS Code 1. In VS Code, run **MCP: Open User Configuration** from the Command Palette. 2. Merge the configuration below into your existing settings. 3. Start the server `komplai`. VS Code asks for the key in a hidden field, so it never ends up in a file. ```json { "inputs": [ { "type": "promptString", "id": "komplai-api-key", "description": "komplai personal API key (mcp:read)", "password": true } ], "servers": { "komplai": { "type": "http", "url": "https://mcp.komplai.dk/mcp", "headers": { "Authorization": "Bearer ${input:komplai-api-key}" } } } } ``` This is the configuration Register lookup in the hub generates. It contains no key. It works in VS Code's extension host, not in Agent Host sessions. See [VS Code's MCP configuration reference](https://code.visualstudio.com/docs/agents/reference/mcp-configuration). ## Other clients Another MCP client works if it supports Streamable HTTP and lets you send a fixed `Authorization: Bearer` header with your personal API key. Keys are never accepted in the URL. Keep the key out of shared configuration and command history: use the client's secret store or an environment variable. To check your key and the connection without a client, start a session with `initialize`: ```bash curl -i https://mcp.komplai.dk/mcp \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"connection-check","version":"1"}}}' ``` A working key answers with the `initialize` result and an `Mcp-Session-Id` header. Without a key, the server answers 401 [api_key_required](https://developers.komplai.dk/errors/api_key_required). Set `KOMPLAI_MCP_SESSION_ID` to the `Mcp-Session-Id` from the response, and close the session again with the same key: ```bash curl -X DELETE https://mcp.komplai.dk/mcp \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Mcp-Session-Id: $KOMPLAI_MCP_SESSION_ID" \ -H "MCP-Protocol-Version: 2025-03-26" ``` Closing a session does not revoke the key. ## Sessions and limits - A session is bound to your organisation, to you and to the key. Another key, or a revoked one, cannot use it. - A key can have 5 sessions at a time. A session ends after 30 minutes without activity. - A request body can be at most 4 MiB. - Access is checked again on every request and every tool call, so a revoked key, an expired key or a withdrawn assignment stops working at once. - Lookups follow your account's request limits. ## Pseudonymise text from the client The client also lists tools to find personal data, pseudonymise text and put the originals back; they work only when the same key has `redact:detect` and you have access to Redact. They use regex only and do not find names. ## Where data goes - The lookup parameters go to the register you query. - Register lookup runs on komplai's EU infrastructure in Germany. - Lookups and regex use no AI, and they do not count towards AI usage or your organisation's monthly AI spending cap. - komplai does not store the text, queries or lists of labels in the Audit log. Metadata about access and usage is recorded. ## Revoke access Revoke the key under **API keys** (`/api-access`) in the hub. The client's sessions stop working at once. --- https://developers.komplai.dk/guides/mcp-clients # Processing approval > See what your organisation's agreement approves for each tool, choose which approved places each tool may use, and give people access. A tool works for a person, in the hub or through the API, only when three things are in place: 1. Your organisation's agreement with komplai covers the tool and approves where it may process data. 2. Your administrator allows that place for the tool. 3. The person has access to the tool. komplai records the agreement. Your administrator reads it in the hub and handles the other two. ## What the agreement approves The agreement names the tools your organisation has, the places each tool may use and the data you may send: - **Places.** Local infrastructure in Denmark, and komplai's EU cloud for a tool where the agreement has it. [Where data is processed](https://developers.komplai.dk/data-processing) describes each place. - **Data.** Test data by default. Personal data needs a data processing agreement that is active and selected on the agreement. [Test data](https://developers.komplai.dk/test-data) shows how a key reads this. The hub never offers a place or a tool that the agreement does not have. To approve more, such as EU cloud for a tool or personal data, your organisation agrees it with komplai. [Contact us](https://en.komplai.dk/#kontakt). ## Read the approval under Data protection Every member can open **Data protection** (`/governance`) in the hub's menu. Administrators see every tool in the agreement; members see the tools they have access to. 1. [Sign in](https://hub.komplai.dk/login) to the hub and open **Data protection**. 2. Under **Data processing**, find the tool. Its row shows **Processing**, **Location** and **Status**: *Set up*, *Not set up* or *Turned off*. 3. Open the row. It says what is sent and what is stored, and lists **Permitted data** (*Test data only* or *Personal data under the data processing agreement*) and, where they apply, the **Request limit** and the **Data processing agreement**. 4. Under **Data processing agreements**, open an agreement with **Preview PDF** or **Download PDF**. Each one shows its version, the date it was signed and a **Checksum (SHA-256)** you can compare with your own copy. Administrators also see the platform backup on the page, and a link to the processing choices. ## Choose which places each tool may use On **Organisation › AI and processing › Processing** (`/settings/processing`), an administrator chooses which of the approved places each tool may use. The page only narrows the approval: it never adds a place, changes the agreement or adds a connection. 1. Open **Organisation** in the menu, then **AI and processing**. **Processing** is the first tab. 2. Each tool has two columns. **In komplai** covers the tool's workspace in the hub. **Through the API** covers calls with an API key; a tool that has no API says so. 3. Tick the places the tool may use: **Local infrastructure** and, where the agreement has it, **EU cloud**. 4. Select **Save choices**. *Saved* appears when the server has stored them. For Redact, the choices are about the language model: **Without an LLM, or with the LLM on local infrastructure** and **With the LLM in the EU cloud**. Through the API, Redact's rules and NER at the place `eu-de` run on komplai's servers in Germany, and NER at the place `local` counts as local processing. What the choices mean: - With no place ticked in a column, new processing stops there. Tasks are never moved to another place, and the AI usage limits still apply. - Through the API, a call that would run at a place your administrator has not ticked is refused with [processing_choice_not_allowed](https://developers.komplai.dk/errors/processing_choice_not_allowed). It is never sent somewhere else. - Until an administrator saves choices for a tool, every approved place is allowed. - The choices cover komplai's processing. Your organisation's own AI connections have their own switches on the **Connections** tab; see [Your own AI connections](https://developers.komplai.dk/guides/ai-connections). - Every change is written to the organisation's **Audit log** (`/settings/audit`). Only the organisation's administrators can change the choices. komplai's read-only support access cannot open the page. ## Give people access On **Organisation › People › Tool access** (`/settings/apps`), tick a tool for a person, or for **Everyone**. Each tick is saved straight away. - Removing access also removes it from the person's API keys. - A tool marked *Turned off* is off for the organisation: you can remove access, but not give new access. - Guests do not get tools. People with access create their own personal API keys (`kp_live_...`) under **APIs and integrations › API keys** (`/api-access`), with the scopes the connection needs. [API keys and authentication](https://developers.komplai.dk/authentication) explains keys and scopes. ## Local models On **Organisation › AI and processing › Local models** (`/settings/local-models`), an administrator chooses which of komplai's validated models on local infrastructure the organisation uses, and the default model for each task. People choose among the models that are switched on, or among every validated model when none is switched on for a task. The tab is there when the organisation has Chat or Decide. ## How the API checks it The API checks the agreement, the administrator's choices, the person's access and the key's scopes on every call, and again while a text job runs. When something is withdrawn, the next call stops with one of these codes: | Code | What happened | | --- | --- | | [processing_not_approved](https://developers.komplai.dk/errors/processing_not_approved) | The organisation's processing approval for the tool is missing or was withdrawn. | | [processing_not_enabled](https://developers.komplai.dk/errors/processing_not_enabled) | The place is not approved for the tool, for example EU cloud. | | [processing_choice_not_allowed](https://developers.komplai.dk/errors/processing_choice_not_allowed) | Your administrator does not allow the place through the API. | | [app_not_assigned](https://developers.komplai.dk/errors/app_not_assigned) | The person behind the key lost access to the tool while the call was admitted. | | [insufficient_scope](https://developers.komplai.dk/errors/insufficient_scope) | The key lacks the scope, its person no longer has the tool, or the approval no longer covers it. | | [processing_access_withdrawn](https://developers.komplai.dk/errors/processing_access_withdrawn) | A text job lost its access after it was created. The job is invalidated and its text and result are deleted. | --- https://developers.komplai.dk/guides/processing-approval # Redact rules > Write your organisation's own Redact rules for text that must always, or never, be pseudonymised, in the Redact workspace, the API and Redact in Word. Redact finds personal data with its own detectors. Your organisation's rules add what only you know about, such as case numbers, project names and internal IDs, and exempt text that must stay readable. The rules apply to every Redact run in your organisation: in the [Redact](https://developers.komplai.dk/tools/redact) workspace in the hub, through the API and in [Redact in Word](https://developers.komplai.dk/tools/redact-word). ## Where you manage rules Rules are under **Organisation › Redact › Rules** (`/settings/redaction-rules`). The page is open to administrators who are assigned Redact, because rules often contain the very names and numbers you want to hide. komplai stores the rules on its servers in Germany until you delete them, and applies them there. The list has the views **Active**, **Disabled** and, if your organisation uses Documents, **Suggestions**. Search by pattern, and select several rules to **Activate**, **Disable** or **Delete** them at once. ## What a rule does Each rule has one of two effects: - **Pseudonymise**: matching text is replaced with a numbered label such as `[CASE-1]`. The same text gets the same label throughout a run. - **Exempt (never pseudonymise)**: matching text is never pseudonymised, even when a detector or another rule finds it. An exempt rule removes every finding that overlaps its match. When a literal exempt rule overlaps the text of a literal pseudonymise rule, the list says so next to the pseudonymise rule: **An exception rule takes precedence, so this rule is not used.** ## Create a rule 1. On **Rules**, choose **Create rule**. 2. Choose the **Effect**. 3. Under **Pattern type**, choose **Literal** for an exact text, or **Pattern (advanced)** for a regular expression. Write the text or pattern, at most 256 characters. 4. For a pseudonymise rule, choose a **Type**. Write a **Label** if you want your own word in the label: `CASE` gives `[CASE-1]`. Without one, the type's own label is used. 5. Choose where it **Applies to**. 6. For a pseudonymise rule, add a **Fixed replacement** if every match should read the same, such as `[CONFIDENTIAL]`. 7. Tick **Case-sensitive** if upper and lower case must match. By default they don't. 8. Choose **Create rule**. The rule is active at once and applies from the next run. A label can contain A to Z, 0 to 9, hyphen and underscore, and is saved in capitals. A fixed replacement has at most 128 characters, and it cannot have the same form as Redact's numbered labels, such as `[CASE-1]`, because it could be mistaken for one. Saving a rule with the same pattern type, pattern and effect as an existing one keeps the existing rule, and the hub says **Rule already existed.** ### How patterns match - A **Literal** rule matches the text wherever it occurs, also inside a longer word: `Falk` also matches in `Falkenberg`. Use a pattern with `\b` to match whole words only. - A **Pattern (advanced)** is a JavaScript regular expression, written without slashes or flags. It is checked before the rule is saved, and a pattern that could overload processing, for example one with repetitions nested inside other repetitions, is refused. - A pattern must never match empty text, as `\d*` does. While one active rule for the API does, every Redact call through the API fails with [`invalid_organisation_policy`](https://developers.komplai.dk/errors/invalid_organisation_policy). ### Example Case numbers of the form `24/01234`, and a project name that must always read the same: | Effect | Pattern type | Pattern | Label | Fixed replacement | | --- | --- | --- | --- | --- | | Pseudonymise | Pattern (advanced) | `\b\d{2}/\d{5}\b` | `CASE` | | | Pseudonymise | Literal | `Project Falcon` | | `[CONFIDENTIAL]` | ## Where rules apply A rule applies to the Redact workspace in the hub, the Redact API and Redact in Word. **Applies to** shows this as **Redact, API and Word**. Redact in Word gets its rules through the API. If your organisation uses Documents, **Applies to** has two choices instead: | Applies to | Used by | | --- | --- | | Redact, API, Word and Documents | The Redact workspace, the Redact API, Redact in Word and Documents | | Documents only | Documents | Older rules for **Word add-in only** are not used anywhere, and the list says so. Create such a rule again for Redact, API and Word if it should apply in Word. ### In the Redact workspace The rules apply to every run, whichever methods the person chooses. Findings from rules are listed under **Own masks and rules**, grouped as **Rule:** followed by the label. A fixed replacement cannot be changed in the workspace: the finding says that the organisation's rule sets the wording. ### Through the API POST /v1/redact, text jobs (POST /v1/redact/jobs) and the file operations POST /v1/redact/file and POST /v1/redact/file/jobs (Beta) apply every active rule your organisation has for **Redact, API and Word** (or **Redact, API, Word and Documents**) to every call, with any key and whichever `detectors` you choose. POST /v1/redact/detect applies them too, and so does Redact in Word, which scans through it. In the answer, a finding from a rule has `source` and `type` set to `custom`. With the two rules from the example: ```bash curl https://api.komplai.dk/v1/redact \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "text": "Case 24/01234 about Project Falcon is closed. See also case 24/01234 and 25/00077.", "detectors": ["regex"], "include": ["mapping"] }' ``` The answer, shortened to the fields that matter here: ```json { "redacted": "Case [CASE-1] about [CONFIDENTIAL] is closed. See also case [CASE-1] and [CASE-2].", "mapping": { "[CASE-1]": "24/01234", "[CONFIDENTIAL]": "Project Falcon", "[CASE-2]": "25/00077" }, "entries": [ { "placeholder": "[CASE-1]", "type": "custom", "value": "24/01234", "confidence": "high", "source": "custom" }, { "placeholder": "[CONFIDENTIAL]", "type": "custom", "value": "Project Falcon", "confidence": "high", "source": "custom" }, { "placeholder": "[CASE-2]", "type": "custom", "value": "25/00077", "confidence": "high", "source": "custom" } ] } ``` A fixed replacement can stand for several originals, so POST /v1/redact/restore never puts it back. It stays in the text and is listed in `fixedTokens`. The [Redact reference](https://developers.komplai.dk/reference/redact) has every field. | Code | When | | --- | --- | | [`processing_policy_changed`](https://developers.komplai.dk/errors/processing_policy_changed) | The rules changed while the call ran. Send it again. | | [`invalid_organisation_policy`](https://developers.komplai.dk/errors/invalid_organisation_policy) | More than 500 active rules apply to the API, or one of them cannot be used. | | [`incoherent_redaction_policy`](https://developers.komplai.dk/errors/incoherent_redaction_policy) | Two rules with different fixed replacements find overlapping text. | | [`unsafe_placeholder`](https://developers.komplai.dk/errors/unsafe_placeholder) | The text already contains a fixed replacement, or a fixed replacement collides with a label. | | [`processing_access_withdrawn`](https://developers.komplai.dk/errors/processing_access_withdrawn) | You read a text job created before the rules changed. | > **Changing rules ends existing text jobs** > > A text job belongs to the rules it was created under. When the rules that apply to the API change, for example when you create, activate, disable or delete one, or when a suggestion from Documents becomes active, a job created before the change can no longer be read. The next time the job is read or processed, komplai invalidates it and deletes its text and result, and reading it answers 403 `processing_access_withdrawn`. Read the results you need before you change the rules, and submit the text again as a new job afterwards. ## Suggestions from Documents If your organisation uses Documents, text that people pseudonymise by hand there becomes a suggestion under **Suggestions**. Only text that looks like a name counts: at least three characters, starting with a capital letter, and not a common word. Each suggestion shows how many users, sessions and events it is based on. **View the evidence** lists who pseudonymised the text, in which document and when, up to the 200 most recent events, with a link to open the document and check it. A suggestion becomes an active rule by itself when two different people, or one person in three different documents, have pseudonymised the same text as the same type. It then applies to **Redact, API, Word and Documents**. Choose **Activate rule** to activate a suggestion before that. To stop a rule that came from suggestions, choose **Disable**: a disabled rule stays disabled when people go on pseudonymising the text, while a deleted rule is created again the next time someone pseudonymises the text by hand. ## Lookup sources Redact Agentic (Alpha) is an experimental Redact method that can look things up in registers while it works. It runs on komplai's local infrastructure in Denmark. **Organisation › Redact › Lookup sources** (`/settings/redact-sources`) has two settings for it: - **Redact Agentic**: when it is on, people in your organisation can choose the method, and NER models in alpha and beta, both in Redact and with personal API keys. - **Sources**: the sources the method may look up. People choose sources for each run from those you allow. A source that is not ready shows why. | Source | What is sent | Recipient | Kept by the recipient | | --- | --- | --- | --- | | CVR | The CVR number or registered company name. Person lookups are not available. | Datafordeleren / Klimadatastyrelsen. Processing location not confirmed. | IP address and user name are logged for up to 9 months. | | BBR | Building, house-number or property IDs. Lookups do not include residents. | Datafordeleren / Klimadatastyrelsen. Processing location not confirmed. | IP address and user name are logged for up to 9 months. | | Web search | Bounded search terms, never the whole document. | Brave Software Inc., USA, outside the EU/EEA. | Search queries for up to 90 days. | | Danish Address Register | Street name, postcode and optional house number. Lookups do not include residents. | Klimadatastyrelsen (Adressevælger). Processing location not confirmed. | Not confirmed. | | Wikidata, local | Nothing is sent to Wikidata: search terms and Wikidata IDs are looked up in a local copy. | Local infrastructure. | Search terms are not stored. | CVR and BBR use komplai's access, or your own Datafordeler key. Web search needs your own Brave Search API key. The Danish Address Register needs no key. Wikidata, local appears where komplai's local copy is ready. Keys you save are stored encrypted and never shown again. Through the API, the method is the request fields `engine` and `sources` on POST /v1/redact, text jobs and the file operations. They need a personal API key: an organisation integration key gets [`integration_not_permitted`](https://developers.komplai.dk/errors/integration_not_permitted). Without the setting the call answers [`agentic_preview_not_enabled`](https://developers.komplai.dk/errors/agentic_preview_not_enabled), and a source you have not allowed answers [`agentic_lookup_not_allowed`](https://developers.komplai.dk/errors/agentic_lookup_not_allowed). --- https://developers.komplai.dk/guides/redact-rules # Publish with Run > Create an app in Run, try it on your own computer, publish versions from the terminal, a pipeline or your AI coding assistant, and use komplai from the app through the app SDK. You need a built browser app, either one HTML file or a folder with `index.html` such as `dist`, and Run turned on for your organisation. The terminal commands need Node.js 22.15 or later. [Run](https://developers.komplai.dk/tools/run) describes who can open an app, the limits and where data is stored. ## Create the app 1. In the hub, open **Run** and choose **New app**. 2. Type the app's name. Run suggests an address from the name; change it if you want another, or empty the field to get a random address. 3. Choose **Create app**. The app opens on its own page, ready for the first version. A new app is Organisation only: members of your organisation sign in to komplai to open it. ## Build for Run - Deliver one self-contained HTML file, or a folder or ZIP file with `index.html` at the top. In a ZIP file, everything may also sit inside one folder. - Build React, Vite or another framework on your own computer and publish the built output, never the source project. - Use relative URLs, or URLs that start with `/` on the app's own address. Client-side routes without a file extension get the app's HTML; a missing JavaScript or CSS file stays a 404. - The packer leaves out hidden files, `node_modules` and source maps, and refuses symbolic links and project files such as `package.json`. Keep `.env` files and keys out of the build: a browser app cannot keep a secret. ## Try it on your own computer `dev` serves your build at `http://localhost:5180` the way Run does, with the same SDK, routes and Content-Security-Policy, and a local stand-in for komplai: ```bash npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish dev ./dist ``` - Every use the app declares in `komplai.json` counts as approved. An undeclared use is refused with `capability_not_approved`, as in Run. - You are `Udvikler`, an administrator. `--as NAME` changes the name and `--member` makes you a member. At `http://localhost:5180/_komplai/dev` each browser signs in as its own person, so a private window can be a second person, and you can end the session to try `session_expired`. - Saved data is kept in memory until you stop the server. - Redact finds patterns only. AI is refused with `ai_not_available_in_dev` unless `KOMPLAI_API_KEY` holds a personal API key with `chat:complete`; calls then go to komplai's API in the EU cloud or through the connection the app names, and EU cloud usage counts towards your organisation's monthly AI spending cap. - Events, errors, counters and every refusal are printed in the terminal. `--port` chooses another port. ## Create a publishing key 1. On the app's page, under **Publish the first version** (or **Publish a new version**), choose **Terminal**. 2. Choose **Create a publishing key**. The key is shown only once. 3. Copy the command Run shows. It contains the address of the command-line tool and the app's upload address, but no key. A publishing key can only publish new versions of that one app. It cannot create apps, change an app's name, address or who can open it, open apps that are Organisation only, or use komplai's AI. It expires after 7 days, and it stops working when it is revoked, when the person who created it leaves the organisation or can no longer change the app, when the app is deleted or when Run is switched off for the organisation. An app can have 10 active keys. Revoke a key under **Publishing keys** on the app's page. > **Keep the key out of code and chats** > > Never put the publishing key in code, Git, a command or a chat with an AI coding assistant. Paste it when the terminal asks, or set `KOMPLAI_PUBLISH_TOKEN` privately in your terminal or your tool's environment. ## Publish a version See what would be published first. This lists every file, checks the manifest as Run does, and uploads nothing: ```bash npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist --dry-run ``` Then run the command from Run in your project folder. Replace `./dist` if your built files are in another folder: ```bash npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist --endpoint https://hub.komplai.dk/api/publish/APP_UUID/releases ``` The command shows the target app, asks you to confirm and asks for the key at a hidden prompt. The new version is live at once at the app's address. Open the address and check the app: an app that is Organisation only asks you to sign in to komplai, because the publishing key gives no access to view the app. If the connection fails or the outcome is uncertain, the upload may still have gone through. Check in Run which version is live before you try again. The command never retries by itself. To avoid typing the upload address each time, save it once. `init` writes `.komplai-publish.json` with the upload address and the build folder, never the key: ```bash npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish init --endpoint https://hub.komplai.dk/api/publish/APP_UUID/releases npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist ``` To upload the files yourself with **Upload file** on the app's page, pack them into a ZIP file without sending anything: ```bash npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish pack ./dist --out app.zip ``` Install the command-line tool only from the package address in the command Run gives you. ## Publish from a pipeline or a script The upload API takes the file itself as the request body. Send a ZIP file as `application/zip` or a single HTML file as `text/html`, with the publishing key as a Bearer token: ```bash curl https://hub.komplai.dk/api/publish/APP_UUID/releases \ -H "Authorization: Bearer $KOMPLAI_PUBLISH_TOKEN" \ -H "Content-Type: application/zip" \ --data-binary @app.zip ``` The command-line tool works in a pipeline too. It reads the key from `KOMPLAI_PUBLISH_TOKEN`, and `--yes` skips the confirmation: ```bash npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist --endpoint https://hub.komplai.dk/api/publish/APP_UUID/releases --yes ``` The endpoint is for terminals and build tools. It refuses any request with an `Origin` header, so JavaScript in a browser cannot call it. Because a publishing key expires after 7 days, a pipeline needs a new key from Run after that. A successful upload answers HTTP 200 with the app's details: `id`, `activeRelease` (the version that is now live), `visibility` and the saved versions in `releases`, each with its id, when it was created, its unpacked size in bytes, its number of files and the SHA-256 checksum of the uploaded file. Ignore fields you do not recognise. If the archive or a capacity check fails, the version that was live stays live. | Status | What happened | | --- | --- | | 400 | The archive or format is invalid, or the manifest cannot be used (`invalid_manifest`) | | 401 | The key is invalid, expired or revoked | | 403 | Missing permission, an `Origin` header, or Run is switched off for the organisation | | 409 | The app is public and the version declares uses that need sign-in (`public_app_capabilities`) | | 413 | The upload is over the limit | | 429 | The traffic or concurrency limit is reached | | 503 | Run is unavailable, or the outcome is uncertain | | 507 | No room for the version in storage | The body is JSON with an `error` code and no credential details. After a 503, check in Run which version is live before you send the file again. ## Publish with your AI coding assistant 1. On the app's page, under **Publish a new version**, choose **AI coding assistant** and **Download the guide (ZIP file)**. The same file is at [hub.komplai.dk/komplai-publish/komplai-publish.zip](https://hub.komplai.dk/komplai-publish/komplai-publish.zip). 2. Unzip it and put the `komplai-publish` folder in `.claude/skills` in your home folder for Claude Code, or in `.codex/skills` for Codex. In a project, Claude Code also reads `.claude/skills` and Codex reads `.agents/skills`. Other assistants can read `SKILL.md` and `API.md` in the folder. 3. Create a publishing key and give the assistant the command from Run, never the key. 4. Start a new conversation and ask the assistant to build or publish the app. In Claude Code you can also type `/komplai-publish`. The assistant tries the app with `dev`, checks it with `--dry-run` and runs the command; you paste the key when the terminal asks. Once you have approved the publication and the target app, it may add `--yes` to skip the confirmation. If the outcome is uncertain, it does not try again: check in Run which version is live first. ## Use komplai from the app Load the SDK from the app's own address. `/_komplai/run/v1.js` defines `komplai` on the page, and `/_komplai/run/v1.mjs` exports it as a module. The SDK sends every call to the app's own address with the person's app session, and Run checks the session, the person's access and the administrator's approval on every call. Never call the hub or komplai's API from the app, and never put a key, token or password in it. Declare what the app uses in `komplai.json` next to `index.html`. With Vite, put the file in `public/` so the build copies it into `dist`. A single HTML file can carry the manifest in `
    ``` | Call | Needs in the manifest | Answers | | --- | --- | --- | | `komplai.app()`, `komplai.theme.current`, `komplai.locale` | nothing | The app's facts, `light` or `dark`, and `da` or `en` | | `komplai.session` | nothing; a public app has no session | `expiresAt()`, `onExpired(fn)`, `renew()` and `signOut()` | | `komplai.me()` | `identity` | `memberId` and the approved fields | | `komplai.ai.chat({ messages })` | `ai.chat` | `{ text, model, processing, usage }` | | `komplai.redact.findings(text)`, `.pseudonymise(text)`, `.restore(text, placeholders)` | `redact.text` | Findings with offsets and type, or text with labels such as `[PERSON-1]` | | `komplai.data.collection(name)` | `data` | `add`, `get`, `list`, `update`, `remove`, `changes`, `watch` and `exportMine` | | `komplai.log.event(name, { ref })`, `.error(error)`, `.count(name)` | `log.events`, `log.errors`, `log.counters` | Writes the event, report or count | In a collection with `scope` set to `person`, each person sees only their own documents. With `app`, everyone who can open the app reads them, and `write` decides whether all members (`members`) or only the app's creator and your organisation's administrators (`managers`) write. With `organisation`, several apps share the collection. A member changes and removes only the documents they created; the app's creator and the administrators can change any. Pass `{ ifVersion: doc.version }` to `update` when it must not overwrite someone else's change. When a call is refused, the app gets a `KomplaiError` with a `code`, a `status` and a `message` in the person's language. Show the message, and write data from komplai into the page with `textContent`, never `innerHTML`. The codes you meet first: - `capability_not_approved`: an administrator has not approved this use for the app yet. - `session_expired`: the person is no longer signed in to the app. `komplai.session.renew()` signs in again and returns to the page. - `app_not_assigned`: the person has no access to the tool the app uses, such as Chat or Redact. - `version_conflict`: someone changed the document meanwhile. Fetch it and try again. `API.md` in the guide lists every call, option, limit and error code. ## Approve what the app uses After you publish a version that declares uses, an administrator opens the app's page in Run and goes to **What the app may use**. Each use shows the app's reason and **Approve** or **Decline**; an approved use can be revoked later. - **AI**: the administrator chooses where the app may use AI, komplai's EU cloud within your organisation's monthly AI spending cap or one of your organisation's own connections, and sets the app's own monthly limit. When the limit is reached, the app's AI stops until the next month. - **Redact**: the app uses patterns and NER on komplai's servers in Germany. The administrator can also allow Redact's language model in komplai's EU cloud. - **Send data to …**: approve where the app may send data before the rest. Try every feature in Run after approval: the local stand-in approves everything. ## Manage the app - **Versions**: **Use this version** makes an earlier version live again. - **Take the app offline**: nobody can open the app until you publish or choose a version again. **Make the newest version live again** brings it back. - **Errors in the app**: errors the app sent from the browser in the last 30 days. Only the person who created the app and your organisation's administrators see them. - **Download the app's data**: all the app's documents, also those each person saved for themselves only. Only your organisation's administrators can download it. - **Delete app and all versions**: type the app's name to confirm. Its publishing keys stop working, links to it stop working, and its address becomes available to others at once. This cannot be undone. --- https://developers.komplai.dk/guides/run # Roll out Word in Microsoft 365 > Deploy Redact in Word to your organisation from the Microsoft 365 admin center with komplai's manifest URL, and test it with pilot users first. As a Microsoft 365 administrator, you deploy Redact in Word from the Microsoft 365 admin center with komplai's manifest file. The people you assign then find it in Word without installing anything. [Redact in Word](https://developers.komplai.dk/tools/redact-word) describes what they see and what is sent. ## Before you deploy In komplai: - Your organisation's agreement includes Redact's API and Word add-in. [Contact us](https://en.komplai.dk/#kontakt) if it does not. - Everyone who should use Word is invited to komplai, under **Organisation** → **People** → **Invitations** (`/team/invitations`) in the hub. See [Invitations](https://developers.komplai.dk/guides/invitations). - They have access to Redact. An administrator assigns it under **Organisation** → **People** → **Tool access** (`/settings/apps`). - People sign in through komplai's sign-in. If your organisation signs in with Entra ID, see [Sign-in with Entra ID and AD FS](https://developers.komplai.dk/guides/entra-id-ad-fs). - Until your agreement covers personal data, Word shows **Test data only**, and people must use test data. See [Processing approval](https://developers.komplai.dk/guides/processing-approval). In your network, allow HTTPS to: | Address | Used for | | --- | --- | | `https://hub.komplai.dk` | The task pane and the sign-in and connection pages | | `https://auth.komplai.dk` | Sign-in | | `https://api.komplai.dk` | Scans | | `https://word.komplai.dk` | The manifest file and the icons | In Microsoft 365, your setup must support centralized deployment of add-ins. See [Microsoft's requirements](https://learn.microsoft.com/en-us/microsoft-365/admin/manage/centralized-deployment-of-add-ins). ## The manifest | What | Value | | --- | --- | | Manifest URL | `https://word.komplai.dk/manifest.xml` | | Installation guide | [word.komplai.dk](https://word.komplai.dk) | | Name in Word and the admin center | [PROD] komplai for Word | | Provider | [PROD] Progressify ApS | | Ribbon | The **[PROD] komplai** tab with the **Open Redact** button | | Host | Word only | | Permission | Read and write the document | The hub also links the manifest and the installation guide under **APIs and integrations** → **Connect a tool** (`/api-access/clients`). The manifest loads the task pane from `https://hub.komplai.dk/office/word`. Changes to Redact in Word therefore reach your users with the hub, without a new manifest. ## Deploy the add-in 1. Go to [admin.microsoft.com](https://admin.microsoft.com). 2. Open **Settings** → **Integrated apps**. 3. Choose **Upload custom apps**. 4. Choose **Provide link to manifest file** and paste `https://word.komplai.dk/manifest.xml`, or upload the downloaded `manifest.xml`. 5. Assign the add-in to the users or groups it applies to. Start with a few pilot users. 6. Accept the permissions and finish the deployment. Microsoft can take a while to show the add-in to every user. A user who has Word open must quit it completely and open it again. ## Test with pilot users Test installation, sign-in and a scan in the versions of Word your organisation uses before people start using the add-in. Test Word for Windows and Word on the web separately: one working does not show that the other does. Use a document with fictional information. 1. Open Word and check that the **[PROD] komplai** tab has the **Open Redact** button. 2. Choose **Open Redact**, then **Sign in**, and sign in with a komplai account. 3. On **Connect Word**, check the organisation's name and choose **Connect Word**. 4. Choose **Scan document**, review the findings and apply a few replacements. 5. Read the document through, then choose **Disconnect**. If the task pane says **Update Word to use this add-in**, that version of Word lacks WordApi 1.6, DialogApi 1.1 or DialogOrigin 1.1. ## Test on one Windows PC with a shared folder For a test on one PC before central deployment, Word for Windows can load the add-in from a trusted shared-folder catalog: 1. Put `manifest.xml` in a folder and share it (right-click → **Properties** → **Sharing**). 2. In Word, choose **File** → **Options** → **Trust Center** → **Trust Center Settings** → **Trusted Add-in Catalogs**. 3. Paste the network path, such as `\\server\folder`, choose **Add catalog** and tick **Show in Menu**. 4. Restart Word, then choose **Insert** → **My Add-ins** → **Shared Folder**. ## Support your users - **The button is missing**: check the assignment in **Integrated apps**, and ask the user to quit Word completely and open it again. - **The connection is refused after sign-in**: the user chose the wrong organisation, or has no access to Redact. Check **Tool access** in the hub. - **The task pane is blank**: the network blocks one of the addresses above. - **Ending a connection**: each Word connection is a personal API key that expires after 24 hours. The user ends it with **Disconnect**, or revokes it under **API keys** (`/api-access`) in the hub. --- https://developers.komplai.dk/guides/word-rollout # komplai developer documentation > Use Redact, Chat, Decide and Coding from your organisation's own systems through komplai's API, and connect Word and MCP clients. Your organisation's systems can use the same tools as the hub through komplai's API: find personal data and pseudonymise text with Redact, send messages to the models in Chat, and get probabilities from Decide. Every call sends an API key and runs on the processing your organisation has approved. ## Where to start - **Your first call:** [Get started](https://developers.komplai.dk/get-started) takes you from a personal API key in the hub to a call to Redact. - **A system that runs without a person,** such as a robot or an integration platform: komplai issues an organisation integration key for Redact. [API keys and authentication](https://developers.komplai.dk/authentication) explains both kinds of key. - **An endpoint:** the [API reference](https://developers.komplai.dk/api) lists every operation with its fields, code samples and a console to try it. - **An error:** every error answer links to its own page, and [Errors](https://developers.komplai.dk/errors) lists them all. - **Where data goes:** [Where data is processed](https://developers.komplai.dk/data-processing). ## What you can connect | Tool | How you connect | Key | | --- | --- | --- | | [Redact](https://developers.komplai.dk/tools/redact) | `/v1/redact`: find personal data, pseudonymise text, restore the originals and send long documents as text jobs | Personal API key or organisation integration key | | [Chat](https://developers.komplai.dk/tools/chat) | `/v1/chat/completions` and `/v1/models`, in OpenAI's chat completion format | Personal API key | | [Decide](https://developers.komplai.dk/tools/decide) (Beta) | `/v1/decide`: typed questions about a text, answered with probabilities | Personal API key | | [Coding](https://developers.komplai.dk/tools/coding) (Beta) | `/v1/coding`: streamed completions for coding clients | Personal API key | | [Register lookup](https://developers.komplai.dk/tools/register-lookup) (Beta) | An MCP client, at Register lookup's own address | Personal API key with `mcp:read` | | [Redact in Word](https://developers.komplai.dk/tools/redact-word) | The Word add-in | Sign-in from Word, no key | [Run](https://developers.komplai.dk/tools/run) publishes finished web apps from a file, the terminal or a coding assistant. A tool marked Beta may still change, and komplai gives notice before it does. Redact's PDF and Word input is in beta too. ## Access and data A key reaches only what your organisation's agreement with komplai covers and what your administrator has assigned to you, and the API checks this again on every call. Without an approved data processing agreement, use test data only: see [Test data](https://developers.komplai.dk/test-data). To create a key, [sign in](https://hub.komplai.dk/login) to the hub. For API access for your organisation, [contact us](https://en.komplai.dk/#kontakt). --- https://developers.komplai.dk/ # Limits > Request limits, AI spending limits, size limits and timeouts in komplai's API, and what to do when a call reaches one. GET /v1/access shows the request limits and Redact's text limits that apply to your key. Text limits and offsets count UTF-16 code units, as string length does in JavaScript and .NET. ## Request limits Every call counts against several per-minute limits at once. The first one reached answers 429 [`rate_limited`](https://developers.komplai.dk/errors/rate_limited) with `Retry-After`, the seconds to wait, at most 60. | Limit | Calls per minute | Shared by | | --- | --- | --- | | Person | Set by komplai for each tool in your organisation, at most 120. GET /v1/access shows it in `services[].limits.requests_per_minute`. | All of a person's personal API keys and their use of the hub, across tools | | Integration | Set by komplai for Redact in your organisation | All keys of one organisation integration, also after komplai issues a new key | | Organisation | 120 | Everyone in the organisation, people and integrations, in the API and in the apps | | API | 300 | Every organisation, in the API and in the apps | | IP address | 300 for calls with a komplai key, 60 for other requests | All calls from one IP address | A 429 from the per-IP limit also carries `x-ratelimit-limit`, `x-ratelimit-remaining` and `x-ratelimit-reset`, which describe that limit. A second key does not give you more calls: your keys share your limit. What counts: - GET /v1/access counts as one call. - Each read of a text job's status or result counts. Wait at least 2 seconds between reads. - DELETE /v1/redact/jobs/{id} counts only against the per-IP limit. - POST /v1/decide/batch counts as one call for up to 100 texts. - GET /v1/openapi.json needs no key and counts only against the per-IP limit. Some work runs without a queue, so when every slot is busy, the call answers 429 [`processing_capacity_busy`](https://developers.komplai.dk/errors/processing_capacity_busy) with `Retry-After`: each API process runs your organisation's redaction rules in at most two workers and reads at most two PDF or Word files at a time. The language model on local infrastructure has a shared queue; when it is full, a synchronous call answers 503 [`model_busy`](https://developers.komplai.dk/errors/model_busy), while a text job waits for its turn. ## AI spending A call that runs a model in komplai's EU cloud is metered at the provider's price and counts towards: - your organisation's monthly AI spending cap, agreed with komplai; - your organisation's own limit, when its administrator has set one below the cap; - your personal limit, when the administrator has set one. It applies to personal API keys only; an organisation integration key has none. When the lowest of these is reached, calls in EU cloud answer 429 [`ai_credit_exhausted`](https://developers.komplai.dk/errors/ai_credit_exhausted) or [`person_ai_credit_exhausted`](https://developers.komplai.dk/errors/person_ai_credit_exhausted). Waiting does not help: the monthly cap starts again next month. The API never moves a call to local infrastructure by itself; choose local processing in the request. Local infrastructure has no AI charge. Your organisation's own AI connections are paid to the provider directly and do not count towards the cap. Your organisation's administrator sees the cap and sets the organisation's own limit and personal limits under **Organisation › AI usage › Limits**. You see your own usage under **APIs and integrations › Usage**. ## Size limits | Operation | Limits | | --- | --- | | POST /v1/redact/detect | Text: 16,000 UTF-16 code units. Body: 100,000 bytes. | | POST /v1/redact | Text: 750,000 UTF-16 code units, or 2,000,000 with `Prefer: respond-async`. | | POST /v1/redact/jobs | Text: 2,000,000 UTF-16 code units, about 800 standard pages of 2,400 characters. | | POST /v1/redact/restore | Text: 750,000 UTF-16 code units. The list of labels (`mapping`): 100,000 entries, 2,000,000 UTF-16 code units and 500 fixed labels. The text with the originals put back: 8,000,000 UTF-16 code units. | | POST /v1/redact/file (Beta) | File: 50 MiB decoded and 2,000 PDF pages. File name: 255 characters. Extracted text: 750,000 UTF-16 code units. | | POST /v1/redact/file/jobs (Beta) | As POST /v1/redact/file, with up to 2,000,000 UTF-16 code units of extracted text. | | Every Redact result | 32 MiB. | | POST /v1/chat/completions | 32 messages and 80,000 UTF-16 code units of content. Body: 400,000 bytes. `max_tokens`: at most 32,768 and the model's `max_output_tokens`. `response_format`: 32,768 bytes, with a schema at most 24 levels deep and 2,048 values. | | POST /v1/decide (Beta) | 80,000 characters as JSON. Body: 320,000 bytes. 64 questions, each with up to 32 criteria. | | POST /v1/decide/batch (Beta) | 100 texts. 200,000 characters as JSON. Body: 800,000 bytes. | | POST /v1/coding/chat/completions (Beta) | Body: 2,000,000 bytes and 2,000,000 characters as JSON. 512 messages and 64 tools. `max_tokens` or `max_completion_tokens`: at most 32,000. | Single fields have their own bounds, such as at most three values in `detectors` or four strings in `stop`. Each operation's page in the [API reference](https://developers.komplai.dk/api) lists them. Redact also bounds the work a text may need: candidate matches, matched characters and coreference matching grow with the text's length, and your organisation's rules have a time limit that grows with the text and the number of rules. A text beyond them answers 413 [`processing_complexity_exceeded`](https://developers.komplai.dk/errors/processing_complexity_exceeded). The bounds are in `text_contract.complexity_limits` in GET /v1/access. Because they grow with the text, splitting it rarely helps. ## Timeouts | Call | Limit | When it is reached | | --- | --- | --- | | POST /v1/redact, POST /v1/redact/file | 300 seconds | A run komplai estimates cannot finish in time is refused before anything runs, with 413 [`use_job`](https://developers.komplai.dk/errors/use_job). A run that still reaches the limit ends with 504 [`processing_timeout`](https://developers.komplai.dk/errors/processing_timeout). | | Reading a PDF or Word file | 120 seconds | 413 [`file_too_complex`](https://developers.komplai.dk/errors/file_too_complex) | | POST /v1/chat/completions | 120 seconds for the model to answer | 504 [`timeout`](https://developers.komplai.dk/errors/timeout) | | POST /v1/decide, POST /v1/decide/batch | 30 seconds | 502 [`service_unavailable`](https://developers.komplai.dk/errors/service_unavailable) | | POST /v1/coding/chat/completions | 600 seconds for the whole answer | 504 [`timeout`](https://developers.komplai.dk/errors/timeout), or an error event with `timeout` once the stream has begun | | Text jobs | No limit while the job makes progress | After 65 minutes without progress, the job ends with [`redact_job_stalled`](https://developers.komplai.dk/errors/redact_job_stalled). After three interruptions, it ends with [`redact_job_attempts_exhausted`](https://developers.komplai.dk/errors/redact_job_attempts_exhausted). | Give your HTTP client a timeout a little longer than the call's limit, so you get komplai's answer instead of your own timeout. For long texts, use a text job or `Prefer: respond-async` rather than a longer wait. A text job and its encrypted result are kept until you delete the job or until its `expiresAt`. The retention period counts from when the job ends. --- https://developers.komplai.dk/limits # llms.txt > Give an AI assistant this documentation as llms.txt, as one full text file or as a Markdown copy of each page. Every page on this site also exists as plain Markdown, for AI assistants and other tools that read text rather than HTML. The copies are built from the same sources as the pages, so they say the same. ## What is available | Address | What it holds | | --- | --- | | [/llms.txt](https://developers.komplai.dk/llms.txt) | An index in the llms.txt format: every page in the navigation with its description, the API reference pages and every error code, each linked to its English Markdown copy. | | [/llms-full.txt](https://developers.komplai.dk/llms-full.txt) | Every English page, every API reference page and every error code in one file. | | `/.md` | The English copy of a page, such as [/get-started.md](https://developers.komplai.dk/get-started.md). The overview is [/index.md](https://developers.komplai.dk/index.md). | | `/da/.md` | The Danish copy of a page, such as [/da/get-started.md](https://developers.komplai.dk/da/get-started.md). | | `/reference/.md` | An API reference page, such as [/reference/redact.md](https://developers.komplai.dk/reference/redact.md): each operation with its description, operation id, scopes, parameters and response statuses. | | `/errors/.md` | An error code, such as [/errors/rate_limited.md](https://developers.komplai.dk/errors/rate_limited.md): what it means, its status, what to do, an example where there is one, and the operations that return it. | The reference copies leave the request and response schemas out. The descriptions in the API reference and on the error pages are in English, so those pages have English copies only. In a copy, links are absolute and a Beta badge is the word (Beta). ## Give it to an assistant - An assistant that can read web pages: give it `https://developers.komplai.dk/llms.txt`, and it can open the pages it needs from there. - An assistant that reads one file: attach or paste `/llms-full.txt`. --- https://developers.komplai.dk/llms-txt # Test data > Work with fictitious data until your organisation's agreement approves personal data, check what your key may send, and use the examples the API documents. Until your organisation's agreement approves personal data for a tool, send only test data to it: invented or synthetic text with no real people in it. That applies to the API, to the hub and to the Try it consoles on this site. ## Check what you may send Each tool has a data mode, set for your whole organisation. A key reads the mode of the tools it reaches, and GET /v1/access shows it in `services[].processing.data_mode`, and at the top level when the key reaches one service: ```bash curl https://api.komplai.dk/v1/access \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` ```json { "services": [ { "service": "redact", "processing": { "data_mode": "synthetic", "agreement_reference": null } } ], "processing": { "data_mode": "synthetic" } } ``` | `data_mode` | What you may send | | --- | --- | | `synthetic` | Test data only | | `personal` | Personal data, under the data processing agreement in `agreement_reference` | The hub shows the same. Under **APIs and integrations › API keys** (`/api-access`), open **Connection details**: the column **Permitted material** says *Test data only* or *Personal data approved* for each service. **Data protection** (`/governance`) shows **Permitted data** for each tool. komplai records the data mode on your organisation's agreement. Test data is the default, and personal data needs a data processing agreement that is active and selected on the agreement. A key cannot change the mode, and the API does not read your text to decide whether it holds personal data: the mode is the limit your organisation has agreed to. [Processing approval](https://developers.komplai.dk/guides/processing-approval) shows where an administrator reads it. ## Where test data has its own rules - **Redact text jobs.** With test data and no storage policy, the result of a text job is kept for 1 hour after the job ends. Personal data in text jobs also needs a storage policy agreed with komplai; without one, the job is refused with [approved_redact_storage_policy_required](https://developers.komplai.dk/errors/approved_redact_storage_policy_required). - **Chat on local infrastructure.** A Chat call that names `processing: "komplai-local"` runs on local infrastructure under test data only, also when your organisation's Chat runs in EU cloud. Leave `processing` out to run under your organisation's Chat processing and its data mode. - **Register lookup** (Beta): use test data only with Register lookup. - **Free models on your own AI connections.** The provider of a free model, such as OpenRouter's `openrouter/free` router, may store and use what is sent. Use such a connection for tests, synthetic data and ideas. Calls with test data count like any other call: towards the request limits and, in EU cloud, towards your organisation's monthly AI spending cap. See [Limits](https://developers.komplai.dk/limits). ## The examples in the API reference The API reference uses one invented person throughout, so you can send the examples as they are and compare the answers: | Field | Value | | --- | --- | | Name | Mette Kjærgaard Holm | | CPR number | 120385-1234 | | Address | Fiktivvej 12, 8000 Aarhus C | | Phone | 21 34 56 78 | | E-mail | mette.holm@example.invalid | This call pseudonymises the full example text with rules and NER. It needs a key with `redact:process`: ```bash curl https://api.komplai.dk/v1/redact \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{"text": "Borgeren Mette Kjærgaard Holm, cpr-nr. 120385-1234, bor på Fiktivvej 12, 8000 Aarhus C. Hun kan kontaktes på 21 34 56 78 eller mette.holm@example.invalid.", "detectors": ["regex", "ner"], "include": ["mapping"]}' ``` ```json { "redacted": "Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [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" } } ``` The other examples test one thing each: - *Sagsbehandleren talte med Mette Kjærgaard Holm om hendes diabetes.* Health data in free text, which only the language model (`llm`) finds. - *Gammelt nummer 150677-8642, erstatningspersonnummer 720385-1234 og cpr-nr. 120385-1234.* Two numbers that look like CPR numbers but whose digits do not decode to a plausible birth date. They stay in the text and are listed in `skipped`. Such a number can still identify a person, so treat it as personal data. - *Ring til Mette Kjærgaard Holm på 21 34 56 78.* A name and a phone number for POST /v1/redact/detect. - *afgoerelse.pdf*, a two-page fictitious PDF with a text layer, for file input (Beta). - A letter from Mette asking for a copy of her application for a building permit, for Decide (Beta). - *Hvor lang tid har jeg til at klage over en afgørelse om boligstøtte?* A question with no personal data, for Chat. Write your own test data the same way: invented names and street names, and e-mail addresses under `example.invalid`, a domain that can never reach a mailbox. Do not take a real case and change a few details. ## Try it consoles Each operation in the [API reference](https://developers.komplai.dk/api) has a **Try it** console, filled in with the operation's first example. Calls are real: komplai processes what you send, each call counts towards your key's limits, and processing in EU cloud counts towards your organisation's monthly AI spending cap. The key you paste stays on the page until you leave it and is sent only to the API. --- https://developers.komplai.dk/test-data # Chat > Send messages to Chat's models through the API, choose where the model runs, and read the answer as one OpenAI-compatible response. The Chat API gives your own systems the models your organisation uses in Chat. POST /v1/chat/completions takes an OpenAI-compatible chat request with text messages and returns the whole answer as one `chat.completion`. You choose where the model runs: on komplai's local infrastructure, in komplai's EU cloud or through one of your organisation's own AI connections. ## Before you start - Your organisation has Chat, and you are assigned Chat. - You have a personal API key (`kp_live_...`) with the scope `chat:complete`. Create it on the hub's **API keys** page at [hub.komplai.dk/api-access](https://hub.komplai.dk/api-access); [API keys and authentication](https://developers.komplai.dk/authentication) explains how. An organisation integration key (`kp_org_...`) gets 403 [integration_not_permitted](https://developers.komplai.dk/errors/integration_not_permitted). ## Your first call Without `processing` and `model`, the call runs where your organisation's Chat runs, with your default model there. ```bash curl https://api.komplai.dk/v1/chat/completions \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "messages": [ {"role": "system", "content": "Answer briefly."}, {"role": "user", "content": "How long do I have to appeal a decision on housing benefit?"} ], "max_tokens": 256 }' ``` ```json { "id": "chatcmpl-8c1d5e3a-2f7b-4a9c-b6e0-3d4f5a6b7c8d", "object": "chat.completion", "created": 1792483200, "model": "qwen3.8-27b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Usually four weeks from the day you received the decision. The deadline is in the decision's guidance on how to appeal." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 41, "completion_tokens": 33 } } ``` The answer is in `choices[0].message.content`. `finish_reason: "length"` means the answer reached `max_tokens` and is incomplete. ## Choose where the model runs `processing` decides where the call runs. The same values work for GET /v1/models. | `processing` | Where the model runs | AI usage | | --- | --- | --- | | `komplai-local` | komplai's local infrastructure in Denmark, run by komplai. Data does not leave the EU. The queue is shared with other organisations, without priority. `local` is accepted too. | No AI charge | | `eu-cloud` | komplai's EU cloud in France. Data does not leave the EU. Needs EU processing approved for Chat in your organisation. | Metered at the provider's price and counts towards the organisation's monthly AI spending cap | | `connection:` | One of your organisation's own AI connections that its administrator has made available through the API. | Your organisation's own agreement with the provider. It does not count towards the cap. | | left out | Where your organisation's Chat runs: local infrastructure, or EU cloud when that is what your organisation's Chat uses. | As for that processing | The API never moves a call to other processing or to another model, also not when the chosen one fails. A choice your organisation does not allow through the API answers [processing_choice_not_allowed](https://developers.komplai.dk/errors/processing_choice_not_allowed). Administrators decide this in the hub under **AI and processing**: the **Processing** tab (`/settings/processing`) sets where each tool may process text through the API, and the **Connections** tab (`/settings/ai`, the **AI connections** page) adds connections and switches **Can be used through the API** on for each one. ## Models GET /v1/models lists the models your key may use at a processing, with their context, their output limit and the reasoning efforts they take. In the EU cloud each model also carries the provider's token rates in `rates`. ```bash curl "https://api.komplai.dk/v1/models?processing=komplai-local" \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` ```json { "object": "list", "data": [ { "id": "qwen3.8-27b", "object": "model", "owned_by": "komplai", "name": "Qwen3.8 27B", "context_tokens": 32768, "max_output_tokens": 4000, "reasoning_efforts": ["none", "low", "medium", "high"] } ] } ``` - On local infrastructure the list holds the models your organisation has switched on, or every selectable model while it has switched on none. In the EU cloud it holds the models on your organisation's EU route. For a connection it holds the one model or router the connection names. - Send `model` with an id from the list at the same processing. Leave it out for your default there: the model you chose in the hub, else your organisation's default. - A model you may not use answers [model_not_enabled](https://developers.komplai.dk/errors/model_not_enabled). The API never picks another one. - `reasoning_effort` takes one of the model's `reasoning_efforts`; another value answers [reasoning_not_enabled](https://developers.komplai.dk/errors/reasoning_not_enabled). More reasoning uses more of the output limit. ```bash curl https://api.komplai.dk/v1/chat/completions \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "processing": "komplai-local", "model": "qwen3.8-27b", "reasoning_effort": "none", "max_tokens": 256, "messages": [ {"role": "user", "content": "How long do I have to appeal a decision on housing benefit?"} ] }' ``` ## Use one of your organisation's connections A connection is your organisation's own infrastructure, such as Azure OpenAI, or its own account with a provider such as Anthropic, OpenAI, Mistral or OpenRouter. It names one model or a router. Its value for `processing` is on the **AI connections** page, under **Value for processing in the API**; ask your administrator for it. ```bash curl https://api.komplai.dk/v1/chat/completions \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "processing": "connection:6d3f9a2e-1b4c-4e7d-8a5f-0c2b9e4d7a31", "max_tokens": 256, "messages": [ {"role": "user", "content": "How long do I have to appeal a decision on housing benefit?"} ] }' ``` The answer adds `processing` and `requested_model`. With a router such as `openrouter/free`, `model` is the model that actually answered and `requested_model` the router the connection names; komplai also records the answering model in your organisation's usage log. - Leave `model` out, or send the model the connection names. - `reasoning_effort` takes only `none`. A connection to Anthropic takes `temperature` up to 1 and no `response_format` other than `text`. - Where a connection processes data, who runs it and whether data stays in the EU/EEA is what your administrator stated for it on the AI connections page. The provider is not a komplai subprocessor. - With a free model, the provider may store and use what is sent. Use it for testing, synthetic data and ideas. - A connection id your organisation does not have answers [connection_not_found](https://developers.komplai.dk/errors/connection_not_found). A connection your administrator has not made available through the API answers [processing_choice_not_allowed](https://developers.komplai.dk/errors/processing_choice_not_allowed) on POST /v1/chat/completions, and GET /v1/models does not list it ([connection_not_found](https://developers.komplai.dk/errors/connection_not_found)). When the provider refuses the call, the code names the reason, such as [connection_unauthorized](https://developers.komplai.dk/errors/connection_unauthorized) or [connection_payment_required](https://developers.komplai.dk/errors/connection_payment_required). [Your own AI connections](https://developers.komplai.dk/guides/ai-connections) shows how an administrator adds one. ## The monthly AI spending cap Only calls to the EU cloud count towards the organisation's monthly AI spending cap. Local infrastructure and your organisation's own connections do not. - Before a call to the EU cloud, komplai reserves a conservative estimate of the input and the whole `max_tokens`. When the answer is in, the known usage is recorded and the rest released. A `max_tokens` that fits the task leaves room for other calls. - The cap applies across the organisation's apps, people and keys. An administrator can set a lower limit for the organisation and personal limits on the **AI usage limits** page (`/settings/ai-budget`). - When the cap or the organisation's own limit is reached, calls stop with [ai_credit_exhausted](https://developers.komplai.dk/errors/ai_credit_exhausted); a reached personal limit answers [person_ai_credit_exhausted](https://developers.komplai.dk/errors/person_ai_credit_exhausted). Retrying does not help until the cap starts again next month. Local processing keeps working. - Without a cap for the month, the EU cloud cannot run: [ai_credit_not_granted](https://developers.komplai.dk/errors/ai_credit_not_granted). ## The answer comes back whole The Chat API does not stream. `stream` is always `false`, and `stream: true` answers 400 [invalid_input](https://developers.komplai.dk/errors/invalid_input), as do tools, images and files. For streamed answers with function calls, coding clients use [Coding](https://developers.komplai.dk/tools/coding). - A request holds at most 32 messages and 80,000 UTF-16 code units of text. `max_tokens` defaults to 2,000 and may not exceed the model's own `max_output_tokens` (GET /v1/models); with the input it must also fit the model's context, otherwise [context_limit](https://developers.komplai.dk/errors/context_limit). - The model has 120 seconds to answer. Give your HTTP client a slightly longer timeout, for example 150 seconds. - After [timeout](https://developers.komplai.dk/errors/timeout) or a 502 [service_unavailable](https://developers.komplai.dk/errors/service_unavailable), the call may have reached the model and used capacity. Do not send it again automatically, and turn off automatic retries of POST in your HTTP client or SDK. - [eu_cloud_refused](https://developers.komplai.dk/errors/eu_cloud_refused) means komplai's EU cloud refused the call. Choose local processing or a connection, and send komplai the `request_id`. ## Structured JSON `response_format` asks for a JSON object (`json_object`) or JSON that follows your schema (`json_schema`). The answer is still text in `choices[0].message.content`: check `finish_reason`, parse it and validate it before you rely on it. ```json { "processing": "komplai-local", "model": "qwen3.8-27b", "max_tokens": 256, "messages": [ {"role": "user", "content": "Answer in JSON. How long do I have to appeal a decision on housing benefit?"} ], "response_format": { "type": "json_schema", "json_schema": { "name": "appeal_deadline", "strict": true, "schema": { "type": "object", "additionalProperties": false, "required": ["weeks", "source"], "properties": { "weeks": {"type": "integer"}, "source": {"type": "string"} } } } } } ``` The whole `response_format` may hold at most 32,768 bytes, 24 levels and 2,048 values, and a `$ref` must point inside the schema. ## What is stored Chat through the API stores no messages and no answers. komplai records the call's metadata: who called, when, which model and how many tokens. Each response has a `Request-Id` header; quote it when you ask komplai about a call. ## Reference and errors - [Chat reference](https://developers.komplai.dk/reference/chat): every field of GET /v1/models and POST /v1/chat/completions, with code samples and a console to try each call. - [Errors](https://developers.komplai.dk/errors): every code with what to do. Request limits are on [Limits](https://developers.komplai.dk/limits). - [Where data is processed](https://developers.komplai.dk/data-processing) compares local infrastructure, the EU cloud and your own connections. --- https://developers.komplai.dk/tools/chat # Coding (Beta) > Connect a coding client to komplai: read the account and terms, choose a model and stream OpenAI-compatible completions with function calls. Coding is in (Beta). It gives coding clients an OpenAI-compatible chat completion, streamed as server-sent events, with text, reasoning and function calls. komplai never runs a tool: the client runs it on your machine, asks you where needed and sends the result back in the next request. Coding uses your organisation's Chat access and approved models. The model runs in komplai's EU cloud, and usage counts towards the organisation's monthly AI spending cap. Coding is not a separate app licence. ## Before you start - Coding is enabled for your organisation, its Chat runs in komplai's EU cloud with an approved setup, and you are assigned Chat. Otherwise every call answers 403 [coding_not_enabled](https://developers.komplai.dk/errors/coding_not_enabled). A completion also needs a monthly AI spending cap for the month; without one it answers 403 [ai_credit_not_granted](https://developers.komplai.dk/errors/ai_credit_not_granted). - You have a personal API key (`kp_live_...`) with the scopes `coding:read` and `coding:complete`. komplai's coding client creates one when you sign in with your organisation, valid for 30 days; [Coding client](https://developers.komplai.dk/tools/coding-client) shows how. You can also create a key with both scopes on the hub's **API keys** page at [hub.komplai.dk/api-access](https://hub.komplai.dk/api-access). An organisation integration key (`kp_org_...`) gets 403 [integration_not_permitted](https://developers.komplai.dk/errors/integration_not_permitted). ## The three calls | Call | Scope | What it does | | --- | --- | --- | | GET /v1/coding/account | `coding:read` | Your organisation, the current terms as `contract`, where a call's data goes, the monthly AI spending cap and this month's use, the default model and the coding models | | GET /v1/coding/models | `coding:read` | The coding models with their limits, in the OpenAI list shape | | POST /v1/coding/chat/completions | `coding:complete` | A streamed completion | 1. Read the account and show its terms to the person before they connect. 2. Pick a model from the account's `models` or from GET /v1/coding/models. 3. Stream a completion with the current `contract` in `X-Komplai-Contract` and a new UUID in `X-Request-Id`. ## Read the account ```bash curl https://api.komplai.dk/v1/coding/account \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` The answer, shortened: ```json { "id": "2e7c4b9a-5d1f-4a3e-8b6c-9f0d1e2a3b4c", "name": "Eksempel Kommune", "contract": "86fb88e41acf1ec181a16eaf5d7725059473b626b7d4289ee1b9c3b2aaed45b0", "defaultModel": "mistral-small-3.2-24b-instruct-2506", "data": { "recipients": "komplai → EU-cloud", "region": "komplais API: Hetzner, Tyskland. Model: komplais EU-cloud, EU · Frankrig.", "checkedAt": "2026-10-13" }, "models": [ { "id": "mistral-small-3.2-24b-instruct-2506", "name": "Mistral Small 3.2 (24B)", "context_length": 128000, "max_output_tokens": 32768, "capabilities": { "function_calling": true }, "reasoning_efforts": [] } ], "credential": { "scopes": ["coding:read", "coding:complete"], "expiresAt": "2026-11-19T08:00:00.000Z" } } ``` - `contract` identifies the current terms: the provider and its terms, the data mode, your organisation's agreement, and the coding models with their prices. Send it with every request to POST /v1/coding/chat/completions. - `data` states who receives a call's data, where it is processed, the provider's terms for training and retention, how usage is accounted, what komplai stores, the source of the provider's terms and when komplai checked them. Show these terms to the person before they connect. - `balance` holds the monthly AI spending cap and this month's use, reserved amount and what is left. Each model in `models` carries the provider's prices. - `credential` names the key's scopes and when it expires. ## Stream a completion Put the contract in a variable, then send the request. `-N` makes curl print each event as it arrives. ```bash KOMPLAI_CODING_CONTRACT=$(curl -s https://api.komplai.dk/v1/coding/account \ -H "Authorization: Bearer $KOMPLAI_TOKEN" | jq -r .contract) curl -N https://api.komplai.dk/v1/coding/chat/completions \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -H "X-Komplai-Contract: $KOMPLAI_CODING_CONTRACT" \ -H "X-Request-Id: $(uuidgen)" \ -d '{ "model": "mistral-small-3.2-24b-instruct-2506", "stream": true, "max_tokens": 256, "messages": [ {"role": "system", "content": "You are a careful coding assistant."}, {"role": "user", "content": "What does this expression evaluate to: 1 + 1?"} ] }' ``` ```text data: {"id":"chatcmpl-5f1e9d2c","object":"chat.completion.chunk","created":1792483200,"model":"mistral-small-3.2-24b-instruct-2506","choices":[{"index":0,"delta":{"role":"assistant","content":"It evaluates to 2"},"finish_reason":null}]} data: {"id":"chatcmpl-5f1e9d2c","object":"chat.completion.chunk","created":1792483200,"model":"mistral-small-3.2-24b-instruct-2506","choices":[{"index":0,"delta":{"content":": the sum of 1 and 1."},"finish_reason":null}]} data: {"id":"chatcmpl-5f1e9d2c","object":"chat.completion.chunk","created":1792483200,"model":"mistral-small-3.2-24b-instruct-2506","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":31,"completion_tokens":14}} data: [DONE] ``` Each `data` line is a `chat.completion.chunk` from the model, passed on after komplai has checked it: text in `choices[0].delta.content`, reasoning in `reasoning_content`, function calls in `tool_calls`, and usage in the last chunk. `data: [DONE]` ends a complete answer. > **A stream without [DONE] is not a complete answer** > > If the call fails after the stream began, the last event is `data: {"error": {"message": ..., "code": ..., "request_id": ..., "doc_url": ...}}` and no `[DONE]` follows. Treat the outcome as unknown, as you would a stream that stops early. The request must have: - `model`: an id from GET /v1/coding/models. Another id answers [model_not_enabled](https://developers.komplai.dk/errors/model_not_enabled). - `stream: true`. `stream_options` is optional; usage is always in the stream. - Exactly one of `max_tokens` and `max_completion_tokens`, from 1 to 32,000 and within the model's `max_output_tokens`. The input and the output together must fit the model's context, otherwise [context_limit](https://developers.komplai.dk/errors/context_limit). A request holds at most 512 messages and 64 tools, and the body at most 2,000,000 bytes. `reasoning_effort` takes one of the model's `reasoning_efforts`; another value answers [reasoning_not_supported](https://developers.komplai.dk/errors/reasoning_not_supported). The answer must finish within 600 seconds, otherwise [timeout](https://developers.komplai.dk/errors/timeout). ## Function calls Describe the functions the model may call in `tools`. When the model wants one, the stream carries `tool_calls` and ends with `finish_reason: "tool_calls"`. Your client runs the function, asks the person where needed, and sends the next request with the conversation so far: the assistant message with its `tool_calls`, then a `tool` message with the result for each call. ```json [ {"role": "user", "content": "What is in README.md?"}, { "role": "assistant", "content": null, "tool_calls": [ {"id": "call_7b2d", "type": "function", "function": {"name": "read_file", "arguments": "{\"path\":\"README.md\"}"}} ] }, {"role": "tool", "tool_call_id": "call_7b2d", "content": "# My project\nA small command-line tool."} ] ``` Every tool call must be answered, by its `tool_call_id`, before the next message. Send earlier `reasoning_content` back unchanged on the assistant message. `tool_choice` takes `auto`, `none`, `required` or one function by name. ## Request ids and retries `X-Request-Id` takes a new UUID (version 4) for each new logical operation. If you do not know whether an operation reached komplai, for example after a dropped connection, send it again with the same id: komplai then answers [duplicate_request](https://developers.komplai.dk/errors/duplicate_request) instead of calling the provider a second time. Never retry automatically with a new id after [coding_service_unavailable](https://developers.komplai.dk/errors/coding_service_unavailable) or [timeout](https://developers.komplai.dk/errors/timeout), because the call may have reached the model and counted towards the cap. `Request-Id` in the response repeats your id. ## When the terms change When the provider, its terms, the data mode, the agreement or the coding models and their prices change, `contract` changes too, and a completion with the old one answers [terms_changed](https://developers.komplai.dk/errors/terms_changed). Read the account again, show the new terms to the person, and send the new contract. Never accept new terms automatically. Ordinary AI usage does not change the contract. ## The monthly AI spending cap Before the provider is called, komplai reserves the most the call can cost under the organisation's monthly AI spending cap. Usage is then metered at the provider's price; cached input has its own price where the provider has one, and reasoning counts as output tokens. Calls stop when the cap or the organisation's own limit is reached ([ai_credit_exhausted](https://developers.komplai.dk/errors/ai_credit_exhausted)) or your personal limit ([person_ai_credit_exhausted](https://developers.komplai.dk/errors/person_ai_credit_exhausted)). The API never switches to another model. ## Where data is processed Prompts, code and tool results go to the coding model in komplai's EU cloud in France. komplai's API runs on its servers in Germany. Data does not leave the EU. komplai stores no prompts, answers or tool results, only the call's metadata for accounting and audit. The provider's own terms for training and retention are in the account's `data`. ## Reference and errors - [Coding reference](https://developers.komplai.dk/reference/coding): every field of the three calls, with code samples. - [Coding client](https://developers.komplai.dk/tools/coding-client): komplai's client for the command line and OpenCode, which signs in, reads the account and sends the headers for you. - [Errors](https://developers.komplai.dk/errors): every code with what to do. --- https://developers.komplai.dk/tools/coding # Coding client (Beta) > komplai's coding client connects the command line and OpenCode to Coding: browser sign-in with your organisation, review of terms and prices, models and logout. komplai's coding client connects a coding tool on your computer to Coding (Beta), the API for coding models at `https://api.komplai.dk/v1/coding`. It has two parts: the command `komplai-code` and a plugin for OpenCode 2.0.28. Your coding tool reads and edits files and runs commands with your approval. komplai returns text, reasoning and function calls, and never runs a tool. The client is not published on public npm. The person responsible for your organisation's setup supplies the approved version and its installation. If nobody has, [contact us](https://en.komplai.dk/#kontakt). ## Before you start - Node.js 22.14 or later, and a browser on the same computer. - Coding is turned on for your organisation. It follows Chat: your organisation's Chat runs in komplai's EU cloud with approved processing and a monthly AI spending cap, and an administrator has given you access to Chat under **Tool access** (`/settings/apps`). ## Sign in ```bash komplai-code login ``` 1. The command prints a sign-in address and opens it in your browser. 2. Sign in with your komplai account, as you do in the hub. 3. **Connect your coding tool** shows each organisation where you can use Coding, with its processing terms: where data is processed, the provider's terms on training and retention, what komplai stores, the data mode, the approved models with the provider's prices in DKK, and how much is left under the organisation's monthly AI spending cap. 4. Under the organisation you choose, tick that you have reviewed the terms and that your coding requests count towards the organisation's monthly AI spending cap. Tick that the key may be saved on this computer. 5. Choose **Connect to** followed by the organisation's name. The terminal prints the organisation and when the access expires. No coding request is sent while you sign in, and no account is created. If no organisation has Coding turned on for you, the page says so. The connection is a personal API key (`kp_live_...`) with `coding:read` and `coding:complete` that expires after 30 days. It is listed under **API keys** (`/api-access`) in the hub, where you can revoke it. Your sign-in token is used only while you connect and is never saved. The key is saved outside your project, in this folder: ```text macOS ~/Library/Application Support/Komplai/coding/ Linux ~/.local/share/komplai/coding/ Windows %USERPROFILE%\AppData\Local\Komplai\coding\ ``` On macOS and Linux, the folder and the file can be read only by you; it is a private file, not an encrypted keychain. On Windows, only your Windows account can open the file, and it is encrypted with Windows DPAPI. The client refuses to save the key inside a repository or in a folder others can read. ## Commands | Command | What it does | | --- | --- | | `komplai-code status` | Shows the organisation, when the access expires, the current terms (`contract`), the monthly AI spending cap and this month's use (`balance`) and the data terms, as JSON | | `komplai-code models` | Lists the approved coding models with their limits and the provider's prices in DKK, as JSON | | `komplai-code logout` | Revokes the key in komplai, then removes it from this computer | `logout` also revokes an expired key. If the network fails, the key stays on the computer so you can run `logout` again. To connect a computer that is already connected, run `logout` first. ## Use it in OpenCode The plugin works with OpenCode 2.0.28 and refuses other versions. 1. Add the plugin file `opencode.js` from the client to `plugins` in your own OpenCode configuration, with its absolute path. 2. In OpenCode's integrations, choose the komplai coding integration and its sign-in. Your browser opens the same sign-in and terms as `komplai-code login`, on the same computer as OpenCode. 3. Choose one of the approved models. ```json { "plugins": ["/path/to/komplai-coding-client/dist/opencode.js"] } ``` The key stays in the client's private file. OpenCode keeps only a marker without the key, and a connection made with `komplai-code login` works in OpenCode too. The plugin adds the commands `komplai-status`, `komplai-models` and `komplai-logout`. OpenCode offers only the approved models. The plugin sends the current terms and a new request id with every call, and it switches OpenCode's automatic retries off, because a retry with a new request id would be billed as a new call. OpenCode's cost fields are in US dollars, so the plugin leaves them empty; the prices in DKK are shown at sign-in and by `komplai-models`. ## When the terms change The terms cover the provider, its terms on data, the data mode, the agreement and the approved models with their prices. When any of them changes, the client stops and asks you to sign in again and review the new terms ([terms_changed](https://developers.komplai.dk/errors/terms_changed)). Ordinary use does not change the terms. ## Where your code is processed - Prompts, code and tool results go through komplai's API at Hetzner in Germany to the approved coding model in komplai's EU cloud in France. - komplai stores no prompts, answers or tool results. Metadata about access and usage is recorded and kept as your organisation's agreement sets out. - The provider does not use the content for training and does not keep it by default, apart from a temporary, project-isolated cache of intermediate results. In a troubleshooting or security investigation, a whole request can be kept for up to two weeks, and aggregated, anonymised usage data for up to six months. The sign-in page shows the terms and when komplai last checked them. - Usage is metered at the provider's price and counts towards your organisation's monthly AI spending cap. Before each call, the most it can cost is reserved under the cap. Calls stop when the cap, your organisation's own limit or your personal limit is reached, and the client never moves to another model. - When the data mode is test data, use test data only. ## Errors The client shows a plain message for each error. The ones you meet most often: | Code | What to do | | --- | --- | | [coding_not_enabled](https://developers.komplai.dk/errors/coding_not_enabled) | Ask your administrator for access to Chat. komplai turns Coding on for your organisation; your administrator can [contact us](https://en.komplai.dk/#kontakt). | | [terms_changed](https://developers.komplai.dk/errors/terms_changed) | Run `komplai-code logout`, then sign in again and review the new terms. | | [ai_credit_exhausted](https://developers.komplai.dk/errors/ai_credit_exhausted) | The organisation's monthly AI spending cap is reached. Ask your administrator. | | [person_ai_credit_exhausted](https://developers.komplai.dk/errors/person_ai_credit_exhausted) | Your personal limit is reached. Ask your administrator. | | [invalid_api_key](https://developers.komplai.dk/errors/invalid_api_key) | The access has expired or was revoked. Run `komplai-code logout`, then sign in again. | ## Build your own client To connect another coding tool, create a personal API key with `coding:read` and `coding:complete` under **API keys** in the hub. Read `GET /v1/coding/account` and show the terms to the person before the first call, then send each call to `POST /v1/coding/chat/completions` with the current terms in `X-Komplai-Contract` and a new UUID in `X-Request-Id` for every operation. [Coding](https://developers.komplai.dk/tools/coding) explains the API, and [the Coding reference](https://developers.komplai.dk/reference/coding) has every field. --- https://developers.komplai.dk/tools/coding-client # Decide (Beta) > Ask Decide typed questions about a text through the API and get probabilities back instead of prose, for one text or a batch of up to 100. Decide is in (Beta). It answers typed questions about a text with probabilities instead of prose: which category a letter belongs to, how urgent it is, whether it contains personal data. A decision model writes no text, so there is nothing to parse. Every answer comes with the full probability distribution behind it and a confidence. Decide runs on komplai's local infrastructure in Denmark, with no AI charge. The text is not stored. ## Before you start - Your organisation has Decide in its agreement and has approved its processing, and an administrator has given you access to Decide under **Organisation › People › Tool access** in the hub. - You have a personal API key (`kp_live_...`) with the scope `decide:process`, created on the hub's **API keys** page at [hub.komplai.dk/api-access](https://hub.komplai.dk/api-access). An organisation integration key (`kp_org_...`) gets 403 [integration_not_permitted](https://developers.komplai.dk/errors/integration_not_permitted). - Beta operations may still change, with notice. Without an approved data processing agreement, use test data only. ## Your first call Send one text in `state` and your questions in `questions`, each under an id you choose. ```bash curl https://api.komplai.dk/v1/decide \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "state": "Hej. Jeg vil gerne have en kopi af min ansøgning om byggetilladelse fra marts. Venlig hilsen Mette Kjærgaard Holm", "questions": { "category": { "type": "choice", "instructions": "Hvad handler henvendelsen om?", "criteria": { "aktindsigt": "Borgeren beder om kopi af dokumenter eller aktindsigt", "klage": "Borgeren klager over en afgørelse", "andet": "Noget andet" } }, "urgency": { "type": "score", "instructions": "Hvor hurtigt skal henvendelsen besvares?", "criteria": ["Inden for den normale frist", "Inden for en uge", "Samme dag"] }, "personal_data": { "type": "noul", "instructions": "Indeholder teksten personoplysninger?", "criteria": { "true": "Ja, for eksempel et navn eller et CPR-nummer", "false": "Nej" } } } }' ``` ```json { "model": "convaiinnovations/laya/multilingual", "answers": { "category": { "type": "choice", "choice": "aktindsigt", "probabilities": { "aktindsigt": 0.91, "klage": 0.03, "andet": 0.06 }, "confidence": 0.672, "action": { "act_probability": 0.88 } }, "urgency": { "type": "score", "score": 0.32, "max": 2, "probabilities": [0.72, 0.24, 0.04], "confidence": 0.356 }, "personal_data": { "type": "noul", "noul": 0.97, "probabilities": { "true": 0.97, "false": 0.03 }, "confidence": 0.806 } }, "usage": { "input_tokens": 118, "output_tokens": 0 }, "latency_ms": 38 } ``` The answers come back under the same ids. `usage.output_tokens` is always 0, and `latency_ms` is the model's own time without the network. ## Question types Each question has `type`, `instructions` (the question in your own words) and `criteria`, whose shape depends on the type. | Type | `criteria` | The answer | | --- | --- | --- | | `choice` | An object of 2 to 32 options: a short key and what that option means | `choice` is the key with the highest probability, and `probabilities` gives every key its probability | | `score` | A list of 2 to 32 levels, lowest first | `score` is the expected level (each level times its probability, added up), `max` the highest level, and `probabilities` one value per level in the order you sent them | | `noul` | `true` and `false`, and what each means | `noul` is the probability that the statement is true | The probabilities in an answer add up to 1. Keep option keys short and machine-friendly, because the answer names the key. Every answer also has: - `confidence`: how decided the answer is, from 0 (spread evenly) to 1 (everything on one option). It says nothing about whether the answer is right. - `action.act_probability`, when the model gives it: how likely the answer is safe to act on without a person checking it. A request takes from 1 to 64 questions. They share one reading of the text, so several questions cost little more than one. `state` is a text or a JSON object, which komplai turns into text; arrays and other values are refused. The request may have at most 80,000 characters as JSON and the body at most 320,000 bytes. Fields that are not listed are ignored. ## Models `model` chooses the decision model: | `model` | Model | | --- | --- | | `komplai-decide` | Laya | | `komplai-decide-claes` | Claes | Leave it out for the default: the model you chose in the hub, else your organisation's default, else `komplai-decide`. `model` in the answer names the model that answered by its checkpoint. A model Decide does not offer your organisation answers 409 [model_not_enabled](https://developers.komplai.dk/errors/model_not_enabled), and 404 when local infrastructure does not offer it right now. The API never picks another model for you. ## Many texts in one call POST /v1/decide/batch asks the same questions about up to 100 texts in `states`, in one pass of the model. The answers come back in `results` in the order of `states`, and the batch is answered whole or refused whole. It counts as one request against your request limit. ```bash curl https://api.komplai.dk/v1/decide/batch \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "states": [ "Hej. Jeg vil gerne have en kopi af min ansøgning om byggetilladelse fra marts.", "Jeg klager over afslaget på min ansøgning om boligstøtte. Afgørelsen er forkert, og jeg har brug for svar hurtigt." ], "questions": { "category": { "type": "choice", "instructions": "Hvad handler henvendelsen om?", "criteria": { "aktindsigt": "Borgeren beder om kopi af dokumenter eller aktindsigt", "klage": "Borgeren klager over en afgørelse", "andet": "Noget andet" } } } }' ``` ```json { "model": "convaiinnovations/laya/multilingual", "results": [ { "answers": { "category": { "type": "choice", "choice": "aktindsigt", "probabilities": { "aktindsigt": 0.91, "klage": 0.03, "andet": 0.06 }, "confidence": 0.672 } }, "usage": { "input_tokens": 61, "output_tokens": 0 } }, { "answers": { "category": { "type": "choice", "choice": "klage", "probabilities": { "aktindsigt": 0.08, "klage": 0.86, "andet": 0.06 }, "confidence": 0.544 } }, "usage": { "input_tokens": 66, "output_tokens": 0 } } ], "usage": { "input_tokens": 127, "output_tokens": 0 }, "latency_ms": 52 } ``` A batch request may have at most 200,000 characters as JSON and the body at most 800,000 bytes. ## Time limits and failures The model has 30 seconds to answer. When it fails, does not answer in time or cannot be reached, the call answers [service_unavailable](https://developers.komplai.dk/errors/service_unavailable). An answer that fails komplai's checks, such as a missing answer or probabilities that do not add up, is never passed on: the call answers [invalid_response](https://developers.komplai.dk/errors/invalid_response). A request that does not have the documented form answers [invalid_input](https://developers.komplai.dk/errors/invalid_input). ## Where data is processed Decide runs only on komplai's validated decision models, on komplai's local infrastructure in Denmark. Data does not leave the EU, and your organisation's own AI connections are never used for Decide. The text is not stored; komplai records the call's metadata, such as who called, when and which model. ## Reference and errors - [Decide reference](https://developers.komplai.dk/reference/decide): every field of POST /v1/decide and POST /v1/decide/batch, with code samples and a console to try each call. - [Errors](https://developers.komplai.dk/errors): every code with what to do. Request limits are on [Limits](https://developers.komplai.dk/limits). --- https://developers.komplai.dk/tools/decide # Redact > Pseudonymise text and the text of PDF and Word files with Redact through the API, choose where each layer runs, and put the originals back. Redact finds personal data in a text and replaces it with labels such as `[PERSON-1]` and `[CPR-1]`. You get the pseudonymised text back and, when you ask for it, the list of labels that lets you put the originals back later, for example into an answer from your own language model. All calls go to `https://api.komplai.dk`. Redact takes both kinds of key: a personal API key (`kp_live_...`) and an organisation integration key (`kp_org_...`) that komplai issues for one of your organisation's own systems, such as a robot or an integration platform. ## Before you start - Your organisation's agreement covers Redact through the API, and you are assigned Redact. An organisation integration key belongs to no person and needs no assignment. - Your key has the scopes for the operations you call: | Scope | Operations | | --- | --- | | `redact:detect` | POST /v1/redact/detect | | `redact:process` | POST /v1/redact, text jobs, PDF and Word files, POST /v1/redact/restore | | `access:read` | GET /v1/access | Create a personal key on the hub's **API keys** page at [hub.komplai.dk/api-access](https://hub.komplai.dk/api-access). [API keys and authentication](https://developers.komplai.dk/authentication) explains both kinds of key. Without an approved data processing agreement, use test data only. The examples on this page use fictitious people. ## Your first call Send a short text to POST /v1/redact with the rules (`regex`) and the name model (`ner`). These two layers also run when you leave `detectors` out. ```bash curl https://api.komplai.dk/v1/redact \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "text": "Borgeren Mette Kjærgaard Holm, cpr-nr. 120385-1234, bor på Fiktivvej 12, 8000 Aarhus C. Hun kan kontaktes på 21 34 56 78 eller mette.holm@example.invalid.", "detectors": ["regex", "ner"], "include": ["mapping"] }' ``` The answer, with some fields left out: ```json { "redacted": "Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [EMAIL-1].", "processing": "local", "offsetEncoding": "utf-16", "configuration": { "engine": "pipeline", "detectors": ["regex", "ner"], "processing": "local" }, "execution": { "completed": true, "detectorsRun": ["regex", "ner"], "nerCalls": 1, "llmCalls": 0 }, "mapping": { "[PERSON-1]": "Mette Kjærgaard Holm", "[CPR-1]": "120385-1234", "[ADRESSE-1]": "Fiktivvej 12, 8000 Aarhus C", "[TLF-1]": "21 34 56 78", "[EMAIL-1]": "mette.holm@example.invalid" } } ``` `redacted` is the pseudonymised text. `mapping` is the list of labels: keep it if you want to put the originals back, and protect it like the source text, because it holds the personal data. `include` asks for extra reports. Each one contains originals, so ask only for what you need: | Report | What it holds | | --- | --- | | `mapping` | The list of labels, label to original, for POST /v1/redact/restore | | `changes` | Exact positions of each change in your text and in `redacted` | | `findings` | Everything the layers found, with offsets, type, confidence and layer | | `skipped` | CPR-shaped numbers the rules left in the text, with the reason | > **Check the result** > > No method guarantees anonymity. Check the result before you use it, and treat the list of labels and the extra reports as personal data. ## Read your setup first GET /v1/access shows what your key reaches, where each layer processes text for your organisation, the NER places and the models a call may choose, and your limits. It sends no text and runs no model. ```bash curl https://api.komplai.dk/v1/access \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` Under `services[].hosting.processing.layers` you find one entry per layer. The `ner` entry lists its places and models, and each `llm` entry lists the language models at that processing. A model with `available: true` can be chosen, and `reason` says why another cannot, for example `not_validated` for a model that is not validated for Redact. The `ner` entry, shortened: ```json { "detector": "ner", "places": [ { "id": "eu-de", "location": "EU · Germany", "available": true, "default": true }, { "id": "local", "location": "Local infrastructure · Denmark", "available": false, "reason": "unconfigured" } ], "models": [ { "id": "danish-pii-ner-v1.3.0", "name": "Dansk NER 1.3.0", "status": "stable", "default": true, "places": ["eu-de", "local"] } ] } ``` `text_contract.jobs_accepting_submissions` says whether text jobs are accepted right now. ## Choose the layers `detectors` takes one, two or all three layers. Without it, `regex` and `ner` run. | Layer | What it finds | Where it runs | | --- | --- | --- | | `regex` | Rules for CPR numbers, phone numbers, e-mail addresses and more | komplai's servers in Germany (EU) | | `ner` | A model for names, organisations and addresses | The NER place: komplai's servers in Germany, or local infrastructure in Denmark | | `llm` | A language model for what rules and NER miss, such as health data in free text | Local infrastructure in Denmark, or komplai's EU cloud | The language model reads the text in parts of at most 12,000 characters and can take up to a minute. When its answer for a part cannot be used, the part is asked again in two overlapping halves. If an answer still cannot be used, the call fails with [incomplete_detection](https://developers.komplai.dk/errors/incomplete_detection) or [invalid_detection](https://developers.komplai.dk/errors/invalid_detection) and returns nothing. Your organisation's own redaction rules always apply on POST /v1/redact, POST /v1/redact/detect, text jobs and files. An administrator writes them in the hub under **Organisation › Redact › Rules**; [Redact rules](https://developers.komplai.dk/guides/redact-rules) shows how. A number that looks like a CPR number but does not decode to a possible birth date stays in the text. Ask for `include: ["skipped"]` to get each one with the reason. Such a number can still identify a person, for example an erstatningspersonnummer with day plus 60. ## NER places and models `nerDeployment` says where the `ner` layer runs: - `eu-de`: komplai's servers in Germany (EU). - `local`: komplai's local infrastructure in Denmark. Leave it out for the default place, the one GET /v1/access marks with `default: true`. Name `local` only when GET /v1/access lists it as available for the operation you call: places have `available` for calls with `detectors`, and `detect.available` for POST /v1/redact/detect and calls without `detectors`. `nerModel` names a NER model by its id from GET /v1/access. Leave it out for the default model. POST /v1/redact/detect and calls without `detectors` run only the default model. ```bash curl https://api.komplai.dk/v1/redact \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "text": "Borgeren Mette Kjærgaard Holm bor på Fiktivvej 12, 8000 Aarhus C.", "detectors": ["ner"], "nerDeployment": "eu-de", "nerModel": "danish-pii-ner-v1.3.0" }' ``` `configuration.nerDeployment` and `configuration.nerModel` in the answer name what ran. A place that cannot be used answers [ner_location_unavailable](https://developers.komplai.dk/errors/ner_location_unavailable) and names the place; an unknown or unavailable model answers [ner_model_unknown](https://developers.komplai.dk/errors/ner_model_unknown) or [ner_model_unavailable](https://developers.komplai.dk/errors/ner_model_unavailable). NER never moves to another place or model. ## Language models and processing `processing` says where the `llm` layer runs: - `local` (default): komplai's local infrastructure in Denmark, with no AI charge. The queue is shared with other organisations, without priority. - `eu-cloud`: komplai's EU cloud in France. It answers faster, needs EU processing approved for your organisation, and its usage counts towards the organisation's monthly AI spending cap. Every call to the model counts on its own, including a part asked again in halves. `model` names a language model validated for Redact at that processing, by its id from the `llm` layer in GET /v1/access. Leave it out for the default model there. A model that is not validated for Redact answers [llm_model_not_validated](https://developers.komplai.dk/errors/llm_model_not_validated), and a local model that local infrastructure does not offer right now answers [local_model_unavailable](https://developers.komplai.dk/errors/local_model_unavailable). ```bash curl https://api.komplai.dk/v1/redact \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "text": "Sagsbehandleren talte med Mette Kjærgaard Holm om hendes diabetes.", "detectors": ["regex", "ner", "llm"], "processing": "local", "model": "qwen3.8-27b-q8", "include": ["findings"] }' ``` The answer replaces the health data too, `"Sagsbehandleren talte med [PERSON-1] om hendes [HELBRED-1]."`, and `configuration.llmModel` names the model that ran. The API never switches between `local` and `eu-cloud` by itself and never picks another model. When the monthly AI spending cap is reached, EU calls stop with [ai_credit_exhausted](https://developers.komplai.dk/errors/ai_credit_exhausted); local processing keeps working. ## Short texts or text jobs | Operation | Text limit | What you get | | --- | --- | --- | | POST /v1/redact/detect | 16,000 | Findings with offsets into your text. The text is not changed, no language model runs and your organisation's rules apply. | | POST /v1/redact | 750,000 | The pseudonymised text in the response, for work that finishes within 300 seconds. | | POST /v1/redact/jobs | 2,000,000 | A text job: stored encrypted and processed in the background. | Limits and every offset count UTF-16 code units, as in JavaScript and .NET. A text job of 2,000,000 code units is about 800 standard pages. Before a synchronous call runs, the API estimates the time from komplai's measured speeds. A run that cannot finish in 300 seconds is refused with [use_job](https://developers.komplai.dk/errors/use_job), its `estimatedSeconds` and `holdSeconds`, and nothing is processed or charged. The estimate cannot cover the EU language model or a wait in the shared queue, so such a run can still end with [processing_timeout](https://developers.komplai.dk/errors/processing_timeout). Send long texts and runs in the EU cloud as text jobs. You can also send POST /v1/redact with the header `Prefer: respond-async`: the call then answers 202 with a text job, exactly as POST /v1/redact/jobs does. Without that header a call never turns into a job. ### Run a text job 1. Submit the text to POST /v1/redact/jobs with a new UUID in `Idempotency-Key`. The answer is 202 with the job's `id`, and `Location` points to its status. 2. Read GET /v1/redact/jobs/{id} until `state` is `succeeded`. Wait at least 2 seconds between reads, because each read counts against your request limit. 3. Read the result at GET /v1/redact/jobs/{id}/result. It is the same as POST /v1/redact returns. 4. Delete the job with DELETE /v1/redact/jobs/{id} when you have what you need. Build the body from a text file with `jq`, then submit it: ```bash jq -n --rawfile text sagsakt.txt \ '{text: $text, detectors: ["regex", "ner"], include: ["mapping"]}' > job.json curl -i https://api.komplai.dk/v1/redact/jobs \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ --data @job.json ``` ```json { "id": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c", "state": "queued", "createdAt": "2026-10-20T08:00:00.000Z", "expiresAt": "2026-10-20T09:00:00.000Z", "progress": { "completed": 0, "total": 0 }, "reused": false } ``` Put the id in `JOB_ID`, then read the status, the result and delete the job: ```bash curl "https://api.komplai.dk/v1/redact/jobs/$JOB_ID" \ -H "Authorization: Bearer $KOMPLAI_TOKEN" curl "https://api.komplai.dk/v1/redact/jobs/$JOB_ID/result" \ -H "Authorization: Bearer $KOMPLAI_TOKEN" curl -X DELETE "https://api.komplai.dk/v1/redact/jobs/$JOB_ID" \ -H "Authorization: Bearer $KOMPLAI_TOKEN" ``` What to know about jobs: - `state` is `queued`, `running`, `succeeded`, `failed`, `cancelled` or `invalidated`. The last three are final and carry `error` with the reason. The result route answers 202 while the job runs and 410 when it ended without a result. - If the connection drops while you submit, send the same request again with the same `Idempotency-Key`. Within the job's lifetime you get the same job back (`reused: true`) instead of a second one. Never reuse a key for another text: that answers [idempotency_conflict](https://developers.komplai.dk/errors/idempotency_conflict). - A job belongs to the key that created it. Another key gets 404, and after an organisation integration key is rotated or revoked, its jobs can no longer be read. - A job has no time limit of its own while it makes progress. One that makes no progress for 65 minutes fails with [redact_job_stalled](https://developers.komplai.dk/errors/redact_job_stalled). A job that is interrupted, for example by a restart, resumes from its encrypted checkpoint; a call to the EU cloud that was in flight is sent again once and counts towards the monthly AI spending cap like any call. - Text jobs with personal data need a storage policy approved for your organisation ([approved_redact_storage_policy_required](https://developers.komplai.dk/errors/approved_redact_storage_policy_required)). ## PDF and Word files Reading PDF and Word files is in (Beta). POST /v1/redact/file takes a PDF with a text layer or a Word `.docx` as base64 in JSON, extracts its text and runs the same Redact processing as for text, with the same options. The answer is pseudonymised text, not a redacted file. `pages` gives each page's offsets in the extracted text and in `redacted`; in a `.docx` they are the body split at the page breaks Word recorded, then headers, footers, footnotes and endnotes as one part each. Besides the reports above, `include` takes `source`: the extracted text the offsets refer to. ```bash jq -n --rawfile data <(base64 < afgoerelse.pdf | tr -d '\n') \ '{file: {filename: "afgoerelse.pdf", data: $data}, detectors: ["regex", "ner"], include: ["mapping"]}' > file.json curl https://api.komplai.dk/v1/redact/file \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ --data @file.json ``` - At most 50 MiB, 2,000 PDF pages and 750,000 UTF-16 code units of extracted text, with the same 300 seconds as POST /v1/redact. Longer files go to POST /v1/redact/file/jobs, which extracts the text while you wait and submits it as a text job; poll, read, restore and delete it with the `/v1/redact/jobs/{id}` operations. - No OCR runs. A page without a text layer, such as a scan, refuses the file with [scanned_pages_not_supported](https://developers.komplai.dk/errors/scanned_pages_not_supported) and the page numbers. With `allowPagesWithoutText: true` the other pages are processed and those pages are reported with `hasText: false`. - Password-protected PDFs answer [encrypted_file](https://developers.komplai.dk/errors/encrypted_file). Word `.doc` files are not read; save them as `.docx`. ## Put the originals back POST /v1/redact/restore puts the originals back into a text with labels, such as an answer from your own model about the pseudonymised text. Send the text and either the list of labels (`mapping`) exactly as POST /v1/redact returned it, or `job` with the id of your own finished text job that was submitted with `include: ["mapping"]` or `["changes"]`. With a job, komplai reads the retained result and you do not hold the list yourself. ```bash curl https://api.komplai.dk/v1/redact/restore \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "text": "Kære [PERSON-1]. Vi har modtaget din ansøgning og svarer på [EMAIL-1].", "mapping": { "[PERSON-1]": "Mette Kjærgaard Holm", "[CPR-1]": "120385-1234", "[ADRESSE-1]": "Fiktivvej 12, 8000 Aarhus C", "[TLF-1]": "21 34 56 78", "[EMAIL-1]": "mette.holm@example.invalid" } }' ``` ```json { "text": "Kære Mette Kjærgaard Holm. Vi har modtaget din ansøgning og svarer på mette.holm@example.invalid.", "restored": 2, "unknownPlaceholders": [] } ``` - Labels match regardless of case and of spaces inside the brackets. A label that is not in the list stays in the text and is listed in `unknownPlaceholders`. - A fixed replacement from your organisation's rules, such as `[SAGSNR]`, can stand for several originals, so it is 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 limit. - The answer contains personal data. Protect it like the source document. ## What is processed where, and what is stored - **Rules** run on komplai's servers in Germany (EU). - **NER** runs in Germany (`eu-de`) or on local infrastructure in Denmark (`local`). - **The language model** runs on local infrastructure in Denmark, or in komplai's EU cloud in France with `processing: "eu-cloud"`. Data does not leave the EU. - **Files** are read in memory on komplai's API servers in Germany and are not stored. POST /v1/redact/file/jobs stores the extracted text encrypted as a text job, with that job's retention. - **Synchronous calls** hold the text in memory while the call runs. The result exists only in the response. - **Text jobs** keep the text encrypted while the job is queued or running, and the result encrypted until you delete the job or it expires at `expiresAt`. Reading the result does not delete it. The retention period comes from your organisation's storage policy and counts from when the job ends. Without such a policy, a job with test data is kept for one hour. - **Usage and audit records** hold metadata, such as who called what and when, not your text. [Where data is processed](https://developers.komplai.dk/data-processing) describes every tool. ## Reference and errors - [Redact reference](https://developers.komplai.dk/reference/redact): every field and response, with code samples and a console to try each call. - [Account reference](https://developers.komplai.dk/reference/account): GET /v1/access. - [Errors](https://developers.komplai.dk/errors): every code with what to do. Rate limits are on [Limits](https://developers.komplai.dk/limits). - [Redact in Word](https://developers.komplai.dk/tools/redact-word) uses the same Redact from inside a Word document. --- https://developers.komplai.dk/tools/redact # Redact in Word > Find personal data in the Word document you have open and replace it with labels through your organisation's Redact: install, sign in, scan and what is sent. Redact in Word finds personal data such as CPR numbers, names and addresses in the document you have open, and replaces the findings you choose with labels. It works through your organisation's Redact in komplai with your own access. You sign in with your komplai account; you do not need an API key. ## Before you start - You are invited to komplai, and an administrator has given you access to Redact. - Your organisation's agreement with komplai includes Redact's API and Word add-in. [Contact us](https://en.komplai.dk/#kontakt) if it does not. - Your Word supports WordApi 1.6, DialogApi 1.1 and DialogOrigin 1.1. If it does not, the task pane says **Update Word to use this add-in**. - Your organisation has tested the add-in in the Word you use. Word for Windows and Word on the web are tested separately. - Your network allows `hub.komplai.dk`, `auth.komplai.dk` and `api.komplai.dk` over HTTPS. ## Install the add-in If your IT department has deployed the add-in centrally, it is already in Word. It is called **[PROD] komplai for Word**, and its tab on the ribbon is **[PROD] komplai**. Otherwise: **Word on the web** 1. Download the manifest file from [word.komplai.dk/manifest.xml](https://word.komplai.dk/manifest.xml). 2. Open a document in Word on the web. 3. Choose **Home** → **Add-ins** → **More Settings**, then **Upload My Add-in**, and choose the manifest file. If uploading is blocked, ask your Microsoft 365 administrator to install the add-in. **Word for Windows** Your Microsoft 365 administrator installs the add-in from the Microsoft 365 admin center and assigns it to you. [Roll out Word in Microsoft 365](https://developers.komplai.dk/guides/word-rollout) has the steps, including a shared-folder catalog for testing on one PC. ## Sign in and connect Word 1. On the ribbon, open the **[PROD] komplai** tab and choose **Open Redact**. The task pane **komplai in Word** opens. 2. Choose **Sign in**. A window opens with komplai's sign-in. Sign in as you do in the hub. 3. On **Connect Word**, check that the organisation is the right one, tick **I authorize this Word connection under the displayed data policy.** and choose **Connect Word**. The task pane then shows your organisation and a **Disconnect** button. The connection is a personal API key with `access:read` and `redact:detect` that expires after 24 hours. It stays only in the task pane's memory, never in the document, the browser's storage or a URL. Closing Word removes it from your computer, and **Disconnect** revokes it at once. The connection is also listed under **API keys** in the hub at [hub.komplai.dk/api-access](https://hub.komplai.dk/api-access), where you can revoke it. If Word refuses to connect because you have too many keys, revoke the ones you no longer use there. ## Scan and replace 1. Under **Detection method**, choose **NER + Regex** to find names as well as patterns, or **Regex** for patterns only, such as CPR numbers. Word remembers your choice. 2. Choose **Scan document**. 3. Go through the findings, jump to each one in the document, and apply the replacements you choose. 4. Read the document through afterwards. Accept or reject tracked changes before you scan: a document whose main text has tracked changes is refused. Redact switches change tracking off while it replaces text and then restores your setting, so the original text is not left behind as a tracked change. If you edit the document after a scan, scan it again. ## What is scanned and sent - **What**: the main text of the document, at most 16,000 characters per scan. Headers, footers, footnotes, text boxes, comments, metadata and images are not scanned. Review them yourself before you share the document. - **Where**: the text goes to komplai's API at Hetzner in Germany. Rules run on komplai's servers in Germany (EU). With **NER + Regex**, NER runs at the default place that [GET /v1/access](https://developers.komplai.dk/reference/account) marks, komplai's servers in Germany unless komplai has changed it. No language model runs on text from Word. - **What is kept**: komplai keeps no copy of the text. Usage and access metadata are recorded. The findings and the original text of what you replaced stay in the task pane's memory until you close it. - **Test data**: when the task pane says **Test data only**, your organisation's agreement covers test data only. Do not scan real personal data. Each scan is a call to [POST /v1/redact/detect](https://developers.komplai.dk/reference/redact) with your connection's key, and it counts towards your personal and your organisation's request limits. ## When something does not work | What you see | What to do | | --- | --- | | The button is missing | Quit Word completely and open it again; closing the document is not enough. On Windows with a shared-folder catalog, the catalog needs **Show in Menu** ticked. | | The task pane is blank, or the connection fails | Your network must allow komplai's hub, sign-in and API over HTTPS. Ask your IT department to check. | | **Word access is unavailable** after sign-in | Check that you chose the right organisation. Ask your organisation's administrator about your access to Redact. | | Too many requests | Your personal request limit is shared with your other keys and your use of the hub, and your organisation shares one limit. Wait a moment and try again ([rate_limited](https://developers.komplai.dk/errors/rate_limited)). | | The connection has expired | Sign in again. A connection lasts 24 hours and ends when you close Word. | --- https://developers.komplai.dk/tools/redact-word # Register lookup (Beta) > Connect an AI assistant to Register lookup, komplai's MCP server for CVR, Retsinformation, Danmarks Statistik and Folketinget, with a personal API key. Register lookup is in (Beta). It is an MCP server that lets your AI assistant look up public Danish registers: CVR, Retsinformation, Danmarks Statistik and Folketinget. Every tool reads; none of them changes data. Register lookups use no AI and do not count towards AI usage or the organisation's monthly AI spending cap. Register lookup has its own address and is not part of `api.komplai.dk`, so it has no page in the API reference. It speaks the Model Context Protocol over Streamable HTTP. - **Address:** `https://mcp.komplai.dk/mcp` - **Transport:** MCP Streamable HTTP, with POST, GET and DELETE on the same address - **Authentication:** `Authorization: Bearer` with a personal API key (`kp_live_...`) that has the scope `mcp:read` ## Before you start - Your organisation has Register lookup in its agreement, and an administrator has given you access to it under **Organisation › People › Tool access** in the hub. - You have a personal API key with `mcp:read`. In the hub, open **Register lookup** (`/modules/mcp`) and choose **Create a key for Register lookup**, or create the key on the **API keys** page at [hub.komplai.dk/api-access](https://hub.komplai.dk/api-access). An organisation integration key (`kp_org_...`) is refused with `integration_not_permitted`. - Use test data only while Register lookup is in beta. ## Connect VS Code The **Register lookup** page in the hub shows the same configuration with a copy button. It contains no key. 1. Create a personal key with `mcp:read`. 2. In VS Code, run **MCP: Open User Configuration** and merge the configuration below into your existing settings. 3. Start the server. VS Code asks for the key in a hidden field, so it never ends up in a file. ```json { "inputs": [ { "type": "promptString", "id": "komplai-api-key", "description": "komplai personal API key (mcp:read)", "password": true } ], "servers": { "komplai": { "type": "http", "url": "https://mcp.komplai.dk/mcp", "headers": { "Authorization": "Bearer ${input:komplai-api-key}" } } } } ``` The configuration works in the VS Code extension host, not in Agent Host sessions. Other clients work if they support Streamable HTTP and a personal Bearer header; [MCP clients](https://developers.komplai.dk/guides/mcp-clients) covers them. ## Try it with curl An MCP client does these steps for you. With curl you can see each one. Start a session with `initialize`. `-i` shows the response headers, where `Mcp-Session-Id` carries the session's id: ```bash curl -i https://mcp.komplai.dk/mcp \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": {"name": "curl", "version": "1"}}}' ``` Put the id in `KOMPLAI_MCP_SESSION_ID`, confirm the session with the `initialized` notification, and call a tool. This one searches Retsinformation: ```bash curl https://mcp.komplai.dk/mcp \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "Mcp-Session-Id: $KOMPLAI_MCP_SESSION_ID" \ -H "MCP-Protocol-Version: 2025-03-26" \ -d '{"jsonrpc": "2.0", "method": "notifications/initialized"}' curl https://mcp.komplai.dk/mcp \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "Mcp-Session-Id: $KOMPLAI_MCP_SESSION_ID" \ -H "MCP-Protocol-Version: 2025-03-26" \ -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "retsinfo_search", "arguments": {"query": "forvaltningsloven", "limit": 3}}}' ``` The answer arrives as a server-sent event: a `data:` line with the JSON-RPC result, whose `content` holds the tool's result as JSON text. `tools/list` instead of `tools/call` lists every tool with its input schema. Close the session when you are done. Closing a session does not revoke the key. ```bash curl -X DELETE https://mcp.komplai.dk/mcp \ -H "Authorization: Bearer $KOMPLAI_TOKEN" \ -H "Mcp-Session-Id: $KOMPLAI_MCP_SESSION_ID" \ -H "MCP-Protocol-Version: 2025-03-26" ``` ## Tools | Tool | Register | What it returns | Where the lookup goes | | --- | --- | --- | --- | | `cvr_lookup` | CVR | A company by CVR number or name: name, address, industry code, employees, company type, bankruptcy flag and owners | cvrapi.dk | | `retsinfo_search` | Retsinformation | Laws, executive orders and circulars as citations: title, type, ministry, date and link. Not the text of the law. | retsinformation.dk | | `dst_find_tables` | Danmarks Statistik | Statistics tables by keyword, with id, coverage, unit and period | api.statbank.dk | | `dst_describe_table` | Danmarks Statistik | A table's variables and the value codes each one accepts | api.statbank.dk | | `dst_get_data` | Danmarks Statistik | Figures from a table for the variable codes you choose | api.statbank.dk | | `oda_search_cases` | Folketinget | Parliamentary cases by title: type, status, resolution and last update | oda.ft.dk | | `oda_get_entity` | Folketinget | Rows of Folketinget's open data: cases, documents, people and bodies, votes, sittings | oda.ft.dk | | `komplai_detect` | Redact | Personal data in a text, found with rules only | Within the service | | `komplai_redact` | Redact | The text with labels such as `[CPR-1]`, and the list of labels | Within the service | | `komplai_rehydrate` | Redact | The text with the originals put back from the list of labels | Within the service | | `list_connectors` | | Every connector on the server and where its data goes | | - CVR is a public register, but for small companies the registered contact details and owner names belong to private individuals: treat them as personal data. When `marketing_protected` is true, the company has opted out of marketing use. - The `komplai_` tools also need `redact:detect` on the same key and access to Redact in your organisation. They use rules only, so they do not find names. The server does not keep the list of labels: `komplai_rehydrate` needs the list that `komplai_redact` returned. `komplai_detect` and `komplai_redact` take up to 50,000 characters per call. For names and longer texts, use [Redact](https://developers.komplai.dk/tools/redact) through the API. ## Sessions and limits - Every request, also GET and DELETE, carries the personal key. A key in the address is refused: the URL may have no query string. - The first request is a POST with `initialize`. The session is bound to your organisation, to you and to the key; another key cannot use it. Revocation, expiry and withdrawn access are checked on every request and again when a tool runs. - At most 5 sessions per key and 500 on the server. A session ends after 30 minutes without activity. - A request body may have at most 4 MiB. The server has its own limit on HTTP requests per minute, and each tool call also counts against your account's request limits. ## When a request is refused Refusals come as a JSON body with `error`: | Status | `error` | What to do | | --- | --- | --- | | 400 | `query_credentials_not_supported` | Remove the query string. Send the key in the `Authorization` header. | | 400 | `initialize_required` | Start a session with a POST of `initialize`. | | 400 | `invalid_session` | Send `Mcp-Session-Id` once. | | 401 | `api_key_required` | Send `Authorization: Bearer` with your personal key. | | 401 | `invalid_api_key` | The key is unknown, expired or revoked. Create a new one. | | 403 | `integration_not_permitted` | Use a personal key, not an organisation integration key. | | 403 | `insufficient_scope` | Use a key with `mcp:read`. | | 403 | `session_owner_mismatch` | The session belongs to another key. Start a new session. | | 403 | `origin_refused` | The request came from a web page on an origin the server does not accept. | | 404 | `unknown_session` | The session has ended. Start a new one with `initialize`. | | 429 | `session_limit` | Close sessions you no longer use with DELETE, or wait for idle ones to end. | | 429 | `rate_limited` | Wait a minute before you send more requests. | | 503 | `account_access_unavailable` | Keys and access could not be checked. Try again shortly. | A tool call that your account may not make right now, for example because your access was withdrawn or your request limit is reached, returns a tool result with `isError: true` whose text names the reason. ## Where data goes - The lookup parameters go to the register you query, at the address in the table above. Access follows your personal key. - The server runs on komplai's servers in Germany (EU). The `komplai_` tools process text there, in memory. - Your organisation's Audit log holds the tool, who called it and usage metadata, never the lookup, the text, the list of labels or the key. - Register lookups use no AI and do not count towards AI usage. [Where data is processed](https://developers.komplai.dk/data-processing) describes every tool. --- https://developers.komplai.dk/tools/register-lookup # Run > Publish a finished web app at its own address on komplai.run, for your organisation or for everyone, and let it use komplai through the app SDK. Run publishes a finished browser app at its own address, such as `name.komplai.run`. You upload the built files, an HTML file, a ZIP file or a build folder such as `dist`, and the new version is live at once. Run is in the hub's menu at [hub.komplai.dk/publish](https://hub.komplai.dk/publish) when it is turned on for your organisation. Apps run in the visitor's browser, and Run does not run server code. Through the app SDK, an app can show who is signed in, use AI and Redact with each person's own access, save data in komplai and write to the Audit log, once an administrator has approved each of these for the app. ## Who can open an app | Access | Who can open the app | | --- | --- | | Organisation only | Every current member of your organisation, after signing in to komplai. Guests cannot open it. | | Public | Anyone, without signing in and without being sent the link. Every file in the live version can be fetched, also files no page links to. | A new app is Organisation only. To make it public, open the app's page in Run, choose **Change access**, select **Public**, type the app's name and choose **Make the app public**. Keep confidential information out of a public app: files someone has already fetched cannot be withdrawn if you limit the app to your organisation again. An app that uses identity, AI, Redact, saved data, events or error reports from komplai can only be Organisation only. From komplai, a public app may only count anonymously and send requests to the origins its manifest names. Only the person who created an app and your organisation's administrators can change it, publish new versions and create publishing keys. Other members of your organisation can view the app in Run. ## Ways to publish On the app's page, under **Publish a new version** (or **Publish the first version**), you choose how: - **Upload file**: choose or drag an HTML file, or a ZIP file with `index.html` at the top level or inside one folder. - **Terminal**: create a publishing key and run the command Run shows. It packs your build folder, shows which app it goes to and asks before it uploads. [Publish with Run](https://developers.komplai.dk/guides/run) takes you through it. - **AI coding assistant**: download the guide for Claude Code, Codex or another assistant, create a publishing key and let the assistant build and publish the app. You paste the key yourself when the terminal asks. You can also let AI write the app inside Run. On **New app**, **Build with AI** opens Build an app: describe the app, try it in a preview with test data and publish it as a new app. On an app's page, **Keep building with AI** continues from the live version when it is one HTML file of at most 1 MB. Build an app uses your access to Chat. What you write and the app's code go to the AI model you choose, in komplai's EU cloud within your organisation's monthly AI spending cap, or through one of your organisation's own AI connections. It never uses local infrastructure. ## Versions and addresses Every version is complete: files from earlier versions are not carried over. Run keeps the 5 newest versions of each app, so publishing a sixth deletes the oldest. Under **Versions** on the app's page, **Use this version** makes an earlier version live again. **Take the app offline** stops anyone from opening it and keeps the saved versions. The app keeps its address through all of this. Each app has its own address on komplai.run. A readable address has 3 to 40 characters, a-z, 0-9 and hyphens, and starts and ends with a letter or digit; letters such as æ, ø and å cannot be used, and some words, such as admin and www, are reserved. When you change the address, the old one forwards to the new one for a year, after which others can take it. An address is not secret, so keep confidential words out of it. ## What an app can use from komplai An app declares what it uses in its manifest, `komplai.json`, with a reason for each use. An administrator approves each use on the app's page under **What the app may use**. The app never gets more than the person using it already has access to. | Use | Capability | What the app gets | | --- | --- | --- | | Identity | `identity` | A member id that stays the same in the organisation, and the fields you ask for: name, organisation, role, groups, department, job title or email | | AI | `ai.chat` | Answers through the person's own access to Chat, in komplai's EU cloud or through your organisation's own AI connections | | Redact | `redact.text` | Findings and pseudonymised text through the person's own access to Redact. The list of labels stays in the browser | | Saved data | `data` | Up to 20 collections, each for one person only, shared in the app or shared between apps | | Events | `log.events` | Named events in the Audit log, with the person and the app | | Error reports | `log.errors` | Errors from the browser, shown on the app's page in Run | | Anonymous counters | `log.counters` | Daily counts without address or identity. A public app may use this | | Outbound requests | `connect` | Exact `https://` origins the app may send requests to. A public app may use this | In `komplai.json`, the uses sit under `uses`, with events, error reports and counters together under `log`. `connect` is a list of origins at the top level. A version that asks for the same or less keeps its approval. A version that asks for more waits for a new approval, and the rest keeps working. For AI, the administrator chooses where the app may run it and sets the app's own monthly limit. For Redact, the administrator chooses whether the app may also use Redact's language model in komplai's EU cloud. [Publish with Run](https://developers.komplai.dk/guides/run) shows the manifest and the SDK calls. ## Limits | Limit | Value | | --- | --- | | One upload | 10 MB | | One version, unpacked | 50 MB | | One file | 10 MB | | Files in one version | 2,000 | | Saved versions per app | 5 | | Active publishing keys per app | 10 | | Lifetime of a publishing key | 7 days | | One saved document | 64 KB as JSON | Run counts 1 MB as 1,024 × 1,024 bytes. Every saved version counts towards your organisation's storage, and each file takes up at least 8 kB. On servers shared with other organisations, an organisation has up to 10 apps, 5 GB of stored app files and 100 GB of traffic per month. On a server used only by your organisation, the defaults are 1,000 apps, 40 GB of stored app files and 1 TB of traffic per month. Traffic is what the apps send to visitors, counted per calendar month in UTC. When the month's traffic is used, your organisation's apps cannot be opened until the next month starts. Run shows your organisation's storage and traffic under **Capacity and limits**. Supported file types: html, htm, css, js, mjs, json, txt, csv, png, jpg, jpeg, gif, webp, avif, svg, ico, woff, woff2, ttf, otf, pdf, mp3, mp4, webm, ogg, wav and wasm. Hidden paths and source maps are refused. Publishing a file is not a security review of the app. ## Where data is processed and stored - **App files** are stored on komplai's server at Hetzner in the EU, in Falkenstein or Nuremberg in Germany or in Helsinki in Finland, on a server shared with other organisations or used only by yours. Run names the place under **Capacity and limits**. - **AI** from an app goes to komplai's EU cloud or to an AI connection the administrator approved, never to local infrastructure. Usage in the EU cloud counts towards your organisation's monthly AI spending cap and the app's own monthly limit. Run has no AI allowance of its own. - **Redact** from an app runs patterns and NER on komplai's servers at Hetzner in Germany, and Redact's language model in komplai's EU cloud only if the administrator approved it. - **Saved data** is encrypted in komplai's database at Hetzner in Germany and included in the daily backup. A collection can delete documents that have not changed for a set number of days. Administrators can download an app's data, including what each person saved for themselves only, and delete a collection's data. - **Events** in the Audit log hold only the event's name, who, when, the app and perhaps an id. - **Error reports** are encrypted in komplai's database for 30 days, without who got the error. - **Anonymous counts** keep only the number per day, with no address or identity, for 400 days. - **Data an app keeps in the browser** stays on that device, unless the app itself sends it to another service. --- https://developers.komplai.dk/tools/run # Redact API reference > 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. Request and response schemas, with examples, are in the OpenAPI document: https://developers.komplai.dk/openapi.json ## POST /v1/redact **Pseudonymise a text** 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. - Operation id: `redactText` - Scopes: `redact:process` - Parameters: `prefer` (header), `idempotency-key` (header) - Responses: 200, 202, 400, 401, 403, 409, 413, 415, 429, 502, 503, 504 ## POST /v1/redact/detect **Find personal data in a text** 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. - Operation id: `detectPersonalData` - Scopes: `redact:detect` - Responses: 200, 400, 401, 403, 413, 415, 429, 502, 503 ## POST /v1/redact/restore **Restore the originals in a text** 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. - Operation id: `restoreRedactText` - Scopes: `redact:process` - Responses: 200, 400, 401, 403, 404, 409, 410, 413, 415, 429, 503 ## POST /v1/redact/jobs **Submit a text job** 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. - Operation id: `submitRedactJob` - Scopes: `redact:process` - Parameters: `idempotency-key` (header) - Responses: 202, 400, 401, 403, 409, 413, 415, 429, 503 ## GET /v1/redact/jobs/{id} **Read the status of a text job** 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. - Operation id: `getRedactJob` - Scopes: `redact:process` - Parameters: `id` (path, required) - Responses: 200, 400, 401, 403, 404, 429, 503 ## DELETE /v1/redact/jobs/{id} **Delete a text job** 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. - Operation id: `deleteRedactJob` - Scopes: `redact:process` - Parameters: `id` (path, required) - Responses: 200, 400, 401, 403, 404, 429, 503 ## GET /v1/redact/jobs/{id}/result **Read the result of a text job** 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. - Operation id: `getRedactJobResult` - Scopes: `redact:process` - Parameters: `id` (path, required) - Responses: 200, 202, 400, 401, 403, 404, 410, 429, 503 ## POST /v1/redact/file **Pseudonymise the text of a PDF or Word file (beta)** (Beta) 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. - Operation id: `redactFile` - Scopes: `redact:process` - Parameters: `prefer` (header), `idempotency-key` (header) - Responses: 200, 202, 400, 401, 403, 409, 413, 415, 422, 429, 502, 503, 504 ## POST /v1/redact/file/jobs **Submit a PDF or Word file as a text job (beta)** (Beta) 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. - Operation id: `submitRedactFileJob` - Scopes: `redact:process` - Parameters: `idempotency-key` (header) - Responses: 202, 400, 401, 403, 409, 413, 415, 422, 429, 503 --- https://developers.komplai.dk/reference/redact # Account API reference > What the key can reach, where each Redact layer processes text, the NER places and models a call may choose, and the limits. Request and response schemas, with examples, are in the OpenAPI document: https://developers.komplai.dk/openapi.json ## GET /v1/access **Read what this key can reach** Lists the services this key reaches in its organisation, with their scopes, hosting, processing and limits. Call it first: for Redact, hosting.processing.layers names where each layer processes text, text_contract the options and limits that apply, and text_contract.jobs_accepting_submissions whether text jobs are accepted. Works for personal keys and for organisation integration keys, which reach Redact only; an organisation integration key's response also names the integration in principal. It sends no text, runs no model and counts as one request. services[].edition is deprecated and is always "custom"; read scopes and processing instead. - Operation id: `readAccess` - Scopes: `access:read` - Responses: 200, 401, 403, 429, 503 --- https://developers.komplai.dk/reference/account # Chat API reference > Chat completions and model discovery on the organisation's approved processing. Needs a personal key with chat:complete; an organisation integration key gets 403 integration_not_permitted. Request and response schemas, with examples, are in the OpenAPI document: https://developers.komplai.dk/openapi.json ## GET /v1/models **List the permitted chat models** The models this key may use for POST /v1/chat/completions, with their context and output limits, the reasoning efforts they take and, in komplai's EU cloud, the provider's token rates. processing chooses which processing to list: komplai's local infrastructure, komplai's EU cloud or one of your organisation's own connections. It sends no text and runs no model. Needs a personal key with chat:complete. - Operation id: `listChatModels` - Scopes: `chat:complete` - Parameters: `processing` (query) - Responses: 200, 400, 401, 403, 404, 429, 503 ## POST /v1/chat/completions **Create a chat completion** An OpenAI-compatible chat completion with text only, returned whole (stream false). It runs where processing says: komplai's local infrastructure in Denmark, komplai's EU cloud when your organisation has it approved for Chat, or one of your organisation's own connections; without processing, where your organisation's Chat runs. The API never moves a call to other processing or another model, also not when the chosen one fails. At most 32 messages and 80,000 UTF-16 code units of text; the model has 120 seconds to answer. In EU cloud, usage is metered at the provider's price and counts towards the organisation's monthly AI spending cap; the call stops when the cap, the organisation's own limit or your personal limit is reached. Needs a personal key with chat:complete. - Operation id: `createChatCompletion` - Scopes: `chat:complete` - Responses: 200, 400, 401, 403, 404, 409, 413, 415, 429, 502, 503, 504 --- https://developers.komplai.dk/reference/chat # Decide (Beta) API reference > Typed questions about a text, answered with probabilities. Beta. Needs a personal key with decide:process; an organisation integration key gets 403 integration_not_permitted. Request and response schemas, with examples, are in the OpenAPI document: https://developers.komplai.dk/openapi.json ## POST /v1/decide **Evaluate one text** (Beta) Decide (beta) answers typed questions about one text with probabilities instead of prose: choice picks one option, score places the text on a scale, and noul says how likely a statement is true. Every answer has the full posterior and a confidence. A decision model writes no text, so there is nothing to parse; it runs on komplai's local infrastructure in Denmark, with no AI charge, and has 30 seconds to answer. The text is not stored. Needs a personal key with decide:process. - Operation id: `evaluateText` - Scopes: `decide:process` - Responses: 200, 400, 401, 403, 404, 409, 413, 415, 429, 502, 503 ## POST /v1/decide/batch **Evaluate several texts** (Beta) Decide (beta): the same questions for up to 100 texts in one call, answered in one pass of the model. The answers come back in the order of states, and the batch is answered whole or refused whole. It counts as one request. Needs a personal key with decide:process. - Operation id: `evaluateTexts` - Scopes: `decide:process` - Responses: 200, 400, 401, 403, 404, 409, 413, 415, 429, 502, 503 --- https://developers.komplai.dk/reference/decide # Coding (Beta) API reference > Account, models and streamed completions for coding clients. Beta. Needs a personal key with coding:read or coding:complete; an organisation integration key gets 403 integration_not_permitted. Request and response schemas, with examples, are in the OpenAPI document: https://developers.komplai.dk/openapi.json ## GET /v1/coding/account **Read the coding account** (Beta) Your organisation, the current terms as contract, where a coding call's data goes, the organisation's monthly AI spending cap and this month's use (in balance, a name kept for installed clients), the default model and the coding models with the provider's prices. Read it before the first completion and whenever a completion answers 409 terms_changed, and show the terms to the person before they connect. It sends no text and runs no model. Needs a personal key with coding:read. - Operation id: `readCodingAccount` - Scopes: `coding:read` - Responses: 200, 401, 403, 429, 503 ## GET /v1/coding/models **List the coding models** (Beta) The models a coding client may use, with their limits and the provider's prices, in the OpenAI list shape, and the account without its models. Needs a personal key with coding:read. - Operation id: `listCodingModels` - Scopes: `coding:read` - Responses: 200, 401, 403, 429, 503 ## POST /v1/coding/chat/completions **Stream a coding completion** (Beta) An OpenAI-compatible chat completion for coding clients, streamed as server-sent events, with text and function calls. komplai never runs a tool: the client runs it, asks the person where needed, and sends the result in the next request. The model runs in komplai's EU cloud on your organisation's approved route. Before the provider is called, the most the call can cost is reserved under the organisation's monthly AI spending cap; usage is metered at the provider's price, and calls stop when the cap, the organisation's own limit or your personal limit is reached. komplai stores no prompts, answers or tool results, only the call's metadata. Send X-Komplai-Contract with the current contract and X-Request-Id with a new UUID for each operation. Needs a personal key with coding:complete. - Operation id: `createCodingChatCompletion` - Scopes: `coding:complete` - Parameters: `X-Komplai-Contract` (header, required), `X-Request-Id` (header, required) - Responses: 200, 400, 401, 403, 409, 413, 415, 429, 502, 503, 504 --- https://developers.komplai.dk/reference/coding # access_service_unavailable > Keys and access could not be checked. HTTP status: 503 ## What to do Try again shortly. If it keeps happening, contact komplai with the request_id. ## Example ```json { "error": "access_service_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/access_service_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/access_service_unavailable # 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. HTTP status: 502 ## What to do Send the text again, or run it with engine pipeline. ## Example ```json { "error": "agent_no_progress", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/agent_no_progress" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/agent_no_progress # agentic_disabled > engine agentic is switched off on this server. HTTP status: 503 ## What to do Leave engine out, which runs pipeline, until Redact Agentic is switched on again. ## Example ```json { "error": "agentic_disabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/agentic_disabled" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/agentic_disabled # agentic_lookup_not_allowed > A source in sources is not approved by the organisation's administrator. HTTP status: 403 ## What to do Remove the source from sources, or ask your organisation's administrator to approve it. ## Example ```json { "error": "agentic_lookup_not_allowed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/agentic_lookup_not_allowed" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/agentic_lookup_not_allowed # agentic_lookup_unavailable > A source in sources is not available right now. HTTP status: 503 ## What to do Remove the source from sources, or try again later. ## Example ```json { "error": "agentic_lookup_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/agentic_lookup_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/agentic_lookup_unavailable # agentic_preview_not_enabled > The organisation's administrator has not turned on the Redact Agentic preview. HTTP status: 403 ## What to do Ask your organisation's administrator to turn on the Redact Agentic preview, or leave engine out. ## Example ```json { "error": "agentic_preview_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/agentic_preview_not_enabled" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/agentic_preview_not_enabled # 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. HTTP status: 429 ## What to do Choose local processing for the call, or ask your organisation's administrator about the limit. Waiting does not help: a monthly cap starts again next month. ## Example ```json { "error": "ai_credit_exhausted", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ai_credit_exhausted" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/ai_credit_exhausted # ai_credit_not_granted > No monthly AI spending cap is set up for this month, so eu-cloud cannot run. HTTP status: 403 ## What to do Choose local processing, or ask your organisation's administrator to have a monthly AI spending cap agreed for EU cloud. ## Example ```json { "error": "ai_credit_not_granted", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ai_credit_not_granted" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/ai_credit_not_granted # api_key_required > No Authorization: Bearer header with a komplai key. HTTP status: 401 ## What to do Send the header Authorization: Bearer with a komplai key, one that starts with kp_live_ or kp_org_. ## Example ```json { "error": "api_key_required", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/api_key_required" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/api_key_required # app_not_assigned > The key's person lost the app or their membership while the request was admitted. HTTP status: 403 ## What to do Ask your organisation's administrator to assign you the app again. ## Example ```json { "error": "app_not_assigned", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/app_not_assigned" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/app_not_assigned # approved_redact_storage_policy_required > Your organisation processes personal data but has no approved storage policy for text jobs. HTTP status: 403 ## What to do Ask your organisation's administrator to approve a storage policy for text jobs, or send short texts to POST /v1/redact. ## Example ```json { "error": "approved_redact_storage_policy_required", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/approved_redact_storage_policy_required" } ``` ## Operations that can return it - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/approved_redact_storage_policy_required # 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. HTTP status: 400 ## What to do Use the id exactly as the API returned it. ## Example ```json { "error": "Bad Request", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/bad-request" } ``` ## Operations that can return it - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/bad-request # chat_cloud_unavailable > The organisation's EU cloud setup cannot be used right now. HTTP status: 503 ## What to do Try again later, or choose local processing. If it keeps happening, contact komplai with the request_id. ## Example ```json { "error": "chat_cloud_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/chat_cloud_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/chat_cloud_unavailable # coding_not_configured > komplai's EU route has no coding terms or coding models on this server. HTTP status: 503 ## What to do Contact komplai with the request_id; there is nothing to change on your side. ## Example ```json { "error": "coding_not_configured", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/coding_not_configured" } ``` ## Operations that can return it - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/coding_not_configured # coding_not_enabled > Coding is not enabled for the organisation, its Chat does not run in komplai's EU cloud with an approved setup, or the key's person is not assigned Chat. HTTP status: 403 ## What to do Ask your organisation's administrator for access to Chat. komplai turns coding on for the organisation; the administrator can contact komplai about it. ## Example ```json { "error": "coding_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/coding_not_enabled" } ``` ## Operations that can return it - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/coding_not_enabled # coding_service_unavailable > The coding model's provider failed or could not be reached, or an unexpected failure happened. HTTP status: 502, 503 ## What to do Try again later. If the stream had begun, the call may have reached the model: do not send it again automatically. ## Example ```json { "error": "coding_service_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/coding_service_unavailable" } ``` ## Operations that can return it - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/coding_service_unavailable # connection_failed > The provider behind one of the organisation's own connections could not be reached or failed. HTTP status: 502 ## What to do Try again later, or check the provider's status. The API never moves the call to other processing. ## Example ```json { "error": "connection_failed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_failed" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_failed # connection_model_unavailable > The provider behind the connection does not know the model the connection names. HTTP status: 409 ## What to do Ask your organisation's administrator to correct the connection's model on the hub's AI processing page. ## Example ```json { "error": "connection_model_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_model_unavailable" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_model_unavailable # connection_not_found > No connection with this id is available to you through the API. HTTP status: 404 ## What to do Check the connection's value on the hub's AI processing page, or ask your organisation's administrator for it. ## Example ```json { "error": "connection_not_found", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_not_found" } ``` ## Operations that can return it - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_not_found # connection_payment_required > The provider behind the connection wants payment on the organisation's account. HTTP status: 502 ## What to do Ask your organisation's administrator to settle the account with the provider. ## Example ```json { "error": "connection_payment_required", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_payment_required" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_payment_required # connection_rate_limited > The provider behind the connection refused the call for now. HTTP status: 429 ## What to do Wait the seconds in Retry-After, then try again. ## Example ```json { "error": "connection_rate_limited", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_rate_limited" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_rate_limited # connection_request_refused > The provider behind the connection refused the request, for example a value it does not take. HTTP status: 502 ## What to do Check the request against the provider's own limits, such as max_tokens or response_format. ## Example ```json { "error": "connection_request_refused", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_request_refused" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_request_refused # connection_unauthorized > The provider refused the connection's key. HTTP status: 502 ## What to do Ask your organisation's administrator to renew the connection's key. ## Example ```json { "error": "connection_unauthorized", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_unauthorized" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_unauthorized # connection_unavailable > The connection cannot be used: its key cannot be read or its address is refused. HTTP status: 503 ## What to do Ask your organisation's administrator to check the connection on the hub's AI processing page. ## Example ```json { "error": "connection_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/connection_unavailable" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/connection_unavailable # 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. HTTP status: 413 ## What to do Shorten the input or lower max_tokens. In Redact, split the text. ## Example ```json { "error": "context_limit", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/context_limit" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/context_limit # detection_service_unavailable > The detection service could not be reached or failed. HTTP status: 502, 503 ## What to do Try again shortly. For a failed text job, submit the text again. ## Example ```json { "error": "detection_service_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/detection_service_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/detection_service_unavailable # detector_unavailable > detectors includes ner, but NER is not set up. HTTP status: 503 ## What to do Leave ner out of detectors, or try again later. ## Example ```json { "error": "detector_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/detector_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/detector_unavailable # duplicate_request > This X-Request-Id was used before with this key, so nothing was sent to the model. HTTP status: 409 ## What to do Use a new UUID for each new operation. If you were retrying an operation whose outcome you did not know, it had already reached komplai: do not send it again. ## Example ```json { "error": "duplicate_request", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/duplicate_request" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/duplicate_request # empty_file > file.data decodes to nothing. HTTP status: 400 ## What to do Send the file's bytes, base64 encoded, in file.data. ## Example ```json { "error": "empty_file", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/empty_file" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/empty_file # encrypted_file > The PDF is password protected. HTTP status: 422 ## What to do Remove the PDF's password and send it again. ## Example ```json { "error": "encrypted_file", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/encrypted_file" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/encrypted_file # 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. HTTP status: 400 ## What to do Send engine pipeline, or leave engine out, with detectors ["regex", "llm"]. ## Example ```json { "error": "engine_retired", "hint": "engine review is retired. Send engine pipeline, or leave engine out, with detectors [\"regex\", \"llm\"].", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/engine_retired" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/engine_retired # eu_cloud_refused > komplai's EU cloud refused the call, so the model did not answer it. HTTP status: 502 ## What to do Choose local processing or one of your organisation's connections, and contact komplai with the request_id. There is nothing to change on your side. ## Example ```json { "error": "eu_cloud_refused", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/eu_cloud_refused" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/eu_cloud_refused # 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. HTTP status: 413 ## What to do Send longer texts to POST /v1/redact, or split the text. ## Example ```json { "error": "exceeds_ner_window", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/exceeds_ner_window" } ``` ## Operations that can return it - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/exceeds_ner_window # file_extraction_unavailable > The file reader could not start or stopped. This is not caused by the file. HTTP status: 503 ## What to do Try again shortly. If it keeps happening, contact komplai with the request_id. ## Example ```json { "error": "file_extraction_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/file_extraction_unavailable" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/file_extraction_unavailable # file_too_complex > Reading the file took more than 120 seconds or more resources than allowed (memory, ZIP entries, XML size or depth). HTTP status: 413 ## What to do Split the file, or send its text to POST /v1/redact or as a text job. ## Example ```json { "error": "file_too_complex", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/file_too_complex" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/file_too_complex # file_too_large > The file is over 50 MiB, or the body is over its byte limit. HTTP status: 413 ## What to do Split the file into parts under the limit. ## Example ```json { "error": "file_too_large", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/file_too_large" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/file_too_large # file_type_mismatch > The extension or contentType disagrees with the file's content. HTTP status: 400 ## What to do Send the file's real extension and contentType, or leave contentType out. ## Example ```json { "error": "file_type_mismatch", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/file_type_mismatch" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/file_type_mismatch # gateway_misconfigured > The connection to the detection service or the language model is misconfigured. HTTP status: 503 ## What to do Contact komplai with the request_id; there is nothing to change on your side. ## Example ```json { "error": "gateway_misconfigured", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/gateway_misconfigured" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/gateway_misconfigured # idempotency_conflict > This Idempotency-Key was used with a different body. Use a new UUID for a new job. HTTP status: 409 ## What to do Use a new UUID as Idempotency-Key for a new job. ## Example ```json { "error": "idempotency_conflict", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/idempotency_conflict" } ``` ## Operations that can return it - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/idempotency_conflict # identity_retired > The person behind a personal key has been removed from komplai. HTTP status: 403 ## What to do Use a key of a person who is still in the organisation. ## Example ```json { "error": "identity_retired", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/identity_retired" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/identity_retired # incoherent_redaction_policy > Your organisation's redaction and allow rules conflict for this text. HTTP status: 503 ## What to do Ask your organisation's administrator to resolve the conflict between its redaction and allow rules. ## Example ```json { "error": "incoherent_redaction_policy", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/incoherent_redaction_policy" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/incoherent_redaction_policy # incomplete_detection > A detection layer did not finish the whole text. No partial result is returned. HTTP status: 502 ## What to do Send the text again. If it fails again, split it or leave out the layer that failed. ## Example ```json { "error": "incomplete_detection", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/incomplete_detection" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/incomplete_detection # 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. HTTP status: 403 ## What to do Use a key with the scope, or ask your organisation's administrator about the assignment. ## Example ```json { "error": "insufficient_scope", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/insufficient_scope" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/insufficient_scope # integration_not_permitted > An organisation integration key cannot use this operation or this option. HTTP status: 403 ## What to do Use a personal key for this operation, or leave the option out. ## Example ```json { "error": "integration_not_permitted", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/integration_not_permitted" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/integration_not_permitted # Internal Server Error > Fastify's reason phrase for a failure the API did not expect. HTTP status: 500 ## What to do Try again. If it keeps happening, contact komplai with the request_id. ## Example ```json { "error": "Internal Server Error", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/internal-server-error" } ``` --- https://developers.komplai.dk/errors/internal-server-error # 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. HTTP status: 401 ## What to do Check that you send the whole key. A personal key is created in the hub's API area; for a new organisation integration key, contact komplai. ## Example ```json { "error": "invalid_api_key", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_api_key" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/invalid_api_key # 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. HTTP status: 400, 415 ## What to do Send a JSON object with the documented fields, and Content-Type application/json. ## Example ```json { "error": "invalid_body", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_body" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_body # invalid_coding_input > The body is not a coding request as documented. HTTP status: 400 ## What to do Correct the request against the field rules of POST /v1/coding/chat/completions. ## Example ```json { "error": "invalid_coding_input", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_coding_input" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/invalid_coding_input # invalid_coding_response > The model provider's stream failed validation. HTTP status: 502 ## What to do Try again later. If the stream had begun, do not send it again automatically. ## Example ```json { "error": "invalid_coding_response", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_coding_response" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/invalid_coding_response # 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. HTTP status: 502 ## What to do Send the text again, or leave out the layer that failed. ## Example ```json { "error": "invalid_detection", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_detection" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/invalid_detection # invalid_detectors > detectors is empty, has an unknown or repeated value, or more than three values. HTTP status: 400 ## What to do Send one to three of regex, ner and llm, each once. ## Example ```json { "error": "invalid_detectors", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_detectors" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_detectors # 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. HTTP status: 400, 422 ## What to do Send a PDF or a Word .docx file that opens, with a filename. ## Example ```json { "error": "invalid_file", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_file" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_file # invalid_file_encoding > file.data is empty or not base64. HTTP status: 400 ## What to do Encode the file's bytes as base64 in file.data. ## Example ```json { "error": "invalid_file_encoding", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_file_encoding" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_file_encoding # invalid_idempotency_key > Idempotency-Key is not a UUID, or it was sent more than once. HTTP status: 400 ## What to do Send one Idempotency-Key header with a UUID, or none. ## Example ```json { "error": "invalid_idempotency_key", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_idempotency_key" } ``` ## Operations that can return it - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_idempotency_key # invalid_include > include has an unknown or repeated value. HTTP status: 400 ## What to do Send include values from mapping, findings, changes and skipped, each once. ## Example ```json { "error": "invalid_include", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_include" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_include # 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. HTTP status: 400 ## What to do Correct the request against the operation's request schema. ## Example ```json { "error": "invalid_input", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_input" } ``` ## Operations that can return it - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/invalid_input # invalid_job > job is not a UUID. HTTP status: 400 ## What to do Send the job's id exactly as POST /v1/redact/jobs returned it. ## Example ```json { "error": "invalid_job", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_job" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_job # invalid_mapping > mapping is not an object, or a value is empty, not a string, or contains NUL or a lone surrogate. HTTP status: 400 ## What to do Send mapping exactly as POST /v1/redact returned it. ## Example ```json { "error": "invalid_mapping", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_mapping" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_mapping # invalid_ner_deployment > nerDeployment is not eu-de or local. HTTP status: 400 ## What to do Send eu-de or local, or leave nerDeployment out. ## Example ```json { "error": "invalid_ner_deployment", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_ner_deployment" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_ner_deployment # invalid_organisation_policy > Your organisation's redaction rules cannot be applied (more than 500 rules, or an invalid rule). HTTP status: 503 ## What to do Ask your organisation's administrator to correct its redaction rules. ## Example ```json { "error": "invalid_organisation_policy", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_organisation_policy" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_organisation_policy # 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`. HTTP status: 400 ## What to do Send mapping exactly as POST /v1/redact returned it. ## Example ```json { "error": "invalid_placeholder", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_placeholder" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_placeholder # invalid_processing > processing is not local or eu-cloud. HTTP status: 400 ## What to do Send local or eu-cloud, or leave processing out. ## Example ```json { "error": "invalid_processing", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_processing" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_processing # invalid_request_id > X-Request-Id is missing or not a version 4 UUID. HTTP status: 400 ## What to do Send a new version 4 UUID in X-Request-Id for each new operation. ## Example ```json { "error": "invalid_request_id", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_request_id" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/invalid_request_id # invalid_response > The model's answer failed validation, so nothing was returned. HTTP status: 502 ## What to do Try again. If it keeps happening, choose another model or contact komplai with the request_id. ## Example ```json { "error": "invalid_response", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_response" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) --- https://developers.komplai.dk/errors/invalid_response # invalid_restore_source > Send exactly one of mapping and job. HTTP status: 400 ## What to do Send exactly one of mapping and job. ## Example ```json { "error": "invalid_restore_source", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_restore_source" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_restore_source # invalid_sources > sources has an unknown or repeated value. HTTP status: 400 ## What to do Send sources from the list in GET /v1/access, each once. ## Example ```json { "error": "invalid_sources", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_sources" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_sources # invalid_text_encoding > text contains NUL or a lone UTF-16 surrogate. HTTP status: 400 ## What to do Remove NUL characters and lone UTF-16 surrogates from text. ## Example ```json { "error": "invalid_text_encoding", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_text_encoding" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/invalid_text_encoding # invalid_token > The key was revoked or expired, or its access ended, while the request was admitted or processed. HTTP status: 401 ## What to do Check that the key is still valid, then send the request again with a valid key. ## Example ```json { "error": "invalid_token", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/invalid_token" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/invalid_token # job_not_finished > The job is still queued or running; state says which. Try again after Retry-After seconds. HTTP status: 409 ## What to do Wait the seconds in Retry-After, then try again. ## Example ```json { "error": "job_not_finished", "state": "running", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/job_not_finished" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/job_not_finished # llm_model_not_applicable > model was sent, but llm is not in detectors, or engine is not pipeline. HTTP status: 400 ## What to do Add llm to detectors, or leave model out. ## Example ```json { "error": "llm_model_not_applicable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/llm_model_not_applicable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/llm_model_not_applicable # 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. HTTP status: 400, 409 ## What to do Name a model that GET /v1/access lists as available, or leave model out once the default is validated. ## Example ```json { "error": "llm_model_not_validated", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/llm_model_not_validated" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/llm_model_not_validated # 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. HTTP status: 503 ## What to do Try again later, or name another available model from GET /v1/access. ## Example ```json { "error": "local_model_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/local_model_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/local_model_unavailable # mapping_not_available > The job kept neither mapping nor changes; hint says how to submit it again. HTTP status: 409 ## What to do Submit the text again with include ["mapping"] or ["changes"]. ## Example ```json { "error": "mapping_not_available", "hint": "The job kept neither mapping nor changes. Submit it again with include [\"mapping\"] or [\"changes\"] to restore from it.", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/mapping_not_available" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/mapping_not_available # 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. HTTP status: 503 ## What to do Wait the seconds in Retry-After, or send the text as a text job, which waits for its turn. ## Example ```json { "error": "model_busy", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/model_busy" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/model_busy # model_not_enabled > The model is not one you may use at this processing, or it is not offered there right now. HTTP status: 404, 409 ## What to do Choose a model from the operation's model list (GET /v1/models, GET /v1/access or GET /v1/coding/models), or leave the model out for the default. ## Example ```json { "error": "model_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/model_not_enabled" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/model_not_enabled # 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. HTTP status: 504 ## What to do Try again later, or send the text as a text job. ## Example ```json { "error": "model_queue_expired", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/model_queue_expired" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/model_queue_expired # 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. HTTP status: 504 ## What to do Send the text again, or send it as a text job. ## Example ```json { "error": "model_stalled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/model_stalled" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/model_stalled # ner_deployment_without_ner > nerDeployment was sent, but ner is not in detectors (or mode is regex). HTTP status: 400 ## What to do Add ner to detectors, or leave nerDeployment out. ## Example ```json { "error": "ner_deployment_without_ner", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_deployment_without_ner" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/ner_deployment_without_ner # 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. HTTP status: 503 ## What to do Choose a place that GET /v1/access lists as available, or leave nerDeployment out. ## Example ```json { "error": "ner_location_unavailable", "nerDeployment": "local", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_location_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/ner_location_unavailable # 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. HTTP status: 403 ## What to do Choose a stable NER model from GET /v1/access, or leave nerModel out. ## Example ```json { "error": "ner_model_preview_required", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_model_preview_required" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/ner_model_preview_required # 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. HTTP status: 400 ## What to do Choose a model that GET /v1/access lists for that place, or leave nerModel out. ## Example ```json { "error": "ner_model_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_model_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/ner_model_unavailable # ner_model_unconfigured > The NER model in nerModel is not set up at the default place on this server. HTTP status: 503 ## What to do Choose another model from GET /v1/access, or leave nerModel out. ## Example ```json { "error": "ner_model_unconfigured", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_model_unconfigured" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/ner_model_unconfigured # ner_model_unknown > No NER model has the id in nerModel. GET /v1/access lists the models you may choose. HTTP status: 400 ## What to do Use a model id from GET /v1/access. ## Example ```json { "error": "ner_model_unknown", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_model_unknown" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/ner_model_unknown # ner_model_without_ner > nerModel was sent, but ner is not in detectors (or mode is regex). HTTP status: 400 ## What to do Add ner to detectors, or leave nerModel out. ## Example ```json { "error": "ner_model_without_ner", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/ner_model_without_ner" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/ner_model_without_ner # no_text_found > The file contains no text at all. HTTP status: 422 ## What to do Make the file's text readable first, for example with OCR; the API reads only a text layer. ## Example ```json { "error": "no_text_found", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/no_text_found" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/no_text_found # Not Found > Fastify's reason phrase: no operation has this method and path. HTTP status: 404 ## What to do Check the method and path against the operations in this document. ## Example ```json { "error": "Not Found", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/not-found" } ``` --- https://developers.komplai.dk/errors/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. HTTP status: 404 ## What to do Check the job's id and the key: a job is visible only to the key that created it, until it expires. ## Example ```json { "error": "not_found", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/not_found" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/not_found # Payload Too Large > Fastify's reason phrase: the body is over the operation's byte limit. HTTP status: 413 ## What to do Send a smaller body; each operation states its limit. ## Example ```json { "error": "Payload Too Large", "statusCode": 413, "code": "FST_ERR_CTP_BODY_TOO_LARGE", "message": "Request body is too large", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/payload-too-large" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/payload-too-large # person_ai_credit_exhausted > Your personal AI limit is reached (personal keys only). HTTP status: 429 ## What to do Choose local processing, or ask your organisation's administrator about your personal limit. ## Example ```json { "error": "person_ai_credit_exhausted", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/person_ai_credit_exhausted" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/person_ai_credit_exhausted # processing_access_changed > The organisation's processing setup changed while the request was handled. Send it again. HTTP status: 403, 409 ## What to do Send the request again. ## Example ```json { "error": "processing_access_changed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_access_changed" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/processing_access_changed # 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. HTTP status: 403 ## What to do Stop reading the job. Submit the text again as a new job, with a new Idempotency-Key, when access allows it. ## Example ```json { "error": "processing_access_withdrawn", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_access_withdrawn" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/processing_access_withdrawn # processing_capacity_busy > All organisation-rule workers in this API process are busy. There is no queue: try again after Retry-After. HTTP status: 429 ## What to do Wait the seconds in Retry-After, then try again. ## Example ```json { "error": "processing_capacity_busy", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_capacity_busy" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/processing_capacity_busy # 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. HTTP status: 403 ## What to do Choose processing your organisation allows, or ask its administrator. ## Example ```json { "error": "processing_choice_not_allowed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_choice_not_allowed" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/processing_choice_not_allowed # 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. HTTP status: 413 ## What to do Check the text for long repetitive patterns, or ask your organisation's administrator to simplify its rules. Splitting the text rarely helps. ## Example ```json { "error": "processing_complexity_exceeded", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_complexity_exceeded" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/processing_complexity_exceeded # processing_not_approved > The organisation's processing approval for the app is missing or was withdrawn. HTTP status: 403 ## What to do Ask your organisation's administrator; processing is approved in the organisation's agreement with komplai. ## Example ```json { "error": "processing_not_approved", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_not_approved" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/processing_not_approved # 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. HTTP status: 403 ## What to do Choose local processing, or ask your organisation's administrator. ## Example ```json { "error": "processing_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_not_enabled" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/processing_not_enabled # processing_outcome_uncertain > A text job submitted before 20 October 2026 was interrupted during work by the language model, so komplai cannot tell whether that step finished. A job now resumes from its checkpoint instead. HTTP status: none; it ends a text job ## What to do Submit the text again as a new job. A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/processing_outcome_uncertain # processing_policy_changed > Your organisation's redaction rules changed while the request ran. Send it again. HTTP status: 409 ## What to do Send the request again. ## Example ```json { "error": "processing_policy_changed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_policy_changed" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/processing_policy_changed # processing_timeout > The call took more than 300 seconds, or the client disconnected. Send long texts as text jobs. HTTP status: 504 ## What to do Send long texts as a text job (POST /v1/redact/jobs). ## Example ```json { "error": "processing_timeout", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/processing_timeout" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/processing_timeout # 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. HTTP status: 429 ## What to do Wait the seconds in Retry-After, then try again. Spread calls out; GET /v1/access shows your limits. ## Example ```json { "error": "rate_limited", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/rate_limited" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/access (https://developers.komplai.dk/reference/account.md) - GET /v1/models (https://developers.komplai.dk/reference/chat.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - GET /v1/coding/account (https://developers.komplai.dk/reference/coding.md) - GET /v1/coding/models (https://developers.komplai.dk/reference/coding.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/rate_limited # 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. HTTP status: 409 ## What to do Name another model in the meantime, and tell komplai the request_id. ## Example ```json { "error": "reasoning_effort_not_supported", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/reasoning_effort_not_supported" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/reasoning_effort_not_supported # reasoning_not_enabled > The model does not take this reasoning_effort, or one of the organisation's own connections was sent one other than none. HTTP status: 409 ## What to do Send a value from the model's reasoning_efforts in GET /v1/models, or leave reasoning_effort out. ## Example ```json { "error": "reasoning_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/reasoning_not_enabled" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) --- https://developers.komplai.dk/errors/reasoning_not_enabled # reasoning_not_supported > The coding model does not take this reasoning_effort. HTTP status: 400 ## What to do Send a value from the model's reasoning_efforts in GET /v1/coding/models, or leave reasoning_effort out. ## Example ```json { "error": "reasoning_not_supported", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/reasoning_not_supported" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/reasoning_not_supported # redact_capabilities_unavailable > Redact's processing details could not be read. HTTP status: 503 ## What to do Try again shortly. ## Example ```json { "error": "redact_capabilities_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_capabilities_unavailable" } ``` ## Operations that can return it - GET /v1/access (https://developers.komplai.dk/reference/account.md) --- https://developers.komplai.dk/errors/redact_capabilities_unavailable # redact_file_not_enabled > File input is switched off on this server. HTTP status: 503 ## What to do Send the file's text to POST /v1/redact or as a text job instead. ## Example ```json { "error": "redact_file_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_file_not_enabled" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/redact_file_not_enabled # redact_job_attempts_exhausted > The text job was interrupted three times, for example by restarts, and was stopped. No partial result is kept. HTTP status: 410 ## What to do Submit the text again as a new job. ## Example ```json { "error": "redact_job_attempts_exhausted", "state": "invalidated", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_job_attempts_exhausted" } ``` ## Operations that can return it - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_job_attempts_exhausted # redact_job_cancelled > The job was deleted or cancelled. HTTP status: 410 ## What to do Submit the text again if you still need the result. ## Example ```json { "error": "redact_job_cancelled", "state": "cancelled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_job_cancelled" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_job_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. HTTP status: 410 ## What to do Submit the text again as a new job. If it fails again, contact komplai with the request_id. ## Example ```json { "error": "redact_job_failed", "state": "failed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_job_failed" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_job_failed # redact_job_integrity_failed > The job's encrypted data could not be read. HTTP status: 503 ## What to do Submit the text again as a new job, and tell komplai the request_id. ## Example ```json { "error": "redact_job_integrity_failed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_job_integrity_failed" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_job_integrity_failed # redact_job_progress_failed > The worker could not record the job's progress, so it stopped the job instead of letting it run unrecorded. No partial result is kept. Submit it again. HTTP status: none; it ends a text job ## What to do Submit the text again as a new job. A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_job_progress_failed # redact_job_service_unavailable > The job store failed. HTTP status: 503 ## What to do Try again shortly. ## Example ```json { "error": "redact_job_service_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_job_service_unavailable" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - DELETE /v1/redact/jobs/{id} (https://developers.komplai.dk/reference/redact.md) - GET /v1/redact/jobs/{id}/result (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/redact_job_service_unavailable # redact_job_stalled > The job made no progress for 65 minutes, longer than any single step can take, and was stopped. Waiting for the language model on local infrastructure is not progress. No partial result is kept. HTTP status: none; it ends a text job ## What to do Submit the text again as a new job, or later when local infrastructure is less busy. A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_job_stalled # redact_job_unavailable > The job ended without a result and without a stored reason. HTTP status: 410 ## What to do Submit the text again as a new job. ## Example ```json { "error": "redact_job_unavailable", "state": "invalidated", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_job_unavailable" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/redact_job_unavailable # redact_jobs_not_enabled > Text jobs are not accepted right now; GET /v1/access shows text_contract.jobs_accepting_submissions. HTTP status: 503 ## What to do Send short texts to POST /v1/redact, and try text jobs again later. ## Example ```json { "error": "redact_jobs_not_enabled", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_jobs_not_enabled" } ``` ## Operations that can return it - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/redact_jobs_not_enabled # redact_restore_unavailable > Unexpected failure while restoring. HTTP status: 503 ## What to do Try again shortly. ## Example ```json { "error": "redact_restore_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_restore_unavailable" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/redact_restore_unavailable # redact_runtime_unavailable > A selected layer (NER or the language model) is not set up or not available right now. HTTP status: 503 ## What to do Leave out the layer that is not available, or try again later. ## Example ```json { "error": "redact_runtime_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/redact_runtime_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/redact_runtime_unavailable # 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. HTTP status: 413 ## What to do Restore the text in parts, each with only the labels it contains. ## Example ```json { "error": "restore_too_large", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/restore_too_large" } ``` ## Operations that can return it - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/restore_too_large # result_too_large > The result would be over 32 MiB. Ask for fewer include reports or split the text. HTTP status: 413 ## What to do Ask for fewer include reports, or split the text. ## Example ```json { "error": "result_too_large", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/result_too_large" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) A text job can also end with this code: its status carries it in the field error. --- https://developers.komplai.dk/errors/result_too_large # 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. HTTP status: 422 ## What to do Send allowPagesWithoutText true to process the other pages, or make the scanned pages readable first. ## Example ```json { "error": "scanned_pages_not_supported", "pages": [ 2 ], "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/scanned_pages_not_supported" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/scanned_pages_not_supported # semantic_runtime_not_configured > No local language model is set up for llm. HTTP status: 503 ## What to do Leave llm out of detectors, or choose processing eu-cloud if your organisation has it. ## Example ```json { "error": "semantic_runtime_not_configured", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/semantic_runtime_not_configured" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/semantic_runtime_not_configured # service_unavailable > The model failed or could not be reached, or local infrastructure is not set up for this call right now. HTTP status: 502, 503 ## What to do Try again later. If the call may have reached the model, do not send it again automatically. ## Example ```json { "error": "service_unavailable", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/service_unavailable" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) --- https://developers.komplai.dk/errors/service_unavailable # terms_changed > X-Komplai-Contract is not the current contract: the provider, its terms, the data mode, the agreement or the coding models and their prices changed. HTTP status: 409 ## What to do Read GET /v1/coding/account again, show the new terms to the person, and send the new contract. ## Example ```json { "error": "terms_changed", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/terms_changed" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/terms_changed # text_too_large > text is over the operation's limit in UTF-16 code units, or the body is over its byte limit. HTTP status: 413 ## What to do Send the text as a text job, or split it under the operation's limit. ## Example ```json { "error": "text_too_large", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/text_too_large" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/restore (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/text_too_large # timeout > The model did not answer in time. The call reached the model, so its outcome is unknown. HTTP status: 504 ## What to do Try again with a shorter input or a lower max_tokens; do not send it again automatically. ## Example ```json { "error": "timeout", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/timeout" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/timeout # too_many_pages > The PDF has more than 2,000 pages. HTTP status: 413 ## What to do Split the PDF into parts of at most 2,000 pages. ## Example ```json { "error": "too_many_pages", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/too_many_pages" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/too_many_pages # unsafe_placeholder > A fixed replacement token from your organisation's rules occurs in the text or collides with a label. HTTP status: 502 ## What to do Remove the fixed replacement token from the text, or ask your organisation's administrator to change it. ## Example ```json { "error": "unsafe_placeholder", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsafe_placeholder" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsafe_placeholder # Unsupported Media Type > Fastify's reason phrase: the body has no Content-Type, or one the API does not read, such as XML or form data. HTTP status: 415 ## What to do Send Content-Type: application/json. ## Example ```json { "error": "Unsupported Media Type", "statusCode": 415, "code": "FST_ERR_CTP_INVALID_MEDIA_TYPE", "message": "Unsupported Media Type", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported-media-type" } ``` ## Operations that can return it - POST /v1/chat/completions (https://developers.komplai.dk/reference/chat.md) - POST /v1/decide (https://developers.komplai.dk/reference/decide.md) - POST /v1/decide/batch (https://developers.komplai.dk/reference/decide.md) - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/unsupported-media-type # unsupported_engine_detectors > The detectors do not fit engine agentic: it needs regex and llm, with optional ner. HTTP status: 400 ## What to do For engine agentic, send detectors regex and llm, with ner if you want it. ## Example ```json { "error": "unsupported_engine_detectors", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_engine_detectors" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_engine_detectors # unsupported_engine_mode > mode disagrees with detectors. Leave mode out when you send detectors. HTTP status: 400 ## What to do Leave mode out when you send detectors. ## Example ```json { "error": "unsupported_engine_mode", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_engine_mode" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_engine_mode # unsupported_engine_sources > sources was sent without engine agentic. HTTP status: 400 ## What to do Leave sources out, or send engine agentic. ## Example ```json { "error": "unsupported_engine_sources", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_engine_sources" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_engine_sources # unsupported_file_type > The file is neither a PDF nor a Word .docx, by its content, its extension or its contentType. HTTP status: 400 ## What to do Send a PDF or a Word .docx file. ## Example ```json { "error": "unsupported_file_type", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_file_type" } ``` ## Operations that can return it - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_file_type # unsupported_pilot_mode > mode is not regex or ner, or semantic is true. No language model runs on this operation. HTTP status: 400 ## What to do Send mode regex or ner, and leave semantic out. The language model runs on POST /v1/redact. ## Example ```json { "error": "unsupported_pilot_mode", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_pilot_mode" } ``` ## Operations that can return it - POST /v1/redact/detect (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_pilot_mode # unsupported_processing > processing eu-cloud needs llm in detectors (and engine pipeline). Add llm to detectors. HTTP status: 400 ## What to do Add llm to detectors, or leave processing out. ## Example ```json { "error": "unsupported_processing", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_processing" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_processing # unsupported_redact_engine > engine is not one of the documented values. HTTP status: 400 ## What to do Send engine pipeline, or leave engine out. ## Example ```json { "error": "unsupported_redact_engine", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_redact_engine" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_redact_engine # unsupported_redact_mode > mode is not regex, ner or semantic. HTTP status: 400 ## What to do Send detectors instead of mode. ## Example ```json { "error": "unsupported_redact_mode", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_redact_mode" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_redact_mode # unsupported_redact_policy > policy is not all-detected. HTTP status: 400 ## What to do Leave policy out, or send all-detected. ## Example ```json { "error": "unsupported_redact_policy", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/unsupported_redact_policy" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/jobs (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file/jobs (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/unsupported_redact_policy # upstream_rate_limited > The coding model's provider refused the call for now. HTTP status: 429 ## What to do Try again later. ## Example ```json { "error": "upstream_rate_limited", "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/upstream_rate_limited" } ``` ## Operations that can return it - POST /v1/coding/chat/completions (https://developers.komplai.dk/reference/coding.md) --- https://developers.komplai.dk/errors/upstream_rate_limited # 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. HTTP status: 413 ## What to do Send the same body as a text job (POST /v1/redact/jobs), or this call with the header Prefer: respond-async. ## Example ```json { "error": "use_job", "estimatedSeconds": 540, "holdSeconds": 300, "request_id": "0f8e2c4a-6b1d-4e3f-9a7c-5d2b8e1f4a60", "doc_url": "https://developers.komplai.dk/errors/use_job" } ``` ## Operations that can return it - POST /v1/redact (https://developers.komplai.dk/reference/redact.md) - POST /v1/redact/file (https://developers.komplai.dk/reference/redact.md) --- https://developers.komplai.dk/errors/use_job