API

AI Data Veil removes personal data from texts before you use them anywhere else: customer emails, tickets, documents. The detection runs on our own servers in Europe, no external AI service sees your text. You pay for tokens only.

Quick start

1. Sign in (Login / Register) and create an API key under Setup → API keys. 2. Send a text:

curl
curl https://api.aidataveil.eu/v1/anonymize \
  -H "Authorization: Bearer $VEIL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello, I am Anna Schmidt from Berlin, anna@example.com.", "lang": "en"}'

The answer contains the veiled text and the list of what was replaced:

response
{
  "text": "Hello, I am [PERSON_1] from [LOCATION_1], [EMAIL_1].",
  "replacements": [
    { "type": "PERSON",   "original": "Anna Schmidt",     "replacement": "[PERSON_1]" },
    { "type": "LOCATION", "original": "Berlin",           "replacement": "[LOCATION_1]" },
    { "type": "EMAIL",    "original": "anna@example.com", "replacement": "[EMAIL_1]" }
  ],
  "infos": {},
  "usage": { "chars": 55, "tokens": 18, "size_class": "S", "weight": 1, "billed_tokens": 18 },
  "meta": { "lang": "en", "mode": "technical", "total_ms": 240 }
}

Authentication

Base address: https://api.aidataveil.eu. Send your key in the header Authorization: Bearer veil_…. Keep keys secret. An account can have up to 5 keys, and you can delete a key at any time.

Request: POST /v1/anonymize

FieldTypeMeaning
textstring, requiredThe text to process.
langde en fr es itLanguage of the text (default de).
modetechnical | fictional[PERSON_1]-style placeholders (default) or invented names and values. Within one text the same term always gets the same replacement.
prefixstring, optionalPlaced before the technical names: with B1 you get [B1_PERSON_1] instead of [PERSON_1]. This keeps placeholders apart when you combine several texts or parts with variable content. Letters, digits, - and _, up to 16 characters. Not used with fictional.
rulesetstringName of one of your rule sets. Without it the key’s default rule set applies.
allowlistlist of stringsTerms that must never be replaced, for this request only.
options.mask_countriesbooleanAlso replace countries and regions (default off).
ruleslist of {label, pattern, mask}Up to five own regex fields (label up to 40, pattern up to 500 characters). Matches appear under infos.
asyncbooleantrue: always process in the background. false: an immediate answer is required (see below).

Response

FieldMeaning
textThe veiled text.
replacementsEvery replaced term: type, original, replacement. Use it to map your answer back.
infosValues of your own regex fields, as they stand in the veiled text.
usageSize of the text: chars, tokens, size_class and billed_tokens.
metaLanguage, mode and timing.

Short and long texts

Texts up to 1,000 tokens (about 3,500 characters, a long email) are answered immediately. Longer texts are accepted and processed in the background; you fetch the result later. Short requests are not delayed by this: they always go first.

longer text
HTTP/1.1 202 Accepted
{
  "request_id": "6549e33e1121a934ac0ece670c8b5017",
  "status": "queued",
  "tokens": 15900,
  "size_class": "XL",
  "result_url": "/v1/requests/6549e33e1121a934ac0ece670c8b5017",
  "poll_after_seconds": 100
}

Fetch the result with GET result_url. The status is queued, processing, done or failed. A finished result comes in blocks of up to 10,000 characters, each with a link to the next one:

block
GET /v1/requests/6549e33e1121a934ac0ece670c8b5017
{
  "request_id": "6549e33e1121a934ac0ece670c8b5017",
  "status": "done",
  "block": 1,
  "blocks": 7,
  "next_url": "/v1/requests/6549e33e1121a934ac0ece670c8b5017?block=2",
  "next_is_confirmation": false,
  "text": "…first 10,000 characters, veiled…",
  "replacements": [ … only those used in this block … ],
  "infos": {}, "usage": { … }, "meta": { … }
}
  • Placeholders are the same in all blocks: [PERSON_1] always means the same term. Each block lists the replacements it contains.
  • infos, usage and meta are in the first block.
  • Fetching block N+1 confirms that block N has arrived; block N is then released (410 block_released if you ask again). If a connection drops, simply request the same block again.
  • The next_url of the last block (next_is_confirmation: true) confirms receipt and deletes the request. Without confirmation the result is deleted 60 minutes after the last block was fetched, after 24 hours at the latest. DELETE /v1/requests/{id} deletes at once.
  • "async": true processes even short texts in the background (same price). "async": false demands an immediate answer; a text that is too long is rejected with 413 too_large_for_immediate.

A complete example in Python:

python
import os, time, requests

API = "https://api.aidataveil.eu"
H = {"Authorization": "Bearer " + os.environ["VEIL_KEY"]}

def anonymize(text, lang="de"):
    r = requests.post(API + "/v1/anonymize", headers=H, json={"text": text, "lang": lang})
    r.raise_for_status()
    if r.status_code == 200:                      # short text: the answer is here
        return r.json()["text"]
    url = API + r.json()["result_url"]            # 202: processed in the background
    while (block := requests.get(url, headers=H).json())["status"] in ("queued", "processing"):
        time.sleep(10)
    if block["status"] == "failed":
        raise RuntimeError(block["error"])
    parts = []
    while True:
        parts.append(block["text"])
        if block["next_is_confirmation"]:         # last block: confirm, the data is deleted
            requests.get(API + block["next_url"], headers=H)
            return "".join(parts)
        block = requests.get(API + block["next_url"], headers=H).json()

Rule sets

Under Setup → Rule sets you collect your own terms: words that are always replaced (project names, customer numbers) and words that are never replaced (your company, products). Assign a rule set to a key as its default, or name it per request with ruleset.

Besides terms, a rule set can contain fields: values of a fixed shape such as an order number. You create a field in Setup → Rule sets by pasting a sample text and clicking the value; we build the pattern for you, you give it a technical name such as Ordernumber. Every match is returned under infos.Ordernumber and, if you like, replaced in the text. Fields of the rule set and rules of the request work together.

Tokens, limits and billing

  • Only tokens are billed. A token is a small piece of a word, roughly 3 to 4 characters. Every answer shows the size in usage.
  • POST /v1/tokens with {"text": "…"} returns the token count and whether the text would be answered immediately. It does not process the text and costs nothing.
  • The monthly token limit belongs to the account and counts for all keys together; creating more keys does not raise it.
  • By default the API stops at the limit and answers with 429 quota_exceeded until the next month or until the plan is upgraded. Continuing and billing the extra tokens afterwards will come with the paid plans; we set it up for you.
  • Owners get an email when the forecast for the month turns yellow or red, if they switched this on in their profile.

Errors

StatusErrorMeaning
400text_required, unsupported_language, unsupported_mode, invalid_rule, unknown_rulesetThe request is incomplete or a value is not allowed.
401missing_api_key, invalid_api_keyThe key is missing, wrong or deleted.
404not_found, block_not_foundUnknown request, a request of another account, a confirmed or expired result, or a block that does not exist.
410block_releasedThe block was released after the next block had been fetched.
413too_large_for_immediateToo long for an immediate answer with "async": false.
429quota_exceededThe monthly limit is reached and the account is set to stop.
502anonymizer_unavailableTemporarily not available. Try again shortly.

Data handling

  • Texts are processed on our own servers in Europe, with models that run locally. No external AI service is involved and nothing is used for training.
  • Immediate requests are processed in memory. We store only counts (requests, tokens), never the text.
  • Background requests are the one exception: the text is stored encrypted until it has been processed and then deleted; the result stays encrypted until you have fetched it (released block by block), at most 24 hours.

← Back to the start page