> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitforms.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Dialer API

> Configure the OrbitForms power dialer from code or an AI agent: settings and caller IDs, call lists built from saved views, call scripts, calls, transcripts, AI feedback, outcomes and statistics, and the do-not-call list. Calls are only ever placed by a person.

The dialer lets a salesperson work through a call list from the browser, one contact after the next. This API covers everything around that: an agent or script can **configure** the dialer, **build call lists** (they are saved views of the Contacts table), **write the call scripts** a rep reads on a call, **read** sessions, calls, transcripts, AI feedback, outcomes and statistics, **set** outcomes and notes on finished calls, and **manage the do-not-call list**. The same endpoints power the dialer tools of the [MCP server](https://docs.orbitforms.ai/mcp/tools.md).

> [!WARNING]
>
> **The API never places a call, buys a number or changes billing.** There is no endpoint to start a dialing session, dial a number, obtain a calling token, buy or release a phone number, or accept the Dialer terms, and no scope grants one. Those actions exist only inside the dashboard for a signed-in person (billing changes: an admin in Settings → Dialer). An agent prepares the list, assigns numbers and reads the results and the costs; a person makes the calls. Settings can still change what those calls cost: a `dialer:write` credential can turn `transcribe_calls` on, which bills every transcribed minute of later calls ([pricing](#phone-numbers-and-pricing)), and `ai_call_feedback`, which uses one AI credit per call.

## Scopes

| Scope | Allows |
| - | - |
| `dialer:read` | Read dialer settings, the workspace's phone numbers, its calling costs and Dialer terms acceptance, preview call lists, list sessions, calls, call transcripts and AI feedback, statistics, call scripts, voicemail greetings and the do-not-call list |
| `dialer:write` | Change dialer settings (including call recording, paid transcription and AI feedback), assign and label phone numbers, set call outcomes and notes, permanently delete call recordings and transcripts, create, change and delete call scripts, add to and remove from the do-not-call list |
| `crm:read` | Also accepted by the call-list preview, since call lists are saved contact views; with `crm:read` alone the preview returns counts only, no `sample` contacts |

Changing `caller_id`, assigning or labelling phone numbers, deleting a call's recording and transcript, and removing numbers from the do-not-call list additionally need a credential whose owner is a team admin (`403 forbidden` otherwise). The **CRM agent** preset in the [Developer Portal](https://orbitforms.ai/developer-portal) includes both dialer scopes.

## Endpoints

| Method | Endpoint | Description |
| - | - | - |
| `GET` | `/api/v1/dialer/settings` | The team's dialer settings (defaults when none are saved) |
| `PATCH` | `/api/v1/dialer/settings` | Change any subset of the settings below; unknown keys are rejected |
| `GET` | `/api/v1/dialer/caller-ids` | The values `caller_id` accepts: the workspace's own numbers in caller-ID form (`phone_number`, `friendly_name`, `kind`). `503 unavailable` when calling is not configured |
| `GET` | `/api/v1/dialer/numbers` | `{ data: { numbers, members } }`: the phone numbers the workspace owns, oldest first, and a map of assignee IDs to name and email. No `POST`: numbers are bought in the dashboard |
| `GET` | `/api/v1/dialer/numbers/:id` | One number: `phone_number`, `number_type` (`local`, `toll_free`), `friendly_name`, `country`, `capabilities`, `assigned_user_id`, `status`, `monthly_price_cents`, purchase dates |
| `PATCH` | `/api/v1/dialer/numbers/:id` | `{ assigned_user_id?: uuid \| null, friendly_name?: string }`: hand the number to a rep, take it back with `null`, or relabel it. Admins only; `409 conflict` when that person already holds a number. No `DELETE`: numbers are released in the dashboard |
| `GET` | `/api/v1/dialer/billing` | What the workspace pays for calling: `numbers` by type and their `monthly_cents`, billable `minutes` this month and their cost, plus `pending_minutes` / `pending_cents` for minutes not yet reported to billing, `transcript_minutes` (minutes transcribed and billed this month, their cost and `per_minute_cents`, plus `pending_minutes` / `pending_cents`), list `prices` (including `transcript_minutes_cents`), `feedback` (AI call feedback written this month: `calls`, the AI `credits` they used and `per_call_credits`), `monthly_total_cents` (numbers only; metered minutes and transcript minutes excluded), the `subscription` record (`status`: `none`, `active`, `canceling`, `past_due`; `cancel_at`; `current_period_end`), the `terms` record (version, path, who accepted it and when, `current`), all in cents, and whether purchase is `configured` |
| `GET` | `/api/v1/dialer/call-lists/preview?view_id=` | What a session built from a saved view would dial: `matching`, `examined`, `dialable`, `skipped` by reason, `truncated`, and a `sample` of the first contacts in order (only for credentials that also hold `contacts:read` or `dialer:read`). Only numbers in the United States are dialable |
| `GET` | `/api/v1/dialer/sessions` | Dialing sessions, newest first (`user_id`, `status`: `active`, `paused`, `completed`, `abandoned`; `page`, `per_page`). Read-only: there is no `POST` |
| `GET` | `/api/v1/dialer/sessions/:id` | `{ data: { session, items } }`; the session carries the `script_id` it was started with; each item has the contact, `phone_e164`, `status` (`queued`, `calling`, `done`, `skipped`), `skip_reason`, `last_call_id` and `outcome` |
| `GET` | `/api/v1/dialer/calls` | Calls, newest first (`contact_id`, `session_id`, `user_id`, `outcome`, `since`, `until`, `page`, `per_page`). Each call carries an `insights` summary (`transcript_status`, `feedback_status`), or `null` when nothing was requested |
| `GET` | `/api/v1/dialer/calls/:id` | One call: numbers, `status`, `answered_by`, `outcome`, `notes`, timings, `duration_seconds`, recording metadata and the `insights` summary |
| `PATCH` | `/api/v1/dialer/calls/:id` | `{ outcome?, notes? }`; `do_not_call` also adds the dialed number to the do-not-call list |
| `GET` | `/api/v1/dialer/calls/:id/insights` | The call's transcript and AI feedback (see [Transcripts and AI feedback](#transcripts-and-ai-feedback)). `404 not_found` until a transcript was requested for the call |
| `DELETE` | `/api/v1/dialer/calls/:id/recording` | Deletes the call's recording and transcript at the providers and keeps the call (see [Deleting recordings](#deleting-recordings)). Admins only; `409 conflict` when the call has neither. Returns the call with `insights: null` |
| `GET` | `/api/v1/dialer/stats` | Statistics for a window (`since`, `until`, default the last 30 days; `user_id`, `session_id`): calls, reached, reach rate, voicemails, talk time, and breakdowns by outcome, person and day |
| `GET` | `/api/v1/dialer/scripts` | The team's call scripts, the default first then by name (see [Call scripts](#call-scripts)) |
| `POST` | `/api/v1/dialer/scripts` | `{ name, content, is_default? }` → the new script (`201`) |
| `GET` | `/api/v1/dialer/scripts/:id` | One script with its full `content` |
| `PATCH` | `/api/v1/dialer/scripts/:id` | `{ name?, content?, is_default? }` (at least one). `is_default: true` takes the flag off the previous default; `409 conflict` when two callers race for it |
| `DELETE` | `/api/v1/dialer/scripts/:id` | Removes the script. Sessions and call insights that used it keep working; their `script_id` becomes `null` |
| `GET` | `/api/v1/dialer/voicemails` | Pre-recorded voicemail greetings, metadata only (`user_id`). Audio is uploaded and played from the dashboard |
| `GET` | `/api/v1/do-not-call` | The do-not-call list (`search` matches digits or the source email, `reason`, `page`, `per_page`) |
| `POST` | `/api/v1/do-not-call` | `{ phones: string[] \| string, reason?, note?, contact_id? }` → `{ added, already_listed, invalid }` (`201` when anything was added) |
| `DELETE` | `/api/v1/do-not-call` | `{ phones?: string[], ids?: string[] }` → `{ removed }`. Admins only |

### Settings

Defaults apply until a team saves its own. `caller_id` is the workspace's **default** outbound number; it must be one of the numbers the workspace owns and is the only setting a non-admin credential cannot change.

| Setting | Type | What it does |
| - | - | - |
| `caller_id` | E.164 string \| null | The workspace's default outbound number, used by anyone without a number assigned to them. Must be one of the phone numbers the workspace owns (`GET /api/v1/dialer/numbers`; bought in Settings → Dialer). Admins only. The first number a workspace buys becomes the default automatically |
| `ring_timeout_seconds` | integer 5–60 | Seconds to let a number ring before treating it as no answer and moving on. Default 25 |
| `auto_advance_delay_seconds` | integer 0–60 | Seconds between one call ending and the next contact being dialed. Default 3 |
| `wrap_up_seconds` | integer 0–300 | After a conversation, seconds the outcome picker waits before saving `connected` and moving on; 0 waits for the person. Default 20 |
| `voicemail_mode` | `live` \| `drop` \| `hangup` | What happens when a call reaches voicemail: `live` (the person hears it and decides), `drop` (play their default pre-recorded greeting after the beep, then move on) or `hangup` (hang up as soon as a machine is detected, then move on). Default `live` |
| `machine_detection` | boolean | Detect answering machines. Required for `drop` and `hangup` and for `transcribe_calls`; when off, every answered call is treated as a person. Default `true` |
| `record_calls` | boolean | Record calls from the moment they are answered (dual channel); recordings are listed on each call. Default `true` |
| `recording_announcement` | boolean | Play a short notice to the called party when they answer ("This call may be recorded for quality and training purposes") before connecting them. Only plays when `record_calls` is on. Helps with all-party-consent recording laws; it does not replace your own consent obligations. Default `false` |
| `skip_recently_called_hours` | integer 0–720 | Leave contacts called within this many hours out of new sessions; 0 never skips. Default 24 |
| `max_attempts_per_contact` | integer 1–50 \| null | Leave contacts with at least this many finished calls out of new sessions; `null` means no limit. Default `null` |
| `default_country` | ISO 3166-1 alpha-2 | Country assumed for phone numbers stored without a country code. Default `US` |
| `transcribe_calls` | boolean | Transcribe recorded conversations (speaker-labelled) once the call ends. Needs `record_calls` and `machine_detection`. Voicemail and unanswered calls are never transcribed. Default `true` |
| `ai_call_feedback` | boolean | After each transcribed conversation, have the AI coach write feedback for the rep: summary, what went well, what to improve, objections and next steps. Needs `transcribe_calls`. Each feedback uses one of the workspace's AI credits; when none are left the call's `feedback_status` is `skipped`, not failed. Default `false` |
| `ai_feedback_focus` | string \| null | Optional instructions for the AI coach: your sales methodology, products, what to look for. Up to 2,000 characters; blank or `null` clears it. Default `null` |

The transcript settings form a chain: `transcribe_calls` needs both `record_calls` and `machine_detection` on (answering-machine detection is what keeps voicemail out of transcripts), and `ai_call_feedback` needs `transcribe_calls` on. A patch that breaks the chain is rejected with `400 invalid_request` and a message naming the fix; turning a parent off never silently turns its dependents off, so send them together: `{ "record_calls": false, "transcribe_calls": false, "ai_call_feedback": false }` to stop recording, or `{ "machine_detection": false, "transcribe_calls": false, "ai_call_feedback": false }` to stop detecting answering machines. The reverse holds too: `{ "transcribe_calls": true, "machine_detection": true }` turns transcription on where detection was off.

```bash theme={null}
curl -X PATCH https://orbitforms.ai/api/v1/dialer/settings \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "voicemail_mode": "drop", "machine_detection": true, "skip_recently_called_hours": 48 }'
```

### Outcomes

Every finished call carries one outcome. The system sets the automatic ones from how the call ended; a person (or `PATCH /api/v1/dialer/calls/:id`) picks a manual one after a conversation. `reached` outcomes count toward the reach rate in statistics.

| Value | Label | Set by | Meaning |
| - | - | - | - |
| `no_answer` | No answer | auto | Rang until the ring timeout |
| `busy` | Busy | auto | Busy signal |
| `failed` | Failed | auto | The number could not be reached (invalid or unroutable) |
| `canceled` | Canceled | auto | Hung up before the contact answered |
| `voicemail` | Voicemail | auto | Reached voicemail; no message left |
| `voicemail_dropped` | Voicemail dropped | auto | A pre-recorded greeting was left |
| `voicemail_left` | Voicemail left | manual | The caller left a message in person |
| `connected` | Connected | manual | Spoke with the contact (reached) |
| `interested` | Interested | manual | Spoke with the contact; they want to continue (reached) |
| `not_interested` | Not interested | manual | Spoke with the contact; they declined (reached) |
| `callback` | Call back | manual | Asked to be called again later (reached) |
| `meeting_booked` | Meeting booked | manual | A meeting was scheduled on the call (reached) |
| `wrong_number` | Wrong number | manual | The number does not belong to the contact |
| `do_not_call` | Do not call | manual | Asked not to be called again; the number goes on the do-not-call list (reached) |

## Phone numbers and pricing

The Dialer is **part of every plan**; there is no flat fee. A workspace needs a phone number to call from: an admin buys numbers in **Settings → Dialer** (also reachable from Billing), and Orbit's platform phone account buys each one on the workspace's behalf. The first purchase asks the admin to accept the Dialer terms at [`/dialer-terms`](https://orbitforms.ai/dialer-terms). Numbers and outbound minutes are charged on a separate **Orbit Dialer** subscription next to the workspace's plan, on the same card; the first number creates it.

| Item | Price | How it is billed |
| - | - | - |
| Local number | \$5 / month | Monthly rental; the first number starts the workspace's monthly Dialer billing cycle, later ones are prorated to it |
| Toll-free number | \$10 / month | Monthly rental; the first number starts the workspace's monthly Dialer billing cycle, later ones are prorated to it |
| Outbound calling | \$0.02 / minute | Per started minute of each answered call, metered and added to the next invoice |
| Call transcription | \$0.05 / minute | Per whole minute of each conversation transcribed (`transcribe_calls` on; voicemail and unanswered calls are never transcribed), metered and added to the next invoice |

How billing behaves:

* **Terms with the first number.** The first purchase requires an admin to accept the current Dialer terms (version `2026-10-26`); the acceptance is recorded before anything is bought. `GET /api/v1/dialer/billing` reports in `terms` which version was accepted, by whom and when, and `terms.current` tells you whether that is still the version in force.
* **One subscription, created on demand.** The first number creates the workspace's Orbit Dialer subscription with the number and the metered minutes on it; later numbers change the quantity. Releasing a number credits the unused part of the month on the next invoice; releasing the last one leaves the subscription with only its metered items, so nothing more is charged until the next purchase.
* **Subscription state.** `subscription.status` is `none` until the first number, then `active`. `past_due` means Stripe is retrying a failed payment; dialing continues meanwhile. `canceling` (with `cancel_at`) only happens when support schedules a cancellation; when it takes effect, or when the subscription ends for non-payment, **every number the workspace owns is released**.
* **Dashboard only.** Buying and releasing numbers, and accepting the terms, change what the workspace is charged, so none of them has an API endpoint or MCP tool. The API reads the costs (`GET /api/v1/dialer/billing`) and the numbers, and can assign and label numbers.

Numbers and reps:

* **One number per rep.** An admin assigns each number to a team member; that person's calls go out on it. A rep can hold one active number at a time (`409 conflict` otherwise).
* **The default number.** Reps without a number of their own use the workspace default, `caller_id` in the settings. The first number a workspace buys becomes the default; if the default is released, the oldest remaining number is used.
* **Assign and label over the API**, buy and release in the dashboard. `GET /api/v1/dialer/numbers` lists what the workspace owns and who holds what; `PATCH /api/v1/dialer/numbers/:id` reassigns or relabels. There is no `POST` or `DELETE` on this resource; a signed-in admin buys and releases from Settings → Dialer. Releasing a paid number credits the unused part of the month on the next invoice.
* **Costs.** `GET /api/v1/dialer/billing` reports the active numbers by type and their monthly total, the billable minutes so far this calendar month and their cost, the transcribed minutes billed so far this month and their cost (`transcript_minutes`), the list prices (`prices`, with `transcript_minutes_cents` for transcription), `feedback` (how many calls the AI coach wrote feedback for this month and the AI credits that used, one per call), `monthly_total_cents` (numbers only; metered usage excluded), the `subscription` state and the `terms` acceptance. Unanswered calls bill nothing, and neither does a call that was not transcribed.

```bash theme={null}
curl -X PATCH https://orbitforms.ai/api/v1/dialer/numbers/NUMBER_ID \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "assigned_user_id": "USER_ID", "friendly_name": "Jane - West coast" }'
```

## Call lists are saved views

A call list is nothing more than a saved view of the Contacts table: its filters pick the people, its sort sets the dialing order. Build one with `POST /api/v1/contact-views` (or `create_contact_view` over MCP), list existing ones with `GET /api/v1/contact-views`, then check what it would dial with `GET /api/v1/dialer/call-lists/preview?view_id=`. The dialer only calls numbers in the **United States**; the country comes from the number itself, so a `+1` number in Jamaica, the Bahamas or Puerto Rico is outside it. The preview applies the dialer settings and reports who is left out and why:

| Skip reason | Why |
| - | - |
| `do_not_call` | The contact is flagged do-not-call or unsubscribed |
| `no_phone` | No phone number on the contact |
| `invalid_phone` | The number cannot be normalised to E.164 with `default_country` |
| `unsupported_country` | The number is outside the United States (or its country cannot be told) |
| `recently_called` | Called within `skip_recently_called_hours` |
| `max_attempts` | Already has `max_attempts_per_contact` finished calls |
| `duplicate_phone` | Another contact earlier in the list has the same number |

A session holds at most 500 dialable contacts (`truncated: true` when the view has more); the first 2,000 contacts of the view are examined. A person then opens the view on the Dialer page and starts dialing. The API does not start sessions; it can only read them afterwards.

## Call scripts

A call script is the text a rep reads during a call. The Dialer page shows it beside the call with the merge fields filled in from the contact being dialed, and highlights the ones it could not fill. Scripts belong to the team; one can be the **default**, which new sessions start with unless the person picks another when they set up the session (the session's `script_id` records which one).

| Field | Notes |
| - | - |
| `name` | 1–120 characters |
| `content` | Plain text, up to 20,000 characters, with merge fields written `{{first_name}}` (case-insensitive; spaces inside the braces are fine). Unknown fields are left as written so a typo is visible |
| `is_default` | At most one script per team. Setting it on one script clears it on the previous default; `false` leaves the team without a default |

Merge fields: `{{first_name}}`, `{{last_name}}`, `{{full_name}}`, `{{company}}`, `{{job_title}}`, `{{email}}`, `{{phone}}` from the contact, and `{{rep_name}}` for the person calling.

```bash theme={null}
curl -X POST https://orbitforms.ai/api/v1/dialer/scripts \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Cold intro", "content": "Hi {{first_name}}, this is {{rep_name}} from Orbit. I saw {{company}} is hiring SDRs...", "is_default": true }'
```

Scripts are read by a person on a call; nothing about them places one. The AI coach is given the session's script, rendered for the contact, so it can judge how closely the conversation followed it.

## Transcripts and AI feedback

With `transcribe_calls` on, every recorded **conversation** (a call a person answered; voicemail and unanswered calls are skipped) is transcribed once it ends, and with `ai_call_feedback` on the AI coach then writes feedback for the rep. Both land on `GET /api/v1/dialer/calls/:id/insights`, one record per call; the call itself carries an `insights` summary with the two statuses so a list can show what is ready. Transcription happens in the background: poll while a status is `queued` or `processing`.

| Field | Meaning |
| - | - |
| `transcript_status` | `queued`, `processing`, `completed`, `failed` or `skipped` (not worth transcribing: voicemail, too short, or the setting was off) |
| `transcript_text` | The whole conversation as speaker-labelled plain text (`Rep: …` / `Contact: …`) |
| `transcript_sentences` | `[{ "speaker": "rep" \| "contact", "start": 1.2, "end": 3.4, "text": "…", "confidence": 0.93 }]`, times in seconds from the start of the recording; `confidence` may be `null` |
| `transcript_language`, `transcript_minutes` | Detected language and the whole minutes of audio transcribed (rounded up); the minutes are metered at the transcription price and show up under `transcript_minutes` in `GET /api/v1/dialer/billing` once billed |
| `transcript_error` | Why a transcript `failed`, when it did |
| `feedback_status` | Same statuses as the transcript; `skipped` when `ai_call_feedback` is off or the workspace had no AI credits left (`feedback_error` says which) |
| `feedback` | The coach's structured feedback (below), or `null` |
| `feedback_model`, `feedback_error` | Which model wrote it; why it `failed`, when it did |
| `script_id` | The script the session used, so `feedback.script_adherence` has something to judge against; `null` when there was none |

`feedback` has this shape:

```json theme={null}
{
  "summary": "Two or three sentences on what happened.",
  "score": 7,
  "went_well": ["Opened with the trigger event", "Asked about the current process"],
  "improve": ["Let the objection on pricing go unanswered"],
  "objections": [{ "objection": "We already use a tool for this", "handled": false, "suggestion": "Ask what the current tool misses before pitching" }],
  "next_steps": ["Send the case study", "Book the follow-up for Thursday"],
  "script_adherence": { "followed": "partly", "notes": "Skipped the qualifying questions" },
  "suggested_outcome": "interested"
}
```

`score` is 1–10 or `null` when the call was too short to judge; `script_adherence.followed` is `yes`, `partly`, `no` or `no_script`; `suggested_outcome` is one of the [outcomes](#outcomes) for the rep to compare with what they picked. The whole record is read-only over the API: the background job writes it.

## Deleting recordings

`DELETE /api/v1/dialer/calls/:id/recording` (or `delete_call_recording` over MCP) removes a call's media: the audio recording is deleted at the carrier, and the transcript, its sentences and the AI feedback are deleted at the transcription service and from Orbit. The call itself stays, with its numbers, timings, `duration_seconds`, outcome and notes, so statistics and the contact's call history are unchanged; its `recording_status` becomes `absent`, its `insights` summary `null`, and `GET /api/v1/dialer/calls/:id/insights` answers `404 not_found` from then on. The deletion is recorded in the workspace's audit log and **cannot be undone**. Admins only (`403 forbidden` otherwise); `409 conflict` when the call has neither a recording nor a transcript.

Deleting a contact also deletes the media of every call made to them, but the two ways of deleting differ when a provider fails. In the dashboard the contact is kept until every call's media is gone, so the delete can simply be retried. `DELETE /api/v1/contacts/:id` purges best effort: if the carrier or transcription service fails for a call, the contact is still deleted and that call keeps its recording or transcript, now with `contact_id: null`. Find such calls with `GET /api/v1/dialer/calls` and remove their media with this endpoint.

```bash theme={null}
curl -X DELETE https://orbitforms.ai/api/v1/dialer/calls/CALL_ID/recording \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

## Do-not-call list

The list is keyed by phone number, stored in E.164 and matched by digits, so `+1 (555) 010-0100` and `5550100100` are the same entry. Numbers in any format are normalised with the team's `default_country`; the response separates `added`, `already_listed` and `invalid`.

* Contacts carrying a listed number are flagged `do_not_call` and skipped by every call list; the pre-dial check blocks them even if a list was built earlier.
* Email unsubscribes and SMS opt-outs add the contact's number automatically (`reason`: `email_unsubscribe`, `sms_opt_out`). The outcome `do_not_call` on a call adds it with `reason: call_outcome`.
* Removing a number from this list does not remove the email unsubscribe or SMS opt-out behind it, and the next unsubscribe adds it back.
* Only admins remove numbers; any credential with `dialer:write` can add them.

```bash theme={null}
curl -X POST https://orbitforms.ai/api/v1/do-not-call \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phones": ["+15550100100", "(555) 010-0101"], "reason": "import", "note": "Legacy suppression file" }'
```

## Responses

Lists return `{ "data": [...], "meta": { "total", "page", "per_page", "total_pages" } }`; single records return `{ "data": {...} }`. Errors return `{ "error", "error_description" }` with a 4xx or 5xx status, for example `403 forbidden` when a non-admin changes `caller_id`, assigns a number or removes a do-not-call entry, `409 conflict` when assigning a number to someone who already holds one or when two callers make different scripts the default at once, `404 not_found` for a call that has no insights yet, and `503 unavailable` when calling is not configured on the instance.

> **[MCP tools](https://docs.orbitforms.ai/mcp/tools.md)**
>
> The same operations as MCP tools

> **[CRM API](https://docs.orbitforms.ai/developers/api/crm.md)**
>
> Saved contact views and the rest of the CRM


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.