Reference

Compliance controls.

You are the caller of record. Rexa.ai places calls on your instruction, under your carrier account, with your consent records — the legal responsibility for who is called, when, and on what basis is yours. What the platform provides is machinery: a pre-dispatch gate, calling-window enforcement, opt-out handling, and an audit trail you can export. This page documents what that machinery actually does.

The pre-dispatch gate

Every outbound call runs a compliance gate before any credit hold is placed or a concurrency slot consumed — a blocked number costs you nothing. The gate short-circuits: the first check that blocks stops the rest from running.

  1. If DNC checking is disabled for your tenant, the gate logs skipped_tenant_disabled and allows the call.
  2. If the destination is outside the North American Numbering Plan, the vendor checks are skipped and the row is logged as non_nanp_no_vendor. Coverage today is NANP only.
  3. Do-Not-Call. A hit blocks with reason on_dnc_list.
  4. Recently reassigned. A number reassigned to a new subscriber blocks with reason reassigned.
  5. Validity. Only when enabled for your tenant. An invalid number blocks with reason invalid.

Results are cached, so repeat dispatches to the same number do not re-bill a vendor lookup. Every evaluation — allowed or blocked, cached or live — writes an audit row.

A blocked dispatch

HTTP/1.1 422 Unprocessable Entity

{
  "error": {
    "type": "compliance_error",
    "code": "dnc_blocked",
    "message": "This number is on a Do-Not-Call list",
    "details": {
      "phone_number": "415*****71",
      "country_code": "1",
      "reason": "on_dnc_list",
      "checked_at": "2026-08-08T14:31:02.881Z"
    }
  }
}

The phone number in details is masked. Three codes come out of the gate:

StatusCodeMeaning
422dnc_blockedThe destination is on a Do-Not-Call registry.
422reassigned_blockedThe destination was recently reassigned to a new subscriber.
422invalid_numberThe destination failed validation.

dnc_blocked and reassigned_blocked carry the error type compliance_error, so you can branch on the category without matching every code.

What you configure

Gate behaviour is a tenant setting, managed from the dashboard rather than the public /v1 API. Three switches:

SettingValuesEffect
dnc_check_enabledbooleanTurns the DNC and reassigned checks on or off. When off, the gate logs the skip and allows.
dnc_fail_modeblock_on_error | allow_on_errorWhat happens when the vendor is unreachable. block_on_error is the default and refuses the call; allow_on_error lets it through and records vendor_error on the row so you can audit which dispatches went out unverified.
numverify_enabledbooleanAdds the number-validity check. Validity-vendor errors always allow the call, regardless of fail mode.

The fail-mode choice is the one worth thinking about. It is the difference between a vendor outage stopping your campaign and a vendor outage sending unscreened calls.

Calling windows

Campaign dialling is confined to a daily window in the recipient's local time. The default window is 09:00 to 20:00 — deliberately narrower than the 08:00–21:00 bounds referenced by the TCPA. A contact outside the window is not dropped; it is deferred to the next opening.

FieldNotes
calling_window_startHH:mm in the campaign timezone. Defaults to 09:00. Calls go out only inside [start, end).
calling_window_endHH:mm in the campaign timezone. Defaults to 20:00.
timezoneIANA timezone applied to uploaded contacts that do not carry their own. Falls through to area-code inference and then the tenant default.
skip_weekendDefaults to true — recipient-local Saturday and Sunday calls and SMS defer to the next weekday window. Email is exempt.
quiet_hours_start / quiet_hours_endDeprecated aliases of the calling-window fields. The old names are misleading: they describe when calls ARE placed.

Daylight saving is handled by the IANA timezone runtime rather than offset arithmetic, so a window does not silently shift by an hour twice a year. A campaign can also carry a per-local-day dispatch cap, which pauses it until local midnight once reached.

Recording and disclosure

Disclosure behaviour is set per call with auto_disclose_mode on POST /v1/calls. Recording itself is opt-in per call via recording_enabled, and requires recording compliance to be configured on the tenant first.

ModeBehaviour
noneSkips disclosure — for jurisdictions where it is not required.
passivePlays the disclosure once on connect.
affirmativeRequires the recipient to consent before the agent proceeds.

Mid-call opt-out

The agent listens for opt-out phrases throughout the call. Six are enabled by default: "stop calling me", "do not call", "don't call me again", "take me off your list", "remove me from your list" and "unsubscribe". You can add your own — the platform list, your tenant list and any per-session additions are merged and de-duplicated.

Added phrases are validated to stop a whole campaign hanging up on politeness: they must be at least four characters, cannot duplicate a default, and cannot be common conversational words such as "no", "yes", "stop", "okay" or "thanks". Rejections come back as too_short, too_broad or duplicate_default.

SettingValues
Actionflag_only, stop_recording, end_call, or stop_recording_and_end_call. Resolved per session, then tenant, then the platform default of flag_only.
Recording retentionkeep_pre_opt_out retains audio up to the opt-out; purge_full_recording removes the whole recording, applied on a 60-minute delay.

Voice-clone consent

A cloned voice cannot be finalised without a consent recording from the named speaker, read from a versioned script that identifies the speaker and the organisation using the voice. The script version is stamped onto the clone, so a later revision to the wording does not retroactively change what an earlier speaker agreed to.

The audit trail

Every gate evaluation is written to a check log you can page through or export as CSV, filtered by blocked-only or by phone prefix. Rows are retained for two years and there is no tenant-facing delete — an audit log you can edit is not an audit log.

{
  "id": "...",
  "phone_masked": "415*****71",
  "country_code": "1",
  "source": "pre_dispatch",
  "session_id": null,
  "on_dnc_list": true,
  "reassigned": null,
  "phone_valid": null,
  "served_from_cache": false,
  "blocked": true,
  "block_reason": "on_dnc_list",
  "checked_at": "2026-08-08T14:31:02.881Z"
}

Phone numbers are masked in the log. source is pre_dispatch, campaign_precheck or admin, and served_from_cache tells you whether the decision came from a cached vendor result or a live lookup.

Separately, a tenant audit log records account mutations — who did what, when, to which resource, with the actor's identity and an optional reason. It is split into administrative actions and your own team's activity, and both views are server-filtered to your tenant.

Next