#Compliance Caller Requests

6 min read

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, internal key or credential material, ciphertext, internal storage details, or stored identifier digests.

#API Routes

RouteMethodAccess
/v1/compliance/caller-requestsGETclient_admin for own tenant/data environment; aidial_admin or aidial_operator with explicit client_id
/v1/compliance/caller-requests/open-countGETSame scope rules as list
/v1/compliance/caller-requestsPOSTInternal aidial_admin or aidial_operator with explicit client_id, or API-key support_ingest/support-ingest
/v1/compliance/caller-requests/{request_id}/status-transitionsPOSTInternal 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:

NameTypeRequiredDescription
statusstringNoOne of needs_review, ready, in_progress, completed, cancelled, unable_to_verify.
due_statestringNoOne of normal, urgent, overdue, closed. The value is derived from status and the due date evaluated in the row's timezone: closed for terminal statuses, overdue once the due date has passed, urgent within seven days of it, otherwise normal.
typestringNoOne of access or deletion.
project_idstringNoActive project filter. Must match [A-Za-z0-9._:-]{1,128}, resolve to an active project for the target tenant, and be in the caller's allowed project scope where applicable.
client_idstringNoRequired for internal roles (aidial_admin, aidial_operator). Customer client_admin reads must omit it or match their own tenant.
page_sizeintegerNoMinimum 1, maximum 50, default 20.
cursorstringNoOpaque pagination cursor returned by a previous list response.

Response:

JSON
{
  "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_label": "Manual review required",
      "project_labels": ["Reception"],
      "status": "needs_review",
      "status_label": "Needs review",
      "linked_support_ticket_reference": "SUP-123",
      "access_mode": "read"
    }
  ]
}

Optional fields without a value are omitted rather than serialized as null. This applies to days_remaining, data_found_count, closed_at_utc, linked_support_ticket_reference, and next_cursor on list, create, and transition responses. Treat an absent field as unset.

Results are ordered by received_at_utc descending, then by id descending. next_cursor is present only when more rows are available.

access_mode is read or transition. List responses return read for customer client_admin reads and transition for internal reads. Create and transition responses always return transition, including for support-ingest API keys, which cannot call the status-transition route.

#Open Count

GET /v1/compliance/caller-requests/open-count

Query parameters:

NameTypeRequiredDescription
client_idstringNoSame scoping rules as list. Required for internal roles.
project_idstringNoOptional active project filter.

Response:

JSON
{
  "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:

NameTypeRequiredDescription
client_idstringConditionalRequired for internal roles (aidial_admin, aidial_operator). API-key support-ingest callers may omit it or provide their own client id.

Request body:

NameTypeRequiredDescription
request_typestringYesaccess or deletion.
identifier_kindstringYesphone or manual.
caller_identifierstringConditionalRequired when identifier_kind is phone. Treated as transient input only.
contact_kindstringYesOne of phone, email, manual, letter, support_ticket, or other.
contact_display_sourcestringNoSource text used only to derive a masked display value for manual identifiers.
received_at_utctimestampYesTime the request was received.
sourcestringYesOne of partner, internal, support, support_ingest, or api.
source_project_idstringNoOptional active project id for the target client.
support_ticket_referencestringNoOptional 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, data_found_state manual_review_required, and a sequential tracking_id in the form REQ-0001 that is unique per tenant and data environment.

due_at_utc is set to 30 days after received_at_utc, evaluated in the timezone of the referenced project when source_project_id is supplied, otherwise the client timezone, and UTC when neither is configured.

Phone identifiers are normalized to E.164, converted to masked display text, and hashed with a keyed server-side HMAC-SHA-256 step. The normalized plaintext is discarded before persistence; only the masked display and the resulting 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:

NameTypeRequiredDescription
client_idstringConditionalRequired. 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:

NameTypeRequiredDescription
expected_revisionintegerYesCurrent revision expected by the caller. Must be at least 1.
statusstringYesOne of needs_review, ready, in_progress, completed, cancelled, or unable_to_verify.
status_notestringYesTransition note, 1 to 500 characters. Stored in workflow history, not returned by list responses.
processing_resultobjectNoOptional processing update.

processing_result fields:

NameTypeRequiredDescription
data_found_statestringNoOne of unknown, searching, manual_review_required, found, not_found, or failed.
data_found_countintegerNoNon-negative count, when known.
project_labelsarray of stringsNoDisplay labels for matched projects.
closed_at_utctimestampNoClosure 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 passed through a keyed server-side HMAC-SHA-256 step 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, internal key 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.created
  • caller_request.status_changed
  • caller_request.support_linked
  • caller_request.processing_recorded
  • caller_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

ConditionStatusCode
Missing authentication, invalid API key, expired API key, expired bearer token, invalid bearer token, or invalid bearer scheme401 UnauthorizedPlatform auth error
Unsupported list filter, invalid pagination cursor, phone identifier that is not valid E.164, missing caller_identifier for identifier_kind phone, or unresolvable tenant/project timezone400 Bad Requestvalidation_failed
Source address blocked by the tenant IP allowlist403 Forbiddenip_allowlist_restricted
Valid authentication but unsupported role, inactive assignment, out-of-scope tenant, out-of-scope project, or missing request id404 Not Foundnot_found
Stale transition revision409 Conflictconflict
Request body or query parsing failure caught by FastAPI validation422 Unprocessable EntityPlatform validation error
Missing required bearer authentication configuration500 Internal Server ErrorPlatform auth error
Caller identifier HMAC unavailable503 Service Unavailablecaller_identifier_hmac_unavailable
Authentication lookup dependency unavailable503 Service UnavailablePlatform auth error
Caller-request storage unavailable503 Service Unavailablecaller_requests_unavailable

Caller-request errors use a flat error envelope with a correlation id:

JSON
{
  "code": "not_found",
  "message": "Requested resource not found.",
  "request_id": "9b603a24-4d95-4d0b-a865-20c0f8a2c5de"
}

Platform authentication and FastAPI validation failures are raised before the caller-request handlers run and use the shared platform error envelope described in Errors.