#Compliance Caller Requests
Compliance caller-request endpoints provide masked access/deletion workflow rows for Compliance > Caller requests.
This is a metadata workflow contract. It does not expose call analytics rows, transcripts, recordings, raw caller identifiers, raw metadata, secret-backend references, ciphertext, wrapped keys, routed database details, or stored identifier digests.
#API Routes
| Route | Method | Access |
|---|---|---|
/v1/compliance/caller-requests | GET | client_admin for own tenant/data environment; aidial_admin or aidial_operator with explicit client_id |
/v1/compliance/caller-requests/open-count | GET | Same scope rules as list |
/v1/compliance/caller-requests | POST | Internal aidial_admin or aidial_operator with explicit client_id, or API-key support_ingest/support-ingest |
/v1/compliance/caller-requests/{request_id}/status-transitions | POST | Internal aidial_admin or aidial_operator with explicit client_id |
All routes use the shared dual-mode authentication dependency. X-API-Key is evaluated before Authorization: Bearer <jwt>. Bearer authentication requires ZITADEL_ISSUER, ZITADEL_AUDIENCE, and ZITADEL_JWKS_URL; these settings are required and have no fallback defaults.
Partner roles (partner_admin and partner_user) and customer non-admin roles (client_manager and client_staff) are denied on every route in this contract and receive 404 Not Found; the denial is enforced before the request reaches the caller-request service. Out-of-scope tenants, inactive assignments, and invalid project scopes also fail closed with 404 Not Found.
#List Requests
GET /v1/compliance/caller-requests
Query parameters:
| Name | Type | Required | Description |
|---|---|---|---|
status | string | No | One of needs_review, ready, in_progress, completed, cancelled, unable_to_verify. |
due_state | string | No | One of normal, urgent, overdue, closed. The value is computed from status, due date, and timezone. |
type | string | No | One of access or deletion. |
project_id | string | No | Active project filter. Must match [A-Za-z0-9._:-]{1,128} and be in the caller's allowed project scope where applicable. |
client_id | string | No | Required for internal roles (aidial_admin, aidial_operator). Customer client_admin reads must omit it or match their own tenant. |
page_size | integer | No | Minimum 1, maximum 50, default 20. |
cursor | string | No | Opaque pagination cursor returned by a previous list response. |
Response:
{
"items": [
{
"id": "4d9f0d7a-8a60-4f8f-b64e-2a96a29d6d6f",
"tracking_id": "REQ-0001",
"revision_number": 1,
"request_type": "access",
"received_at_utc": "2026-05-01T00:00:00Z",
"due_at_utc": "2026-05-31T00:00:00Z",
"due_date_local": "2026-05-31",
"timezone": "Australia/Brisbane",
"due_state": "normal",
"days_remaining": 28,
"caller_display": "+61***123",
"contact_kind": "phone",
"identifier_kind": "phone",
"data_found_state": "manual_review_required",
"data_found_count": null,
"data_found_label": "Manual review required",
"project_labels": ["Reception"],
"status": "needs_review",
"status_label": "Needs review",
"closed_at_utc": null,
"linked_support_ticket_reference": "SUP-123",
"access_mode": "read"
}
],
"next_cursor": null
}access_mode is read or transition and reflects whether the authenticated caller can transition the returned workflow row.
#Open Count
GET /v1/compliance/caller-requests/open-count
Query parameters:
| Name | Type | Required | Description |
|---|---|---|---|
client_id | string | No | Same scoping rules as list. Required for internal roles. |
project_id | string | No | Optional active project filter. |
Response:
{
"open_count": 3
}Open rows are requests whose status is not completed, cancelled, or unable_to_verify.
#Create Request
POST /v1/compliance/caller-requests
Query parameters:
| Name | Type | Required | Description |
|---|---|---|---|
client_id | string | Conditional | Required for internal roles (aidial_admin, aidial_operator). API-key support-ingest callers may omit it or provide their own client id. |
Request body:
| Name | Type | Required | Description |
|---|---|---|---|
request_type | string | Yes | access or deletion. |
identifier_kind | string | Yes | phone or manual. |
caller_identifier | string | Conditional | Required when identifier_kind is phone. Treated as transient input only. |
contact_kind | string | Yes | One of phone, email, manual, letter, support_ticket, or other. |
contact_display_source | string | No | Source text used only to derive a masked display value for manual identifiers. |
received_at_utc | timestamp | Yes | Time the request was received. |
source | string | Yes | One of partner, internal, support, support_ingest, or api. |
source_project_id | string | No | Optional active project id for the target client. |
support_ticket_reference | string | No | Optional reference matching [A-Za-z0-9._:-]{1,128}. |
Successful creation returns 201 Created with a caller-request item. New rows start in needs_review with revision 1.
Phone identifiers are normalized to E.164, converted to masked display text, and HMACed with server-side identifier-hashing key caller-identifier-hmac. The normalized plaintext is discarded before persistence; only the masked display and internal HMAC digest are stored. If server-side identifier hashing is unavailable, creation fails with 503 Service Unavailable and no workflow row is persisted. Manual identifiers do not produce a deterministic digest.
#Status Transitions
POST /v1/compliance/caller-requests/{request_id}/status-transitions
Query parameters:
| Name | Type | Required | Description |
|---|---|---|---|
client_id | string | Conditional | Required. Only internal roles (aidial_admin, aidial_operator) may transition; the value must identify the target client. Support-ingest API keys cannot transition requests. |
Request body:
| Name | Type | Required | Description |
|---|---|---|---|
expected_revision | integer | Yes | Current revision expected by the caller. Must be at least 1. |
status | string | Yes | One of needs_review, ready, in_progress, completed, cancelled, or unable_to_verify. |
status_note | string | Yes | Transition note, 1 to 500 characters. Stored in workflow history, not returned by list responses. |
processing_result | object | No | Optional processing update. |
processing_result fields:
| Name | Type | Required | Description |
|---|---|---|---|
data_found_state | string | No | One of unknown, searching, manual_review_required, found, not_found, or failed. |
data_found_count | integer | No | Non-negative count, when known. |
project_labels | array of strings | No | Display labels for matched projects. |
closed_at_utc | timestamp | No | Closure timestamp. If omitted for terminal statuses, the API sets it to the current UTC time. |
Successful transitions return 200 OK with the updated caller-request item. If expected_revision is stale, the route returns 409 Conflict. If the request id is not in scope, the route returns 404 Not Found.
#Privacy Contract
Caller identifiers are transient input only. identifier_kind is limited to phone or manual. Phone values are normalized to E.164, masked for display, and HMACed through server-side decryption before the plaintext value is discarded. Manual, email, letter, support-ticket, and other contact records expose only masked display text and remain manual-review workflows without a deterministic digest.
Response models expose only the safe fields shown above. They never include raw identifiers, HMAC digests, ciphertext, secret-backend references, transcript text, recording URLs, raw metadata, client_id, source_project_id, API keys, or bearer tokens.
These endpoints do not perform phone or transcript decryption and do not unlock raw caller identifiers based on client PII flags. PII-sensitive call data remains outside this contract.
#Persistence And Audit
Caller-request workflow rows are stored in the local API metadata database on the serving API host, scoped by client_id and data_env. The implementation uses the API metadata store path and does not resolve routed tenant data store analytics routes for these endpoints.
Create and transition mutations write the workflow change and caller_request.* audit rows in one database transaction against portal_audit_events; audit failure rolls back the caller-request mutation.
Audit actions emitted by this contract are:
caller_request.createdcaller_request.status_changedcaller_request.support_linkedcaller_request.processing_recordedcaller_request.processing_failed
Audit metadata is limited to safe request identifiers, status/type state, due state, data-found count, and support-ticket reference where present.
#Error Semantics
| Condition | Status |
|---|---|
| Missing authentication, invalid API key, expired API key, expired bearer token, invalid bearer token, or invalid bearer scheme | 401 Unauthorized |
| Unsupported list filter or service-level caller-request validation failure | 400 Bad Request |
| Request body or query parsing failure caught by FastAPI validation | 422 Unprocessable Entity |
| Valid authentication but unsupported role, inactive assignment, out-of-scope tenant, out-of-scope project, or missing request id | 404 Not Found |
| Stale transition revision | 409 Conflict |
| Missing required bearer authentication configuration | 500 Internal Server Error |
| Caller identifier HMAC unavailable, authentication lookup dependency unavailable, or caller-request storage unavailable | 503 Service Unavailable |