kriyam.aistudioAPI reference
PII Detection & Masking

Scan a file

POSThttps://studioapi.kriyam.ai/models/mask/pii/v1

Content type multipart/form-data

Scans a spreadsheet or delimited file for personal data and tells you which rows hold what. The call is synchronous: you get back the finished run, already charged, with a downloadable report under output_urls.report.

Request

curl -X POST "https://studioapi.kriyam.ai/models/mask/pii/v1" \
  -H "X-API-Key: $KRIYAM_API_KEY" \
  -F "file=@customers.csv" \
  --form-string 'types=["phone", "aadhaar"]' \
  -F "mask_style=box"

Response

{9 items
"id":"f47b1d90-8c35-4a2e-b6d1-5e0a93..."
"tool_url_path":"pii-detection"
"status":"completed"
"result":{1 item
"scan":{5 items
"rows_flagged":12
"type_counts":{3 items
"EMAIL":9
"PHONE":5
"PAN":2
}
"findings":[2 items
0:{2 items
"row":4
"types":[1 item
0:"EMAIL"
]
}
1:{2 items
"row":17
"types":[2 items
0:"PHONE"
1:"PAN"
]
}
]
"truncated":false
"unparsed_lines":0
}
}
"error":null
"credits":2
"output_urls":{1 item
"report":"https://storage.example/...sig..."
}
"output_filenames":{1 item
"report":"scan.log"
}
"created_at":"2026-09-18T09:12:04.182741Z"
}

Authentication

Send your key in the X-API-Key header. See Authentication.

Request

Body

NameTypeRequiredDescription
filefileRequired

The file to scan.

typesarrayOptional

PDF or image only. Repeat for each kind of data to find and mask (e.g. person_name, phone, aadhaar, diagnosis); every kind when omitted. A kind left out is neither reported nor masked.

mask_stylestringOptional

PDF or image only. box (default) blacks out each value; label fills it with a tint naming what was removed. Either way the value is deleted from the file, not covered.

Default box

boxlabel

Response

200 OK

Returns the run envelope. The fields below are what this tool puts inside it.

FieldTypeDescription
result.scan.rows_flaggedinteger

How many rows contain personal data, across the whole file — not capped.

result.scan.type_countsobject

How many rows each kind was found in, keyed by type. Also whole-file.

result.scan.findings[]object[]

The flagged rows, at most 500 of them, each {row, types}. row is 1-based. No values are returned — locating the data is the point, and returning it would recreate the exposure you're scanning for.

result.scan.truncatedboolean

True when there were more than 500 flagged rows and findings holds only the first of them. The counts above are still complete.

result.scan.unparsed_linesinteger

Lines of the underlying report that couldn't be interpreted. Non-zero means the scan is incomplete — surface it, or a low finding count reads as a clean file.

output_urls.reportstring

The full scan log, always kept whatever the parse recovered. Presigned and short-lived.

Errors

StatusCodeWhen
400—

The file is empty or can't be read.

Every keyed call can also get401402403404429— see Errors.