# The pre-dial gate

Source: https://docs.usetone.ai/compliance

> Five checks that run before every call, and the audit rows they leave whether they pass or block.

India regulates who may be called, about what, and when. TCCCPR liability sits
with the sender — you — and there is no statutory safe harbour for using a
vendor. What Tone can do is run the checks and keep the evidence that you ran
them.

## What runs, in order

Every dial — direct, campaign, or BYO — runs all six, inside the same
transaction as the call record.

| # | Check | Can block? | |
|---|---|---|---|
| 1 | `dlt` | no — warns | Your registration and whether the from-number suits the purpose |
| 2 | `a2p` | no — warns | Whether an auto-dialer pre-declaration is on file with your access provider |
| 3 | `time_window` | yes | The calling band for the agent's purpose, in IST |
| 4 | `dnc` | yes | Your suppression list — **the only list we hard-block on** |
| 5 | `carrier_dnd` | **never** | Carrier metadata, advisory only |
| 6 | `consent` | no — warns, promotional only | Whether consent is on record. A valid consent also overrides a carrier DND flag — never a suppression |

Each writes a row with an outcome of `pass`, `warn` or `block`, **whatever it
decided**. The table is append-only at the database level: nothing can edit or
delete a check after the fact, which is the entire point of having one.

```bash
curl -H "Authorization: Bearer $TONE_KEY" \
  "$TONE_API/v1/compliance/checks?e164=%2B919876543210&outcome=block"
```

## The A2P pre-declaration

TCCCPR regulation 4 requires notifying your Originating Access Provider, in
writing and in advance, that auto-dialer / robo-call technology is in use.
File the declaration with your access provider, then record its reference
under **Compliance → Auto-dialer pre-declaration** — the `a2p` check warns on
every call placed without one, on every purpose, and each evidence record
cites the declaration when it exists.

## Why carrier DND only warns

The authoritative Do-Not-Call register is deliberately not exposed to
telemarketers — that is its design, not an oversight. What a carrier returns is
metadata, and the carrier disclaims it. Blocking on advisory data would silently
drop legitimate calls and give you no way to tell which; passing it through
labelled as advisory lets you decide.

🔴 **Tone does not claim authoritative NCPR scrubbing**, and you should not
either. What we block on is your own suppression list plus cross-customer
opt-outs, labelled as such.

## Calling windows

Narrowed from the industry default of 08:00 because we cannot read an individual
recipient's registered preference band, so the safe assumption is the tightest
one.

| Purpose | Window (IST) | Basis |
|---|---|---|
| `promotional` | 09:00 – 21:00 | TCCCPR preference band |
| `collections` | 08:00 – 19:00 | RBI recovery-agent rules |
| `service` | none | Schedule II — may not be blocked |
| `transactional` | none | Schedule II — may not be blocked |

There is **no override**, and no request field reaches the gate. A caller who
could opt out of being checked would make every audit row meaningless.

## Where purpose comes from

From durable configured state, never from the request:

- A **Tone agent** supplies its own `purpose`.
- A **BYO number** has no agent, so the organization's declared sender
  classification is used. Set it in the dashboard under **Telephony → Compliance
  → Sender classification**; dialling before declaring one is a `422`.

## Checking without dialling

If you dial on your own carrier, ask for the verdict directly. It writes the same
audit rows a dial writes, and answers `200` either way — a refusal is a verdict,
not an error.

```bash
curl "$TONE_API/v1/compliance/check" -X POST \
  -H "Authorization: Bearer $TONE_KEY" -H 'content-type: application/json' \
  -d '{"e164":"+919876543210","purpose":"promotional"}'
```

See [Compliance as an API](/quickstart-compliance).

## When a call is blocked

`403`, with `error.code` naming which check stopped it:

| Code | From |
|---|---|
| `blocked_dnd` | `dnc`, `carrier_dnd` or a stale `scrub` |
| `blocked_opt_out` | `consent`, `time_window`, or a recorded outcome |
| `blocked_dlt_invalid` | `dlt` or `a2p` |

`error.details` carries `checkType` and `reason`, and the audit row is already
written — so a block is fully explainable after the fact from
`GET /v1/compliance/evidence`.

## Sealed evidence records

Beyond the raw audit rows, every call attempt — completed calls **and refused
dials** — produces one sealed evidence record: the legal basis to call (your
DNC result, the consent record relied on, the carrier signal), how the call
was placed (DLT registration, A2P declaration, calling window, the number's
status at dial time, whether the AI disclosure was spoken and when), and the
outcome.

Each record carries a sha256 of its canonical content plus the previous
record's hash, forming a per-organisation chain: editing any record breaks its
own hash, and deleting or reordering one breaks every later link.

```bash
# the record for one call, or the same as a PDF at /evidence.pdf
curl -H "Authorization: Bearer $TONE_KEY" \
  "$TONE_API/v1/calls/{id}/evidence"

# prove the chain's integrity, on demand
curl -H "Authorization: Bearer $TONE_KEY" \
  "$TONE_API/v1/compliance/evidence-records/verify"
```

The table is append-only at the database level, and its rows survive even an
organisation deletion. Records seal shortly after a call ends; a refused dial
seals in the same transaction as its refusal.
