#Compliance Caller Requests

5 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, secret-backend references, ciphertext, wrapped keys, routed database 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 computed from status, due date, and timezone.
typestringNoOne of access or deletion.
project_idstringNoActive project filter. Must match [A-Za-z0-9._:-]{1,128} 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_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:

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.

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:

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

ConditionStatus
Missing authentication, invalid API key, expired API key, expired bearer token, invalid bearer token, or invalid bearer scheme401 Unauthorized
Unsupported list filter or service-level caller-request validation failure400 Bad Request
Request body or query parsing failure caught by FastAPI validation422 Unprocessable Entity
Valid authentication but unsupported role, inactive assignment, out-of-scope tenant, out-of-scope project, or missing request id404 Not Found
Stale transition revision409 Conflict
Missing required bearer authentication configuration500 Internal Server Error
Caller identifier HMAC unavailable, authentication lookup dependency unavailable, or caller-request storage unavailable503 Service Unavailable