{
  "info": {
    "_postman_id": "0b400360-026d-48b8-ab04-00f12d46ee2d",
    "name": "komplai Account API",
    "description": "The komplai account API. Most integrations use **Redact**: pseudonymise text, find personal data, put the originals back, and read the text of PDF and Word files (beta). Guides, one page per error code and consoles to try each call are at https://developers.komplai.dk.\n\nVersion 1.3.0. Set {{token}} to your key in the environment.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.komplai.dk",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Redact",
      "description": "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.",
      "item": [
        {
          "name": "Pseudonymise a text",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "prefer",
                "value": "respond-async",
                "description": "Optional. respond-async answers 202 with a text job, exactly as POST /v1/redact/jobs, instead of holding the connection; the answer carries Preference-Applied: respond-async. Without it the call never becomes a job. Ignored while text jobs are not accepted.",
                "disabled": true
              },
              {
                "key": "idempotency-key",
                "value": "{{$guid}}",
                "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                "disabled": true
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"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.\",\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"include\": [\n    \"mapping\",\n    \"changes\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/redact",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact"
              ]
            },
            "description": "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.\n\nUse 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.\n\nOrganisation integration keys cannot use engine agentic: 403 integration_not_permitted.\n\nhttps://developers.komplai.dk/reference/redact#redactText"
          },
          "response": [
            {
              "name": "Rules and NER, with mapping and changes",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "prefer",
                    "value": "respond-async",
                    "description": "Optional. respond-async answers 202 with a text job, exactly as POST /v1/redact/jobs, instead of holding the connection; the answer carries Preference-Applied: respond-async. Without it the call never becomes a job. Ignored while text jobs are not accepted.",
                    "disabled": true
                  },
                  {
                    "key": "idempotency-key",
                    "value": "{{$guid}}",
                    "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                    "disabled": true
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"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.\",\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"include\": [\n    \"mapping\",\n    \"changes\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"redacted\": \"Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [EMAIL-1].\",\n  \"engine\": \"pipeline\",\n  \"mode\": \"ner\",\n  \"processing\": \"local\",\n  \"policy\": \"all-detected\",\n  \"policyVersion\": \"redact-text-v1\",\n  \"offsetEncoding\": \"utf-16\",\n  \"charsIn\": 154,\n  \"charsOut\": 103,\n  \"truncated\": false,\n  \"degraded\": false,\n  \"configuration\": {\n    \"engine\": \"pipeline\",\n    \"mode\": \"ner\",\n    \"detectors\": [\n      \"regex\",\n      \"ner\"\n    ],\n    \"sources\": [],\n    \"processing\": \"local\"\n  },\n  \"execution\": {\n    \"completed\": true,\n    \"detectorsRun\": [\n      \"regex\",\n      \"ner\"\n    ],\n    \"detectionPasses\": 1,\n    \"nerCalls\": 1,\n    \"llmCalls\": 0\n  },\n  \"mapping\": {\n    \"[PERSON-1]\": \"Mette Kjærgaard Holm\",\n    \"[CPR-1]\": \"120385-1234\",\n    \"[ADRESSE-1]\": \"Fiktivvej 12, 8000 Aarhus C\",\n    \"[TLF-1]\": \"21 34 56 78\",\n    \"[EMAIL-1]\": \"mette.holm@example.invalid\"\n  },\n  \"entries\": [\n    {\n      \"placeholder\": \"[PERSON-1]\",\n      \"type\": \"person\",\n      \"value\": \"Mette Kjærgaard Holm\",\n      \"confidence\": \"medium\",\n      \"source\": \"ner\"\n    },\n    {\n      \"placeholder\": \"[CPR-1]\",\n      \"type\": \"cpr\",\n      \"value\": \"120385-1234\",\n      \"confidence\": \"high\",\n      \"source\": \"regex\"\n    },\n    {\n      \"placeholder\": \"[ADRESSE-1]\",\n      \"type\": \"address\",\n      \"value\": \"Fiktivvej 12, 8000 Aarhus C\",\n      \"confidence\": \"high\",\n      \"source\": \"ner\"\n    },\n    {\n      \"placeholder\": \"[TLF-1]\",\n      \"type\": \"phone\",\n      \"value\": \"21 34 56 78\",\n      \"confidence\": \"medium\",\n      \"source\": \"regex\"\n    },\n    {\n      \"placeholder\": \"[EMAIL-1]\",\n      \"type\": \"email\",\n      \"value\": \"mette.holm@example.invalid\",\n      \"confidence\": \"high\",\n      \"source\": \"regex\"\n    }\n  ],\n  \"changes\": [\n    {\n      \"start\": 9,\n      \"end\": 29,\n      \"outputStart\": 9,\n      \"outputEnd\": 19,\n      \"original\": \"Mette Kjærgaard Holm\",\n      \"replacement\": \"[PERSON-1]\",\n      \"type\": \"person\"\n    },\n    {\n      \"start\": 39,\n      \"end\": 50,\n      \"outputStart\": 29,\n      \"outputEnd\": 36,\n      \"original\": \"120385-1234\",\n      \"replacement\": \"[CPR-1]\",\n      \"type\": \"cpr\"\n    },\n    {\n      \"start\": 59,\n      \"end\": 86,\n      \"outputStart\": 45,\n      \"outputEnd\": 56,\n      \"original\": \"Fiktivvej 12, 8000 Aarhus C\",\n      \"replacement\": \"[ADRESSE-1]\",\n      \"type\": \"address\"\n    },\n    {\n      \"start\": 109,\n      \"end\": 120,\n      \"outputStart\": 79,\n      \"outputEnd\": 86,\n      \"original\": \"21 34 56 78\",\n      \"replacement\": \"[TLF-1]\",\n      \"type\": \"phone\"\n    },\n    {\n      \"start\": 127,\n      \"end\": 153,\n      \"outputStart\": 93,\n      \"outputEnd\": 102,\n      \"original\": \"mette.holm@example.invalid\",\n      \"replacement\": \"[EMAIL-1]\",\n      \"type\": \"email\"\n    }\n  ]\n}"
            },
            {
              "name": "A new job",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "prefer",
                    "value": "respond-async",
                    "description": "Optional. respond-async answers 202 with a text job, exactly as POST /v1/redact/jobs, instead of holding the connection; the answer carries Preference-Applied: respond-async. Without it the call never becomes a job. Ignored while text jobs are not accepted.",
                    "disabled": true
                  },
                  {
                    "key": "idempotency-key",
                    "value": "{{$guid}}",
                    "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                    "disabled": true
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"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.\",\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"include\": [\n    \"mapping\",\n    \"changes\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact"
                  ]
                }
              },
              "status": "Accepted",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"queued\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 0\n  },\n  \"reused\": false\n}"
            }
          ]
        },
        {
          "name": "Find personal data in a text",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"text\": \"Ring til Mette Kjærgaard Holm på 21 34 56 78.\",\n  \"mode\": \"ner\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/redact/detect",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "detect"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/redact#detectPersonalData"
          },
          "response": [
            {
              "name": "A name and a phone number",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"text\": \"Ring til Mette Kjærgaard Holm på 21 34 56 78.\",\n  \"mode\": \"ner\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/detect",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "detect"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"findings\": [\n    {\n      \"start\": 9,\n      \"end\": 29,\n      \"type\": \"person\",\n      \"value\": \"Mette Kjærgaard Holm\",\n      \"confidence\": \"high\",\n      \"source\": \"ner\"\n    },\n    {\n      \"start\": 33,\n      \"end\": 44,\n      \"type\": \"phone\",\n      \"value\": \"21 34 56 78\",\n      \"confidence\": \"medium\",\n      \"source\": \"regex\"\n    }\n  ],\n  \"truncated\": false,\n  \"degraded\": false\n}"
            }
          ]
        },
        {
          "name": "Restore the originals in a text",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"text\": \"Kære [PERSON-1]. Vi har modtaget din ansøgning og svarer på [EMAIL-1].\",\n  \"mapping\": {\n    \"[PERSON-1]\": \"Mette Kjærgaard Holm\",\n    \"[CPR-1]\": \"120385-1234\",\n    \"[ADRESSE-1]\": \"Fiktivvej 12, 8000 Aarhus C\",\n    \"[TLF-1]\": \"21 34 56 78\",\n    \"[EMAIL-1]\": \"mette.holm@example.invalid\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/redact/restore",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "restore"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/redact#restoreRedactText"
          },
          "response": [
            {
              "name": "Both labels restored",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"text\": \"Kære [PERSON-1]. Vi har modtaget din ansøgning og svarer på [EMAIL-1].\",\n  \"mapping\": {\n    \"[PERSON-1]\": \"Mette Kjærgaard Holm\",\n    \"[CPR-1]\": \"120385-1234\",\n    \"[ADRESSE-1]\": \"Fiktivvej 12, 8000 Aarhus C\",\n    \"[TLF-1]\": \"21 34 56 78\",\n    \"[EMAIL-1]\": \"mette.holm@example.invalid\"\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/restore",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "restore"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"text\": \"Kære Mette Kjærgaard Holm. Vi har modtaget din ansøgning og svarer på mette.holm@example.invalid.\",\n  \"restored\": 2,\n  \"unknownPlaceholders\": []\n}"
            }
          ]
        },
        {
          "name": "Submit a text job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "idempotency-key",
                "value": "{{$guid}}",
                "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                "disabled": true
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"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.\",\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"include\": [\n    \"mapping\",\n    \"changes\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/redact/jobs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "jobs"
              ]
            },
            "description": "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.\n\nOrganisation integration keys cannot use engine agentic: 403 integration_not_permitted.\n\nhttps://developers.komplai.dk/reference/redact#submitRedactJob"
          },
          "response": [
            {
              "name": "A new job",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "idempotency-key",
                    "value": "{{$guid}}",
                    "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                    "disabled": true
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"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.\",\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"include\": [\n    \"mapping\",\n    \"changes\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/jobs",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "jobs"
                  ]
                }
              },
              "status": "Accepted",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"queued\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 0\n  },\n  \"reused\": false\n}"
            }
          ]
        },
        {
          "name": "Read the status of a text job",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/redact/jobs/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "jobs",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                  "description": "The job's id from POST /v1/redact/jobs."
                }
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/redact#getRedactJob"
          },
          "response": [
            {
              "name": "Queued",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/jobs/:id",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "jobs",
                    ":id"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                      "description": "The job's id from POST /v1/redact/jobs."
                    }
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"queued\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 0\n  }\n}"
            }
          ]
        },
        {
          "name": "Delete a text job",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/redact/jobs/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "jobs",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                  "description": "The job's id from POST /v1/redact/jobs."
                }
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/redact#deleteRedactJob"
          },
          "response": [
            {
              "name": "Cancelled and deleted",
              "originalRequest": {
                "method": "DELETE",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/jobs/:id",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "jobs",
                    ":id"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                      "description": "The job's id from POST /v1/redact/jobs."
                    }
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"cancelled\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 1\n  },\n  \"error\": \"redact_job_cancelled\"\n}"
            }
          ]
        },
        {
          "name": "Read the result of a text job",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/redact/jobs/:id/result",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "jobs",
                ":id",
                "result"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                  "description": "The job's id from POST /v1/redact/jobs."
                }
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/redact#getRedactJobResult"
          },
          "response": [
            {
              "name": "Rules and NER, with mapping and changes",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/jobs/:id/result",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "jobs",
                    ":id",
                    "result"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                      "description": "The job's id from POST /v1/redact/jobs."
                    }
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"redacted\": \"Borgeren [PERSON-1], cpr-nr. [CPR-1], bor på [ADRESSE-1]. Hun kan kontaktes på [TLF-1] eller [EMAIL-1].\",\n  \"engine\": \"pipeline\",\n  \"mode\": \"ner\",\n  \"processing\": \"local\",\n  \"policy\": \"all-detected\",\n  \"policyVersion\": \"redact-text-v1\",\n  \"offsetEncoding\": \"utf-16\",\n  \"charsIn\": 154,\n  \"charsOut\": 103,\n  \"truncated\": false,\n  \"degraded\": false,\n  \"configuration\": {\n    \"engine\": \"pipeline\",\n    \"mode\": \"ner\",\n    \"detectors\": [\n      \"regex\",\n      \"ner\"\n    ],\n    \"sources\": [],\n    \"processing\": \"local\"\n  },\n  \"execution\": {\n    \"completed\": true,\n    \"detectorsRun\": [\n      \"regex\",\n      \"ner\"\n    ],\n    \"detectionPasses\": 1,\n    \"nerCalls\": 1,\n    \"llmCalls\": 0\n  },\n  \"mapping\": {\n    \"[PERSON-1]\": \"Mette Kjærgaard Holm\",\n    \"[CPR-1]\": \"120385-1234\",\n    \"[ADRESSE-1]\": \"Fiktivvej 12, 8000 Aarhus C\",\n    \"[TLF-1]\": \"21 34 56 78\",\n    \"[EMAIL-1]\": \"mette.holm@example.invalid\"\n  },\n  \"entries\": [\n    {\n      \"placeholder\": \"[PERSON-1]\",\n      \"type\": \"person\",\n      \"value\": \"Mette Kjærgaard Holm\",\n      \"confidence\": \"medium\",\n      \"source\": \"ner\"\n    },\n    {\n      \"placeholder\": \"[CPR-1]\",\n      \"type\": \"cpr\",\n      \"value\": \"120385-1234\",\n      \"confidence\": \"high\",\n      \"source\": \"regex\"\n    },\n    {\n      \"placeholder\": \"[ADRESSE-1]\",\n      \"type\": \"address\",\n      \"value\": \"Fiktivvej 12, 8000 Aarhus C\",\n      \"confidence\": \"high\",\n      \"source\": \"ner\"\n    },\n    {\n      \"placeholder\": \"[TLF-1]\",\n      \"type\": \"phone\",\n      \"value\": \"21 34 56 78\",\n      \"confidence\": \"medium\",\n      \"source\": \"regex\"\n    },\n    {\n      \"placeholder\": \"[EMAIL-1]\",\n      \"type\": \"email\",\n      \"value\": \"mette.holm@example.invalid\",\n      \"confidence\": \"high\",\n      \"source\": \"regex\"\n    }\n  ],\n  \"changes\": [\n    {\n      \"start\": 9,\n      \"end\": 29,\n      \"outputStart\": 9,\n      \"outputEnd\": 19,\n      \"original\": \"Mette Kjærgaard Holm\",\n      \"replacement\": \"[PERSON-1]\",\n      \"type\": \"person\"\n    },\n    {\n      \"start\": 39,\n      \"end\": 50,\n      \"outputStart\": 29,\n      \"outputEnd\": 36,\n      \"original\": \"120385-1234\",\n      \"replacement\": \"[CPR-1]\",\n      \"type\": \"cpr\"\n    },\n    {\n      \"start\": 59,\n      \"end\": 86,\n      \"outputStart\": 45,\n      \"outputEnd\": 56,\n      \"original\": \"Fiktivvej 12, 8000 Aarhus C\",\n      \"replacement\": \"[ADRESSE-1]\",\n      \"type\": \"address\"\n    },\n    {\n      \"start\": 109,\n      \"end\": 120,\n      \"outputStart\": 79,\n      \"outputEnd\": 86,\n      \"original\": \"21 34 56 78\",\n      \"replacement\": \"[TLF-1]\",\n      \"type\": \"phone\"\n    },\n    {\n      \"start\": 127,\n      \"end\": 153,\n      \"outputStart\": 93,\n      \"outputEnd\": 102,\n      \"original\": \"mette.holm@example.invalid\",\n      \"replacement\": \"[EMAIL-1]\",\n      \"type\": \"email\"\n    }\n  ]\n}"
            },
            {
              "name": "Still running",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/jobs/:id/result",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "jobs",
                    ":id",
                    "result"
                  ],
                  "variable": [
                    {
                      "key": "id",
                      "value": "3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c",
                      "description": "The job's id from POST /v1/redact/jobs."
                    }
                  ]
                }
              },
              "status": "Accepted",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"running\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 1\n  }\n}"
            }
          ]
        },
        {
          "name": "Pseudonymise the text of a PDF or Word file (beta)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "prefer",
                "value": "respond-async",
                "description": "Optional. respond-async answers 202 with a text job, exactly as POST /v1/redact/file/jobs, instead of holding the connection. Without it the call never becomes a job.",
                "disabled": true
              },
              {
                "key": "idempotency-key",
                "value": "{{$guid}}",
                "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                "disabled": true
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"file\": {\n    \"filename\": \"afgoerelse.pdf\",\n    \"contentType\": \"application/pdf\",\n    \"data\": \"JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=\"\n  },\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"processing\": \"local\",\n  \"include\": [\n    \"mapping\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/redact/file",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "file"
              ]
            },
            "description": "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.\n\nOrganisation integration keys cannot use engine agentic: 403 integration_not_permitted.\n\nhttps://developers.komplai.dk/reference/redact#redactFile"
          },
          "response": [
            {
              "name": "A two-page PDF with rules and NER",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "prefer",
                    "value": "respond-async",
                    "description": "Optional. respond-async answers 202 with a text job, exactly as POST /v1/redact/file/jobs, instead of holding the connection. Without it the call never becomes a job.",
                    "disabled": true
                  },
                  {
                    "key": "idempotency-key",
                    "value": "{{$guid}}",
                    "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                    "disabled": true
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"file\": {\n    \"filename\": \"afgoerelse.pdf\",\n    \"contentType\": \"application/pdf\",\n    \"data\": \"JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=\"\n  },\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"processing\": \"local\",\n  \"include\": [\n    \"mapping\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/file",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "file"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"redacted\": \"Afgørelse til [PERSON-1]\\ncpr-nr. [CPR-1], [ADRESSE-1]\\n\\nTelefon [TLF-1]\\n[EMAIL-1]\",\n  \"engine\": \"pipeline\",\n  \"mode\": \"ner\",\n  \"processing\": \"local\",\n  \"policy\": \"all-detected\",\n  \"policyVersion\": \"redact-text-v1\",\n  \"offsetEncoding\": \"utf-16\",\n  \"charsIn\": 131,\n  \"charsOut\": 80,\n  \"truncated\": false,\n  \"degraded\": false,\n  \"configuration\": {\n    \"engine\": \"pipeline\",\n    \"mode\": \"ner\",\n    \"detectors\": [\n      \"regex\",\n      \"ner\"\n    ],\n    \"sources\": [],\n    \"processing\": \"local\"\n  },\n  \"execution\": {\n    \"completed\": true,\n    \"detectorsRun\": [\n      \"regex\",\n      \"ner\"\n    ],\n    \"detectionPasses\": 1,\n    \"nerCalls\": 1,\n    \"llmCalls\": 0\n  },\n  \"mapping\": {\n    \"[PERSON-1]\": \"Mette Kjærgaard Holm\",\n    \"[CPR-1]\": \"120385-1234\",\n    \"[ADRESSE-1]\": \"Fiktivvej 12, 8000 Aarhus C\",\n    \"[TLF-1]\": \"21 34 56 78\",\n    \"[EMAIL-1]\": \"mette.holm@example.invalid\"\n  },\n  \"entries\": [\n    {\n      \"placeholder\": \"[PERSON-1]\",\n      \"type\": \"person\",\n      \"value\": \"Mette Kjærgaard Holm\",\n      \"confidence\": \"medium\",\n      \"source\": \"ner\"\n    },\n    {\n      \"placeholder\": \"[CPR-1]\",\n      \"type\": \"cpr\",\n      \"value\": \"120385-1234\",\n      \"confidence\": \"high\",\n      \"source\": \"regex\"\n    },\n    {\n      \"placeholder\": \"[ADRESSE-1]\",\n      \"type\": \"address\",\n      \"value\": \"Fiktivvej 12, 8000 Aarhus C\",\n      \"confidence\": \"high\",\n      \"source\": \"ner\"\n    },\n    {\n      \"placeholder\": \"[TLF-1]\",\n      \"type\": \"phone\",\n      \"value\": \"21 34 56 78\",\n      \"confidence\": \"medium\",\n      \"source\": \"regex\"\n    },\n    {\n      \"placeholder\": \"[EMAIL-1]\",\n      \"type\": \"email\",\n      \"value\": \"mette.holm@example.invalid\",\n      \"confidence\": \"high\",\n      \"source\": \"regex\"\n    }\n  ],\n  \"file\": {\n    \"type\": \"pdf\",\n    \"bytes\": 1025,\n    \"pageCount\": 2\n  },\n  \"pages\": [\n    {\n      \"number\": 1,\n      \"start\": 0,\n      \"end\": 83,\n      \"hasText\": true,\n      \"redactedStart\": 0,\n      \"redactedEnd\": 53\n    },\n    {\n      \"number\": 2,\n      \"start\": 85,\n      \"end\": 131,\n      \"hasText\": true,\n      \"redactedStart\": 55,\n      \"redactedEnd\": 80\n    }\n  ]\n}"
            },
            {
              "name": "A new job for a two-page PDF",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "prefer",
                    "value": "respond-async",
                    "description": "Optional. respond-async answers 202 with a text job, exactly as POST /v1/redact/file/jobs, instead of holding the connection. Without it the call never becomes a job.",
                    "disabled": true
                  },
                  {
                    "key": "idempotency-key",
                    "value": "{{$guid}}",
                    "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                    "disabled": true
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"file\": {\n    \"filename\": \"afgoerelse.pdf\",\n    \"contentType\": \"application/pdf\",\n    \"data\": \"JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=\"\n  },\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"processing\": \"local\",\n  \"include\": [\n    \"mapping\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/file",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "file"
                  ]
                }
              },
              "status": "Accepted",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"queued\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 0\n  },\n  \"reused\": false,\n  \"file\": {\n    \"type\": \"pdf\",\n    \"bytes\": 1025,\n    \"pageCount\": 2\n  },\n  \"pages\": [\n    {\n      \"number\": 1,\n      \"start\": 0,\n      \"end\": 83,\n      \"hasText\": true\n    },\n    {\n      \"number\": 2,\n      \"start\": 85,\n      \"end\": 131,\n      \"hasText\": true\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Submit a PDF or Word file as a text job (beta)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "idempotency-key",
                "value": "{{$guid}}",
                "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                "disabled": true
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"file\": {\n    \"filename\": \"afgoerelse.pdf\",\n    \"contentType\": \"application/pdf\",\n    \"data\": \"JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=\"\n  },\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"processing\": \"local\",\n  \"include\": [\n    \"mapping\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/redact/file/jobs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "redact",
                "file",
                "jobs"
              ]
            },
            "description": "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.\n\nOrganisation integration keys cannot use engine agentic: 403 integration_not_permitted.\n\nhttps://developers.komplai.dk/reference/redact#submitRedactFileJob"
          },
          "response": [
            {
              "name": "A new job for a two-page PDF",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "idempotency-key",
                    "value": "{{$guid}}",
                    "description": "Optional. A new UUID for each job, in upper or lower case. If the connection drops, send the same request again with the same key: within the job's lifetime the same key and body return the same job (reused true) instead of a second one, and the same key with another body answers 409 idempotency_conflict. Never reuse a key for another text. The key is bound to your organisation, the owner (person or integration) and the API key. The default {{$guid}} is Postman's variable for a new UUID on each request; in other tools, generate a UUID for each job or leave the header out.",
                    "disabled": true
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"file\": {\n    \"filename\": \"afgoerelse.pdf\",\n    \"contentType\": \"application/pdf\",\n    \"data\": \"JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFs0IDAgUiA2IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iago0IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgMyAwIFIgPj4gPj4gL0NvbnRlbnRzIDUgMCBSID4+CmVuZG9iago1IDAgb2JqCjw8IC9MZW5ndGggMTMxID4+CnN0cmVhbQpCVCAvRjEgMTIgVGYgNzIgNzIwIFRkIDE2IFRMIChBZmf4cmVsc2UgdGlsIE1ldHRlIEtq5nJnYWFyZCBIb2xtKSBUaiBUKiAoY3ByLW5yLiAxMjAzODUtMTIzNCwgRmlrdGl2dmVqIDEyLCA4MDAwIEFhcmh1cyBDKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSAzIDAgUiA+PiA+PiAvQ29udGVudHMgNyAwIFIgPj4KZW5kb2JqCjcgMCBvYmoKPDwgL0xlbmd0aCA5NCA+PgpzdHJlYW0KQlQgL0YxIDEyIFRmIDcyIDcyMCBUZCAxNiBUTCAoVGVsZWZvbiAyMSAzNCA1NiA3OCkgVGogVCogKG1ldHRlLmhvbG1AZXhhbXBsZS5pbnZhbGlkKSBUaiBUKiBFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjcgMDAwMDAgbiAKMDAwMDAwMDIyNCAwMDAwMCBuIAowMDAwMDAwMzUwIDAwMDAwIG4gCjAwMDAwMDA1MzIgMDAwMDAgbiAKMDAwMDAwMDY1OCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgwMgolJUVPRgo=\"\n  },\n  \"detectors\": [\n    \"regex\",\n    \"ner\"\n  ],\n  \"processing\": \"local\",\n  \"include\": [\n    \"mapping\"\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/redact/file/jobs",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "redact",
                    "file",
                    "jobs"
                  ]
                }
              },
              "status": "Accepted",
              "code": 202,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"3f2b8c1e-7d4a-4e9b-a6c5-2d1e0f9a8b7c\",\n  \"state\": \"queued\",\n  \"createdAt\": \"2026-10-20T08:00:00.000Z\",\n  \"expiresAt\": \"2026-10-20T09:00:00.000Z\",\n  \"progress\": {\n    \"completed\": 0,\n    \"total\": 0\n  },\n  \"reused\": false,\n  \"file\": {\n    \"type\": \"pdf\",\n    \"bytes\": 1025,\n    \"pageCount\": 2\n  },\n  \"pages\": [\n    {\n      \"number\": 1,\n      \"start\": 0,\n      \"end\": 83,\n      \"hasText\": true\n    },\n    {\n      \"number\": 2,\n      \"start\": 85,\n      \"end\": 131,\n      \"hasText\": true\n    }\n  ]\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Account",
      "description": "What the key can reach, where each Redact layer processes text, the NER places and models a call may choose, and the limits.",
      "item": [
        {
          "name": "Read what this key can reach",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/access",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "access"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/account#readAccess"
          },
          "response": [
            {
              "name": "An organisation integration key with Redact",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/access",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "access"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"organisation_id\": \"5b0d6c2e-8f3a-4d1b-9c7e-2a4f6b8d0e13\",\n  \"principal\": {\n    \"type\": \"integration\",\n    \"integration_id\": \"7a9c1e3f-5b7d-4f9a-8c2e-4d6f8a0b2c4e\",\n    \"name\": \"Sagsbehandlingsrobot\"\n  },\n  \"scopes\": [\n    \"access:read\",\n    \"redact:detect\",\n    \"redact:process\"\n  ],\n  \"services\": [\n    {\n      \"service\": \"redact\",\n      \"edition\": \"custom\",\n      \"scopes\": [\n        \"access:read\",\n        \"redact:detect\",\n        \"redact:process\"\n      ],\n      \"hosting\": {\n        \"id\": \"komplai-local\",\n        \"environment\": \"prod\",\n        \"shared\": true,\n        \"api\": {\n          \"provider\": \"komplai\",\n          \"name\": \"Komplai EU cloud\",\n          \"region\": \"EU · Germany\"\n        },\n        \"processing\": {\n          \"kind\": \"per-layer\",\n          \"provider\": \"komplai\",\n          \"layers\": [\n            {\n              \"detector\": \"regex\",\n              \"processing\": \"local\",\n              \"provider\": \"komplai\",\n              \"location\": \"EU · Germany\",\n              \"configured\": true\n            },\n            {\n              \"detector\": \"ner\",\n              \"processing\": \"local\",\n              \"provider\": \"komplai\",\n              \"location\": \"EU · Germany\",\n              \"configured\": true,\n              \"ner_deployment\": \"eu-de\",\n              \"places\": [\n                {\n                  \"id\": \"eu-de\",\n                  \"location\": \"EU · Germany\",\n                  \"available\": true,\n                  \"reason\": null,\n                  \"default\": true,\n                  \"detect\": {\n                    \"available\": true,\n                    \"reason\": null\n                  }\n                },\n                {\n                  \"id\": \"local\",\n                  \"location\": \"Local infrastructure · Denmark\",\n                  \"available\": false,\n                  \"reason\": \"unconfigured\",\n                  \"default\": false,\n                  \"detect\": {\n                    \"available\": false,\n                    \"reason\": \"unconfigured\"\n                  }\n                }\n              ],\n              \"models\": [\n                {\n                  \"id\": \"danish-pii-ner-v1.3.0\",\n                  \"name\": \"Dansk NER 1.3.0\",\n                  \"status\": \"stable\",\n                  \"default\": true,\n                  \"places\": [\n                    \"eu-de\",\n                    \"local\"\n                  ]\n                }\n              ]\n            },\n            {\n              \"detector\": \"llm\",\n              \"processing\": \"local\",\n              \"provider\": \"komplai\",\n              \"location\": \"Local infrastructure · Denmark\",\n              \"configured\": true,\n              \"available\": true,\n              \"reason\": null,\n              \"models\": [\n                {\n                  \"id\": \"qwen3.8-27b-q8\",\n                  \"name\": \"Qwen 3.8 · 27B (Q8)\",\n                  \"available\": true,\n                  \"reason\": null,\n                  \"default\": true\n                }\n              ]\n            },\n            {\n              \"detector\": \"llm\",\n              \"processing\": \"eu-cloud\",\n              \"provider\": \"komplai\",\n              \"location\": \"EU · France\",\n              \"configured\": true,\n              \"models\": [\n                {\n                  \"id\": \"mistral-small-3.2-24b-instruct-2506\",\n                  \"name\": \"Mistral Small 3.2 (24B)\",\n                  \"available\": true,\n                  \"reason\": null,\n                  \"default\": true\n                },\n                {\n                  \"id\": \"qwen3.5-397b-a17b\",\n                  \"name\": \"Qwen3.5 (397B-A17B)\",\n                  \"available\": false,\n                  \"reason\": \"not_validated\",\n                  \"default\": false\n                }\n              ]\n            }\n          ]\n        }\n      },\n      \"processing\": {\n        \"data_mode\": \"synthetic\",\n        \"agreement_reference\": null,\n        \"modes\": [\n          \"regex\",\n          \"ner\",\n          \"semantic\"\n        ],\n        \"text_contract\": {\n          \"supported_engines\": [\n            \"pipeline\"\n          ],\n          \"detector_choices\": [\n            \"regex\",\n            \"ner\",\n            \"llm\"\n          ],\n          \"explicit_detector_selection\": true,\n          \"true_ner_only\": true,\n          \"local_configured_detectors\": [\n            \"regex\",\n            \"ner\",\n            \"llm\"\n          ],\n          \"default_mode\": \"ner\",\n          \"default_processing\": \"local\",\n          \"policy\": \"all-detected\",\n          \"offset_encoding\": \"utf-16\",\n          \"synchronous_max_utf16_chars\": 750000,\n          \"job_max_utf16_chars\": 2000000,\n          \"file_input\": {\n            \"beta\": true,\n            \"operations\": [\n              \"POST /v1/redact/file\",\n              \"POST /v1/redact/file/jobs\"\n            ],\n            \"formats\": [\n              \"pdf\",\n              \"docx\"\n            ],\n            \"max_file_bytes\": 52428800,\n            \"max_pdf_pages\": 2000,\n            \"extraction_timeout_ms\": 120000,\n            \"ocr\": false,\n            \"pages_without_text\": \"refused unless allowPagesWithoutText\",\n            \"extraction\": {\n              \"step\": \"file-extraction\",\n              \"processing\": \"local\",\n              \"provider\": \"komplai\",\n              \"location\": \"EU · Germany\",\n              \"storage\": \"memory\",\n              \"ocr\": false,\n              \"retention\": \"The file and its extracted text are held in memory while the request runs and are not stored. POST /v1/redact/file/jobs stores the extracted text encrypted as a text job, with that job's retention.\"\n            }\n          },\n          \"result_max_bytes\": 33554432,\n          \"complexity_limits\": {\n            \"candidate_matches_per_utf16_char\": 2,\n            \"candidate_matches_base\": 1000,\n            \"matched_utf16_chars_per_utf16_char\": 16,\n            \"matched_utf16_chars_base\": 16000,\n            \"coreference_work_per_utf16_char\": 4,\n            \"coreference_work_base\": 4000,\n            \"organisation_rule_timeout_base_ms\": 5000,\n            \"organisation_rule_timeout_ns_per_utf16_char_per_rule\": 20,\n            \"organisation_rule_workers_per_process\": 2,\n            \"organisation_rule_queue\": false,\n            \"exceeded_error\": \"processing_complexity_exceeded\"\n          },\n          \"jobs_accepting_submissions\": true,\n          \"semantic_requires_configured_approved_runtime\": true,\n          \"eu_cloud_requires_explicit_selection_and_shared_ai_budget\": true\n        },\n        \"storage\": {\n          \"synchronous_input\": \"transient_processor_memory\",\n          \"synchronous_result\": \"response_only\",\n          \"job_input\": \"encrypted_while_queued_or_running\",\n          \"job_result\": \"encrypted_until_agreed_expiry_or_deletion\",\n          \"result_read_deletes\": false,\n          \"personal_job_storage_policy_required\": true,\n          \"backup_retention\": \"separate_infrastructure_agreement\",\n          \"usage_and_audit\": \"metadata_only_separate_retention\"\n        }\n      },\n      \"limits\": {\n        \"requests_per_minute\": 60\n      }\n    }\n  ],\n  \"hosting\": {\n    \"id\": \"komplai-local\",\n    \"environment\": \"prod\",\n    \"shared\": true,\n    \"api\": {\n      \"provider\": \"komplai\",\n      \"name\": \"Komplai EU cloud\",\n      \"region\": \"EU · Germany\"\n    },\n    \"ner\": {\n      \"provider\": \"komplai\",\n      \"name\": \"Komplai EU cloud\",\n      \"region\": \"EU · Germany\",\n      \"deployment\": \"eu-de\",\n      \"places\": [\n        {\n          \"id\": \"eu-de\",\n          \"location\": \"EU · Germany\",\n          \"available\": true,\n          \"reason\": null,\n          \"default\": true,\n          \"detect\": {\n            \"available\": true,\n            \"reason\": null\n          }\n        },\n        {\n          \"id\": \"local\",\n          \"location\": \"Local infrastructure · Denmark\",\n          \"available\": false,\n          \"reason\": \"unconfigured\",\n          \"default\": false,\n          \"detect\": {\n            \"available\": false,\n            \"reason\": \"unconfigured\"\n          }\n        }\n      ]\n    }\n  },\n  \"processing\": {\n    \"data_mode\": \"synthetic\"\n  },\n  \"limits\": {\n    \"requests_per_minute\": 60,\n    \"organisation_requests_per_minute\": 120,\n    \"shared_requests_per_minute\": 300\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Chat",
      "description": "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.",
      "item": [
        {
          "name": "List the permitted chat models",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/models",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "models"
              ],
              "query": [
                {
                  "key": "processing",
                  "value": "komplai-local",
                  "description": "Which processing to list. komplai-local: komplai's local infrastructure in Denmark, with no AI charge (local is accepted too). eu-cloud: komplai's EU cloud, when your organisation has EU processing approved for Chat; usage is metered at the provider's price and counts towards the organisation's monthly AI spending cap. connection:<id>: one of your organisation's own connections that its administrator has made available through the API, shown with its value on the hub's AI processing page; the organisation pays the provider itself, and the usage does not count towards the cap. Leave it out to list your organisation's Chat processing: local infrastructure, or EU cloud when that is what your organisation's Chat uses.",
                  "disabled": true
                }
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/chat#listChatModels"
          },
          "response": [
            {
              "name": "Local infrastructure",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/models",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "models"
                  ],
                  "query": [
                    {
                      "key": "processing",
                      "value": "komplai-local",
                      "description": "Which processing to list. komplai-local: komplai's local infrastructure in Denmark, with no AI charge (local is accepted too). eu-cloud: komplai's EU cloud, when your organisation has EU processing approved for Chat; usage is metered at the provider's price and counts towards the organisation's monthly AI spending cap. connection:<id>: one of your organisation's own connections that its administrator has made available through the API, shown with its value on the hub's AI processing page; the organisation pays the provider itself, and the usage does not count towards the cap. Leave it out to list your organisation's Chat processing: local infrastructure, or EU cloud when that is what your organisation's Chat uses.",
                      "disabled": true
                    }
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"object\": \"list\",\n  \"data\": [\n    {\n      \"id\": \"qwen3.8-27b\",\n      \"object\": \"model\",\n      \"owned_by\": \"komplai\",\n      \"name\": \"Qwen3.8 27B\",\n      \"context_tokens\": 32768,\n      \"max_output_tokens\": 4000,\n      \"reasoning_efforts\": [\n        \"none\",\n        \"low\",\n        \"medium\",\n        \"high\"\n      ]\n    },\n    {\n      \"id\": \"qwen3.8-27b-q8\",\n      \"object\": \"model\",\n      \"owned_by\": \"komplai\",\n      \"name\": \"Qwen3.8 27B (Q8)\",\n      \"context_tokens\": 32768,\n      \"max_output_tokens\": 4000,\n      \"reasoning_efforts\": [\n        \"none\",\n        \"low\",\n        \"medium\",\n        \"high\"\n      ]\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Create a chat completion",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Svar kort og på dansk.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Hvor lang tid har jeg til at klage over en afgørelse om boligstøtte?\"\n    }\n  ],\n  \"max_tokens\": 256\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/chat/completions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "chat",
                "completions"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/chat#createChatCompletion"
          },
          "response": [
            {
              "name": "Your default model and processing",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Svar kort og på dansk.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Hvor lang tid har jeg til at klage over en afgørelse om boligstøtte?\"\n    }\n  ],\n  \"max_tokens\": 256\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/chat/completions",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "chat",
                    "completions"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"chatcmpl-8c1d5e3a-2f7b-4a9c-b6e0-3d4f5a6b7c8d\",\n  \"object\": \"chat.completion\",\n  \"created\": 1792483200,\n  \"model\": \"qwen3.8-27b\",\n  \"choices\": [\n    {\n      \"index\": 0,\n      \"message\": {\n        \"role\": \"assistant\",\n        \"content\": \"Du har normalt 4 uger til at klage, regnet fra den dag du fik afgørelsen. Fristen står i afgørelsens klagevejledning.\"\n      },\n      \"finish_reason\": \"stop\"\n    }\n  ],\n  \"usage\": {\n    \"prompt_tokens\": 41,\n    \"completion_tokens\": 33\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Decide",
      "description": "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.",
      "item": [
        {
          "name": "Evaluate one text",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"state\": \"Hej. Jeg vil gerne have en kopi af min ansøgning om byggetilladelse fra marts. Venlig hilsen Mette Kjærgaard Holm\",\n  \"questions\": {\n    \"category\": {\n      \"type\": \"choice\",\n      \"instructions\": \"Hvad handler henvendelsen om?\",\n      \"criteria\": {\n        \"aktindsigt\": \"Borgeren beder om kopi af dokumenter eller aktindsigt\",\n        \"klage\": \"Borgeren klager over en afgørelse\",\n        \"andet\": \"Noget andet\"\n      }\n    },\n    \"urgency\": {\n      \"type\": \"score\",\n      \"instructions\": \"Hvor hurtigt skal henvendelsen besvares?\",\n      \"criteria\": [\n        \"Inden for den normale frist\",\n        \"Inden for en uge\",\n        \"Samme dag\"\n      ]\n    },\n    \"personal_data\": {\n      \"type\": \"noul\",\n      \"instructions\": \"Indeholder teksten personoplysninger?\",\n      \"criteria\": {\n        \"true\": \"Ja, for eksempel et navn eller et CPR-nummer\",\n        \"false\": \"Nej\"\n      }\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/decide",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "decide"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/decide#evaluateText"
          },
          "response": [
            {
              "name": "A letter and three questions",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"state\": \"Hej. Jeg vil gerne have en kopi af min ansøgning om byggetilladelse fra marts. Venlig hilsen Mette Kjærgaard Holm\",\n  \"questions\": {\n    \"category\": {\n      \"type\": \"choice\",\n      \"instructions\": \"Hvad handler henvendelsen om?\",\n      \"criteria\": {\n        \"aktindsigt\": \"Borgeren beder om kopi af dokumenter eller aktindsigt\",\n        \"klage\": \"Borgeren klager over en afgørelse\",\n        \"andet\": \"Noget andet\"\n      }\n    },\n    \"urgency\": {\n      \"type\": \"score\",\n      \"instructions\": \"Hvor hurtigt skal henvendelsen besvares?\",\n      \"criteria\": [\n        \"Inden for den normale frist\",\n        \"Inden for en uge\",\n        \"Samme dag\"\n      ]\n    },\n    \"personal_data\": {\n      \"type\": \"noul\",\n      \"instructions\": \"Indeholder teksten personoplysninger?\",\n      \"criteria\": {\n        \"true\": \"Ja, for eksempel et navn eller et CPR-nummer\",\n        \"false\": \"Nej\"\n      }\n    }\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/decide",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "decide"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"model\": \"convaiinnovations/laya/multilingual\",\n  \"answers\": {\n    \"category\": {\n      \"type\": \"choice\",\n      \"choice\": \"aktindsigt\",\n      \"probabilities\": {\n        \"aktindsigt\": 0.91,\n        \"klage\": 0.03,\n        \"andet\": 0.06\n      },\n      \"confidence\": 0.672,\n      \"action\": {\n        \"act_probability\": 0.88\n      }\n    },\n    \"urgency\": {\n      \"type\": \"score\",\n      \"score\": 0.32,\n      \"max\": 2,\n      \"probabilities\": [\n        0.72,\n        0.24,\n        0.04\n      ],\n      \"confidence\": 0.356\n    },\n    \"personal_data\": {\n      \"type\": \"noul\",\n      \"noul\": 0.97,\n      \"probabilities\": {\n        \"true\": 0.97,\n        \"false\": 0.03\n      },\n      \"confidence\": 0.806\n    }\n  },\n  \"usage\": {\n    \"input_tokens\": 118,\n    \"output_tokens\": 0\n  },\n  \"latency_ms\": 38\n}"
            }
          ]
        },
        {
          "name": "Evaluate several texts",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"states\": [\n    \"Hej. Jeg vil gerne have en kopi af min ansøgning om byggetilladelse fra marts. Venlig hilsen Mette Kjærgaard Holm\",\n    \"Jeg klager over afslaget på min ansøgning om boligstøtte. Afgørelsen er forkert, og jeg har brug for svar hurtigt.\"\n  ],\n  \"questions\": {\n    \"category\": {\n      \"type\": \"choice\",\n      \"instructions\": \"Hvad handler henvendelsen om?\",\n      \"criteria\": {\n        \"aktindsigt\": \"Borgeren beder om kopi af dokumenter eller aktindsigt\",\n        \"klage\": \"Borgeren klager over en afgørelse\",\n        \"andet\": \"Noget andet\"\n      }\n    },\n    \"urgency\": {\n      \"type\": \"score\",\n      \"instructions\": \"Hvor hurtigt skal henvendelsen besvares?\",\n      \"criteria\": [\n        \"Inden for den normale frist\",\n        \"Inden for en uge\",\n        \"Samme dag\"\n      ]\n    },\n    \"personal_data\": {\n      \"type\": \"noul\",\n      \"instructions\": \"Indeholder teksten personoplysninger?\",\n      \"criteria\": {\n        \"true\": \"Ja, for eksempel et navn eller et CPR-nummer\",\n        \"false\": \"Nej\"\n      }\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/decide/batch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "decide",
                "batch"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/decide#evaluateTexts"
          },
          "response": [
            {
              "name": "Two letters, the same three questions",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"states\": [\n    \"Hej. Jeg vil gerne have en kopi af min ansøgning om byggetilladelse fra marts. Venlig hilsen Mette Kjærgaard Holm\",\n    \"Jeg klager over afslaget på min ansøgning om boligstøtte. Afgørelsen er forkert, og jeg har brug for svar hurtigt.\"\n  ],\n  \"questions\": {\n    \"category\": {\n      \"type\": \"choice\",\n      \"instructions\": \"Hvad handler henvendelsen om?\",\n      \"criteria\": {\n        \"aktindsigt\": \"Borgeren beder om kopi af dokumenter eller aktindsigt\",\n        \"klage\": \"Borgeren klager over en afgørelse\",\n        \"andet\": \"Noget andet\"\n      }\n    },\n    \"urgency\": {\n      \"type\": \"score\",\n      \"instructions\": \"Hvor hurtigt skal henvendelsen besvares?\",\n      \"criteria\": [\n        \"Inden for den normale frist\",\n        \"Inden for en uge\",\n        \"Samme dag\"\n      ]\n    },\n    \"personal_data\": {\n      \"type\": \"noul\",\n      \"instructions\": \"Indeholder teksten personoplysninger?\",\n      \"criteria\": {\n        \"true\": \"Ja, for eksempel et navn eller et CPR-nummer\",\n        \"false\": \"Nej\"\n      }\n    }\n  }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{baseUrl}}/v1/decide/batch",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "decide",
                    "batch"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"model\": \"convaiinnovations/laya/multilingual\",\n  \"results\": [\n    {\n      \"answers\": {\n        \"category\": {\n          \"type\": \"choice\",\n          \"choice\": \"aktindsigt\",\n          \"probabilities\": {\n            \"aktindsigt\": 0.91,\n            \"klage\": 0.03,\n            \"andet\": 0.06\n          },\n          \"confidence\": 0.672,\n          \"action\": {\n            \"act_probability\": 0.88\n          }\n        },\n        \"urgency\": {\n          \"type\": \"score\",\n          \"score\": 0.32,\n          \"max\": 2,\n          \"probabilities\": [\n            0.72,\n            0.24,\n            0.04\n          ],\n          \"confidence\": 0.356\n        },\n        \"personal_data\": {\n          \"type\": \"noul\",\n          \"noul\": 0.97,\n          \"probabilities\": {\n            \"true\": 0.97,\n            \"false\": 0.03\n          },\n          \"confidence\": 0.806\n        }\n      },\n      \"usage\": {\n        \"input_tokens\": 118,\n        \"output_tokens\": 0\n      }\n    },\n    {\n      \"answers\": {\n        \"category\": {\n          \"type\": \"choice\",\n          \"choice\": \"klage\",\n          \"probabilities\": {\n            \"aktindsigt\": 0.08,\n            \"klage\": 0.86,\n            \"andet\": 0.06\n          },\n          \"confidence\": 0.544,\n          \"action\": {\n            \"act_probability\": 0.79\n          }\n        },\n        \"urgency\": {\n          \"type\": \"score\",\n          \"score\": 1.15,\n          \"max\": 2,\n          \"probabilities\": [\n            0.15,\n            0.55,\n            0.3\n          ],\n          \"confidence\": 0.113\n        },\n        \"personal_data\": {\n          \"type\": \"noul\",\n          \"noul\": 0.12,\n          \"probabilities\": {\n            \"true\": 0.12,\n            \"false\": 0.88\n          },\n          \"confidence\": 0.471\n        }\n      },\n      \"usage\": {\n        \"input_tokens\": 112,\n        \"output_tokens\": 0\n      }\n    }\n  ],\n  \"usage\": {\n    \"input_tokens\": 230,\n    \"output_tokens\": 0\n  },\n  \"latency_ms\": 52\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Coding",
      "description": "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.",
      "item": [
        {
          "name": "Read the coding account",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/coding/account",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "coding",
                "account"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/coding#readCodingAccount"
          },
          "response": [
            {
              "name": "An organisation on komplai's EU route",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/coding/account",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "coding",
                    "account"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"2e7c4b9a-5d1f-4a3e-8b6c-9f0d1e2a3b4c\",\n  \"name\": \"Eksempel Kommune\",\n  \"contract\": \"86fb88e41acf1ec181a16eaf5d7725059473b626b7d4289ee1b9c3b2aaed45b0\",\n  \"balance\": {\n    \"periodStart\": \"2026-10-01T00:00:00.000Z\",\n    \"periodEnd\": \"2026-11-01T00:00:00.000Z\",\n    \"packageDkk\": 2500,\n    \"budgetMicros\": 2500000000,\n    \"spentMicros\": 412350000,\n    \"reservedMicros\": 1200000,\n    \"availableMicros\": 2086450000,\n    \"active\": true,\n    \"organisationLimitMicros\": null,\n    \"limitMicros\": 2500000000\n  },\n  \"defaultModel\": \"mistral-small-3.2-24b-instruct-2506\",\n  \"data\": {\n    \"recipients\": \"komplai → EU-cloud\",\n    \"region\": \"komplais API: Hetzner, Tyskland. Model: komplais EU-cloud, EU · Frankrig.\",\n    \"training\": \"komplais EU-cloud bruger ikke input, prompts eller svar til at træne, genoptræne eller forbedre grundmodellerne.\",\n    \"retention\": \"Prompt- og svarindhold gemmes som udgangspunkt ikke. Midlertidig, projektisoleret cache af mellemresultater er automatisk og kan ikke fravælges. Ved særlige fejlfindings- eller sikkerhedshændelser, herunder undersøgelser af HTTP 500-fejl, kan hele forespørgslen gemmes i op til to uger. Aggregerede, anonymiserede forbrugsdata kan gemmes i op til seks måneder.\",\n    \"source\": \"https://developers.komplai.dk/data-processing\",\n    \"checkedAt\": \"2026-10-13\",\n    \"version\": \"eu-cloud-2026-10-13\",\n    \"mode\": \"synthetic\",\n    \"accounting\": \"Forbruget måles til udbyderens pris i DKK og tæller med i organisationens månedlige loft for AI-forbrug. Cachet input har sin egen pris, hvor udbyderen har en. Ræsonnement tæller som outputtokens. Når loftet eller din personlige grænse er nået, stopper kaldene. Der skiftes aldrig automatisk til en anden model.\",\n    \"platformStorage\": \"komplai gemmer forbrugs- og adgangsmetadata til regnskab og revision. Kode-API'et gemmer ikke prompts, svar eller værktøjsresultater. Se organisationens aftale for metadataenes slettefrist.\"\n  },\n  \"models\": [\n    {\n      \"id\": \"mistral-small-3.2-24b-instruct-2506\",\n      \"name\": \"Mistral Small 3.2 (24B)\",\n      \"object\": \"model\",\n      \"owned_by\": \"komplai\",\n      \"context_length\": 128000,\n      \"max_output_tokens\": 32768,\n      \"capabilities\": {\n        \"function_calling\": true\n      },\n      \"reasoning_efforts\": [],\n      \"pricing\": {\n        \"currency\": \"DKK\",\n        \"prompt\": \"0.000001119\",\n        \"completion\": \"0.000002611\",\n        \"input_cache_read\": \"0.000001119\"\n      }\n    },\n    {\n      \"id\": \"qwen3.5-397b-a17b\",\n      \"name\": \"Qwen3.5 (397B-A17B)\",\n      \"object\": \"model\",\n      \"owned_by\": \"komplai\",\n      \"context_length\": 250000,\n      \"max_output_tokens\": 16384,\n      \"capabilities\": {\n        \"function_calling\": true\n      },\n      \"reasoning_efforts\": [\n        \"none\",\n        \"low\",\n        \"medium\",\n        \"high\"\n      ],\n      \"pricing\": {\n        \"currency\": \"DKK\",\n        \"prompt\": \"0.000004476\",\n        \"completion\": \"0.000026856\",\n        \"input_cache_read\": \"0.000004476\"\n      }\n    }\n  ],\n  \"credential\": {\n    \"id\": \"a4b6c8d0-1e3f-4a5b-9c7d-2e4f6a8b0c1d\",\n    \"scopes\": [\n      \"coding:read\",\n      \"coding:complete\"\n    ],\n    \"expiresAt\": \"2026-11-19T08:00:00.000Z\"\n  }\n}"
            }
          ]
        },
        {
          "name": "List the coding models",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/coding/models",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "coding",
                "models"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/coding#listCodingModels"
          },
          "response": [
            {
              "name": "An organisation on komplai's EU route",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/v1/coding/models",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "v1",
                    "coding",
                    "models"
                  ]
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"object\": \"list\",\n  \"data\": [\n    {\n      \"id\": \"mistral-small-3.2-24b-instruct-2506\",\n      \"name\": \"Mistral Small 3.2 (24B)\",\n      \"object\": \"model\",\n      \"owned_by\": \"komplai\",\n      \"context_length\": 128000,\n      \"max_output_tokens\": 32768,\n      \"capabilities\": {\n        \"function_calling\": true\n      },\n      \"reasoning_efforts\": [],\n      \"pricing\": {\n        \"currency\": \"DKK\",\n        \"prompt\": \"0.000001119\",\n        \"completion\": \"0.000002611\",\n        \"input_cache_read\": \"0.000001119\"\n      }\n    },\n    {\n      \"id\": \"qwen3.5-397b-a17b\",\n      \"name\": \"Qwen3.5 (397B-A17B)\",\n      \"object\": \"model\",\n      \"owned_by\": \"komplai\",\n      \"context_length\": 250000,\n      \"max_output_tokens\": 16384,\n      \"capabilities\": {\n        \"function_calling\": true\n      },\n      \"reasoning_efforts\": [\n        \"none\",\n        \"low\",\n        \"medium\",\n        \"high\"\n      ],\n      \"pricing\": {\n        \"currency\": \"DKK\",\n        \"prompt\": \"0.000004476\",\n        \"completion\": \"0.000026856\",\n        \"input_cache_read\": \"0.000004476\"\n      }\n    }\n  ],\n  \"account\": {\n    \"id\": \"2e7c4b9a-5d1f-4a3e-8b6c-9f0d1e2a3b4c\",\n    \"name\": \"Eksempel Kommune\",\n    \"contract\": \"86fb88e41acf1ec181a16eaf5d7725059473b626b7d4289ee1b9c3b2aaed45b0\",\n    \"balance\": {\n      \"periodStart\": \"2026-10-01T00:00:00.000Z\",\n      \"periodEnd\": \"2026-11-01T00:00:00.000Z\",\n      \"packageDkk\": 2500,\n      \"budgetMicros\": 2500000000,\n      \"spentMicros\": 412350000,\n      \"reservedMicros\": 1200000,\n      \"availableMicros\": 2086450000,\n      \"active\": true,\n      \"organisationLimitMicros\": null,\n      \"limitMicros\": 2500000000\n    },\n    \"defaultModel\": \"mistral-small-3.2-24b-instruct-2506\",\n    \"data\": {\n      \"recipients\": \"komplai → EU-cloud\",\n      \"region\": \"komplais API: Hetzner, Tyskland. Model: komplais EU-cloud, EU · Frankrig.\",\n      \"training\": \"komplais EU-cloud bruger ikke input, prompts eller svar til at træne, genoptræne eller forbedre grundmodellerne.\",\n      \"retention\": \"Prompt- og svarindhold gemmes som udgangspunkt ikke. Midlertidig, projektisoleret cache af mellemresultater er automatisk og kan ikke fravælges. Ved særlige fejlfindings- eller sikkerhedshændelser, herunder undersøgelser af HTTP 500-fejl, kan hele forespørgslen gemmes i op til to uger. Aggregerede, anonymiserede forbrugsdata kan gemmes i op til seks måneder.\",\n      \"source\": \"https://developers.komplai.dk/data-processing\",\n      \"checkedAt\": \"2026-10-13\",\n      \"version\": \"eu-cloud-2026-10-13\",\n      \"mode\": \"synthetic\",\n      \"accounting\": \"Forbruget måles til udbyderens pris i DKK og tæller med i organisationens månedlige loft for AI-forbrug. Cachet input har sin egen pris, hvor udbyderen har en. Ræsonnement tæller som outputtokens. Når loftet eller din personlige grænse er nået, stopper kaldene. Der skiftes aldrig automatisk til en anden model.\",\n      \"platformStorage\": \"komplai gemmer forbrugs- og adgangsmetadata til regnskab og revision. Kode-API'et gemmer ikke prompts, svar eller værktøjsresultater. Se organisationens aftale for metadataenes slettefrist.\"\n    },\n    \"credential\": {\n      \"id\": \"a4b6c8d0-1e3f-4a5b-9c7d-2e4f6a8b0c1d\",\n      \"scopes\": [\n        \"coding:read\",\n        \"coding:complete\"\n      ],\n      \"expiresAt\": \"2026-11-19T08:00:00.000Z\"\n    }\n  }\n}"
            }
          ]
        },
        {
          "name": "Stream a coding completion",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "X-Komplai-Contract",
                "value": "86fb88e41acf1ec181a16eaf5d7725059473b626b7d4289ee1b9c3b2aaed45b0",
                "description": "contract from GET /v1/coding/account, which needs coding:read. When the terms changed since, the call answers 409 terms_changed: read the account again, show the new terms to the person, and send the new contract."
              },
              {
                "key": "X-Request-Id",
                "value": "{{$guid}}",
                "description": "A new UUID (version 4) for each new logical operation. Send the same id again only to retry an operation whose outcome you do not know: komplai then answers 409 duplicate_request instead of calling the provider a second time. Request-Id in the response repeats it."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"model\": \"mistral-small-3.2-24b-instruct-2506\",\n  \"stream\": true,\n  \"stream_options\": {\n    \"include_usage\": true\n  },\n  \"max_tokens\": 256,\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"You are a careful coding assistant.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"What does this expression evaluate to: 1 + 1?\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/coding/chat/completions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "coding",
                "chat",
                "completions"
              ]
            },
            "description": "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.\n\nhttps://developers.komplai.dk/reference/coding#createCodingChatCompletion"
          },
          "response": []
        }
      ]
    }
  ]
}
