ShinrAIHosted on STACKIT

Native PII API v2

Detect, protect, and restore personal data in text, tables, JSON, transcripts, images, audio, and documents with one contract.

One contract for every deployment

The same request body works on the hosted API, the sandbox and an installation in your own cluster. The offline edition serves the native API v1 until its image includes v2. The Azure, AWS and Google contracts stay available as compatibility APIs.

API 2.0.0 is stable

Changes within 2.x are additive: new fields, parameters, values and routes. A breaking change gets a new major version with a new path prefix. We announce it 12 months ahead, and the previous major version stays served during that period.

Ignore response fields and values that you do not know. API versions →

Features at a glance

Every feature has a one-line explanation and a minimal request. The sections below give the details.

export SHINRAI_API_KEY=shr_live_...

Inputs

Text Find personal data in a text. Every entity comes back with its type, position and confidence.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" -d '{"text": "Anna Weber, anna.weber@example.org, IBAN DE89 3704 0044 0532 0130 00"}'

Several texts Send up to 256 texts in one request. One request keeps one replacement map for all of them.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" -d '{"texts": ["Anna Weber called.", "Call Anna Weber back at +49 30 1234567."]}'

Text files Send a text file as it is and get the protected text back.

curl -s "https://api.getshinrai.com/v2/protect?preset=label" -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: text/plain" -H "Accept: text/plain" --data-binary @letter.txt

Tables Protect rows and columns. Every entity names its row and column.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"inputs": [{"kind": "table", "columns": [{"name": "name"}, {"name": "email"}], "rows": [["Anna Weber", "anna@example.org"]]}]}'

JSON Protect every string in a JSON value, for example a tool call. Every entity carries a JSON Pointer to its string.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"inputs": [{"kind": "json", "value": {"customer": {"name": "Anna Weber", "email": "anna@example.org"}}}]}'

Transcripts Send a transcript with word times. Every entity comes back with the times of its words.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"inputs": [{"kind": "transcript", "forms": {"display": "Call Anna Weber"}, "atoms_form": "display", "time_unit": "ms",
       "atoms": [{"text": "Call", "t0": 0, "t1": 300}, {"text": "Anna", "t0": 350, "t1": 600}, {"text": "Weber", "t0": 600, "t1": 950}]}]}'

Pages Send the text of a page with the word boxes from your own OCR or PDF text layer. Every entity comes back with its boxes.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"inputs": [{"kind": "page", "text": "Anna Weber", "box_unit": "px",
       "atoms": [{"start": 0, "end": 4, "page": 1, "box": [10, 20, 40, 12]}, {"start": 5, "end": 10, "page": 1, "box": [54, 20, 50, 12]}]}]}'

Images Find personal data in a screenshot or a scan. The OCR reads 14 languages, and every entity comes back with pixel boxes.

curl -s "https://api.getshinrai.com/v2/detect?language=de" -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: image/png" --data-binary @screenshot.png

Redacted images Get the redacted image back, with every entity filled black.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: image/png" -H "Accept: image/png" --data-binary @screenshot.png -o redacted.png

Audio Send a recording of up to 5 minutes and get it back with every personal detail bleeped.

curl -sS "https://api.getshinrai.com/v2/protect?language=de" -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: audio/mpeg" -H "Accept: audio/wav" --data-binary @call.mp3 -o call.redacted.wav

Audio transcripts Get the transcript of a recording and the times of every entity, without the audio.

curl -sS "https://api.getshinrai.com/v2/detect?language=de" -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: audio/mpeg" --data-binary @call.mp3

Detection

Language and model Set the language for the best results, and pin a model version when you need the same results over time.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber wohnt in Darmstadt.", "detection": {"language": "de", "model": "latest"}}'

Types Include or exclude types by their ShinrAI names or by the names of Google, AWS, Azure or Presidio.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber, anna@example.org, +49 30 1234567", "detection": {"types": {"include": ["EMAIL_ADDRESS", "PHONE_NUMBER"], "vocabulary": "google"}}}'

Confidence floors Set a confidence floor for all types, per type or per language.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber, Darmstadt", "detection": {"thresholds": {"default": 0.5, "per_type": {"CITY": 0.8}}}}'

Ignored values and your own values Never report values such as your company name, and find values of your own with a type.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Innovius support: case K-4711 for Anna Weber", "detection": {"exclude_values": {"values": ["Innovius"]},
       "custom": {"user_values": [{"value": "K-4711", "type": "CUSTOMER_ID"}]}}}'

Your own spans Protect the spans that your own detector found, alone or together with the ShinrAI detection.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"inputs": [{"kind": "text", "text": "Ticket for Anna Weber", "entities": [{"type": "PERSON", "span": {"start": 11, "end": 21}}]}],
       "detection": {"mode": "provided"}}'

Long texts Choose how the model reads a long text: automatic, sentence by sentence, or as one piece.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber called. She lives in Darmstadt.", "detection": {"spans": {"segment": "sentence"}}}'

Protection

Pseudonymisation Pseudonymise and keep the mapping, so you can restore an answer later.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber lives in Darmstadt.", "policy": {"preset": "pseudonymize"}, "output": {"include": ["entities", "mapping"]}}'

Labels and masks Replace every value with a numbered label such as [PERSON_1], or mask it with a character.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber, anna@example.org", "policy": {"preset": "label", "rules": [{"types": ["EMAIL"], "action": "mask", "mask": {"char": "*"}}]}}'

Partial and generalised values Keep the e-mail domain and the last four digits of a card, generalize names and places.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber aus Biberach, anna@example.org, Karte 4111 1111 1111 1111", "language": "de",
       "policy": {"default": {"action": "generalize"}, "rules": [{"types": ["EMAIL", "CREDIT_CARD"], "action": "partial"}]}}'

Rules per type Choose an action per type: replace with a fixed text, remove or keep.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber from Darmstadt, +49 30 1234567, anna@example.org", "policy": {"preset": "pseudonymize",
       "rules": [{"types": ["PHONE"], "action": "replace", "replace": {"value": "[phone]"}}, {"types": ["EMAIL"], "action": "remove"},
                 {"types": ["CITY"], "action": "keep"}]}}'

Outputs

Annotations Get years, amounts, legal references and bias terms as annotations. Protect never changes them.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "In 2019 Anna Weber paid 1,200 EUR.", "output": {"include": ["entities", "annotations"]}}'

Linkage risk Estimate how likely a text singles out a person. It is a heuristic, not a count.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "The 34-year-old head surgeon from Biberach joined in 2019.", "output": {"include": ["entities", "linkage_risk"]}}'

Offsets, texts and statistics Get positions in UTF-16 or UTF-8, the entity texts, statistics and a shorter entity list.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber, anna@example.org", "output": {"offset_unit": "utf16", "include_text": true, "include": ["entities", "stats"], "max_entities": {"per_input": 10}}}'

Restore and sessions

Restore Restore a text that contains the surrogates. Send the mapping.delta entries as original and replacement pairs.

curl -s https://api.getshinrai.com/v2/restore -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mapping": {"known": [{"original": "Anna Weber", "replacement": "Julia Brandt"}]}, "inputs": [{"id": "1", "text": "Julia Brandt replied."}]}'

Restore tables Compile a mapping into a restore table and restore in your own code, for example in a streamed model answer.

curl -s https://api.getshinrai.com/v2/restore-tables -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"mapping": {"known": [{"original": "Anna Weber", "replacement": "Julia Brandt"}]}}'

One replacement Get one replacement for a value and type that you choose.

curl -s https://api.getshinrai.com/v2/replacements -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"value": "Anna Weber", "type": "PERSON", "language": "de"}'

Sessions Keep one map across many requests with a session (24 hours from its creation by default), then export it.

SESSION=$(curl -s -X POST https://api.getshinrai.com/v2/sessions -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" -d '{"ttl_s": 3600}' | python3 -c 'import sys, json; print(json.load(sys.stdin)["id"])')
curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" -d '{"text": "Anna Weber called.", "mapping": {"session": "'$SESSION'"}}'
curl -s https://api.getshinrai.com/v2/sessions/$SESSION/mapping -H "Authorization: Bearer $SHINRAI_API_KEY"

Known pairs Give earlier pairs to a new request, so the same values keep the same surrogates.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber called again.", "mapping": {"known": [{"original": "Anna Weber", "replacement": "Julia Brandt"}]}}'

Jobs

Text batches Protect up to 20,000 texts from a JSONL file in the background, at half price.

UPLOAD=$(curl -s https://api.getshinrai.com/v2/uploads -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/x-ndjson" --data-binary @rows.jsonl | python3 -c 'import sys, json; print(json.load(sys.stdin)["id"])')
curl -s https://api.getshinrai.com/v2/jobs -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"kind": "text_batch", "inputs": [{"kind": "file", "source": {"upload": "'$UPLOAD'"}}]}'

Documents Get a PDF or Word file back as a redacted PDF, together with its protected text.

UPLOAD=$(curl -s https://api.getshinrai.com/v2/uploads -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/pdf" --data-binary @contract.pdf | python3 -c 'import sys, json; print(json.load(sys.stdin)["id"])')
curl -s https://api.getshinrai.com/v2/jobs -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"kind": "document", "inputs": [{"kind": "file", "source": {"upload": "'$UPLOAD'"}}]}'

Long recordings Bleep a recording of up to 60 minutes in the background.

UPLOAD=$(curl -s https://api.getshinrai.com/v2/uploads -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: audio/mpeg" --data-binary @meeting.mp3 | python3 -c 'import sys, json; print(json.load(sys.stdin)["id"])')
curl -s https://api.getshinrai.com/v2/jobs -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Content-Type: application/json" \
  -d '{"kind": "audio", "inputs": [{"kind": "audio", "source": {"upload": "'$UPLOAD'"}, "language": "de"}]}'

Tiers, retries and account

Tiers Choose realtime for small inputs with low latency, or batch for half price.

curl -s "https://api.getshinrai.com/v2/detect?tier=realtime" -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: text/plain" --data-binary 'Call Anna Weber at +49 30 1234567.'

Safe retries Retry with the same Idempotency-Key. The service charges the request once.

curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" -H "Idempotency-Key: order-4711" \
  -H "Content-Type: application/json" -d '{"text": "Anna Weber, order 4711"}'

Capabilities What this deployment serves: models, languages, input kinds, tiers your plan allows and limits.

curl -s https://api.getshinrai.com/v2/capabilities -H "Authorization: Bearer $SHINRAI_API_KEY"

Types list List every type with its description and the names of Google, AWS, Azure and Presidio.

curl -s https://api.getshinrai.com/v2/types -H "Authorization: Bearer $SHINRAI_API_KEY"

Usage Your balance and the last 30 days.

curl -s https://api.getshinrai.com/v2/usage -H "Authorization: Bearer $SHINRAI_API_KEY"

OpenAPI Get the full OpenAPI 3.1 document of the v2 API.

curl -s https://api.getshinrai.com/v2/openapi.json -o shinrai-pii-api-v2.json

Start with the capabilities

Read the capabilities once at start. They list the models, languages, input kinds, tiers and limits of your deployment.

curl -s https://api.getshinrai.com/v2/capabilities -H "Authorization: Bearer $SHINRAI_API_KEY"

Send any input kind

A plain text needs no wrapper. For a text file, an image or a recording, send the file itself as the request body and put options in the query string.

InputHow to send itNotes
Text{"text": "..."} or text/plainSend JSON or the raw file
Tables"kind": "table"Columns and rows
JSON"kind": "json"All strings of the value
Transcripts"kind": "transcript"Forms and word atoms with times
Pages"kind": "page"Text plus word boxes from your own OCR or PDF text layer
Imagesimage/png, image/jpeg, image/bmp, image/tiff, image/webpUp to 6 MiB: OCR, pixel boxes per entity and the redacted image
Audioaudio/wav, audio/mpeg, audio/ogg, audio/flac, audio/mp4, audio/aac, audio/webmUp to 5 minutes and 12 MiB: time intervals per entity and the bleeped recording
DocumentsPOST /v2/jobsPDF and DOCX through a job: the redacted PDF and the protected text

Detect, protect and restore text

Most integrations start with text. Detect finds the personal data. Protect returns the text with every entity replaced. Restore puts the original values back into a later text, for example a model answer.

curl -s https://api.getshinrai.com/v2/detect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" -d '{"text": "Anna Weber, anna.weber@example.org, IBAN DE89 3704 0044 0532 0130 00"}'
curl -s https://api.getshinrai.com/v2/protect -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Anna Weber lives in Darmstadt.", "policy": {"preset": "pseudonymize"}, "output": {"include": ["entities", "mapping"]}}'
curl -s https://api.getshinrai.com/v2/restore -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mapping": {"known": [{"original": "Anna Weber", "replacement": "Julia Brandt"}]}, "inputs": [{"id": "1", "text": "Julia Brandt replied."}]}'

What is semantic encryption?

ShinrAI calls its context-preserving, reversible replacement semantic encryption. It is a form of pseudonymisation: sensitive values become useful alternatives, and your application can restore originals using its mapping.

Protect the mapping as sensitive data and keep it out of AI prompts. Realistic replacements do not mean every word is cryptographically encrypted or that the text is automatically anonymous.

Languages and data categories · Model changelog · Compare ShinrAI

Choose how to protect

A preset sets one policy for all types. Rules set an action per type.

SettingValues
Presetpseudonymize, mask, label, strict
Action per typesurrogate, label, mask, partial, generalize, replace, remove, keep
  • Pseudonymize writes realistic surrogates that you can restore.
  • Partial keeps what does not identify: the e-mail domain, the phone country prefix, the last four digits of a card or account, the year of a date.
  • Generalize writes a phrase for the kind of name, place or organisation, in the input language.
  • Partial and generalize are one-way.

Control detection

  • Set a confidence floor for all types, per type or per language.
  • Include or exclude types by their canonical names or by the names of Google, AWS, Azure or Presidio.
  • Exclude values that must never be reported, such as your company name, or add values of your own.
  • Send the spans of your own detector, alone or together with the ShinrAI detection.
  • Ask for annotations: years, amounts, legal references and bias terms. Protect never changes them.
  • Ask for the linkage risk: an estimate of how likely an input singles out a person. It is a heuristic, not a count.

Restore and keep one map

Ask for the mapping when you must restore an answer later. The mapping contains the original values. Store it as sensitive application data and keep it out of model prompts.

  • Within one request, a value keeps one surrogate.
  • The next request draws new surrogates, so repeated requests cannot map surrogates back to originals.
  • For the same surrogates across requests, use a session or send the earlier pairs as known mappings.
  • Account-wide consistency is available as an option. It is weaker: anyone with the key can then build a table of originals by repetition.
  • Other customers always get different surrogates.
  • Restore tables let you restore in your own code, for example in a streamed model answer.

A session holds one map on the server. It lives at most 24 hours from its creation, or up to 7 days with the extended-sessions setting of your account. The map is stored encrypted, and only your key can read it.

Protect screenshots and scans

  • OCR reads every language the model serves. Send the language for Arabic, Hebrew, Japanese and Korean images.
  • Every entity comes back with pixel boxes, one per text line or one per word.
  • Protect returns the image with the regions filled.
  • The realtime tier takes one image per request, up to 4.2 megapixels and 3 MiB.

Protect audio

  • Send a recording of up to 5 minutes and 12 MiB as the body of a detect or protect request on the standard tier.
  • Protect returns the recording as WAV with every personal detail bleeped. Ask for silence instead of the tone, and widen the muted intervals if you need to.
  • Ask for JSON to get the protected transcript and the times of every entity instead of audio.
  • Send the language: the speech recognition and the detection then read the right language.
  • Audio costs the records of its transcript, at least 10 records per started minute.
  • One audio request per account runs at a time. Recordings up to 60 minutes run as a job.
  • A word that the speech recognition mishears and the model then misses stays audible. Listen to sensitive recordings before you share them.

Run large batches, documents and recordings as jobs

Use a job when the work is too large for one request: many texts, a PDF or Word file, or a long recording. A job runs in the background at the batch weight and keeps its results for 24 hours.

  1. Upload a JSONL file with one input per line, a PDF or DOCX file, or a recording.
  2. Start the job with the upload ID.
  3. Poll the job and download the artifacts.
{"custom_id": "row-1", "text": "Anna Schmidt, anna@example.com"}
{"custom_id": "row-2", "text": "Call +49 30 1234567", "language": "de"}
{"custom_id": "row-3", "input": {"kind": "table", "columns": [{"name": "email"}], "rows": [["max@example.org"]]}}
curl -s https://api.getshinrai.com/v2/uploads \
  -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/x-ndjson" \
  --data-binary @rows.jsonl
curl -s https://api.getshinrai.com/v2/jobs \
  -H "Authorization: Bearer $SHINRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: rows-2026-09-28" \
  -d '{"kind": "text_batch",
       "inputs": [{"kind": "file", "source": {"upload": "up_..."}}],
       "output": {"artifacts": ["protected", "entities"]}}'
curl -s https://api.getshinrai.com/v2/jobs/$JOB -H "Authorization: Bearer $SHINRAI_API_KEY"

An upload is deleted when the last job that reads it ends. Add ?keep=true to the upload when several jobs read it: it then lives 24 hours, extended by every job that reads it. Deleting a job also deletes a kept upload as soon as no other job reads it. Delete a job to remove its results before the 24 hours end.

A document job returns the redacted PDF, the protected text and the entities. An audio job returns the redacted WAV, the protected transcript and the entities with their times.

Document jobs guide →

Limits

The hosted API applies these limits. The capabilities return the values of your deployment.

LimitStandardRealtimeBatchJobs
Inputs per request64420020,000 lines
Characters per input200.0004.000200.000200.000
Request body12 MiB12 MiB12 MiB50 MB upload
Image6 MiB4.2 megapixels, 3 MiB6 MiBNot served
Audio5 minutes, 12 MiBNot servedNot served60 minutes, 50 MB
DocumentNot servedNot servedNot servedPDF or DOCX, 10 MB

A request above a limit answers 413 and is not charged. Your plan sets the tiers you can use and the number of requests per minute.

Tiers, retries and usage

TierWeightBest for
Standard×1Default
Batch×0.5Half price, lowest priority
Realtime×1.6Small inputs and low latency, plans from Team
  • Send an Idempotency-Key header to retry safely. A repeat with the same key and body is charged once.
  • Restore, sessions, capabilities, types and usage are free.
  • Failed calls are not charged.

Errors

Every error has a code, a message, the request ID and whether a retry can succeed. Validation errors point to the field with a JSON Pointer and never repeat your data.

  • Retry only when the error says that a retry can succeed, and wait for the time in the Retry-After header.
  • A limit error names the limit. For audio it points to the job route.
  • An option that your deployment does not serve yet answers 501.

Reference