Conduyt MCP Server
MCP server for Conduyt CRM — expose your CRM as AI-accessible tools. Covers the core CRM surface (contacts, deals, pipelines, custom fields, automations, messaging, and more); use conduyt_api_catalog to discover the full set of 600+ REST endpoints.
299 Tools
Discovery
conduyt_api_catalog | Discover all 600+ API endpoints |
conduyt_check_permissions | Introspect current API key permissions |
conduyt_search | Global search across contacts, deals, companies, tasks |
Contacts
conduyt_list_contacts | List and search contacts with filters |
conduyt_get_contact | Get full contact details with timeline; hasOutboundSms = the workspace has ever provably texted the contact; hasOutboundEmail = the same for email; duplicateProposals and heldIdentifiers = the open possible-duplicate lines and held identifiers |
conduyt_create_contact | Create a new contact (a 409 with existingId, rule, ruleVersion, matchedOn, reason means the identity policy identified the incoming person with that record: confirm the identity (name, company) before updating it, a shared phone or email is not proof, and the server creates (with a passive duplicate proposal) a different person on a shared identifier; 409 identifier_changed / owner_busy and 503 IDENTITY_INDEX_NOT_READY are retryable, nothing written; with callId: the lead for a contact-less inbound call, linked in the same transaction; the server derives source "Inbound Call" and the owner) |
conduyt_update_contact | Update contact fields; optional expectedRevision (0..2147483647) refuses a stale save with 409 contact_changed (code + current revision in the error) |
conduyt_merge_contacts | DESTRUCTIVE: merge duplicates into a survivor (POST /contacts/merge, owner/admin); the losers are deleted. Two steps: without confirmImpact a preview (counts, guardCounts, identifierOverflow, blockers); with confirmImpact: true plus the preview's expectedCounts, expectedGuardCounts (and expectedIdentifiers) the merge; the confirm is sent only against a preview this server returned in the last 10 minutes (else refused locally); the server pins the record counts, guard counts and identifier plan, not other field edits made after the preview; 75 s timeout. Moved counts 409, 503 merge_contacts_busy / merge_budget_exhausted + Retry-After surfaced verbatim, never retried |
conduyt_list_duplicate_proposals | List a contact's possible duplicates (GET /contacts/{id}/duplicate-proposals): open and not-sure proposals (id, status, rule, other, raisedHere) and the identifiers held from it (value-free); a record you cannot view has no id; keyset paged with cursor / limit (default 50) and held_cursor / held_limit (default 20), answers total, nextCursor, the held twins and membership revisions (re-read page one when a later page answers another revision) |
conduyt_list_import_duplicate_proposals | The duplicate proposals one import raised on the records it created (GET /imports/{id}/duplicate-proposals, contacts:view): every status, oldest first, page / per_page (default 50), { rows, meta }; a record you cannot view is "A contact you cannot view" with no id |
conduyt_decide_duplicate_proposal | Decide one proposal (POST /contacts/{id}/duplicate-proposals/{proposalId}, contacts:edit on both records): not_sure keeps both visible, different is final (never shown again), merge records a pair ALREADY merged (this tool never merges: use conduyt_merge_contacts first, else 409 not_merged); 409 already_decided, 403 other_record_not_editable; answers the list's membershipRevision and total after the decision and previousMembershipRevision; never retried |
conduyt_add_contact_collaborator | Add a team member as a collaborator (POST /contacts/{id}/collaborators); optional expectedRevision, 409 contact_changed |
conduyt_remove_contact_collaborator | Remove a collaborator (DELETE /contacts/{id}/collaborators, body); optional expectedRevision, 409 contact_changed, 404 when not a collaborator |
conduyt_add_tags | Add tags to a contact |
Deals
conduyt_list_deals | List deals by pipeline, stage, or assignee; rows carry hasNextStep and nextAppointmentAt. With health_summary=true it answers the Pipeline health strip for the same filtered set (totalOpenDeals, atRiskValue, checks[], deals); health_check, health_limit, health_offset, health_cursor (the previous nextCursor, passed back unchanged) and health_rows_only page one check's deals (rows-only answers {data:{deals:{check, offset, items, hasMore, nextCursor}}}). With board_snapshot=true, pipeline (or pipelineName) and board_columns ([{stageId, limit?}], 1-50 columns of that pipeline, limit 1-1000, at most 5000 rows) every column is read from ONE database snapshot (a moved deal is in exactly one column): { columns: [{ stageId, limit, deals }], meta: { board_snapshot: true } }, rows only; a stage filter, the health_* arguments or page (a snapshot is always page one) are refused locally before any request. 503 board_snapshot_busy (snapshot only) and gate_busy (any call) carry Retry-After: the GET is retried within its budget, then the error reaches you |
conduyt_pipeline_health | Pipeline health for one pipeline or all visible active pipelines (GET /deals/inspection): the six checks over open deals by money at risk; check adds that check's deals, paged by cursor (or offset). Cursor 400s carry health_cursor_invalid / _context / _blank / _needs_check, health_filter_conflict |
conduyt_pipeline_health_fix_deal | Pipeline health quick fix for a deal row (PATCH /deals/{id} with checkOrigin): stale = stageId (+ expectedStageId), unassigned = assignedTo, missing_close_date = expectedCloseDate, missing_contact = contactId; expectedUpdatedAt required. Refusals verbatim, never retried: 409 deal_changed / deal_check_cleared (with the deal's current health row), uncoded 409s, 400 health_fix_mismatch |
conduyt_pipeline_health_fix_next_action | Pipeline health "Set next action" (POST /tasks with checkOrigin high_value_idle / needs_action, dealId, expectedDealUpdatedAt, optional idempotencyKey sent as the Idempotency-Key header). At most one non-done quick-fix task per deal; refusals verbatim, never retried: 409 deal_changed / deal_has_next_action / deal_check_cleared, 400 health_fix_mismatch, idempotency 409/503 |
conduyt_get_stage_rules / conduyt_set_stage_rules | Read / set one stage's rule (requiredFields incl. custom:<fieldKey>, requiredDocuments 0-20, lost-reason label and options, lostReasonAllowOther); other stages untouched; revision-aware, retried once on a 409 |
conduyt_get_deal_card_fields / conduyt_set_deal_card_fields | Read / replace the kanban card fields (1-8, built-ins or custom:<fieldKey>) |
conduyt_get_settings_revision | The account settingsRevision (plus stored stage rules and rot days): pass it as expectedSettingsRevision to conduyt_archive_pipeline / conduyt_delete_stage so a stale one is refused 409 stale_settings_revision |
conduyt_get_pipeline_rot_days / conduyt_set_pipeline_rot_days | Read / set the stale-in-stage threshold per pipeline (pipelineRotDays, 1-90 days); only the pipelines sent change; revision-aware, retried once on a 409 |
conduyt_get_deal | Get deal details with history, including custom-field values |
conduyt_create_deal | Create a deal with full attributes — currency (e.g. GBP), probability, priority, expected close date, contact/company, and structured custom-field values |
conduyt_update_deal | Move stage, change value/currency, set probability or close date, reassign, mark won/lost, or write custom-field values; optional expectedUpdatedAt pins the updatedAt you read, and a stale pin returns 409 deal_changed with the current updatedAt and writes nothing |
conduyt_import_deals | Bulk-import deals (pipeline/stage by name, contact by email) via the canonical import engine — dedupes, side-effect-free, owner/admin only |
Tasks
conduyt_list_tasks | List tasks by assignee, status, due date |
conduyt_create_task | Create and assign a task |
Pipelines
conduyt_list_pipelines | List active pipelines with stages (each carries color, automationOnly, sortOrder) |
conduyt_list_archived_pipelines | List archived pipelines (GET /pipelines?archived=true, owner / admin key): id, name, archivedName, color, archivedAt, openDeals, stageCount |
conduyt_create_pipeline | Create a pipeline, optionally with its full set of stages (no stage-count cap; up to 50) and a palette color |
conduyt_update_pipeline | Rename a pipeline, change its description, set it as default, set automationOnly (only automations, API keys and owners / admins move or edit its cards), color (one of the 10 palette colours) or sortOrder (owner / admin key) |
conduyt_archive_pipeline | Archive a pipeline and move its open deals to another pipeline in one transaction (moveOpenDealsTo, optional expectedSettingsRevision); refusals carry stale_settings_revision, target_not_open, dpp_post_close, archive_too_large, target_archived, intake_target, pipeline_archived; an already-archived pipeline answers alreadyArchived |
conduyt_restore_pipeline | Restore an archived pipeline (appended last, never the default; 409 name_taken when an active pipeline has its name) |
conduyt_reorder_pipelines / conduyt_reorder_stages | Set the board-menu order of the pipelines / a pipeline's column order in one transaction with expectedRevision (409 order_changed carries the current revision) |
conduyt_delete_pipeline | Delete a pipeline (move/remove its deals first) |
conduyt_create_stage | Append a stage to a pipeline (e.g. 'On Hold', 'Declined/Dead') |
conduyt_update_stage | Rename, recolor, reorder, or change won/lost flags on a stage |
conduyt_delete_stage | Soft-delete a stage: an EMPTY stage can always be deleted (history kept, hidden from every list, GET / PATCH then 404, no restore in v1, name reusable); moveTo re-homes its live deals first, expectedSettingsRevision refuses the delete when settings changed (409 stale_settings_revision; the answer then carries the new settingsRevision). Refusals are 409s whose message is surfaced verbatim: deals in the stage, used by N active automation(s) (names), DPP status map, pipeline_archived, intake_target. A run parked before the delete fails at that step with a clear reason |
Activities
conduyt_list_activities | List recent CRM activities |
conduyt_create_activity | Log a call, meeting, or note |
AI
conduyt_ai_insights | AI-powered CRM analytics (11 query types, incl. report_catalog, saved_report and dashboard: run any saved report or board) |
Automations
conduyt_list_automations | List all automations with status |
conduyt_get_automation | Get automation with full action graph |
conduyt_create_automation | Create a new automation with triggers and actions |
conduyt_update_automation | Update trigger, actions, or activation status |
conduyt_publish_automation | Push draft actions to live |
conduyt_resolve_names | Convert tag/pipeline/user names to UUIDs |
Workflow Sandbox
conduyt_workflow_validate | Validate a workflow graph without saving — returns errors and warnings |
conduyt_workflow_simulate | Dry-run a workflow against a real or stub contact — step-by-step trace with compliance and provider checks; optional dealId (deal occurrence), companyId (company occurrence) and executionId (replays a stored run, admin or owner only, supplies the company its payload carried) |
conduyt_workflow_promote | Safely publish a workflow — validates first, refuses if errors exist |
Sequences (Email and SMS)
conduyt_list_sequences | List Email and SMS sequences: filter by type, On/Off, archived; view=summary for a light row each |
conduyt_get_sequence | One sequence: steps, sender, send window, stop rules, enrollment switches, people per run status |
conduyt_create_sequence | Create an Email or SMS sequence from saved templates (type fixed at creation, created Off unless isActive) |
conduyt_update_sequence | Change steps and settings, turn On or Off, archive or restore |
conduyt_list_sequence_senders | Who can be a sequence's sender, per channel (address for email, assigned line for SMS) |
conduyt_preflight_sequence_enrollment | Check contacts before enrolling: eligible, skipped and why, blockers |
conduyt_pick_sequence_list | Who of a Smart View or Smart List goes in next, with a cursor to continue |
conduyt_enroll_in_sequence | Enroll contacts into a sequence (up to 500 per call) |
conduyt_unenroll_from_sequence | Remove a contact from a sequence (the run ends as removed) |
conduyt_list_sequence_enrollments | The runs in a sequence: status, endedReason, current step, engagement; all_active for every live run |
conduyt_get_sequence_stats | Sends, opens and clicks in total and per step |
Messaging
conduyt_sms_transports | What a workflow Send SMS step can speak through today: Twilio numbers, Project Blue lines held by active reps, the WhatsApp sender, the Voicemail Drop recordings, webhook provider count, FromK.ai coming soon |
conduyt_voice_drop | Place a voice drop to a contact: an outbound Twilio call with answering-machine detection that plays a Voicemail Drop recording to a machine (hangs up on a person unless onHuman is play); governed like a call (calls-tier consent, calling hours, one live call per lead) |
conduyt_whatsapp_templates | The account's WhatsApp templates (Twilio Content) with Meta's approval verdict: sid, text with {{n}} placeholders, variables, approval |
conduyt_send_sms | Send SMS to a contact (max 1600 chars); transport twilio, project_blue, or whatsapp (an approved template by Content SID, or free-form within the 24-hour window) |
conduyt_send_email | Send a single email to a contact |
conduyt_check_message | Grade a draft text or email before sending (POST /messages/check): score, grade, verdict, flagged words with safer alternatives (Unicode code-point offsets), checks, a text's segment count. Educates, never blocks; nothing stored or sent. context template / first / conversation (pick from hasOutboundSms); provider: "twilio" (text only; the notices in Twilio's wording; an email with a provider is a 400) and clean: true (adds the cleaner's proposal); the answer carries breakdown, notices, unicodeCulprits, englishDictionary (loaded / not_loaded: the final grade is only meaningful when it is loaded) and engine.version (2.2.1); 20 per minute per account; 400 / 403 / 413 / 429 surfaced verbatim, never retried |
conduyt_list_sms_provider_options | The workspace's active SMS providers, redacted (GET /sms-providers/template-options): { data: [{ id, name, color }] }, nothing else. Needs email_templates.view or settings.view (scopes emails / sms / messages / settings); read-only |
conduyt_get_message_check_minimum_grade | The admin's Message check minimum grade to send (settings.messageCheck.minimumGrade): enabled, per-channel sms / email minimum (letter A-F, score 0-100 or null) and adminOverride. Groundwork: stored and read back, not enforced yet. Owner / admin only (anyone else gets visible: false); settings scope |
conduyt_update_message_check_minimum_grade | Change it (PATCH /settings): enabled, smsMinimum, emailMinimum, adminOverride; sends the whole block with the settings revision it read. enabled: true is refused 400 minimum_grade_not_available_yet; a non-owner / non-admin gets 403 forbidden; 422 for E, fractions, out-of-range scores; all verbatim, never retried |
conduyt_log_message | Record a message on a contact's timeline; an inbound SMS STOP or START records the number's opt-out or opt-in and answers smsConsent |
Calendly
conduyt_get_calendly_status | The Calendly connection (GET /integrations/calendly/status): own connection (an owner / admin key also gets every user's), event types and the selected ones, selectionSaved, liveSync (on / pending / plan_refused), import progress, last booking, last error. Tokens never returned; integrations scope, read-only |
conduyt_get_calendly_import_progress | The status read narrowed to one connection: `import { status (idle |
conduyt_list_calendly_event_types | Re-read the user's event types from Calendly (GET /integrations/calendly/event-types); 404 / 409 revoked / 502 surfaced verbatim |
conduyt_set_calendly_event_types | Choose the event types that sync (PATCH /integrations/calendly/event-types { eventTypeUris, connectionId? }, at most 200, only these sync, empty list stops syncing); the first save or an added type starts the silent import; needs active billing |
conduyt_disconnect_calendly | Disconnect (POST /integrations/calendly/disconnect { connectionId? }): removes the webhook and the connection, appointments stay; { disconnected, webhookRemoved, cleanupPending } |
Connecting Calendly is browser-only (OAuth 2.0 + PKCE): the user opens {app}/api/v1/integrations/calendly/oauth/install while signed in (Settings > Integrations > Calendly). API keys are refused there (scope integrations-oauth), so there is no tool; the sync cron and the webhook receiver are not key-callable.
Call log search (read-only, dialer:view)
conduyt_search_dialer_history | Search and filter the dialer call log for QA (GET /dialer/history, 200 per page): q (200 characters at most; matches name, number, agent and transcript, not notes), recordedOnly, disposition (100 characters at most), userId, dateFrom / dateTo, direction, status, mine. Each row carries match { field, snippet, ranges } when q is given; meta.incomplete with incompleteReason: "number_matches_capped" means total is a lower bound; 400s surfaced verbatim |
conduyt_count_unknown_callers | The toll-free counter (GET /calls/unknown-callers): for a line since an ISO since (start of day, within 31 days), total inbound calls that arrived with no contact and unmatched still contact-less; dialer:view |
conduyt_link_call | Link a contact-less call to an existing contact (POST /calls/{id}/link, the unknown-caller prompt's Search a contact + Attach): attachNumber writes the number into the next free phone slot, dryRun previews; refusals call_already_linked, no_free_phone_slot, number_on_another_contact, number_owner_undecidable, contact_not_editable, number_unusable; dialer:create (+ contacts:edit to attach) |
conduyt_search_dialer_calls | The recordings / voicemail list with the same search and filters (GET /dialer/calls, 100 per page) |
No tool carries call audio. Fetch it with GET {API base}/api/v1/dialer/call/{id}/media?type=recording (or type=voicemail) and the header Authorization: Bearer <API key>; add &download=1 (or download=true) for a Content-Disposition: attachment file. The conduyt CLI does it: conduyt dialer recording download <callId> [--voicemail] [-o file].
Companies
conduyt_list_companies | List and search companies |
conduyt_get_company | Get company with contacts and deals |
conduyt_create_company | Create a new company record |
conduyt_update_company | Update company details |
Tags
conduyt_list_tags | List all tags with contact counts |
conduyt_create_tag | Create a new tag |
conduyt_update_tag | Rename or recolor a tag |
conduyt_delete_tag | Delete a tag |
conduyt_merge_tags | Merge two tags (deduplicate) |
Calendar & Appointments
conduyt_list_calendars | List calendars with appointment counts |
conduyt_list_appointments | List appointments by date, calendar, contact, assignee |
conduyt_get_appointment | Get appointment with contact and assignee details |
conduyt_create_appointment | Create an appointment (times require timezone) |
conduyt_update_appointment | Reschedule, reassign, or cancel |
conduyt_appointment_outcome | Completed / no-show / cancelled / rescheduled: sets the status and moves the deal to the mapped stage |
conduyt_appointment_outcome_undo | Reverse the last outcome: status back, deal back to its previous stage when untouched since |
Forms
conduyt_list_forms | List web forms with submission counts |
conduyt_get_form | Get form with fields and settings |
conduyt_create_form | Create a new web form |
conduyt_list_form_submissions | List submissions for a form |
Invoices
conduyt_list_invoices | List invoices by status, contact, or date |
conduyt_get_invoice | Get invoice with line items and payments |
conduyt_create_invoice | Create invoice with line items (auto-calculates totals) |
conduyt_update_invoice | Update draft invoice items or details |
conduyt_send_invoice | Send invoice via email with PDF and Stripe payment link |
Webhooks
conduyt_list_webhooks | List registered webhooks |
conduyt_create_webhook | Register a new webhook (returns signing secret) |
conduyt_update_webhook | Update URL, events, or enable/disable |
conduyt_delete_webhook | Delete a webhook endpoint |
WordPress forms
conduyt_get_form_intake_status | Whether any intake address is active and how many ({ hasActive, activeCount }, count only, integrations scope, read-only) |
conduyt_list_form_intakes | List the intake addresses: every active one with its full URL, then the revoked history (newest 200) |
conduyt_create_form_intake | Create an intake address for one Gravity Forms / WPForms / Elementor form (returns its full URL) |
conduyt_revoke_form_intake | Revoke an intake address (the row is kept for history) |
Status metadata
conduyt_list_status_metadata / conduyt_get_status_metadata | Read the status taxonomy rows (one per stage and code); updatedAt is the version for expectedUpdatedAt |
conduyt_create_status_metadata | Create a row (stageId, code, bucket slugs, lifecycleStage, drip fields, isTerminal, notes) |
conduyt_update_status_metadata | Update a row; expectedUpdatedAt refuses a row changed or moved since (409 metadata_changed with the current row); 404 status_metadata_not_found |
conduyt_delete_status_metadata | Delete a row (expectedUpdatedAt as above) |
conduyt_import_status_metadata | Set-based import (max 1000; merge or replace); read errors[] even on a 200; 409 pipeline_archived when an item names a stage of an archived pipeline |
Mailchimp (API key scope integrations)
conduyt_get_mailchimp_settings | The Mailchimp connection: audience, source, settings and sync status (connected: false when none) |
conduyt_update_mailchimp_settings | PUT the audience (listId), source (smart list or tag), statusIfNew, unsubscribeSetsOptOut; only the fields sent change |
conduyt_list_mailchimp_audiences | The connected account's audiences (id, name, memberCount) |
conduyt_mailchimp_push_now | Run one sync pass now (ran is false while another pass holds the connection) |
conduyt_mailchimp_retry_unsubscribes | Retry undelivered unsubscribes (one per account per 10 minutes: 429 retry_cooldown) |
conduyt_mailchimp_reconcile_statuses | Full reconciliation of a blocked unsubscribe check (restart: true replaces a completed run; else 409 reconciliation_completed); owner / admin key |
conduyt_mailchimp_confirm_reconciliation | Confirm the reconciliation report and resume the check; owner / admin key |
Timeouts: the Mailchimp write/action tools and conduyt_import_status_metadata use a 60 s per-call timeout and conduyt_archive_pipeline 75 s (the client default is 30 s), above the server budgets; if a call still reports a timeout the server may have applied it, so re-read (conduyt_get_mailchimp_settings, conduyt_list_pipelines / conduyt_list_archived_pipelines, conduyt_list_status_metadata) before repeating it. The destructive tools (both deletes, archive, restore, reorders, status-metadata import and writes, Mailchimp settings and reconcile) take a strict input: a wire spelling such as expected_updated_at or a typo is InvalidParams and nothing is sent; an import item with an unknown key is refused as a whole, and mode: "replace" with no items (which would delete every row) is refused before any request. Tools without arguments (push, retry, confirm-reconciliation, the reads) reject any argument too. A body that stalls after the headers until the deadline is reported as the same "may have applied it" timeout, never retried for a mutation.
The Mailchimp OAuth connect and callback are browser-only: connect Mailchimp in the app (Settings > Integrations), then configure it here.
Notifications
conduyt_list_notifications | List notifications for current user; meta.latestByType is {type: {latest, count}} over the last 24 h (newest createdAt + row count per type, read state ignored) next to unreadCount / unreadByType |
conduyt_create_notification | Send in-app + push notification to a team member |
Team Chat
conduyt_list_chat_channels | GET /chat/channels: your channels; also CREATES your memberships in the auto channels the first time |
conduyt_get_chat_unread | GET /chat/unread: per channel { channelId, unread, soundUnread, newestSeq, latestSeq }; may list an auto channel you have not opened yet (no membership row) |
conduyt_list_chat_messages | List a channel's messages, newest first; every message carries seq (commit-ordered position in the channel); does not move the read marker; on a 403 "Not a member of this channel" it calls GET /chat/channels once and retries once |
conduyt_mark_chat_read | Acknowledge read up to one message (readUpTo = message UUID; the marker only moves forward, an older or foreign message is a no-op; same one-retry membership bootstrap) |
The rest of team chat (sending, reactions, pins, presence, uploads) is not wrapped yet; GET /chat/messages/{messageId}/location is a UI deep-link helper and deliberately not wrapped.
Custom Fields
conduyt_list_custom_fields | List custom field definitions (contact/deal) |
conduyt_create_custom_field | Create a custom field (text, number, date, select, etc.) |
conduyt_update_custom_field | Update label, options, or required status |
conduyt_delete_custom_field | Delete a custom field |
Smart Lists
conduyt_list_smart_lists | List all segments with contact counts |
conduyt_get_smart_list | Get smart list with filters |
conduyt_create_smart_list | Create static or dynamic smart list |
conduyt_update_smart_list | Update name, filters, or type |
conduyt_add_contacts_to_smart_list | Add contacts to a static list (max 500) |
conduyt_get_smart_list_contacts | Get contacts in a smart list |
Users & Team
conduyt_list_users | List team members with optional stats |
conduyt_get_user | Get user profile and permissions |
conduyt_create_user | Create user directly (no invite email) |
conduyt_update_user | Update profile, role, or permissions |
conduyt_get_user_stats | Get performance stats (deals, tasks, activity) |
conduyt_invite_user | Invite team member via email |
conduyt_deactivate_user | Deactivate a user (optionally reassign their records) |
conduyt_reactivate_user | Reactivate a deactivated user |
Bulk Operations
conduyt_ai_import_contacts | AI-powered bulk import (up to 1000, auto-tag, smart list, automation) |
conduyt_export_contacts | Export contacts as JSON with filters |
conduyt_export_deals | Export deals as JSON with filters |
conduyt_bulk_tag_contacts | Add one tag to many contacts |
conduyt_bulk_untag_contacts | Remove one tag from many contacts |
conduyt_bulk_edit_contacts | Apply the same field changes to many contacts |
conduyt_bulk_update_contacts | Apply per-contact field changes (each row has its own id) |
conduyt_bulk_delete_contacts | Soft-delete many contacts |
conduyt_bulk_dnc_contacts | Add/remove DNC or litigator mark on many contacts (compliance) |
conduyt_bulk_edit_deals | Apply the same field changes to many deals (e.g. bulk reassign) |
conduyt_bulk_update_deals | Apply per-deal field changes (each row has its own id) |
Drip Campaigns
conduyt_list_drip_campaigns | List SMS/email drip campaigns |
conduyt_get_drip_campaign | Get campaign with steps and provider config |
conduyt_create_drip_campaign | Create a drip campaign with schedule |
conduyt_update_drip_campaign | Update campaign settings |
conduyt_list_drip_enrollments | List enrollments by campaign, contact, status |
conduyt_batch_pause_enrollments | Pause all active enrollments |
conduyt_batch_resume_enrollments | Resume paused enrollments |
conduyt_batch_stop_enrollments | Permanently stop enrollments |
Lead Scoring
conduyt_list_scoring_rules | List scoring rules |
conduyt_create_scoring_rule | Create a scoring rule |
conduyt_update_scoring_rule | Update rule name, points, or condition |
conduyt_delete_scoring_rule | Delete a scoring rule |
conduyt_recalculate_scores | Recalculate all contact scores |
Products
conduyt_list_products | List product catalog |
conduyt_get_product | Get product details |
conduyt_create_product | Create a product |
conduyt_update_product | Update product pricing or details |
Templates
conduyt_list_templates | List email/SMS templates; each row carries bodyMode (blocks or html); the pasted html is not repeated in a list row |
conduyt_get_template | Get template content; an HTML-mode template answers its pasted source in html |
conduyt_create_template | Create an email or SMS template: blocks (body required, bodyMode blocks or omitted) or pasted HTML (email only: bodyMode: "html" + html, 102,400 bytes at most). provider binds an SMS template to a provider by the id from conduyt_list_sms_provider_options (preferred) or a legacy textual value the workspace already uses (sent as given; omitted on update = unchanged, null unbinds); unknown keys are refused. Refusals surfaced verbatim: html_too_large, html_script, html_conditional_comment, html_office_markup, html_duplicate_attribute, template_corrupt, invalid_body_mode, html_required, html_without_html_mode |
conduyt_update_template | Partial update of a template (content, subject, category, bodyMode / html); same refusals as create |
Dashboard
conduyt_dashboard | Full CRM dashboard (pipeline, activities, metrics, follow-ups) |
AI Extended
conduyt_ai_compose_email | AI-generated email with context-aware tone |
conduyt_ai_enrich_contact | AI-powered contact data enrichment |
conduyt_ai_summarize_contact | AI summary with sentiment and next steps |
conduyt_ai_chat | Conversational AI assistant grounded in your CRM (optionally pinned to a record) |
conduyt_ai_improve_email | Rewrite an email draft for clarity, tone, and persuasiveness |
conduyt_ai_deal_insights | AI risk/momentum analysis and next actions for a single deal |
conduyt_ai_conversation_intelligence | AI summary/sentiment/objections for a transcribed call |
conduyt_ai_call_disposition | AI-suggested disposition for a call from its transcript |
conduyt_ai_daily_brief | AI daily brief — today's priorities for a user |
conduyt_ai_next_actions | AI-ranked next actions for a user |
conduyt_ai_feed | Chronological stream of AI-surfaced events and insights |
conduyt_ai_usage | AI usage and budget report over a rolling window (owner/admin only) |
conduyt_ai_task_import_and_enroll | AI task (preview only): bulk import + tag + enroll + smart list — execution is human-session-only |
conduyt_ai_task_segment_and_act | AI task (preview only): segment by filter, then tag/assign/update — execution is human-session-only |
conduyt_ai_task_pipeline_cleanup | AI task (preview only): find stale deals and tag/move/notify/report — execution is human-session-only |
Privacy (GDPR)
conduyt_export_contact_data | GDPR data-portability export — full portable JSON of everything held about a contact (owner/admin) |
conduyt_forget_contact | IRREVERSIBLE GDPR right-to-be-forgotten erasure — requires confirm='FORGET' (owner only) |
Dialer
conduyt_sync_local_presence | Reconcile the Local Presence pool from Twilio (LP-named, voice, US +1, max 50) |
Lifecycle (master lead status + intake deals)
conduyt_get_lifecycle_settings | Effective master statuses (defaults + customs) and intake-deals config |
conduyt_update_intake_deals | Configure automatic deal creation on live intake (webhooks, forms, bookings) |
conduyt_update_booking_creates_own_card | settings.bookingCreatesOwnCard: a booking creates its own card owned by the host instead of reusing the contact's open intake card (strict input; conduyt_get_lifecycle_settings reads it) |
conduyt_update_master_statuses | Set the account's custom lead lifecycle statuses |
Reply Capture (inbound email)
conduyt_reply_capture_get | Current state: configured/live, capture domain + reply address, pending DNS records, provider health |
conduyt_reply_capture_setup | Create the receiving subdomain (must be a subdomain of the verified sending domain) and return its DNS records |
conduyt_reply_capture_verify | Check DNS and promote to live once the provider confirms inbound receiving |
conduyt_reply_capture_remove | Remove capture (and finish an interrupted removal) — requires confirm='REMOVE'; replies to already-sent email are lost |
Error text grammar
A refused call (HTTP 4xx/5xx) fails the tool with this text, stable across tools:
Conduyt API <status>: <server message>[ [Retry-After: <N>s]][ <details>]
[Retry-After: Ns] appears only when the server sent the header (shown, never acted on: a mutation is never retried).
<details> appears only when the body had more than error: it is ONE JSON object and the FINAL token. To extract it, try
each { from the left until the rest of the text parses as JSON (a server message may itself contain a brace). The object
carries scalars first (code, revision), then nested objects whole; HealthFixRefusal.row is always whole, any other nested
object too large for the bound is left out and named in _omitted. Every HTTP refusal takes this path, including the multipart call-flow audio upload; a tool that adds its own words (a missing-scope or busy note) puts them BEFORE this text. Example:
Conduyt API 503: Contact merge in progress [Retry-After: 5s] {"code":"merge_in_progress"}
The contact merge route (POST /contacts/merge, tool conduyt_merge_contacts) answers a retryable 503 with Retry-After and the code merge_contacts_busy (a contact stayed busy for the whole lock budget) or merge_budget_exhausted (the request's time budget ran out), nothing changed. Any tool that reaches it surfaces the refusal in this grammar and never retries it (one API job per key); the caller retries after the stated seconds.
Setup
npm install
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"conduyt": {
"command": "npx",
"args": ["-y", "conduyt-mcp"],
"env": {
"CONDUYT_API_URL": "https://conduyt.app",
"CONDUYT_API_KEY": "cdy_your_key_here"
}
}
}
}
Claude Code
Add to .mcp.json or settings:
{
"mcpServers": {
"conduyt": {
"command": "npx",
"args": ["-y", "conduyt-mcp"],
"env": {
"CONDUYT_API_URL": "https://conduyt.app",
"CONDUYT_API_KEY": "cdy_your_key_here"
}
}
}
}
Authentication
Generate an API key in Conduyt at Settings > API Keys. Keys use the cdy_ prefix and support three tiers:
- read — GET requests only
- write — GET + POST + PATCH
- admin — Full access including DELETE
Scopes can be restricted to specific modules (contacts, deals, tasks, etc.).
Environment Variables
CONDUYT_API_URL | Yes | Base URL (e.g. https://conduyt.app) |
CONDUYT_API_KEY | Yes | API key starting with cdy_ |