{"openapi":"3.1.0","info":{"title":"IncognitoShare API","version":"1.0.0","summary":"Find and remove personal information in files.","description":"Scan images, PDFs, Word and Excel files for personal information, and get a cleaned\ncopy back.\n\n**Files are never stored.** Uploaded bytes are held in memory for the duration of one\nrequest and are not written to disk, to a database, or to a log. Previews in findings\nare always masked.\n\nUploads are limited to 20971520 bytes and 30 seconds. Rate limits are 30 requests per minute with an API key\nand 10 per minute per IP without one.","license":{"name":"UNLICENSED","identifier":"UNLICENSED"},"contact":{"name":"IncognitoShare","url":"https://incognitoshare.com"}},"servers":[{"url":"https://incognitoshare.com","description":"Production"},{"url":"http://localhost:3000","description":"Local development"}],"tags":[{"name":"Scanning","description":"Check and clean files."},{"name":"Rules","description":"The detector configuration."},{"name":"Telemetry","description":"Anonymous usage events."},{"name":"Account","description":"Keys and signups."}],"security":[{"apiKey":[]}],"paths":{"/api/v1/health":{"get":{"tags":["Rules"],"summary":"Liveness check.","security":[],"responses":{"200":{"description":"The service is up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/api/v1/rules":{"get":{"tags":["Rules"],"summary":"The current rule pack.","description":"Cacheable. Send `If-None-Match` with the previous `ETag` to get a 304. The pack is immutable once published, so its version is a sound ETag.","security":[],"parameters":[{"name":"If-None-Match","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The current pack.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RulePack"}}},"headers":{"ETag":{"schema":{"type":"string"},"description":"The pack version, quoted."},"Cache-Control":{"schema":{"type":"string"}}}},"304":{"description":"Your cached copy is current."}}}},"/api/v1/scan":{"post":{"tags":["Scanning"],"summary":"Check a file for personal information.","description":"The file is read into memory, scanned, and discarded. Nothing is stored. Finding previews are masked before they leave the process.","parameters":[{"name":"ocr","in":"query","required":false,"description":"Read text out of images. Off by default because it is slow. Not available on the hosted deployment, which does not bundle a recognition model.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The file to check."}},"required":["file"]}}}},"responses":{"200":{"description":"The scan result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResult"}}}},"401":{"description":"No API key, or the key is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The file is over the size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"The body was not multipart/form-data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"OCR was requested but is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The file took too long to process.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sanitize":{"post":{"tags":["Scanning"],"summary":"Remove hidden data from a file.","description":"Returns the cleaned bytes. `X-Removed` and `X-Remaining` carry base64url-encoded JSON arrays of plain-language labels — the kind of thing removed, never its value. Visible document content is not rewritten.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"The cleaned file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-Removed":{"schema":{"type":"string"},"description":"base64url JSON array of what was removed."},"X-Remaining":{"schema":{"type":"string"},"description":"base64url JSON array of what was left for you to decide about."},"Content-Disposition":{"schema":{"type":"string"}}}},"401":{"description":"No API key, or the key is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The file is over the size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The file took too long to process.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/scan-events":{"post":{"tags":["Telemetry"],"summary":"Record an anonymous usage event.","description":"Categories and counts only. Any field that looks like file content — a filename, a hash, a preview — is rejected with a 400.","security":[{"apiKey":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanEvent"}}}},"responses":{"202":{"description":"Accepted."},"400":{"description":"Invalid, or an attempt to send content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/waitlist":{"post":{"tags":["Account"],"summary":"Join the launch waitlist.","description":"Idempotent: signing up twice returns `already_present`, not an error.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistRequest"}}}},"responses":{"200":{"description":"Added, or already there.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistResponse"}}}},"400":{"description":"The email address is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me":{"get":{"tags":["Account"],"summary":"The caller, their plan, and what is left today.","description":"Answers for a session cookie or an API key. Reports counts only — never what was scanned.","security":[{"apiKey":[]},{"session":[]}],"responses":{"200":{"description":"The account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"Not signed in and no API key supplied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/usage/consume":{"post":{"tags":["Account"],"summary":"Charge one check against today's allowance.","description":"Called by the website before it checks a file. The body carries a size and a file kind — the file itself is read in a web worker and never leaves the device, so there is nothing else to send. This is accounting, not access control.","security":[{"apiKey":[]},{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsumeUsageRequest"}}}},"responses":{"200":{"description":"Counted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsumeUsageResponse"}}}},"400":{"description":"Invalid body, or a field that is not allowed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in and no API key supplied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The file is larger than the plan allows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The day's allowance is spent, or the rate limit was hit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/plan":{"post":{"tags":["Account"],"summary":"Set a user's plan. Temporary.","description":"Behind `ADMIN_TOKEN`, and only exists because there is no payment provider yet. It goes away when billing arrives.","security":[{"adminToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPlanRequest"}}}},"responses":{"200":{"description":"Changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPlanResponse"}}}},"400":{"description":"Invalid body, or an unknown plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing or wrong admin token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No account with that address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/api-keys":{"get":{"tags":["Account"],"summary":"List your own keys. Never returns a key itself.","security":[{"session":[]}],"responses":{"200":{"description":"The keys.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeySummary"}}}}},"401":{"description":"Not signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Account"],"summary":"Create a key for the signed-in account.","description":"Needs a browser session: an API key cannot mint API keys, because a key that can issue keys cannot meaningfully be revoked. The full key is returned exactly once — only a SHA-256 of it is stored.","security":[{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Invalid body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"An API key was used instead of a session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/api-keys/{id}":{"delete":{"tags":["Account"],"summary":"Revoke one of your own keys.","security":[{"session":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeApiKeyResponse"}}}},"401":{"description":"Not signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No active key with that id — it does not exist, is already revoked, or belongs to someone else. The three are not distinguished on purpose.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"A key from POST /api/v1/api-keys. Looks like `isk_live_…`."},"adminToken":{"type":"apiKey","in":"header","name":"x-admin-token","description":"The shared `ADMIN_TOKEN`. Development only."},"session":{"type":"apiKey","in":"cookie","name":"authjs.session-token","description":"The browser session cookie, set by signing in at /signin. Not something a program holds — use an API key instead."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["bad_request","invalid_body","unauthorized","forbidden","not_found","method_not_allowed","payload_too_large","unsupported_media_type","rate_limited","quota_exceeded","timeout","unprocessable","internal_error","service_unavailable"],"description":"Stable machine-readable code."},"message":{"type":"string","description":"Human-readable explanation. May change."},"fields":{"type":"array","items":{"type":"string"}}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"description":"Every error from this API has this shape."},"Health":{"type":"object","properties":{"status":{"type":"string","const":"ok"},"version":{"type":"string","description":"API version."},"rulesVersion":{"description":"Current rule pack, if the database is reachable.","type":["string","null"]}},"required":["status","version","rulesVersion"],"additionalProperties":false,"description":"Liveness. Deliberately says nothing about the host or the build."},"Finding":{"type":"object","properties":{"type":{"type":"string","enum":["email","phone","credit_card","iban","us_ssn","passport_mrz","ip_address","secret_token","date_of_birth","street_address","signature","licence_plate","person_name","gps_location","device_info","software_info","timestamp","document_author","comment","tracked_change","hidden_content","embedded_file","fake_redaction","barcode","boarding_pass","sensitive_column","face"]},"severity":{"type":"string","enum":["low","medium","high"]},"message":{"type":"string","description":"User-facing message from the rule pack."},"location":{"type":"object","properties":{"kind":{"type":"string","enum":["metadata-field","text-range","page","sheet-cell","bounding-box"]},"field":{"type":"string"},"page":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"sheet":{"type":"string"},"cell":{"type":"string"},"start":{"type":"integer","minimum":0,"maximum":9007199254740991},"end":{"type":"integer","minimum":0,"maximum":9007199254740991},"x":{"type":"number"},"y":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"}},"required":["kind"],"additionalProperties":false,"description":"Where in the file the finding is. Which fields are present depends on `kind`."},"preview":{"type":"string","description":"Always masked. The API never returns an unredacted sensitive value."},"fixable":{"type":"boolean","description":"Whether POST /sanitize would remove this."}},"required":["type","severity","message","location","preview","fixable"],"additionalProperties":false,"description":"One detection."},"ScanResult":{"type":"object","properties":{"fileType":{"type":"string","enum":["image","pdf","word","excel","csv","text","unknown"]},"riskLevel":{"type":"string","enum":["none","low","medium","high"],"description":"Highest severity found, or \"none\". Never presented as \"safe\"."},"findings":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["email","phone","credit_card","iban","us_ssn","passport_mrz","ip_address","secret_token","date_of_birth","street_address","signature","licence_plate","person_name","gps_location","device_info","software_info","timestamp","document_author","comment","tracked_change","hidden_content","embedded_file","fake_redaction","barcode","boarding_pass","sensitive_column","face"]},"severity":{"type":"string","enum":["low","medium","high"]},"message":{"type":"string","description":"User-facing message from the rule pack."},"location":{"type":"object","properties":{"kind":{"type":"string","enum":["metadata-field","text-range","page","sheet-cell","bounding-box"]},"field":{"type":"string"},"page":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"sheet":{"type":"string"},"cell":{"type":"string"},"start":{"type":"integer","minimum":0,"maximum":9007199254740991},"end":{"type":"integer","minimum":0,"maximum":9007199254740991},"x":{"type":"number"},"y":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"}},"required":["kind"],"additionalProperties":false,"description":"Where in the file the finding is. Which fields are present depends on `kind`."},"preview":{"type":"string","description":"Always masked. The API never returns an unredacted sensitive value."},"fixable":{"type":"boolean","description":"Whether POST /sanitize would remove this."}},"required":["type","severity","message","location","preview","fixable"],"additionalProperties":false,"description":"One detection."}},"rulesVersion":{"type":"string"},"durationMs":{"type":"number","minimum":0}},"required":["fileType","riskLevel","findings","rulesVersion","durationMs"],"additionalProperties":false,"description":"The result of scanning one file."},"RulePack":{"type":"object","properties":{"version":{"type":"string","description":"Calendar version, e.g. 2026.10.2."},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["email","phone","credit_card","iban","us_ssn","passport_mrz","ip_address","secret_token","date_of_birth","street_address","signature","licence_plate","person_name","gps_location","device_info","software_info","timestamp","document_author","comment","tracked_change","hidden_content","embedded_file","fake_redaction","barcode","boarding_pass","sensitive_column","face"]},"severity":{"type":"string","enum":["low","medium","high"]},"message":{"type":"string"},"fixable":{"type":"boolean"},"enabled":{"type":"boolean"}},"required":["id","severity","message","fixable","enabled"],"additionalProperties":false}}},"required":["version","rules"],"additionalProperties":false,"description":"The current rule pack. Clients cache this and pass it back to the library."},"ScanEvent":{"type":"object","properties":{"client":{"type":"string","enum":["web","extension","ios","android","api"]},"fileType":{"type":"string","enum":["image","pdf","word","excel","csv","text","unknown"]},"findingTypes":{"maxItems":27,"type":"array","items":{"type":"string","enum":["email","phone","credit_card","iban","us_ssn","passport_mrz","ip_address","secret_token","date_of_birth","street_address","signature","licence_plate","person_name","gps_location","device_info","software_info","timestamp","document_author","comment","tracked_change","hidden_content","embedded_file","fake_redaction","barcode","boarding_pass","sensitive_column","face"]},"description":"Detector ids only. Categories, never values."},"riskLevel":{"type":"string","enum":["none","low","medium","high"]},"action":{"type":"string","enum":["scanned","downloaded_clean","blurred","dismissed"]}},"required":["client","fileType","findingTypes","riskLevel","action"],"additionalProperties":false,"description":"Anonymous usage event. Contains no filename, content, preview or identifier."},"WaitlistRequest":{"type":"object","properties":{"email":{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"source":{"default":"web","type":"string","enum":["web","extension","ios","android","api"]}},"required":["email","source"],"additionalProperties":false,"description":"Join the launch waitlist. Signing up twice is idempotent."},"WaitlistResponse":{"type":"object","properties":{"status":{"type":"string","enum":["added","already_present"]}},"required":["status"],"additionalProperties":false},"MeResponse":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"email":{"type":"string","format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":["string","null"]}},"required":["id","email","name"],"additionalProperties":false},"plan":{"type":"object","properties":{"id":{"type":"string","enum":["free","pro","team"]},"label":{"type":"string"},"scansPerDay":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Checks per day through the website. `null` is unlimited — not zero."},"maxBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Largest file the website checker accepts."}},"required":["id","label","scansPerDay","maxBytes"],"additionalProperties":false},"usage":{"type":"object","properties":{"day":{"type":"string","description":"The quota day, `YYYY-MM-DD` in UTC."},"scans":{"type":"integer","minimum":0,"maximum":9007199254740991},"sanitizes":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["day","scans","sanitizes"],"additionalProperties":false},"remainingScans":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"`null` is unlimited."}},"required":["user","plan","usage","remainingScans"],"additionalProperties":false,"description":"The caller and their allowance. Counts only — there is no field here, and none in the database behind it, that could say what any of those checks found."},"ConsumeUsageRequest":{"type":"object","properties":{"fileType":{"type":"string","enum":["image","pdf","word","excel","csv","text","unknown"],"description":"Kind of file, for capacity planning."},"bytes":{"type":"integer","minimum":0,"maximum":1073741824,"description":"The size of the file. Its size — never its contents."}},"required":["fileType","bytes"],"additionalProperties":false},"ConsumeUsageResponse":{"type":"object","properties":{"day":{"type":"string"},"scans":{"type":"integer","minimum":0,"maximum":9007199254740991},"remainingScans":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["day","scans","remainingScans"],"additionalProperties":false},"SetPlanRequest":{"type":"object","properties":{"email":{"type":"string","maxLength":320,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"The account to change."},"plan":{"type":"string","enum":["free","pro","team"]}},"required":["email","plan"],"additionalProperties":false},"SetPlanResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"email":{"type":"string","format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"plan":{"type":"string","enum":["free","pro","team"]}},"required":["id","email","plan"],"additionalProperties":false},"CreateApiKeyRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"A label so you can tell your keys apart."}},"required":["name"],"additionalProperties":false},"CreateApiKeyResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"prefix":{"type":"string"},"key":{"type":"string","description":"The only time the full key is ever returned. Store it now; we keep only a hash."},"createdAt":{"type":"string"}},"required":["id","name","prefix","key","createdAt"],"additionalProperties":false,"description":"A newly created key."},"ApiKeySummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"prefix":{"type":"string"},"createdAt":{"type":"string"},"lastUsedAt":{"type":["string","null"]},"revokedAt":{"type":["string","null"]}},"required":["id","name","prefix","createdAt","lastUsedAt","revokedAt"],"additionalProperties":false},"RevokeApiKeyResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"revokedAt":{"type":"string"}},"required":["id","revokedAt"],"additionalProperties":false},"SanitizeReport":{"type":"object","properties":{"removed":{"type":"array","items":{"type":"string"},"description":"Plain-language labels. Never the removed values."},"remaining":{"type":"array","items":{"type":"string"},"description":"What was deliberately left for a human to decide."}},"required":["removed","remaining"],"additionalProperties":false,"description":"Returned in the X-Removed and X-Remaining headers, base64url-encoded JSON."}}}}