Skip to content

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.

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.

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.

Submit a batch and receive the final result in the same response.

Example request:

Terminal window
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:

StatusMeaning
200Final result (same shape as GET /mask)
400Invalid request (missing data, bad params)
403No valid license (AM-5001)
504Processing 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.

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:

Terminal window
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.

Poll for an async result. Pass the IDs from the 202 body as Agent Mask headers:

Terminal window
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"
StatusMeaning
200Final result
202Still processing
404Unknown batch (AM-1005)
500Processing 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"}
]
}
]
]
}
{
"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.

Per-row params (all optional):

ParameterDefaultPurpose
detection_modeaccuratefast uses lightweight detection; accurate uses the full detection pipeline
threshold0.5Minimum detection confidence
entitiesallRestrict to specific entity types
entity_configPer-entity operator config and custom entities
allow_listValues/patterns to never mask
languageenInput language (multi-language image)
entity_collapseIdentity-aware grouping aggressiveness (0–1)
compress_resultssync: false, async: truePer-row result compression
include_entity_ledgertrueInclude placeholder→original mapping
include_analyzer_resultstrueInclude detection metadata
include_redacted_documentfalseReturn redacted document bytes for visual formats

For shared request options and supported features, use:

  • Operatorstype_numbered, constant, mask, hash, faker, encrypt, keep, entity_type, and date_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 params fields in HTTP requests

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.

Returns 200 with a status string once the service is up.

Returns a production-safe configuration status:

{"status": "configured"}

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.