Let an AI agent — Claude, Grok, Cursor, Codex, and more — operate your RingTonic account in plain language: campaigns, call tracking, contacts, call flows, appointments, and analytics, over the same services the dashboard and REST API use. 51 tools, one endpoint.
POST https://ringtonic.app/mcp
Available only on ringtonic.app. MCP is RingTonic-branded, so it never runs on a white-label agency domain.
rt_ key is shown once — copy it.Every request carries a bearer token — a RingTonic personal access token minted for MCP:
Authorization: Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
MCP keys are user-bound, not workspace-bound: one key reaches every workspace where its creator is an owner or admin, narrowed by the scopes you grant. Reach is checked on every call — remove or demote the member and the key loses that workspace immediately. A key always carries at least one resource scope; a REST API key or an all-abilities key is rejected and never reaches the server.
Every tool that touches account data takes a workspace — a
workspace public uuid (stable and canonical) or an exact name (a convenience;
names are not unique and can be renamed, so prefer the uuid). When your key reaches exactly one workspace the
parameter is optional and defaults to it. When unsure, ask
“which accounts can I manage?” first — that lists each workspace's uuid, your role, its timezone and
currency, and whether its plan enables the API. An unreachable workspace or a foreign uuid answers
not-found — the same as one that does not exist, so nothing leaks
across accounts.
A key grants only what you select. A call to a tool the key lacks answers
insufficient-scope, and the tool never appears in the agent's
tool list. Grant narrowly — a read-only key yields a read-only agent.
| Scope | Grants |
|---|---|
campaigns:read / campaigns:write |
List and read campaigns; create, update, delete them (and attach a call flow). |
call-logs:read / call-logs:write |
List and read calls incl. signed recording/voicemail URLs; update lead status, deal value, tags; delete. |
contacts:read / contacts:write |
List, read, and match contacts; upsert and delete. |
conversions:read / conversions:write |
List conversion events; record a conversion that advances a funnel stage. |
tracking-numbers:read / tracking-numbers:write |
List and read tracking numbers; update friendly name, assignment, and call-control flags. |
numbers:provision |
Search available numbers, purchase, and release. Never bundled into tracking-numbers:write — it spends money. |
call-flows:read / call-flows:write |
List and read flows, versions, and graphs; create, draft, publish, roll back, clone, delete. |
appointments:read / appointments:write |
List and read appointments; book, reschedule, and set status (cancel/complete/no-show). |
form-submissions:read |
List and read captured web-form submissions. Read-only — there is no write scope. |
tags:read / tags:write |
List contact tags; create, update, delete. |
products:read / products:write |
List the product/service catalog; create, update, delete. |
blocked-numbers:read / blocked-numbers:write |
Read the effective block list; block and unblock workspace-scope numbers. |
webhooks:read / webhooks:write |
List and read webhook endpoints + delivery stats; create, update, delete, test, regenerate the signing secret. |
analytics:read |
The four analytics tools — call metrics, attribution, funnel, and per-number performance. |
crm:force |
A modifier only: allows a backward or terminal funnel-stage move (force_stage) inside upsert_contact / record_conversion. Grants no tool of its own and still requires an owner/admin actor. |
get_ detail tool, return the full resource with its fields preserved.
search_form_submissions also folds a single-uuid full-detail
lookup. List results are wrapped in a cursor envelope (data,
next_cursor, prev_cursor), and a few detail tools embed a
nested envelope (a contact's events, a call flow's versions). The analytics tools return computed reports, not resource rows.per_page
(default 25, max 100) and cursor; each result carries
next_cursor/prev_cursor. Follow the cursors — never guess offsets.
list_workspaces and search_available_numbers return their whole set (no cursor).YYYY-MM-DD) is midnight-to-midnight in the target workspace's timezone; a datetime with an offset is
taken literally. The four analytics tools take date-only values and echo the effective (possibly clamped) range.idempotency_key. Generate one key per operation and reuse the same key on retry — the retry
replays the recorded result instead of acting twice. This matters most for
purchase_number, book_appointment, and regenerate_secret.rate-limit-exceeded with a
retry_after. Number purchases also share one daily cap across the API and MCP.validation-error, forbidden,
insufficient-scope, plan-required,
not-found, rate-limit-exceeded,
idempotency-conflict, conflict,
provision-cap-exceeded, and server-error.RingTonic authenticates with a bearer API key, so any client that sends an
Authorization header works — including the ChatGPT desktop app (via its shared Codex config). Only ChatGPT on the web (chatgpt.com connectors) still needs OAuth and cannot connect yet. Use one of these:
Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
claude mcp add --transport http ringtonic https://ringtonic.app/mcp \
--header "Authorization: Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
[mcp_servers.ringtonic]
url = "https://ringtonic.app/mcp"
http_headers = { Authorization = "Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
export RINGTONIC_MCP_TOKEN=rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
codex mcp add ringtonic --url https://ringtonic.app/mcp \
--bearer-token-env-var RINGTONIC_MCP_TOKEN
Authorization: Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{
"mcpServers": {
"ringtonic": {
"url": "https://ringtonic.app/mcp",
"headers": { "Authorization": "Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
}
}
}
{
"mcpServers": {
"ringtonic": {
"serverUrl": "https://ringtonic.app/mcp",
"headers": { "Authorization": "Bearer rt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
}
}
}
Paste one of these as a single instruction — the agent chains the tools and reports back. Great for the recurring numbers you send clients.
Show me last week's top campaigns by calls for Downtown Dental.
list_workspaces → get_call_metrics → search_campaigns
Which tracking numbers are converting best for Acme this month? Rank them by booked appointments.
get_number_performance → search_appointments
For the lead who called from (415) 555-0133 yesterday, book a follow-up Thursday 2pm and tag them 'hot-lead'.
search_calls → match_contact → book_appointment → update_call
Grab me a new local number in area code 512 and wire it to the Spring Promo campaign.
search_available_numbers → purchase_number
Build a Q3 client report for Downtown Dental: total calls, qualified-lead rate, closed revenue, and top 3 sources.
get_call_metrics + get_funnel_metrics + get_attribution_report
Find every 'won' deal last month and confirm each contact record has a deal value set.
search_conversions → get_contact → upsert_contact
Audit the Acme account: which campaigns have no call flow attached and which numbers are unassigned?
search_campaigns → get_campaign → search_tracking_numbers
Pull this week's web form submissions on Spring Promo, flag the spam, and show which became contacts.
search_form_submissions → match_contact → get_contact
For the campaign we're sunsetting, mark yesterday's no-shows, then delete it and return its numbers to inventory.
search_appointments → set_appointment_status → delete_campaign
Across all my client workspaces, tell me which one had the biggest week-over-week jump in qualified calls.
list_workspaces → get_attribution_report (per workspace)
Block the harassing caller at +1 800 555 0111 and delete the calls they left.
search_calls → manage_blocked_numbers → delete_call
Clone the Main IVR, add an after-hours voicemail branch to the copy, and publish it.
clone_call_flow → get_call_flow → update_call_flow_draft → publish_call_flow
All 51 tools, grouped by area. Each shows its scope, whether it only reads (read-only) or changes data (destructive), its parameters, and a prompt you can copy and try.
list_workspaces
any key
read-only
List every workspace this key can reach, with the caller's role and whether the workspace's plan currently enables the API/MCP surface. Call this first when unsure which workspace to pass to other tools. The uuid is the stable, canonical identifier to use.
Which client accounts can I manage with this connection?
get_workspace
any key
read-only
Read one workspace's profile — name, timezone, currency, consent defaults, and the custom-field schema you need before writing custom_fields on contacts.
What timezone and currency is the Downtown Dental account set to, and what custom contact fields does it have?
search_campaigns
campaigns:read
read-only
List a workspace's campaigns as compact rows (uuid, name, tracking type, routing status, attached call flow). Cursor-paginated. Use get_campaign for a campaign's full detail.
Show me all the website-tracker campaigns in the Acme account.
get_campaign
campaigns:read
read-only
Read one campaign's full detail by uuid — tracking config, routing flags, timezone override, and the attached call flow.
Pull up the full configuration for the Spring Promo campaign.
create_campaign
campaigns:write
write
Create a campaign. tracking_type is "static" (forward a number) or "dni" (website/dynamic-number tracker). Optionally link existing unassigned tracking numbers by uuid. Pass idempotency_key and reuse it on retry so a retry does not create a second campaign.
Set up a new static campaign called 'Radio Spot – Q3' that forwards calls to +1 512 555 0180.
update_campaign
campaigns:write
write
Update one campaign by uuid (partial — omit a field to leave it unchanged). Also attaches or detaches its call flow: pass call_flow as a flow uuid to attach, or null to detach. Pass idempotency_key and reuse it on retry.
Turn on call recording for the Spring Promo campaign and attach my 'Main IVR' call flow to it.
delete_campaign
campaigns:write
destructive
Delete one campaign by uuid. Requires number_action: "unassign" returns its tracking numbers to your inventory, "release" permanently gives them back to the provider (which additionally needs the numbers:provision scope).
Delete the old Radio Spot campaign and put its tracking numbers back into my inventory.
search_calls
call-logs:read
read-only
List a workspace's calls as compact rows (uuid, direction, status, timing, caller, lead status, campaign, tracking number, contact). Cursor-paginated. Use get_call for a call's full detail, transcript, and recording.
List every missed call on the Downtown Dental campaign in the last 7 days.
get_call
call-logs:read
read-only
Read one call's full detail by uuid — timing, caller, lead status, keyword spots, attribution, and signed recording/voicemail URLs. Pass include_transcript to also return the transcript.
Give me the recording and full transcript of that call from (415) 555-0133 yesterday.
update_call
call-logs:write
write
Update one call by uuid: its lead_status (qualification), deal_value (minor units of the workspace currency, e.g. cents), and tags (replaces the whole set — each entry is an existing tag uuid or exact name; [] or null clears them). Omit a field to leave it unchanged.
Mark that call as a qualified lead worth $2,500 and tag it 'hot-lead'.
delete_call
call-logs:write
destructive
Permanently delete one call log by uuid. This cannot be undone: the recording, transcript, and daily metrics are removed and the contact's call counts are corrected.
Permanently delete that spam test call from the log.
search_contacts
contacts:read
read-only
List a workspace's contacts as compact rows (uuid, name, phone, email, company, lead status, source). Cursor-paginated. Use match_contact to resolve identifiers, or get_contact for full detail.
Show me all contacts at the 'proposal sent' stage for Acme.
match_contact
contacts:read
read-only
Diagnose which contact a set of identifiers (external_id, phone, email) resolves to, without writing anything. Reports matched / ambiguous / conflicting / no-match with public uuids, so you can pick the right target before an upsert.
Do I already have a contact for the number +1 415 555 0133?
get_contact
contacts:read
read-only
Read one contact's full detail by uuid — identifiers, stage, deal value, custom fields, tags. Pass include_events to also embed the conversion-event timeline (cursor-paginated under events).
Pull John Carter's full contact record and his conversion history.
upsert_contact
contacts:write
write
Create or update a contact. Without contact: identify-or-create by external_id/phone/email (a match on phone/email returns the contact unchanged; use contact to update it). With contact (a uuid from match_contact/search_contacts): update that contact — the identifiers become new values, and lead_status/deal_value/force_stage are accepted only here. Send idempotency_key and reuse it on retry.
Add a new contact named Maria Gomez, phone +1 305 555 0190, email maria@example.com.
delete_contact
contacts:write
destructive
Delete one contact by uuid. This is a soft delete: the contact stops appearing in searches, its tags are detached, but its call history is preserved and a later postback with the same identifier restores it.
Remove Maria Gomez from the contacts list.
search_conversions
conversions:read
read-only
List a workspace's conversion events (stage change, source, value, linked contact/call/form) as full rows. Cursor-paginated.
List all deals we closed (won conversions) last month with their values.
record_conversion
conversions:write
write
Record a conversion that moves a contact to a funnel stage and writes an auditable event. Identify the contact by contact uuid or by external_id/phone/email; create_if_missing creates one when nothing matches. won/proposal_sent stages need value_cents (or inherit_value). Send idempotency_key and reuse it on retry.
Log a won deal worth $4,000 for the contact at +1 305 555 0190.
search_tracking_numbers
tracking-numbers:read
read-only
List a workspace's tracking numbers (phone number, friendly name, assigned campaign, call-control flags). Cursor-paginated.
Which of my tracking numbers aren't assigned to any campaign right now?
get_tracking_number
tracking-numbers:read
read-only
Read one tracking number's full detail by uuid — phone number, friendly name, assigned campaign, provider, CNAM, call-control flags, and ad location.
Show me the full details of the (415) 555-0148 tracking number.
update_tracking_number
tracking-numbers:write
write
Update one tracking number by uuid: friendly_name, campaign_uuid (assign, or null to unassign — re-points the number at the provider), cnam_lookup_enabled, calls_enabled + calls_disabled_action/message (Agency plan), and ad_location. Omit a field to leave it unchanged.
Rename the 415 number to 'Billboard – I-280' and point it at the Spring Promo campaign.
search_available_numbers
numbers:provision
read-only
Search the telephony provider for numbers you could buy in a country. Provider-agnostic. Not paginated (one bounded page); narrow with number_type, area_code, contains, or capabilities. Nothing is reserved — a listed number can be sold before you buy it, so on a purchase failure, search again.
Find me a local number available in the 512 area code.
purchase_number
numbers:provision
destructive
Buy a tracking number. THIS SPENDS MONEY — always send idempotency_key and reuse it on retry, or a timeout-retry buys a second number. Name an exact phone_number from search_available_numbers, OR give search criteria (country, number_type, area_code, contains, capabilities) to auto-pick the first match — not both. Optionally assign a campaign_uuid and a friendly_name. Subject to the workspace daily purchase cap (shared with the REST API).
Buy me a new local tracking number in area code 415 and label it 'Downtown billboard'.
release_number
numbers:provision
destructive
Release one tracking number by uuid back to the telephony provider. NOT REVERSIBLE: the number leaves your account, stops taking calls immediately, and can be bought by someone else. Call history is kept (soft delete). To take a number out of service without giving it up, unassign it instead (update_tracking_number with campaign_uuid: null).
Give up the old 305 number we no longer advertise.
list_call_flows
call-flows:read
read-only
List a workspace's call flows (name, description, publish status, live version, attached-campaign count). Cursor-paginated. Use get_call_flow for a flow's versions and graph.
List all the call flows in the Acme account and whether they are published.
get_call_flow
call-flows:read
read-only
Read one call flow's full detail by uuid — status, live version, attached campaigns, and (cursor-paginated under versions) its publish history. Pass include_graph to also return the draft and/or published node/edge graph.
Show me the current draft graph of the Main IVR flow and its version history.
create_call_flow
call-flows:write
write
Create a call flow. It starts as a draft (no live version) and answers no calls until you publish it. graph is optional — omit it for a blank flow, or send a node/edge graph (Go-To targets are call-flow uuids). A graph is validated at publish strictness now, so an invalid one is rejected at create time. Pass idempotency_key and reuse it on retry so a retry does not create a second flow.
Create a new empty call flow called 'After-Hours Routing'.
update_call_flow_draft
call-flows:write
write
idempotent
Replace a call flow's DRAFT graph wholesale (the published version and live routing are untouched until you publish). Read the current graph with get_call_flow (include_graph: draft) first, then send the full nodes/edges graph back. Go-To targets are call-flow uuids. To keep a webhook credential, echo it back as its masked value ******** — it is restored only while the webhook's url and method are unchanged. The graph is validated at publish strictness: invalid graphs return per-node validation errors. A concurrent change to the draft returns a conflict — re-read and re-apply.
Update the After-Hours flow's draft so unanswered calls go to voicemail.
publish_call_flow
call-flows:write
write
Publish a call flow's draft as a new live version. THIS CHANGES CALL ROUTING: every campaign using this flow starts answering with the new version. A flow with generated audio returns status "publishing" and becomes active (or failed) shortly — poll get_call_flow. A busy flow (a concurrent or still-generating publish) returns a conflict; a draft that cannot go live (invalid graph, a node type your plan lacks, or a required test call) returns a validation-error. Pass idempotency_key and reuse it on retry so a retry does not publish twice.
Publish the After-Hours Routing flow so it goes live.
rollback_call_flow
call-flows:write
write
idempotent
Restore a past version's graph into the call flow's DRAFT (by version_number, from get_call_flow's versions history). This activates nothing — call publish_call_flow afterwards to put the restored graph live. Pass idempotency_key and reuse it on retry.
Roll the Main IVR back to version 3 as a draft so I can review it before republishing.
clone_call_flow
call-flows:write
write
Duplicate a call flow by uuid. The copy is a new draft (name suffixed " (Copy)") with no published version — it answers no calls until you publish it. Pass idempotency_key and reuse it on retry so a retry does not create a second copy.
Make a copy of the Main IVR flow so I can build a variant.
delete_call_flow
call-flows:write
destructive
Delete one call flow by uuid. THIS CHANGES CALL ROUTING: every campaign using this flow is detached (call_flow_id nulled) and falls back to its non-flow routing, and its tracking numbers are re-synced at the provider. The flow is soft-deleted. There is no undo through this API.
Delete the old 'Test IVR' call flow.
search_appointments
appointments:read
read-only
List a workspace's appointments (status, start/end time, title, linked contact and call). Cursor-paginated.
Show me all the appointments booked for next week.
get_appointment
appointments:read
read-only
Read one appointment's full detail by uuid — status, timing, title, notes, location, calendar event id, linked contact and call, and cancellation info.
Pull up the details of Maria Gomez's consultation appointment.
book_appointment
appointments:write
write
Book an appointment. Identify the customer with contact (a uuid from match_contact/search_contacts) OR an inline new_contact (a phone is required; needs the contacts:write scope). start_at is an ISO-8601 instant WITH an offset or Z; duration_minutes is 5-480. Confirmations and reminders are opt-in. A slot overlap returns a conflict — to book anyway resend with ignore_conflicts under a NEW idempotency_key. Send idempotency_key and reuse it on retry.
Book a 30-minute follow-up call with the contact at +1 305 555 0190 for Thursday at 2pm and text them a confirmation.
reschedule_appointment
appointments:write
write
Reschedule or edit a booked appointment (identified by its uuid). Send only the fields to change: start_at and/or duration_minutes to move it, or title/notes/location to edit details — at least one is required. Only booked appointments can be edited. A slot overlap returns a conflict; resend with ignore_conflicts to override. Not idempotent — a repeat re-syncs the calendar and re-notifies, so do not blind-retry.
Move Maria's Thursday appointment to Friday at 10am.
set_appointment_status
appointments:write
destructive
idempotent
Set an appointment's status by uuid: cancelled (removes the calendar event, optionally notifies the customer via notify_customer, records reason), completed, no_show, or booked (re-open a terminal appointment). reason, notify_customer and idempotency_key apply only when cancelling; send idempotency_key on a cancellation and reuse it on retry so the retry replays instead of cancelling twice.
Mark yesterday's 3pm appointment as a no-show.
search_form_submissions
form-submissions:read
read-only
List a workspace's captured form submissions (campaign, fields, marketing params, consent, spam flag). Cursor-paginated. Pass uuid to return one submission's full payload instead (cannot be combined with filters, sort, cursor, or per_page).
Show me the web form submissions we captured on the Spring Promo campaign this week.
list_tags
tags:read
read-only
List a workspace's contact tags (name, color). Cursor-paginated, alphabetical by default.
What contact tags exist in the Acme account?
manage_tags
tags:write
destructive
Create, update, or delete a workspace contact tag. action: "create" (name required, optional hex color; pass idempotency_key and reuse it on retry so a retry does not create a second tag), "update" (tag uuid + the fields to change), or "delete" (tag uuid). Tag names are unique per workspace.
Create a new contact tag called 'VIP' in blue.
list_products
products:read
read-only
List a workspace's product/service catalog (name, description, category, price range, active flag). Cursor-paginated, alphabetical by default.
List the services in Acme's catalog and their prices.
manage_products
products:write
destructive
Create, update, or delete a product/service in the workspace catalog. action: "create" (name required; optional description, category, price_min/price_max in integer cents, is_active; pass idempotency_key and reuse it on retry so a retry does not create a second entry), "update" (product uuid + the fields to change; omit a field to leave it unchanged, send null to clear a nullable one), or "delete" (product uuid).
Add a service called 'Teeth Whitening' priced between $150 and $300.
list_blocked_numbers
blocked-numbers:read
read-only
List a workspace's effective blocked numbers, including account-inherited entries (flagged scope "account", read_only true). Cursor-paginated.
Show me the numbers we've blocked on this account.
manage_blocked_numbers
blocked-numbers:write
destructive
Block or unblock a phone number for the workspace. action: "block" (phone_number + reason; optional note; pass idempotency_key and reuse it on retry) or "unblock" (blocked_number uuid). Only the workspace's own entries can be unblocked — account-inherited entries (scope "account") are read-only.
Block the spam caller at +1 800 555 0111 as harassment.
list_webhook_endpoints
webhooks:read
read-only
List a workspace's webhook endpoints (url, subscribed events, active flag, health). Cursor-paginated. Use get_webhook_endpoint for a single endpoint's delivery statistics.
What webhook endpoints are configured for Acme and are they healthy?
get_webhook_endpoint
webhooks:read
read-only
Read one webhook endpoint's full detail by uuid — url, subscribed events, health, and 24-hour delivery statistics (count, success rate, average response time).
Show me the delivery stats for our Zapier webhook over the last day.
manage_webhook_endpoints
webhooks:write
destructive
Manage webhook endpoints. action: "create" (name, https url, events[]; returns the signing secret ONCE — it enters this conversation; pass idempotency_key and reuse it on retry), "update" (webhook_endpoint uuid + fields; setting is_active true re-enables and resets the failure circuit breaker), "delete" (webhook_endpoint uuid), "test" (webhook_endpoint uuid + event_type the endpoint subscribes to — queues a sample delivery; idempotency_key replays instead of sending twice), or "regenerate_secret" (webhook_endpoint uuid — rotates and returns a NEW secret ONCE; ALWAYS pass idempotency_key and reuse it on retry, or a blind retry rotates twice and strands the first value).
Create a webhook to https://hooks.example.com/rt that fires on the appointment.booked event.
get_call_metrics
analytics:read
read-only
Call totals, a day/week/month time series, and status/direction/lead_status breakdowns over a date range, optionally for one campaign. Totals and the time series are inbound marketing analytics (matching the dashboard); the breakdowns count every call in the window across both directions. Dates are YYYY-MM-DD in the workspace (or scoped campaign) timezone.
How many calls did each week bring in over the last quarter, and what's the answered-vs-missed split?
get_attribution_report
analytics:read
read-only
Attribution totals and top source, per-source performance rows (calls, qualified, conversion rate, cost, revenue, ROI), and a per-source-and-medium breakdown over a date range, optionally for one campaign. Dates are YYYY-MM-DD in the workspace timezone.
Which marketing sources drove the most qualified calls and best ROI last month?
get_funnel_metrics
analytics:read
read-only
The lifecycle stage funnel (per-stage counts, exits, and percent-from-previous) plus per-source-and-medium revenue rows (leads, qualified, won, revenue) over a date range, optionally for one campaign. Dates are YYYY-MM-DD in the workspace timezone.
Show me the lead funnel for Acme this month — how many leads made it to 'won'?
get_number_performance
analytics:read
read-only
Per-tracking-number call volume, answered/missed/failed/spam counts, missed rate, and average duration over a date range, optionally for one campaign. Dates are YYYY-MM-DD in the workspace timezone.
How many calls did each tracking number get last week, and which had the worst missed-call rate?