# API: Phone menus and transfers

| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | `/v1/voice/ivr/menus` | Phone menus (hosted IVR) per number, and the numbers that can take one | `settings:read` |
| POST | `/v1/voice/ivr/menus` | Create a phone menu (owner): menus (keys or spoken words), messages, a business-hours branch; routes to the voice agent, a ring group, voicemail or another node. Off until enabled | `settings:write` |
| DELETE | `/v1/voice/ivr/menus/:id` | Delete a phone menu (owner): the number's own inbound routing answers again | `settings:write` |
| PUT | `/v1/voice/ivr/menus/:id` | Change a phone menu (owner): saved as a new version | `settings:write` |
| POST | `/v1/voice/ivr/menus/:id/restore` | Publish an older version again (owner), as a new version | `settings:write` |
| GET | `/v1/voice/ivr/menus/:id/versions` | A phone menu's versions (newest first) | `settings:read` |
| GET | `/v1/voice/ivr/navigations` | Recent phone-tree navigations: goal, each menu heard and key pressed, and how it ended | `calls:read` |
| POST | `/v1/voice/ivr/navigations` | Call a company and navigate its phone tree to a person (sales, support, the operator, someone by name). Placed through the calling gate (window, opt-outs, do-not-call, consent, caller ID, policy); `call_id` instead navigates a call already live | `messages:send` |
| GET | `/v1/voice/ivr/paths` | Learned phone-tree paths per company number and goal (replayed on the next call, re-learned when the menu changes) | `calls:read` |
| DELETE | `/v1/voice/ivr/paths/:id` | Forget a learned path (owner) | `settings:write` |
| GET | `/v1/voice/ivr/sessions` | Recent calls through a phone menu: the path taken (keys, words, retries) and the route | `calls:read` |
| POST | `/v1/voice/ivr/simulate` | Try a phone menu without a call: its problems, and what happens to a caller who presses these keys or says these words | `settings:read` |
| GET | `/v1/voice/transfer/queues` | Transfer queues: who the AI hands live calls to (account owner first, then members by skill, round-robin), seconds to accept, attempts, fallback | `settings:read` |
| POST | `/v1/voice/transfer/queues` | Add a transfer queue (owner) | `settings:write` |
| DELETE | `/v1/voice/transfer/queues/:id` | Delete a transfer queue (owner) | `settings:write` |
| PUT | `/v1/voice/transfer/queues/:id` | Change a transfer queue (owner) | `settings:write` |
| GET | `/v1/voice/transfers` | Recent warm transfers with their legs and timings, and time to a person (p50/p95) and the success rate | `calls:read` |
| POST | `/v1/voice/transfers` | Hand a live call to a person now (warm: they get the context and accept with 1) | `messages:send` |
| GET | `/v1/voice/transfers/:id` | A transfer's screen pop: the caller, account, deal, reason, summary and transcript so far (withheld when the caller objected to recording), every leg | `transcripts:read` |
| POST | `/v1/voice/transfers/:id/pass` | Pass on a transfer ringing you (the next person is rung) | `calls:write` |

## Examples

### GET /v1/voice/ivr/menus

Phone menus (hosted IVR) per number, and the numbers that can take one

```bash
curl -s "https://api.closefinch.com/v1/voice/ivr/menus" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/menus`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/ivr/menus

Create a phone menu (owner): menus (keys or spoken words), messages, a business-hours branch; routes to the voice agent, a ring group, voicemail or another node. Off until enabled

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/ivr/menus" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/menus`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### DELETE /v1/voice/ivr/menus/$ID

Delete a phone menu (owner): the number's own inbound routing answers again

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/voice/ivr/menus/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/menus/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PUT /v1/voice/ivr/menus/$ID

Change a phone menu (owner): saved as a new version

```bash
curl -s -X PUT "https://api.closefinch.com/v1/voice/ivr/menus/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/menus/${id}`, {
  method: "PUT",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/voice/ivr/menus/$ID/restore

Publish an older version again (owner), as a new version

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/ivr/menus/$ID/restore" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/menus/${id}/restore`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/ivr/menus/$ID/versions

A phone menu's versions (newest first)

```bash
curl -s "https://api.closefinch.com/v1/voice/ivr/menus/$ID/versions" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/menus/${id}/versions`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/voice/ivr/navigations

Recent phone-tree navigations: goal, each menu heard and key pressed, and how it ended

```bash
curl -s "https://api.closefinch.com/v1/voice/ivr/navigations" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/navigations`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/ivr/navigations

Call a company and navigate its phone tree to a person (sales, support, the operator, someone by name). Placed through the calling gate (window, opt-outs, do-not-call, consent, caller ID, policy); `call_id` instead navigates a call already live

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/ivr/navigations" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/navigations`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/ivr/paths

Learned phone-tree paths per company number and goal (replayed on the next call, re-learned when the menu changes)

```bash
curl -s "https://api.closefinch.com/v1/voice/ivr/paths" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/paths`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### DELETE /v1/voice/ivr/paths/$ID

Forget a learned path (owner)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/voice/ivr/paths/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/paths/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/voice/ivr/sessions

Recent calls through a phone menu: the path taken (keys, words, retries) and the route

```bash
curl -s "https://api.closefinch.com/v1/voice/ivr/sessions" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/sessions`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/ivr/simulate

Try a phone menu without a call: its problems, and what happens to a caller who presses these keys or says these words

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/ivr/simulate" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/ivr/simulate`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/transfer/queues

Transfer queues: who the AI hands live calls to (account owner first, then members by skill, round-robin), seconds to accept, attempts, fallback

```bash
curl -s "https://api.closefinch.com/v1/voice/transfer/queues" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfer/queues`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/transfer/queues

Add a transfer queue (owner)

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/transfer/queues" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfer/queues`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### DELETE /v1/voice/transfer/queues/$ID

Delete a transfer queue (owner)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/voice/transfer/queues/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfer/queues/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PUT /v1/voice/transfer/queues/$ID

Change a transfer queue (owner)

```bash
curl -s -X PUT "https://api.closefinch.com/v1/voice/transfer/queues/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfer/queues/${id}`, {
  method: "PUT",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/transfers

Recent warm transfers with their legs and timings, and time to a person (p50/p95) and the success rate

```bash
curl -s "https://api.closefinch.com/v1/voice/transfers" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfers`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/transfers

Hand a live call to a person now (warm: they get the context and accept with 1)

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/transfers" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfers`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/voice/transfers/$ID

A transfer's screen pop: the caller, account, deal, reason, summary and transcript so far (withheld when the caller objected to recording), every leg

```bash
curl -s "https://api.closefinch.com/v1/voice/transfers/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfers/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/voice/transfers/$ID/pass

Pass on a transfer ringing you (the next person is rung)

```bash
curl -s -X POST "https://api.closefinch.com/v1/voice/transfers/$ID/pass" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/voice/transfers/${id}/pass`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

Request and response schemas: [https://www.closefinch.com/openapi.json](https://www.closefinch.com/openapi.json). All resources: [API reference](https://www.closefinch.com/docs/api).
