HTTP API
The service listens on port 8000 (configurable via PORT).
This page covers the self-hosted HTTP API: authentication, synchronous and asynchronous masking, polling, response shape, diagnostics, and common errors. Operators, entity configuration, supported entities, language handling, and document parameters use the shared Agent Mask references.
Authentication
Section titled “Authentication”When the API_KEY environment variable is set, the mask endpoints
(POST /mask, POST /mask/sync, GET /mask) require:
Authorization: Bearer <API_KEY>Missing or wrong credentials return 401 with code AM-5002 and a
WWW-Authenticate: Bearer header. The diagnostics endpoints (/health,
/config, /license) do not require API key authentication, so probes and
license troubleshooting work without credentials. When API_KEY is unset
(the default), no authentication is required anywhere.
Mask processing additionally requires a valid license
key; without one, POST /mask and
POST /mask/sync return 403 with code AM-5001.
Async polling headers
Section titled “Async polling headers”Self-hosted clients should use the Agent Mask polling headers:
x-agent-mask-query-id: <query_id>x-agent-mask-batch-id: <batch_id>The Snowflake external function names are still accepted as backwards-compatible aliases:
sf-external-function-current-query-id: <query_id>sf-external-function-query-batch-id: <batch_id>Mixed pairs are valid, such as x-agent-mask-query-id with
sf-external-function-query-batch-id. If both names for the same ID are sent,
their values must match; conflicting values return 400 with AM-2002.
POST /mask/sync
Section titled “POST /mask/sync”Submit a batch and receive the final result in the same response.
Example request:
curl -s -X POST http://localhost:8000/mask/sync \ -H "Content-Type: application/json" \ -d '{ "data": [ [ 0, "Patient John Smith, DOB 01/02/1980, called from 555-867-5309.", {} ] ] }'Example 200 response:
{ "data": [ [ 0, { "columns": [ { "index": 0, "deidentified_text": "Patient [PERSON_1], DOB [DATE_TIME_1], called from [PHONE_NUMBER_1].", "analyzer_results": [] } ], "entity_ledger": [ {"placeholder": "[PERSON_1]", "text": "John Smith"} ] } ] ]}Each row is [row_index, text, params]. text may be a string (one field), an
array of strings (related fields), or a base64-encoded zlib-compressed
document.
Responses:
| Status | Meaning |
|---|---|
200 | Final result (same shape as GET /mask) |
400 | Invalid request (missing data, bad params) |
403 | No valid license (AM-5001) |
504 | Processing exceeded SYNC_TIMEOUT_SECONDS (AM-1007) — the work continues in the background; poll GET /mask with the returned query_id/batch_id |
Sync responses default to uncompressed result rows. Pass
"compress_results": true per row to receive base64-compressed rows
instead.
Sync responses use the same data payload as GET /mask. Async polling
responses may also include timing metadata for operational troubleshooting, so
clients should treat unknown top-level fields as optional.
POST /mask
Section titled “POST /mask”Submit a batch asynchronously. If you omit polling headers, the service
generates IDs and returns them in the 202 body.
This example sets compress_results: false so the final response is readable:
curl -s -X POST http://localhost:8000/mask \ -H "Content-Type: application/json" \ -d '{ "data": [ [ 0, "Patient John Smith, DOB 01/02/1980, called from 555-867-5309.", {"compress_results": false} ] ] }'Example 202 response:
{ "status": "processing", "query_id": "018f4d6a-8f6e-7b1a-a6d7-7ef8b9d7a001", "batch_id": "7b89352a-3a7f-4729-950b-c6f63d7fbf5c"}If you provide x-agent-mask-query-id and x-agent-mask-batch-id on the POST,
the service uses those values instead of generating IDs.
GET /mask
Section titled “GET /mask”Poll for an async result. Pass the IDs from the 202 body as Agent Mask
headers:
curl -s http://localhost:8000/mask \ -H "x-agent-mask-query-id: 018f4d6a-8f6e-7b1a-a6d7-7ef8b9d7a001" \ -H "x-agent-mask-batch-id: 7b89352a-3a7f-4729-950b-c6f63d7fbf5c"| Status | Meaning |
|---|---|
200 | Final result |
202 | Still processing |
404 | Unknown batch (AM-1005) |
500 | Processing failed — body carries the error details |
While the batch is still running, GET /mask returns 202:
{"status": "processing"}When complete, GET /mask returns 200 with the final result:
{ "data": [ [ 0, { "columns": [ { "index": 0, "deidentified_text": "Patient [PERSON_1], DOB [DATE_TIME_1], called from [PHONE_NUMBER_1].", "analyzer_results": [] } ], "entity_ledger": [ {"placeholder": "[PERSON_1]", "text": "John Smith"} ] } ] ]}Result shape
Section titled “Result shape”{ "data": [ [0, { "columns": [ { "index": 0, "deidentified_text": "[PERSON_1] called [PHONE_NUMBER_1]", "analyzer_results": [ … ] } ], "entity_ledger": [ { "placeholder": "[REDACTED_PERSON_1]", "text": "John Smith", … } ] }] ]}The entity_ledger maps placeholders to original values; analyzer_results
carries detection metadata. Both can be omitted per row with
include_entity_ledger: false / include_analyzer_results: false.
Request parameters
Section titled “Request parameters”Per-row params (all optional):
| Parameter | Default | Purpose |
|---|---|---|
detection_mode | accurate | fast uses lightweight detection; accurate uses the full detection pipeline |
threshold | 0.5 | Minimum detection confidence |
entities | all | Restrict to specific entity types |
entity_config | — | Per-entity operator config and custom entities |
allow_list | — | Values/patterns to never mask |
language | en | Input language (multi-language image) |
entity_collapse | — | Identity-aware grouping aggressiveness (0–1) |
compress_results | sync: false, async: true | Per-row result compression |
include_entity_ledger | true | Include placeholder→original mapping |
include_analyzer_results | true | Include detection metadata |
include_redacted_document | false | Return redacted document bytes for visual formats |
For shared request options and supported features, use:
- Operators —
type_numbered,constant,mask,hash,faker,encrypt,keep,entity_type, anddate_shift - Entities — built-in and custom entity detection
- Documents — PDF, DOCX, images, DICOM, RTF, and ZIP archives
- Request Parameters — the full parameter reference; object fields map to JSON
paramsfields in HTTP requests
GET /license
Section titled “GET /license”License diagnostics. This endpoint does not require API key authentication:
{"state": "valid", "tier": "trial", "org": "example.com", "expires_at": "2026-06-19T15:47:28+00:00"}state is one of valid, missing, invalid, expired.
GET /health
Section titled “GET /health”Returns 200 with a status string once the service is up.
GET /config
Section titled “GET /config”Returns a production-safe configuration status:
{"status": "configured"}Error format
Section titled “Error format”Errors return a JSON object with an error message (prefixed with an
AM-XXXX code), plus query_id/batch_id when known. Responses avoid exposing
implementation details; use container logs for detailed troubleshooting.