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/mcp
02#authentication

Choose 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

#scopes
crm:fullFull access

Every 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
crm:readRead-only

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

credentiallifetime
OAuth access token1 hourrefresh on demand
OAuth refresh token30 daysrotates on every use; a replayed token revokes the family
Personal access tokennone · 30 · 90 · 365 daysyour 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
connect claude
# claude.ai → Settings → Connectors
# → Add custom connector
Name Capable
URL https://crm.capable.run/api/mcp
# consent screen shows the requested
# scope; approve once per workspace.
connect claude code
$ claude mcp add --transport http \
capable https://crm.capable.run/api/mcp
# registers via OAuth dynamic client
# registration (RFC 7591) + PKCE.
scripts · bearer pat
# 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.

03#copilot

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.

  1. Ask your admin to install the Capable agent package for your tenant. Microsoft’s agent publishing guide explains the available installation routes.
  2. Open the Capable agent in Microsoft 365 Copilot, sign in to Capable when prompted and approve workspace access.
  3. 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.

04#tools

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 tools

merge_records

destructive

Merge duplicate contacts/accounts.

read_changes

read

The 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

create

Admin CRM import: describe → preview (no writes) → user reviews exact values/exclusions → stage the same preparation → start jobId in background.

add_note

create

Attach a free-form note to any record (account / contact / opportunity / touch).

get_record

read

Fetch any record's full detail by id.

get_record { "type": "task", "id": "91ab…" }

create_record

create

Create 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

update

Patch object_type + id; returns the fresh record.

update_record { "object_type": "task", "id": "91ab…",
"data": { "status": "done" } }

search_records

read

List/filter any object; built-ins use typed search filters.

search_records { "object_type": "contact",
"query": "lindqvist" }

delete_record

destructive

Archive by object_type + id (soft delete; restore_record undoes it).

propose_updates

readthe wedge — propose, approve, commit

Use 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

read

Prepare all 1–500 changes without CRM writes.

get_review_status

read

Read status/details; no approval or writes.

commit_reviewed_updates

idempotent

Save approved selection; first confirmation freezes it.

get_context

read

Bounded record context with per-section coverage: complete, truncated, unavailable or unknown.

get_context { "type": "contact",
"id": "6f2c…" }

get_help

read

Search verified Capable how-to/setup/troubleshooting articles verbatim with citations, or fetch article_key; offer related topics.

restore_record

update

Bring 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 tools

manage_linkedin_conversation

destructive

Owner-only controls; never send messages or auto-share.

manage_linkedin_privacy

destructive

Owner-only LinkedIn review/erasure; no provider/sign-in changes.

Accounts

4 tools

get_company_billing

read

A company's billing state (prospect, `working` = paid active, or archived): activation quote, annual capacity, approval need, live work blocking archive.

manage_company_billing

update

Activate a company, or request human approval for activation, after reviewing get_company_billing.

add_account_contact

create

Link 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

destructive

Unlink a contact from an account (the contact and the account themselves are kept).

Onboarding

3 tools

start_onboarding

read

Read saved choices, entry context and workspace evidence for one useful customer result.

show_workspace_setup

read

Show the workspace-setup step so the user can confirm the motion(s) you recommended, name the workspace, and save.

finalize_workspace_setup

idempotent

Commit onboarding answers into the workspace config; omitted fields stay untouched.

Opportunities

2 tools

get_pipeline_summary

read

Summarize opportunities by type/stage and pipeline_by_lens using stage roles, not labels.

set_opportunity_products

update

Replace an opportunity's entire product set and derive its value.

Subscriptions

2 tools

renew_subscription

idempotent

Renew 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

destructive

Cancel a subscription.

Touches

1 tool

log_touch

create

Record 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 tools

record_meeting

create

Send the Capable notetaker bot to a video call.

stop_recording

destructive

Pull the notetaker bot out of a call and cancel the recording.

share_recording

create

Share 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 tools

get_scheduling_settings

read

Read 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

create

Create a private booking-page draft or edit one of your pages.

set_booking_page_status

update

Publish or pause your booking page when the user requests it.

update_availability

update

Patch personal availability/photo across workspaces; existing meetings stay put.

update_scheduling_calendars

update

Choose which of your connected calendars block availability and where new meetings are created.

manage_time_blocks

update

Manage personal Google/Outlook calendar blocks with no attendees; nothing is sent.

find_times

read

Find three chronologically labeled slots; nothing is held.

find_times { "duration": 30,
"window_start": "2026-07-06",
"window_end": "2026-07-10" }

propose_meeting

create

Place reversible, expiring, invitee-invisible calendar holds and STAGE the invitee email; this tool never emails anyone.

send_meeting_invite

update

Sends the picker email to the invitee.

cancel_meeting

destructive

Cancel 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

update

Moves a booked meeting to a new time in place.

Reports

4 tools

run_report

read

Preview 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

read

Show an analysis/dashboard from saved CRM records as a card with "Save as view", or text if unavailable/requested.

export_report

read

Export one saved analysis's results as CSV through the single audited egress path.

schedule_report

update

Schedule 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 tools

create_quote

create

Draft a quote for an account from catalog product IDs and quantities.

update_quote

update

Update a quote: change its status (exactly draft → sent → accepted / lost), link an opportunity, or replace its line items.

Workspace

5 tools

set_exchange_rates

update

Set/remove Fixed workspace FX rates (admin-only).

update_workspace

update

Admin PATCH; omitted/unchanged fields stay.

manage_members

update

Admin-only membership controls.

manage_approvals

update

Admin-only governance queue for requests held by policy/autonomy.

manage_webhooks

update

Admin-only change-feed webhooks.

Schema

11 tools

define_object

create

Create a new custom object TYPE (e.g. Partner, Product, Investor) to operate on via create_record / update_record / search_records (admin-only).

update_object

update

Admin-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

create

Add a custom field to any object that supports them (core objects with custom fields, or any custom object).

define_enum_value

idempotent

Admin-only add, relabel, recolor, position, archive or reorder of built-in pick-list values listed by describe_schema.

define_pipeline

create

Create an additional pipeline (a named stage sequence) for opportunities or a custom object.

update_pipeline

update

Update 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

create

Create a top-level program (a parallel workstream like Investor Relations or Partnerships, a peer of the built-in Revenue motion).

define_rollup

create

Create 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

create

Create 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

idempotent

Apply 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

read

Read 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.

66 tools · one door — the count is computed from tools/list, never typed.
05#limits

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 minute
read
120req/min

get_record, search_records, describe_schema…

write
60req/min

create_record, log_touch, update_record…

expensive_read
20req/min

the heavy reads — run_report, show_report, export_report, get_context, find_times

expensive_write
20req/min

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

A tool’s result only gains fields — existing fields don’t disappear or change meaning. Build against today’s shapes and tomorrow’s release won’t break them.

Admins hold the keys

Workspace admins can gate any tool behind approval, deny it outright, or cap exports per role — and API traffic obeys the same policies as every other door. Tokens are revocable the moment they should be.

Every call leaves a row

Tool, actor, workspace, source, outcome — reads and writes, denials included. Exports ride a single audited egress path with per-role row caps and column redaction.

One door, honestly

MCP is the whole API for reading and changing your CRM — there is no separate REST surface or webhook fan-out to fall behind it. The live catalog defines the available tool surface; nothing more, nothing hidden. The one addition is a send-only door for your product’s own events, below: it can’t read anything, and what it writes rides the same rulebook.

What every call passes through

#governance
rate limitsuspensiontoken scopeobject gatepolicyfield valueswrite scopehandleraudit
07#product-events

Product 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

A capture key can only send. It reads nothing, answers 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

Every message carries a messageId. Sending the same one again is counted once; a different message under a used id is refused.

People, not guesses

A verified email becomes a contact. Only the events an admin chooses are recorded; a company is suggested for a human to confirm unless the workspace has turned on automatic creation for named milestones.

Test first

Test keys check your messages and show what would happen, without changing the CRM.
08#website-enquiries

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

Lead and task 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

Contact creation matches an existing email and fills blank fields. A lead stores the stated company without creating an account or opportunity. Tasks link to the contact, so keep the full message and lead link in the task description. Lead owner and task assignee default to the token’s user; pass owner_id and assignee_id for an authorised handoff. A task may also carry an agreed due_at date.

Confirm the actual result

Parse either JSON or SSE, match the JSON-RPC response ID, and check for protocol and tool errors. Require 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

Validate and limit form input, protect the public endpoint from abuse, and keep enquiry contents out of diagnostic logs. No opportunity or paid account is created by this example. Customer acknowledgement emails remain your responsibility. Internal new-lead emails are available through Capable’s opt-in notification setting below.

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.