---
title: MCP recipes
description: Worked tasks for the Queue CallBack MCP server: example prompts, tool calls in order with arguments, what comes back, scopes and pitfalls.
status: Stable
last_updated: 2026-11-05
canonical: https://queuecallback.com/docs/mcp/recipes
---

# MCP recipes

This page walks through nine everyday tasks done through the Queue CallBack MCP server: for each, an example prompt, the tool calls an agent makes in order with their key arguments, what comes back, the scopes it needs and the pitfalls. The reporting tasks only read. The callback, queue, organization and IVR tasks change something, and each says how the change is confirmed.

> For AI agents: this page is also available as Markdown at https://queuecallback.com/docs/mcp/recipes.md. The whole MCP documentation in one file: https://queuecallback.com/docs/llms-full.txt

How to read the examples:

- Values in angle brackets, such as `"<queue id>"`, are placeholders. Take every id from a list or get tool earlier in the same conversation. Never invent an id or a token.
- Responses are trimmed to the fields the task needs. A successful call answers with one JSON object, both in `structuredContent` and as JSON text. A refused call sets `isError: true`, explains the fix in plain text, and puts `code` (and `retry_after_seconds` where retrying helps) in `structuredContent.error`.
- Tool names are shown bare (`get_callback_summary`). Your client may prefix them, for example `mcp__queuecallback__get_callback_summary`.
- Every argument is listed in the tool reference, for example [the `get_callback_summary` reference](/docs/mcp/tools#get_callback_summary).

## Recipes at a glance

| Recipe | Scopes | Changes something | Confirmation |
|---|---|---|---|
| [Yesterday's callbacks by queue](#yesterdays-callbacks-by-queue) | `reports:read` | No | None |
| [One caller's journey](#one-callers-journey) | `reports:read` (`pii:read` to search by number) | No | None |
| [Waiting callbacks right now](#waiting-callbacks-right-now) | `reports:read`, `callbacks:read` | No | None |
| [IVR menu choices last week](#ivr-menu-choices-last-week) | `reports:read`, as an organization admin with the Custom IVR add-on | No | None |
| [Complete a callback by hand](#complete-a-callback-by-hand) | `callbacks:read`, `callbacks:write` | Yes, places no call | The agent asks the user |
| [Requeue an expired callback](#requeue-an-expired-callback) | `callbacks:read`, `callbacks:dial` | Yes, places real calls | Approval prompt on every call, two-call confirm token |
| [Change a queue's callback settings, voice or language](#change-a-queues-callback-timeout-and-requeue-settings) | `queues:read`, `queues:write` | Yes | Approval prompt on every call, two-call confirm token |
| [Rename the organization](#rename-the-organization) | `org:read`, `org:write` | Yes | The agent asks the user |
| [A small IVR change](#a-small-ivr-change-preview) (Preview) | `ivr:read`, `ivr:write`, `ivr:publish` | Yes, callers hear it after publish | Approval prompt on `publish_flow`, token from `validate_flow` |

Claude Code asks the user before every call of the tools marked "Approval prompt on every call", even when an allow rule matches. Other clients, Claude Desktop through `mcp-remote` included, may not, so the agent also asks in the conversation ([approval prompts](/docs/mcp/safety#approval-prompts)). For the tasks marked "The agent asks the user", no client prompt is forced, so the agent confirms in the conversation before it calls the tool. Queue CallBack can switch changes off on the server; while it is off, clients see only the read-only tools. The full scope list is on [the access page](/docs/mcp/access#scopes).

## Before you start

Call `get_me` first. It takes no arguments and needs no scope. Read these fields from its answer:

| Field | What it tells the agent |
|---|---|
| `scopes` | The scopes that take effect for this key. A recipe whose scopes are missing will not find its tools. |
| `pii_allowed` | `false`: caller and callback numbers keep only their last four digits (`+*******4567`), keyed-in digits read `[redacted]`, and searching by phone number is refused. See [caller data](/docs/mcp/safety#caller-data). |
| `custom_ivr_enabled` | `false`: the IVR flow tools are not listed. |
| `ivr_reporting_enabled` | `false`: the five IVR report tools are not listed, so the IVR recipe cannot run. The callback reports still work. |
| `role` | The role the key acts with, for example `org_admin`. Queue settings changes and renames need an organization admin. |

[Check the connection](/docs/mcp/connect#check-the-connection) shows a full `get_me` answer.

## Time zones in reports

Queue CallBack reports count days and show times in a time zone, and the default is `America/New_York`. An agent that leaves the zone out gives a wrong answer to anyone outside US Eastern time, with no error.

| Tools | Argument | Default |
|---|---|---|
| `get_callback_summary`, `list_callbacks`, `get_callback_journey`, `get_ivr_summary`, `list_ivr_calls`, `get_flow_decisions`, `get_live_stats` | `tz` (`get_live_stats` also still accepts `timezone`, the deprecated old name) | `America/New_York` |
| `list_callback_queue` | none: `time_range` is a rolling window (`1h`, `24h`, `7d`, `30d`); `today` also means the last 24 hours, not since midnight | — |

- Pass an IANA zone name such as `America/Chicago`, `Europe/London` or `Australia/Sydney`. The zone sets where each day starts and ends, the buckets of a series, and the offset of every time in the answer. For `get_live_stats`, today runs from local midnight to the next local midnight in that zone.
- An unknown name is refused with HTTP 400 and changes nothing: "Invalid tz: must be an IANA timezone name" from most tools, and the code `invalid_timezone` from `get_live_stats`. Fix the name; do not retry it unchanged.

- `get_organization` carries no time zone. Ask the user which zone their reports use, and name the zone in the answer.
- `preset` is `today`, `yesterday`, `7d` (the default), `30d` or `90d`. `7d` means the last 7 days including today, not last calendar week.
- For a calendar week or month, send `from` and `to` (`YYYY-MM-DD`, both days included, in `tz`). Together they replace `preset`. One request spans at most 400 days by default.

## Yesterday's callbacks by queue

The task: yesterday's callback totals, completion rate and waits, split by queue.

Example prompt: "How did yesterday go? Callbacks per queue, the completion rate and the median wait. We're on Central time."

Scopes: `reports:read`.

1. Call `get_callback_summary` for the whole organization:

   ```json
   {"preset": "yesterday", "tz": "America/Chicago"}
   ```

   It returns (trimmed):

   ```json
   {
     "totals": {"completed": 41, "expired": 5, "failed": 1, "cancelled": 2, "active": 0, "total": 49},
     "completionRate": 83.67,
     "waitMedianSeconds": 210,
     "waitAvgSeconds": 254.3,
     "bucket": "hour",
     "series": [{"t": "2026-11-04T09:00:00-06:00", "completed": 6, "expired": 1, "failed": 0, "cancelled": 0, "waitMedianSeconds": 195, "waitAvgSeconds": 220.5}],
     "byQueue": [
       {"configurationId": "<queue id>", "name": "Main line", "extensionNumber": "8001", "count": 31},
       {"configurationId": "<queue id>", "name": "Billing", "extensionNumber": "8002", "count": 18}
     ],
     "topAgents": [{"agentName": "<agent name>", "agentExtensionNumber": "101", "count": 12, "waitMedianSeconds": 190}],
     "liveNow": {"waiting": 2, "inProgress": 1}
   }
   ```

2. For one queue's statuses and waits, call `get_callback_summary` again with that queue's `configurationId` as `queue_id`:

   ```json
   {"preset": "yesterday", "tz": "America/Chicago", "queue_id": "<queue id>"}
   ```

What the fields mean:

- `completionRate` is completed callbacks as a percentage of finished ones (0 when none finished). Completed covers callbacks where an agent took the callback and the transfer to the customer was started, and callbacks marked complete by hand with `complete_callback` (`transferMethod` `manual` in `list_callbacks`).
- `waitMedianSeconds` and `waitAvgSeconds` cover completed callbacks, and are `null` when none completed.
- `byQueue` gives only a `count` per queue, most first. `name` reads `(deleted)` for a queue that no longer exists.
- `topAgents` lists agents by completed callbacks, at most 50.
- `liveNow` counts callbacks waiting and being put through right now, whatever the date range.

Pitfalls:

- `tz` defaults to `America/New_York`.
- Without `status`, only finished callbacks are counted (`completed`, `expired`, `failed`, `cancelled`). To include callbacks from that day that are still open, send `"status": "completed,expired,failed,cancelled,active"`.
- With `bucket` left at `auto`, the series uses hours for ranges up to 2 days and days for longer ones.
- A busy reporting service refuses with a retry delay. Wait `retry_after_seconds`, then repeat ([retries](/docs/mcp/errors#retries)).

## One caller's journey

The task: find one callback and show what happened to it, including the IVR steps of the call it came from.

Example prompt: "A customer whose number ends in 4567 says nobody called back yesterday afternoon. What happened?"

Scopes: `reports:read`. Searching by phone number also needs an effective `pii:read` (`pii_allowed: true` in `get_me`).

1. Find the callback with `list_callbacks`. With `pii_allowed: true`, search by number. Send digits only, without spaces or dashes: the search matches part of the number as it is stored.

   ```json
   {"preset": "yesterday", "tz": "America/Chicago", "status": "completed,expired,failed,cancelled,active", "search": "4567"}
   ```

   With `pii_allowed: false`, a search made only of digits and phone punctuation is refused with `insufficient_scope`. Leave `search` out, narrow with `queue_id` or `agent`, and scan the masked numbers for the last four digits:

   ```json
   {"preset": "yesterday", "tz": "America/Chicago", "status": "completed,expired,failed,cancelled,active", "sort": "created", "dir": "asc", "limit": 100}
   ```

   It returns `callbacks` (each with `id`, `createdAt`, `callbackNumber`, `callerNumber`, `status`, `waitSeconds`, `agentName`, `configurationName`, `attemptCount`, `requeueCount`, `source`) plus `total`, `limit` and `offset`. For the next page, raise `offset` by `limit`.

2. Call `get_callback_journey` with the callback's `id`:

   ```json
   {"callback_id": "<callback id>", "tz": "America/Chicago"}
   ```

   It returns (trimmed, masked key):

   ```json
   {
     "callback": {
       "id": "<callback id>",
       "createdAt": "2026-11-04T14:10:00-06:00",
       "callbackNumber": "+*******4567",
       "status": "expired",
       "waitSeconds": null,
       "configurationName": "Billing",
       "attemptCount": 2,
       "requeueCount": 0,
       "expiresAt": "2026-11-04T15:10:00-06:00",
       "transferInitiatedAt": null,
       "completedAt": null
     },
     "ivrSteps": [
       {"index": 0, "nodeName": "Greeting", "nodeType": "<node type>", "enteredAt": "2026-11-04T14:09:20-06:00", "durationMs": 4000, "input": null, "route": null, "error": null, "branch": "default"},
       {"index": 1, "nodeName": "Main menu", "nodeType": "<node type>", "enteredAt": "2026-11-04T14:09:24-06:00", "durationMs": 5000, "input": "[redacted]", "route": null, "error": null, "branch": "input_equals:2"}
     ]
   }
   ```

   `waitSeconds` is `null` for an expired, failed or cancelled callback that never reached an agent. For a callback still waiting, it counts up to now.

Pitfalls:

- `tz` defaults to `America/New_York`, so "yesterday afternoon" can fall on the wrong day without it.
- Without `status`, `list_callbacks` lists only finished callbacks; callbacks still open need `active`.
- Several callers can share the last four digits. Confirm the match with the user by time and queue before acting on it.
- Without `pii:read`, each step's `input` reads `[redacted]` and phone numbers in `route` and `error` are masked.
- `ivrSteps` is empty when the callback did not come from an IVR call.

## Waiting callbacks right now

The task: how many callbacks are waiting now, and which ones.

Example prompt: "How many callbacks are waiting right now, and which have been waiting longest?"

Scopes: `reports:read` for the counts, `callbacks:read` for the list.

1. Call `get_live_stats` with the user's zone in `tz`:

   ```json
   {"tz": "America/Chicago"}
   ```

   It returns (trimmed):

   ```json
   {
     "success": true,
     "data": {
       "totalQueued": 3,
       "totalActive": 1,
       "totalProcessing": 0,
       "totalRetry": 0,
       "queueDepth": 3,
       "totalCompleted": 22,
       "totalFailed": 0,
       "totalExpired": 2,
       "totalCancelled": 1,
       "successRate": 88,
       "userTimezone": "America/Chicago",
       "todayStart": "2026-11-05T00:00:00-06:00",
       "todayEnd": "2026-11-06T00:00:00-06:00",
       "refreshRate": 30
     }
   }
   ```

   `totalQueued`, `totalActive` (in their call now), `totalProcessing` and `totalRetry` count callbacks by their current status, with no time limit. `queueDepth` is `totalQueued` plus `totalProcessing`. `totalCompleted`, `totalFailed`, `totalExpired` and `totalCancelled` count callbacks created between `todayStart` and `todayEnd`: the local day in `tz`, from midnight to midnight, shown with the zone's offset. `successRate` is `totalCompleted` as a percentage of those four counts together.

2. List the open callbacks with `list_callback_queue`. Without `time_range`, `status` `active` lists every open callback, however old:

   ```json
   {"status": "active", "limit": 50}
   ```

   It returns `callbacks` (each with `id`, `callbackNumber`, `status`, `attemptCount`, `requeueCount`, `nextAttempt`, `expiresAt`, `createdAt`, `agentName`; `requeueCount` here repeats `attemptCount`) plus `total`, `page`, `pageSize`, `totalPages` and `hasNextPage`. The list is newest first, so the longest-waiting callbacks are at the end of the last page.

Pitfalls:

- `tz` defaults to `America/New_York`. `get_live_stats` still accepts `timezone`, the old name of `tz`; send `tz`. If both are sent, they must name the same zone, or the call is refused.
- `list_callback_queue` pages with `page` (from 1), not `offset`. Its `status` field shows the raw status, such as `queued`. `active` as a filter means every callback not completed, failed, expired or cancelled; it does not mean every row is waiting to be dialed now, so read each row's `status` and `nextAttempt`. New statuses can appear: treat a status you do not know as open, not final.
- Sending `time_range` with `status` `active` narrows the list to callbacks created in that window.
- These are point-in-time reads, not a stream. Call again for fresh numbers; `refreshRate` is the seconds between refreshes the server recommends.

## IVR menu choices last week

The task: which options callers chose in an IVR menu during last calendar week, and where they hung up.

Example prompt: "Which menu options did callers pick on the main line last week, Monday to Sunday, and where did they drop off?"

Scopes: `reports:read`. The IVR call reports are for organization admins of organizations with the Custom IVR add-on: `get_me` must show `ivr_reporting_enabled: true`. Otherwise the tools below are not listed, and a call to one answers [`ivr_reporting_not_enabled`](/docs/mcp/errors#ivr_reporting_not_enabled).

1. Pick the flow with `list_ivr_flow_stats` (no arguments needed). It returns `flows`, most used first, each with `flowId`, `name`, `configurationName`, `extensionNumber`, `totalCalls` and `lastUsedAt`.

2. Call `get_flow_decisions` with explicit dates (here, for a request made on Thursday 2026-11-05):

   ```json
   {"flow_id": "<flow id>", "from": "2026-10-26", "to": "2026-11-01", "tz": "America/Chicago"}
   ```

   It returns (trimmed, masked key):

   ```json
   {
     "flowId": "<flow id>",
     "flowName": "Main line callback flow",
     "nodes": [
       {
         "nodeId": "<node id>",
         "name": "Main menu",
         "nodeType": "<node type>",
         "hits": 420,
         "endedHereCount": 18,
         "isBranching": true,
         "branches": [
           {"condition": "input_equals:1", "targetNodeId": "<node id>", "targetName": "Sales", "count": 250, "isSelfLoop": false},
           {"condition": "input_equals:2", "targetNodeId": "<node id>", "targetName": "Request a callback", "count": 152, "isSelfLoop": false}
         ],
         "variable": "menu_choice",
         "topValues": [{"value": "[redacted]", "count": 250}, {"value": "[redacted]", "count": 152}]
       }
     ]
   }
   ```

3. Optional: `get_ivr_summary` with the same `flow_id`, `from`, `to` and `tz` gives outcome rates (handed off, callback requested, completed, abandoned) and the nodes where abandoned calls ended.

What the fields mean: `hits` counts how many times calls entered the node (a caller who hears the menu twice counts twice), `endedHereCount` counts calls whose last node it was (the drop-off), and `branches` lists the exits calls took, most first.

Pitfalls:

- `preset` `7d` is the last 7 days including today, not last calendar week. Use `from` and `to`.
- `tz` defaults to `America/New_York`.
- Without `pii:read`, `topValues[].value` reads `[redacted]`; the counts stay. The `caller` filter needs `pii:read`.
- `branches` is empty for a node that does not branch.

## Complete a callback by hand

The task: mark an open callback as done so it leaves the queue and is not dialed again.

Example prompt: "The customer on the 9:40 callback in the support queue already reached us by email. Take it out of the queue."

Scopes: `callbacks:read`, `callbacks:write`.

1. Find the callback and check it is still open with `list_callback_queue`:

   ```json
   {"status": "active", "time_range": "24h"}
   ```

   `list_callback_queue` rows name no queue. When `metadata` carries `configuration_id`, match it against the `id` values from `list_queues` (needs `queues:read`). Otherwise find the callback with `list_callbacks` and `"status": "active"` (needs `reports:read`), whose rows carry `configurationName`.

2. Show the user the callback (queue, time, masked number) and get a clear yes. `complete_callback` has no confirm token and no forced approval prompt, so the agent must ask.

3. Call `complete_callback`:

   ```json
   {"callback_id": "<callback id>"}
   ```

   It returns:

   ```json
   {"message": "Callback completed successfully", "id": "<callback id>", "completedBy": "Claude Code (API key)"}
   ```

   `completedBy` is the API key's name followed by `(API key)`. `agentName` is added when an agent took the call.

Pitfalls:

- `complete_callback` places no call. The callback's status becomes `completed` with transfer method `manual`, so it counts as completed in callback reports and in the completion rate.
- A callback already completed or cancelled answers 404. A retry of a call that worked also answers 404, so check `list_callback_queue` before telling the user it failed.
- There is no undo: `requeue_callback` takes only expired, failed or cancelled callbacks.

## Requeue an expired callback

The task: put an expired callback back in the queue. This places real calls: the dialer rings the queue and, once an agent answers, calls the customer.

Example prompt: "The 2:10 pm callback on the billing queue expired before anyone took it. Requeue it."

Scopes: `callbacks:read` and `callbacks:dial`. The portal never preselects `callbacks:dial`, and it warns that the scope places real phone calls and belongs only to a client you trust to dial.

1. Find the callback with `list_callback_queue`:

   ```json
   {"status": "expired", "time_range": "24h"}
   ```

   Check that its `status` is `expired`, `failed` or `cancelled`, and note which one it is. In `list_callback_queue`, `requeueCount` repeats `attemptCount`; read the real requeue count from `get_callback_journey` or `list_callbacks` (both need `reports:read`).

   `list_callback_queue` rows name no queue. When `metadata` carries `configuration_id`, match it against the `id` values from `list_queues` (needs `queues:read`). Otherwise find the callback with `list_callbacks` and `"status": "expired"` (needs `reports:read`), whose rows carry `configurationName`.

2. Show the user which callback will be dialed (queue, time, masked number).

3. First call of `requeue_callback`, without a token. It changes nothing and sends nothing to the Queue CallBack API:

   ```json
   {"callback_id": "<callback id>"}
   ```

   It returns:

   ```json
   {
     "confirmation_required": true,
     "tool": "requeue_callback",
     "will_apply": {"callback_id": "<callback id>"},
     "confirm_token": "<confirm token>",
     "confirm_expires_at": "2026-11-05T20:25:00Z",
     "message": "Nothing was changed yet. Show the user what requeue_callback will change. Once they agree, call requeue_callback again with the same arguments and confirm_token set to confirm_token (single use, valid until confirm_expires_at). Send an idempotency_key with that call and reuse it on any retry, so the change is never applied twice."
   }
   ```

4. Once the user agrees, the second call with the token and a fresh `idempotency_key` (letters, digits, `. _ : -`, at most 255 characters; a random UUID works). The confirm token is bound to `callback_id` only, and the first call sends nothing to the Queue CallBack API, so the key matters only on this second call: send it here.

   ```json
   {"callback_id": "<callback id>", "confirm_token": "<confirm token>", "idempotency_key": "<fresh random key>"}
   ```

   It returns (trimmed):

   ```json
   {
     "request_id": "<request id>",
     "callback_id": "<callback id>",
     "status": "pending",
     "handle": "<handle>",
     "handle_expires_at": "2026-11-06T20:16:00Z",
     "handle_status_tool": "get_requeue_status"
   }
   ```

5. Follow it with `get_requeue_status` every few seconds until `status` is `succeeded`, `failed`, `conflict` or `interrupted`. A requeue can take about a minute.

   ```json
   {"handle": "<handle>"}
   ```

   It returns (trimmed):

   ```json
   {
     "request_id": "<request id>",
     "callback_id": "<callback id>",
     "status": "succeeded",
     "mode": "async",
     "idempotency_key": "<fresh random key>",
     "completed_at": "2026-11-05T20:16:40Z",
     "result": {"http_status": 200, "body": {"message": "Callback requeued successfully", "callback_id": "<callback id>"}},
     "handle_kind": "requeue"
   }
   ```

Claude Code shows the approval prompt on every call of `requeue_callback`, the first call included. Other clients, Claude Desktop through `mcp-remote` included, may not, so the agent also asks in the conversation.

Never re-run a requeue without checking. If the answer to step 4 was lost, or came back as `backend_timeout`:

1. Do not repeat step 4 with the same token. The token was spent when the call ran, so the repeat answers `confirm_refused` with `confirm_token_spent: true`. A second call that failed says so itself: its error carries `confirm_token_spent: true` and a `next_step` with the steps below.
2. If you have the handle, call `get_requeue_status`. If not, call `list_callback_queue` with `"search": "<callback id>"` and `"time_range": "30d"`. A requeued callback is back in `queued` (or a later status). Confirm with `requeueCount` from `get_callback_journey` (needs `reports:read`).
3. If it was not requeued and the user still wants it: make the first call again for a new token, get the user's yes, then send the second call with the same `idempotency_key` as before. If the first attempt reached Queue CallBack, this returns that attempt's recorded status (and a handle) instead of dialing again. If it never arrived, the requeue runs now, once.
4. If the recorded status is `failed` or `conflict` and the user still wants the requeue, make a new first call and send a new `idempotency_key`. The old key only replays the failed attempt.

Pitfalls:

- `interrupted` means the server stopped before recording the outcome. Check the callback before requeueing again.
- At most 5 requeues per callback in 24 hours by default; more answers `requeue_limit_reached`.
- A callback that is still waiting cannot be requeued; the API refuses it.
- Idempotency keys are unique per organization. A key already used for another callback answers `idempotency_key_reused`, so use a fresh random key for each requeue.
- The confirm token is single use, valid 10 minutes and bound to `callback_id` ([confirm tokens](/docs/mcp/safety#confirm-tokens)).

## Change a queue's callback timeout and requeue settings

The task: change how long callbacks wait before they expire, and whether and how often expired callbacks are dialed again.

Example prompt: "On the support queue, let callbacks wait 30 minutes before they expire, and requeue expired ones up to 3 times."

Scopes: `queues:read`, `queues:write`. The key's creator must be an organization admin. The queue itself is created in the portal; these tools change its settings.

| Portal label | Argument | Values |
|---|---|---|
| **Queue Timeout (minutes)** | `callback_timeout_minutes` | 1 to 1440 |
| **Auto-Requeue Expired Callbacks** | `auto_requeue` | `true` or `false` |
| **Max Requeue Attempts** | `max_requeue_attempts` | 1 to 10 |
| **Manual Callback Only** | `manual_callback` | `true` or `false`; stored and shown in the portal, nothing in the call path reads it |

1. Find the queue with `list_queues` (no arguments needed). It returns `configurations`, each with `id` and `name`.

2. Read the current values with `get_queue`:

   ```json
   {"queue_id": "<queue id>"}
   ```

   The answer carries `callback_timeout_minutes`, `auto_requeue`, `max_requeue_attempts` and `manual_callback`, among the queue's other settings.

3. Show the user each current value next to the new one.

4. First call of `update_queue_settings`, without a token. It changes nothing:

   ```json
   {"queue_id": "<queue id>", "callback_timeout_minutes": 30, "auto_requeue": true, "max_requeue_attempts": 3}
   ```

   It returns `confirmation_required: true`, `tool: "update_queue_settings"`, `will_apply` (the arguments above, echoed), a single-use `confirm_token`, `confirm_expires_at` (10 minutes) and a `message` that says nothing was changed yet.

5. Once the user agrees, repeat exactly the same arguments with the token:

   ```json
   {"queue_id": "<queue id>", "callback_timeout_minutes": 30, "auto_requeue": true, "max_requeue_attempts": 3, "confirm_token": "<confirm token>"}
   ```

   It returns:

   ```json
   {
     "queue_id": "<queue id>",
     "settings": {"callback_timeout_minutes": 30, "max_requeue_attempts": 3, "auto_requeue": true, "manual_callback": false},
     "changes": [
       {"field": "callback_timeout_minutes", "from": 60, "to": 30, "takes_effect": "applies to callbacks queued from now on; callbacks already waiting keep their expiry"},
       {"field": "auto_requeue", "from": false, "to": true, "takes_effect": "applies at the next expiry of every callback of the queue, those already waiting included"}
     ],
     "updated_at": "2026-11-05T20:31:02Z",
     "message": "2 setting(s) changed (changes says when each takes effect). The queue keeps running and was not re-registered."
   }
   ```

   A setting that already had the new value is not listed in `changes`. Here `max_requeue_attempts` was already 3.

Pitfalls:

- `will_apply` only echoes the arguments; nothing is read from the queue. Read `get_queue` before the first call to show what changes.
- The second call must send the same settings with the same values. Adding, dropping or changing one answers `confirm_refused` and changes nothing; make the first call again.
- Give at least one setting. Only the settings given change. The queue keeps running, and its voice, extensions and status stay as they are. The requeue delay cannot be set.
- Out-of-range values are refused on the first call, before a token is issued.
- An organization can make a few settings changes at once, then about one a minute; more answers `queue_write_limited` with `retry_after_seconds`. A call that changes nothing is not counted.
- If Queue CallBack has switched queue settings changes off, `update_queue_settings` is not listed or answers `queue_settings_disabled`. Change the settings in the portal under **Configurations**.

A queue's voice or language changes the same way, in two calls with a confirm token, after the user agrees:

- Voice: `list_voices` for an active voice id, `get_queue` for the current voice, then `set_queue_voice` with `queue_id`, `voice` and optionally `speed` (0.5 to 2.0).
- Language: `get_queue` for the current language, then `set_queue_language` with `queue_id` and `language` (`en-US`, `es-ES` or `fr-FR`).
- A stored change reaches the queue's next callers. The server first renders the queue's prompts in the new voice or language (up to 15 seconds), and the answer's `warm` says what is still being prepared, so prefer a quiet time. Voice and language changes count against their own `queue_write_limited` limit.

## Rename the organization

The task: change the organization's name.

Example prompt: "Rename our organization to Example Plumbing and Heating."

Scopes: `org:read`, `org:write`. The key's creator must be an organization admin.

1. Read the current name with `get_organization` (no arguments). It returns `id`, `name`, `created_at` and `assistant_enabled`.

2. Confirm the exact new name with the user, spelling and capitals included.

3. Call `set_organization_name`:

   ```json
   {"name": "Example Plumbing and Heating"}
   ```

   It returns:

   ```json
   {"message": "Organization updated successfully", "updated_at": "2026-11-05T20:40:00Z"}
   ```

4. Optional: call `get_organization` again to show the new name.

Pitfalls:

- `set_organization_name` runs on the first call: no confirm token and no forced approval prompt. The agent must confirm first.
- Every user of the organization sees the new name in the portal.
- The name is 1 to 200 characters.
- About one rename every 6 seconds; faster answers 429.

## A small IVR change (Preview)

The task: change one step of an IVR flow and publish it, with the user seeing the change first. The IVR tools are Preview: node types, their fields and validation messages will change, so discover them at runtime ([node types](/docs/mcp/ivr#node-types)). The full loop, with restore and discard, is in [Edit a flow safely](/docs/mcp/ivr#edit-a-flow-safely).

Example prompt: "In the main line flow, change the greeting to say we close at 6 pm on Fridays. Show me the change before it goes live."

Scopes: `ivr:read`, `ivr:write`, `ivr:publish`. The organization needs the Custom IVR add-on (`custom_ivr_enabled: true`) and must edit its flows through drafts.

1. `list_flows` (no arguments needed) to find the flow's `id`.
2. `get_flow` with `{"flow_id": "<flow id>"}` to read the nodes, each node's config, and `draft.etag`.
3. Optional: `create_flow_draft` with `{"flow_id": "<flow id>"}` opens a draft without changing anything (`edit_flow_draft` starts one from the live graph by itself). It returns `created`, `etag` and `message`. Callers keep hearing the live flow.
4. `get_node_type` for the node's type, if the config needs a field you have not seen.
5. `edit_flow_draft` with one operation. `config_json` replaces the whole config, so start from the config `get_flow` returned:

   ```json
   {
     "flow_id": "<flow id>",
     "etag": "<draft.etag from get_flow, or the etag from create_flow_draft if you called it>",
     "ops": [
       {"op": "update_node", "node_id": "<node id>", "name": "", "config_json": "<the node's whole config with the one change, as a JSON-encoded string>"}
     ]
   }
   ```

   An empty `name` keeps the current name. The answer carries the new etag.
6. `validate_flow` with `{"flow_id": "<flow id>"}`. It returns `valid`, `errors`, `warnings`, `digest`, `draft.base_version`, `confirm_token` and `confirm_for: "publish_flow"`.
7. `diff_flow` with `{"flow_id": "<flow id>"}`. The default compares the published version with the draft, which is exactly what a publish changes. Show it to the user.
8. Once the user agrees, `publish_flow` (asks for approval on every call):

   ```json
   {"flow_id": "<flow id>", "expected_digest": "<digest from validate_flow>", "base_version": 4, "confirm_token": "<confirm token from validate_flow>"}
   ```

   It returns `message`, `version` (with `version_number`) and `changes`. When prompts are still being rendered, it also returns a `handle` for `get_publish_status`.

Pitfalls:

- A stale etag answers `revision_mismatch` with the current etag, and nothing changes. Read the flow again before retrying.
- Any edit after `validate_flow` makes the publish fail. Validate again for a new digest and token.
- An organization that edits flows live, not through drafts, is refused; use the portal's flow builder.
