Capable API
Build on your commercial context.
Connect Claude, ChatGPT, Microsoft 365 Copilot, or your own tools to Capable.
One endpoint
Capable uses MCP over Streamable HTTP. The reference below covers all 66 listed tools.
https://crm.capable.run/api/mcpChoose how to connect
Apps sign in with OAuth 2.1; scripts carry a personal access token. Both arrive at the same endpoint, resolve to a person in a workspace, and pass the same rulebook — there is no service backdoor.
OAuth 2.1
for apps- Dynamic client registration (RFC 7591) — Capable exposes runtime registration; no pre-issued client key is required.
- PKCE on every grant, discovery via RFC 8414 / RFC 9728 metadata.
- Access tokens live 1h; refresh tokens rotate on every use and cap at 30d — a replayed refresh token revokes its whole family.
Personal access tokens
for scripts- Minted in Settings → Apps & API access, scoped to you in one workspace — shown once, cpbl_pat_…, hashed at rest (SHA-256).
- Pick the scope at mint — full or read-only — and an optional expiry; revoke anytime from the same panel.
- A personal access token authenticates its bearer's user authorization in one workspace; it does not identify the downstream MCP client.
Two scopes
#scopesEvery listed tool — reads, writes, schema. Still bounded by the caller's role, write scope, and workspace policies.
- The default — the standard Claude connection runs on it
- Writes remain subject to role + per-record write scope
- Admin governance policies apply on top, unchanged
Every read tool — including read-type exports (CSV) — and nothing that writes.
- Writes are refused before governance — a read-only credential can never queue a write for approval
- Exports still ride the audited egress path (row caps, redaction)
- An unrecognized scope authorizes nothing — the guard fails closed
Scopes narrow; they never grant. Whatever the credential, workspace governance policies and per-record write scope still apply on top.
Token lifetimes
| credential | lifetime | |
|---|---|---|
| OAuth access token | 1 hour | refresh on demand |
| OAuth refresh token | 30 days | rotates on every use; a replayed token revokes the family |
| Personal access token | none · 30 · 90 · 365 days | your call at mint; revoke anytime — expiry is encouraged for script keys |
Claude or ChatGPT
Add Capable using the MCP endpoint, sign in, and authorize your workspace. Your app discovers the tools available to you.
Connection instructions# claude.ai → Settings → Connectors# → Add custom connectorName CapableURL https://crm.capable.run/api/mcp# consent screen shows the requested# scope; approve once per workspace.
$ claude mcp add --transport http \capable https://crm.capable.run/api/mcp# registers via OAuth dynamic client# registration (RFC 7591) + PKCE.
# scripts: a personal access token as# a bearer — plain JSON-RPC over HTTP.$ curl -s https://crm.capable.run/api/mcp \-H "Authorization: Bearer cpbl_pat_…" \-H "Content-Type: application/json" \-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Claude and ChatGPT use the endpoint’s authorization discovery. Scripts can send a personal access token as a bearer credential.
Microsoft 365 Copilot
Use Capable from an installed agent in Microsoft 365 Copilot with your work account. Your Microsoft 365 admin must allow and assign the custom agent. This is separate from consumer Copilot at copilot.com.
- Ask your admin to install the Capable agent package for your tenant. Microsoft’s agent publishing guide explains the available installation routes.
- Open the Capable agent in Microsoft 365 Copilot, sign in to Capable when prompted and approve workspace access.
- Ask it to read your workspace. Then try one customer task and review the exact proposed changes before saving. Installation or sign-in alone does not verify a successful tool call.
For a Copilot Studio agent, add https://crm.capable.run/api/mcp as an MCP tool with OAuth dynamic discovery, then publish the agent to Microsoft 365 Copilot. Follow Microsoft’s MCP setup guide.
The same workspace permissions and reviewed writes apply. Validate sign-in, reading, field-by-field approval and saved results in your tenant before rollout. Contact us for the agent package and rollout help.
Tools, grouped by job.
All 66 listed tools appear here, generated from the live catalog so this reference cannot drift. read tools are available to crm:read; anything that writes needs crm:full. Writes return the affected record’s full state, and searches are keyset-paginated.
Universal
16 toolsmerge_records
destructiveMerge duplicate contacts/accounts.
read_changes
readThe workspace's change feed, oldest first: each record created, updated, archived, restored or deleted on any object, with the names of the changed fields (never values), when, the actor and the basis of the values (person, reviewed, approved, collected, imported, automated).
migrate_crm
createAdmin CRM import: describe → preview (no writes) → user reviews exact values/exclusions → stage the same preparation → start jobId in background.
add_note
createAttach a free-form note to any record (account / contact / opportunity / touch).
get_record
readFetch any record's full detail by id.
get_record { "type": "task", "id": "91ab…" }
create_record
createCreate a built-in or custom record with object_type + data; relationships take ids; built-ins use typed domain logic.
create_record { "object_type": "partner","data": { "name": "Globex" } }
update_record
updatePatch object_type + id; returns the fresh record.
update_record { "object_type": "task", "id": "91ab…","data": { "status": "done" } }
search_records
readList/filter any object; built-ins use typed search filters.
search_records { "object_type": "contact","query": "lindqvist" }
delete_record
destructiveArchive by object_type + id (soft delete; restore_record undoes it).
propose_updates
readthe wedge — propose, approve, commitUse for requested CRM changes from notes, emails or freeform requests.
tools/call propose_updates{"text": "Call with Sara — moving to Oslo in March; will intro their platform lead…"}# → matched records + schema; approved changes# commit through the individual write tools
review_proposed_updates
readPrepare all 1–500 changes without CRM writes.
get_review_status
readRead status/details; no approval or writes.
commit_reviewed_updates
idempotentSave approved selection; first confirmation freezes it.
get_context
readBounded record context with per-section coverage: complete, truncated, unavailable or unknown.
get_context { "type": "contact","id": "6f2c…" }
get_help
readSearch verified Capable how-to/setup/troubleshooting articles verbatim with citations, or fetch article_key; offer related topics.
restore_record
updateBring back a soft-deleted record by object_type + id — the undo of delete_record, for every type it archives (a quote with its lines, a subscription with its ARR, a file while its contents remain, an email_body by its touch id).
Contacts
2 toolsmanage_linkedin_conversation
destructiveOwner-only controls; never send messages or auto-share.
manage_linkedin_privacy
destructiveOwner-only LinkedIn review/erasure; no provider/sign-in changes.
Accounts
4 toolsget_company_billing
readA company's billing state (prospect, `working` = paid active, or archived): activation quote, annual capacity, approval need, live work blocking archive.
manage_company_billing
updateActivate a company, or request human approval for activation, after reviewing get_company_billing.
add_account_contact
createLink a contact to an account with a role from the workspace's account_contacts.role values (seed defaults: champion / economic_buyer / decision_maker / user / blocker / influencer / csm_primary).
remove_account_contact
destructiveUnlink a contact from an account (the contact and the account themselves are kept).
Onboarding
3 toolsstart_onboarding
readRead saved choices, entry context and workspace evidence for one useful customer result.
show_workspace_setup
readShow the workspace-setup step so the user can confirm the motion(s) you recommended, name the workspace, and save.
finalize_workspace_setup
idempotentCommit onboarding answers into the workspace config; omitted fields stay untouched.
Opportunities
2 toolsget_pipeline_summary
readSummarize opportunities by type/stage and pipeline_by_lens using stage roles, not labels.
set_opportunity_products
updateReplace an opportunity's entire product set and derive its value.
Subscriptions
2 toolsrenew_subscription
idempotentRenew a subscription: advance current_term_started_at and current_term_ends_at forward by one billing cadence (or accept explicit dates), optionally update mrr_cents/seats/plan_name (for renewals with uplift).
cancel_subscription
destructiveCancel a subscription.
Touches
1 toollog_touch
createRecord a call, email, meeting or LinkedIn activity; link account_id, contact_id or opportunity_id (resolve IDs first).
log_touch { "type": "call", "contact_id": "6f2c…","summary": "Kickoff — scope agreed" }
Recorder
3 toolsrecord_meeting
createSend the Capable notetaker bot to a video call.
stop_recording
destructivePull the notetaker bot out of a call and cancel the recording.
share_recording
createShare one recorded call outside the workspace through a private, expiring link to a page that plays it and, unless include_transcript is false, its transcript.
Scheduling
11 toolsget_scheduling_settings
readRead owned booking pages/URLs, availability, photo and your calendar connection to Capable: status, provider (Google or Microsoft) and calendars; plus scheduling activation and edit revisions.
save_booking_page
createCreate a private booking-page draft or edit one of your pages.
set_booking_page_status
updatePublish or pause your booking page when the user requests it.
update_availability
updatePatch personal availability/photo across workspaces; existing meetings stay put.
update_scheduling_calendars
updateChoose which of your connected calendars block availability and where new meetings are created.
manage_time_blocks
updateManage personal Google/Outlook calendar blocks with no attendees; nothing is sent.
find_times
readFind three chronologically labeled slots; nothing is held.
find_times { "duration": 30,"window_start": "2026-07-06","window_end": "2026-07-10" }
propose_meeting
createPlace reversible, expiring, invitee-invisible calendar holds and STAGE the invitee email; this tool never emails anyone.
send_meeting_invite
updateSends the picker email to the invitee.
cancel_meeting
destructiveCancel a meeting — DESTRUCTIVE and two-step: the first call (without confirm) changes nothing and returns what cancelling will do ({cancelled:false, requires_confirm:true}); confirm with the user, then call again with confirm:true.
reschedule_meeting
updateMoves a booked meeting to a new time in place.
Reports
4 toolsrun_report
readPreview analysis/dashboard data for your own reading; shows the user nothing.
run_report { "definition": { "version": 1, "object": "touch","group_by": { "ref": { "kind": "field", "field": "type" } },"aggregations": [{ "fn": "count", "alias": "n" }] } }
show_report
readShow an analysis/dashboard from saved CRM records as a card with "Save as view", or text if unavailable/requested.
export_report
readExport one saved analysis's results as CSV through the single audited egress path.
schedule_report
updateSchedule one saved analysis to be emailed as a digest (CSV attached) to workspace members on a daily / weekly / monthly cadence (UTC); a dashboard cannot be scheduled — choose or save one panel as an analysis first.
Quoting
2 toolscreate_quote
createDraft a quote for an account from catalog product IDs and quantities.
update_quote
updateUpdate a quote: change its status (exactly draft → sent → accepted / lost), link an opportunity, or replace its line items.
Workspace
5 toolsset_exchange_rates
updateSet/remove Fixed workspace FX rates (admin-only).
update_workspace
updateAdmin PATCH; omitted/unchanged fields stay.
manage_members
updateAdmin-only membership controls.
manage_approvals
updateAdmin-only governance queue for requests held by policy/autonomy.
manage_webhooks
updateAdmin-only change-feed webhooks.
Schema
11 toolsdefine_object
createCreate a new custom object TYPE (e.g. Partner, Product, Investor) to operate on via create_record / update_record / search_records (admin-only).
update_object
updateAdmin-only patch of a custom object's label, plural, blurb, icon, shared-write mode, enabled flag or display_field (null resets to name).
define_field
createAdd a custom field to any object that supports them (core objects with custom fields, or any custom object).
define_enum_value
idempotentAdmin-only add, relabel, recolor, position, archive or reorder of built-in pick-list values listed by describe_schema.
define_pipeline
createCreate an additional pipeline (a named stage sequence) for opportunities or a custom object.
update_pipeline
updateUpdate a pipeline by pipeline_key (or pipeline_id; id wins): rename it (label), re-point it (applies_to), replace its stages (including each stage's entry requirements) or set which opportunity types default to it (default_for_types).
define_program
createCreate a top-level program (a parallel workstream like Investor Relations or Partnerships, a peer of the built-in Revenue motion).
define_rollup
createCreate a derived-metric rollup that aggregates a custom source object onto a target field (e.g. usage_revenue = sum of usage records onto an account field).
define_automation
createCreate an automation rule: when trigger_event fires (record.written) and condition_spec matches, run action_tool with action_args (a {{placeholder}} template over the trigger facts).
apply_template
idempotentApply a curated schema template from the workspace's registry — a pre-vetted bundle of objects, fields, pick-list values, pipelines and starter views — in one step (admin-only).
describe_schema
readRead the complete workspace shape: built-in/custom objects and fields, valid values and semantic roles, relationships (FK graph), pipelines/stages, active motions, qualification framework, programs, rollups and automation rules.
Built to be trusted with the door open.
Every authorized tool call crosses the same metered, additive, governed, and audited rulebook.
Rate limits
per workspace × user · rolling minuteget_record, search_records, describe_schema…
create_record, log_touch, update_record…
the heavy reads — run_report, show_report, export_report, get_context, find_times
the heavy writes — propose_updates, propose_meeting, record_meeting; a burst of heavy reads never blocks them
Every tool declares its tier. Over the limit, the call is refused with a machine-readable budget — tier, limit, remaining, seconds to reset.
Additive-only outputs
Admins hold the keys
Every call leaves a row
One door, honestly
What every call passes through
#governanceProduct events
Send sign-ups and milestones from your own product’s backend, in the Segment Spec shape (identify · group · track). Available to workspaces we’ve enabled; an admin connects it in Settings → Data management → Product events.
POST /api/capture/v1
Authorization: Bearer cpbl_cap_…
Content-Type: application/json
{ "batch": [
{ "type": "identify", "messageId": "m-1", "userId": "u_42",
"traits": { "email": "ada@example.com", "email_verified": true } },
{ "type": "track", "messageId": "m-2", "userId": "u_42",
"event": "Workspace Created" }
] }Send-only keys
200 once your batch is stored (with a status per message), and is kept on your servers — never in a browser or app.Safe to retry
messageId. Sending the same one again is counted once; a different message under a used id is refused.People, not guesses
Test first
Receive website enquiries
Connect your form to your own backend, then call Capable’s MCP API. A person’s explicit enquiry can become a lead and an assigned follow-up task. This integration is available through the same public API as other records.
First call describe_schema and check that contacts, leads and tasks are enabled. Keep a crm:full workspace PAT on your server, never in the form or browser. The token’s user needs permission to create these records; workspace policies still apply.
During setup, have an admin add a text field to leads with define_field({object_type: "lead", label: "Website enquiry message", field_type: "text"}). Check describe_schema first and reuse an existing field when present. Use the returned key in custom_fields; the example assumes website_enquiry_message. Save the full submitted message on the lead so it remains available even if the later task call needs a retry.
// On your server, after validating the submitted form:
const contact = await callTool("create_record", {
object_type: "contact",
data: { first_name: "Sam Example", email: "sam@example.com" }
});
const contactId = contact.result.contact.id;
const lead = await callTool("create_record", {
object_type: "lead",
data: {
request_id: "1d39f925-7d32-4fa3-8360-64dbb4fdad73",
name: "Sam Example", email: "sam@example.com",
company_name: "Example Ltd", source: "Website enquiry",
custom_fields: { website_enquiry_message: "We would like to discuss our setup." },
contact_id: contactId
}
});
const leadId = lead.result.lead.id;
await callTool("create_record", {
object_type: "task",
data: {
request_id: "f43a9af5-2f3d-4466-a821-01948b27b758",
title: "Respond to Example Ltd",
description: "Company: Example Ltd\nName: Sam Example\nEmail: sam@example.com\nMessage: We would like to discuss our setup.\nLead: https://crm.capable.run/records/lead?open=lead%3A" + leadId,
contact_id: contactId
}
});The example’s callTool sends the request below and returns the completed tool’s structuredContent. Replace the example values with validated form values and generate separate UUIDs for each new lead and task. Keep those UUIDs and the exact payload in your backend’s submission record for retries.
HTTP request envelope
POST /api/mcp
Authorization: Bearer <server-side workspace PAT>
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: create_record
{
"jsonrpc": "2.0",
"id": "response-correlation-id",
"method": "tools/call",
"params": {
"name": "create_record",
"arguments": { "object_type": "lead", "data": {
"request_id": "1d39f925-7d32-4fa3-8360-64dbb4fdad73",
"name": "Sam Example", "email": "sam@example.com"
} },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": {
"name": "website-enquiries", "version": "1.0.0"
}
}
}
}Keep each enquiry once
data.request_id values become their record IDs. Identical retries by the same user in the same workspace return the stored record, including simultaneous retries. Different details, a changed record or a deleted record are refused without overwriting or recreating it. Check the record before continuing; do not use a fresh UUID to bypass a conflict. The JSON-RPC id only matches responses and does not deduplicate a submission.One person, a clear follow-up
owner_id and assignee_id for an authorised handoff. A task may also carry an agreed due_at date.Confirm the actual result
resultType: complete and the returned contact, lead and task IDs before showing success. An approval request is pending, not saved. The three calls are separate writes; after an interrupted request, resume with the same payloads and IDs. Persist the submission and delivery state before sending if you need automatic recovery.Your form, your delivery
Notify your team when an enquiry arrives
An admin can open Settings → Notifications, turn on new-lead emails, and choose the lead owner, up to 20 workspace members, or one shared inbox. Set the source to Website enquiry to match this example exactly, or leave it empty for every new lead. Select website_enquiry_message to include the enquiry text.
For the same setup through MCP, call update_workspace with {lead_notifications: {action: "read"}}. Use the returned member IDs, message-field keys and rule version in a lead_notifications command with action: "configure", enabled, source_filter, recipient_mode (owner, members or inbox), recipient_ids, recipient_email, message_field_key and expected_version. Use null for no source, no message field or an absent rule version, and an empty recipient list for owner or inbox mode. For inbox mode, set recipient_email to one mailbox; use null in the other modes. Send notification settings on their own. Review the preview and repeat with confirm: true at the top level.
A shared inbox does not need a Capable membership. Choose an inbox your team controls: everyone with access to it or its forwarding destinations can read the lead details and selected enquiry message. Existing email forwarding can deliver these alerts to Slack; Capable does not set up that forwarding. Opening the linked lead still requires workspace access.
Capable sends the internal email through its configured mail service, with a link to the lead and the submitter’s address as Reply-To when valid. It does not send an acknowledgement to the submitter. The rule applies only to newly created matching leads; updates, identical creation retries and existing leads do not trigger another email. Delivery begins after the lead is saved, independently of the later task call.
Settings shows recent delivery status. Temporary delivery failures retry for up to 23 hours with duplicate protection. Disabling or changing a rule cancels its pending deliveries. Workspace access, member eligibility or the configured shared-inbox address are checked again before sending. A sent status means the email provider accepted it, not that the recipient opened it.