# Outbound calls and compliance

Queue AI calls through the API. Every call is checked against consent, Do Not Call lists, calling hours and daily limits before it can ring.

`POST /outbound-calls` asks the AI receptionist to call someone, and `POST /leads` with a `callback` asks it to call a new lead back straight away (speed-to-lead). Calls from the API go through exactly the same checks as calls started in the portal, and the API cannot switch any of them off. A call is either **refused** (it will never be placed), **delayed** (accepted, it rings later) or **allowed** (it rings now).

These rules are how Vocenya applies the TCPA and state calling rules to AI voice calls. They are not legal advice: you remain responsible for having consent for the calls you ask for.

## Before you start

The account needs, all set in the portal:

- Outbound AI calling switched on, and the outbound calling terms accepted.
- An active subscription and an AI receptionist to make the call.
- For a lead `callback`: an active Pro plan too. Callbacks are not available in HIPAA mode.

The API key needs the `outbound:write` scope. To try the rules without ringing anyone, use a test key: test calls are checked the same way and then simulated. See [Test mode](https://vocenya.com/docs/test-mode#outbound-calls-in-test-mode).

## Website lead form

For leads from the business's own website you do not need the API: the portal's [Outbound calls](https://vocenya.com/app/outbound) page has a ready-made lead form under **Add the lead form to your website**, once speed-to-lead is on. Each lead it takes records the visitor's consent with the business's consent wording and queues the callback.

- **Embed (recommended).** One line where the form should appear. It loads the hosted form in an iframe that sizes itself, shows the business's consent text, and is protected by Cloudflare Turnstile without adding the website's domain anywhere:

  ```html
  <script src="https://vocenya.com/f/embed.js" data-form="YOUR_FORM_KEY" async></script>
  ```

  Copy it from the portal, which fills in the form key. Where a site builder blocks scripts, use the iframe code shown next to it. The same form has a direct link and a QR code to share on a Google Business Profile, social media or flyers, and an optional thank-you page on the website to send visitors to after they submit.
- **HTML form (advanced).** A plain form to style like the website, posting to the business's intake URL. It is protected by a hidden spam trap and rate limits, plus Cloudflare Turnstile when the business adds its own Turnstile keys in the portal (the snippet then includes the site key, and every lead is checked with the business's secret).
- **API.** From a server or CRM, create a lead with a `callback`, as below.

## Consent

An AI call needs consent to AI calls on record for that number:

- `purpose: "marketing"` (the default) needs **marketing** consent to AI calls.
- `purpose: "informational"` is for reminders and follow-ups the person asked for. Any active AI-call consent covers it.
- HIPAA-mode accounts may only make `informational` calls.

A lead `callback` records the consent as it queues the call: send `consent_text`, the exact wording the person agreed to, plus `source_url`, `ip_address` and `user_agent` from the moment they agreed when you have them.

```bash
curl -X POST https://vocenya.com/api/public/v1/leads \
  -H "Authorization: Bearer $VOCENYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Maria Rivera",
  "phone_number": "(512) 555-0123",
  "reason": "Wants a quote for a water heater replacement",
  "callback": {
    "consent_text": "I agree to receive an automated AI phone call from Rivera Plumbing about my request.",
    "source_url": "https://www.example.com/contact"
  }
}'
```

## Do Not Call

Numbers on your own Do Not Call list or on GH's list are never called. Manage yours with the [Do Not Call endpoints](https://vocenya.com/docs/reference/do-not-call). When a person asks not to be called, add them with `opted_out: true`: it becomes a permanent opt-out, their AI-call consent is revoked, and the entry cannot be removed (`opt_out_permanent`).

## Calling hours and limits

- Calls ring only between **8am to 8pm** in the time zone of the number being called. That is stricter than the federal 8am to 9pm, because several states end at 8pm.
- A number is called at most **3 times in 24 hours**.
- A number that is already on a call for your account is never rung twice at once.

None of these refuse the call: it is accepted and rings as soon as it is allowed.

## The decision

`POST /outbound-calls` answers `202 Accepted` with the queued call in `data` and a `decision`:

```json
{
  "data": { "id": 88, "source": "api", "purpose": "marketing", "status": "queued", "phone_number": "+15125550123" },
  "decision": {
    "allowed": false,
    "reason": "outside_hours",
    "message": "It is outside calling hours (8am to 8pm) where that number is.",
    "retry_at": "2026-09-29T08:00:00-05:00"
  }
}
```

`decision.allowed` is `true` when the call can ring now. Otherwise `decision.retry_at` says when it will:

| `decision.reason` | Meaning |
| --- | --- |
| `outside_hours` | It is outside calling hours (8am to 8pm) where that number is. |
| `daily_limit` | That number has already been called three times in the last 24 hours. |
| `call_in_progress` | That number is already on a call for this client. |

Asking again for a number that already has a call from the API waiting returns that same call, so retries never stack up calls.

## Refusals

A call that can never be placed is refused with `422`, a `code` and, for calling rules, the `decision`:

| `code` | Meaning |
| --- | --- |
| `invalid_number` | That is not a valid US phone number. |
| `do_not_call` | That number is on a Do Not Call list. |
| `no_consent` | There is no consent on record for AI calls to that number. |
| `service_inactive` | The subscription is not active. |
| `terms_not_accepted` | The outbound calling terms have not been accepted. |
| `hipaa_marketing` | HIPAA accounts can only make appointment reminder calls. |
| `trial_minutes_exhausted` | The AI minutes included in the free trial are used up. Start the plan to make more AI calls. |
| `outbound_disabled` | Outbound AI calling is not switched on for this account. |
| `no_receptionist` | This account has no AI receptionist to make the call. |

Never try to work around a refusal, for example by changing the `purpose` without the matching consent.

## Voicemail

Every AI call runs the carrier's answering machine detection. A call that voicemail answers ends with status `voicemail` and `answered_by: "machine"`; a call a person answered has `answered_by: "human"` (`unknown` when detection could not tell, `null` when there was no result). What happens next is the account's voicemail setting, chosen on the **Outbound calls** page of the portal:

- **Leave a short message** (default): once the greeting ends, the virtual assistant says who called, why in one neutral sentence (never an appointment's details), and the number to call back. `voicemail_left_at` is set and the message is the last turn of the transcript.
- **Hang up and try again later**: a new call is scheduled about 90 minutes later with `blocked_reason: "voicemail_retry"`, within calling hours and the daily limit. The first call still ends as `voicemail`.
- **Hang up**: nothing is left.

## Following up

- `GET /outbound-calls/{outboundCall}` shows a call's status, `answered_by`, and `blocked_reason` when it was blocked at dial time (the rules are checked again just before dialing).
- Subscribe to [`outbound_call.completed`](https://vocenya.com/docs/webhook-events#outbound-call-completed) to hear when calls end.
