API openapi.jsonSign in
API reference

Build on Plodder

Everything you can do in Plodder, you can do over HTTP: create tasks, update deals, write docs, book meetings, and run any of the 190 tools Plodder's own agents use. Plodder can also tell your server when things change, with 127 signed webhook events.

Base URLhttps://app.useplodder.com
FormatJSON in, JSON out
AuthBearer API key

Authentication

Make a key in Plodder under Settings, Integrations and API, API keys. Pick the scopes it needs. Keys start with ctrl_ and are shown once, so store them somewhere safe.

Send the key in the Authorization header on every request:

curl https://app.useplodder.com/api/external/tasks?limit=5 \
  -H "Authorization: Bearer ctrl_your_key"
curl -X POST https://app.useplodder.com/api/external/tasks \
  -H "Authorization: Bearer ctrl_your_key" \
  -H "Content-Type: application/json" \
  -d '{"title": "Call Jordan back", "due_date": "2026-11-12"}'

A key acts as the person who made it and only reaches what that person can see.

Scopes

Every route and tool checks the key's scopes. Write includes read.

tasks:read tasks:writeTasks, views, schedules, comments
projects:read projects:writeProjects, stages, folders, templates
docs:read docs:writeDocs, sheets, slides, designs, discussions, properties
meetings:read meetings:writeMeeting notes and transcripts
crm:read crm:writePeople, businesses, deals, notes, clients
bookings:read bookings:writeCalendar events, booking calendars, bookings
forms:read forms:writeForms and responses
messages:read messages:writeEmail, texts, chat (reading and organizing)
calls:read calls:writePhone calls, recordings, video calls
automations:read automations:writeWorkflows, routines, agents
reports:read reports:writeDashboards and activity
files:read files:writeDrive, uploads, imports
esign:read esign:writePDF marks, signature requests, documents and contract templates
payments:read payments:writePayment links, invoices, subscriptions, refunds, recorded payments
commissions:read commissions:writeSales team payees, commission lines, monthly statements
instantly:read instantly:writeCold email campaigns
webhooks:read webhooks:writeOutgoing webhooks and their delivery log
users:read users:writeThe people who log in and the team roster (never passwords or sessions)
admin:read admin:writeWorkspaces, team, settings, everything else
messages:sendSend texts and email
*Full access

Errors and approvals

StatusMeaning
401No key, or the key is wrong or revoked.
403The key is missing a scope. The body lists them in missing_scopes.
400Bad input, or no access to that record. A name that matches more than one person is refused here too: pass an id or email instead.
202The action waits for a person to approve it in the Plodder Inbox (deleting, sending and money). The body has approval_id and approve_url.
{ "error": "Missing scope", "missing_scopes": ["crm:write"] }

REST API

The core records have plain routes. Anything else is reachable through the agent tools below.

Tasks

GET/api/external/taskstasks:read

List tasks (filters, offset/limit paging), or one task with ?id.

Query parameters
FieldTypeNotes
idinteger or stringNumeric id or public id.
workspace_idinteger or stringNumeric id or public id.
project_idinteger or stringNumeric id or public id.
assigneestringTeam id, login id, email or a name fragment.
statusstring
prioritystring
include_completedstring"false" hides done, cancelled and archived.
limitinteger
offsetinteger
POST/api/external/taskstasks:write

Create a task.

Body (JSON)
FieldTypeNotes
title requiredstring
descriptionstring
statusstring
prioritystring
assigneestringTeam id, login id (u_12 or 12), email or name.
due_datestringYYYY-MM-DD
start_datestring
duration_minutesinteger
workspace_idinteger or stringNumeric id or public id.
project_idinteger or stringNumeric id or public id.
stage_idinteger or stringNumeric id or public id.
labelsstring
blocked_bystring
agentstringThe agent creating it (marks the task as agent work).
needs_approvalboolean
auto_scheduleboolean
force_newbooleanCreate even when an open task with the same title exists.
PATCH/api/external/taskstasks:write

Update a task (id in the body).

Body (JSON)
FieldTypeNotes
titlestring
descriptionstring
statusstring
prioritystring
assigneestringTeam id, login id (u_12 or 12), email or name.
due_datestringYYYY-MM-DD
start_datestring
duration_minutesinteger
workspace_idinteger or stringNumeric id or public id.
project_idinteger or stringNumeric id or public id.
stage_idinteger or stringNumeric id or public id.
labelsstring
blocked_bystring
agentstringThe agent creating it (marks the task as agent work).
needs_approvalboolean
auto_scheduleboolean
force_newbooleanCreate even when an open task with the same title exists.
id requiredinteger or stringNumeric id or public id.
DELETE/api/external/taskstasks:write

Delete a task (soft).

Query parameters
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.

Activities

GET/api/external/activitiestasks:read

A task's comment thread (task_id), or many (task_ids=1,2,3).

Query parameters
FieldTypeNotes
task_idinteger or stringNumeric id or public id.
task_idsstringComma separated ids.
POST/api/external/activitiestasks:write

Comment on a task.

Body (JSON)
FieldTypeNotes
task_id requiredinteger or stringNumeric id or public id.
message requiredstring
agentstring
activity_typestring

Projects

GET/api/external/projectsprojects:read

List projects, or one with ?id (detail=true adds stages, tasks, progress).

Query parameters
FieldTypeNotes
idinteger or stringNumeric id or public id.
workspace_idinteger or stringNumeric id or public id.
detailstring"true"
POST/api/external/projectsprojects:write

Create a project.

Body (JSON)
FieldTypeNotes
name requiredstring
workspace_idinteger or stringNumeric id or public id.
folder_idinteger or stringNumeric id or public id.
colorstring
business_idinteger
PATCH/api/external/projectsprojects:write

Update a project.

Body (JSON)
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.
namestring
colorstring
statusstring
descriptionstring
DELETE/api/external/projectsprojects:write

Soft delete a project and its tasks and stages.

Query parameters
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.

Stages

GET/api/external/stagesprojects:read

A project's stages.

Query parameters
FieldTypeNotes
project_id requiredinteger or stringNumeric id or public id.
POST/api/external/stagesprojects:write

Create a stage.

Body (JSON)
FieldTypeNotes
project_id requiredinteger or stringNumeric id or public id.
name requiredstring
colorstring
PATCH/api/external/stagesprojects:write

Update a stage.

Body (JSON)
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.
namestring
colorstring
sort_orderinteger
DELETE/api/external/stagesprojects:write

Delete a stage.

Query parameters
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.

Folders

GET/api/external/foldersprojects:read

List folders.

Query parameters
FieldTypeNotes
workspace_idinteger or stringNumeric id or public id.
namestring
POST/api/external/foldersprojects:write

Create a folder (returns the existing one with the same name).

Body (JSON)
FieldTypeNotes
name requiredstring
workspace_idinteger or stringNumeric id or public id.
colorstring
parent_idinteger or stringNumeric id or public id.
PATCH/api/external/foldersprojects:write

Update a folder.

Body (JSON)
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.
namestring
colorstring
parent_idstring or integer or null
sort_orderinteger
DELETE/api/external/foldersprojects:write

Delete a folder.

Query parameters
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.

Docs

GET/api/external/docsdocs:read

List docs, or one with ?id.

Query parameters
FieldTypeNotes
idinteger or stringNumeric id or public id.
workspace_idinteger or stringNumeric id or public id.
project_idinteger or stringNumeric id or public id.
searchstring
POST/api/external/docsdocs:write

Create a doc (content is Markdown). No workspace_id = the key owner's primary workspace (agent tools can then edit it); a workspace the owner is not in is 403.

Body (JSON)
FieldTypeNotes
title requiredstring
contentstring
workspace_idinteger
project_idinteger
folder_idinteger
PATCH/api/external/docsdocs:write

Update a doc. Delete is not offered on the API (docs delete for good).

Body (JSON)
FieldTypeNotes
id requiredinteger or stringNumeric id or public id.
titlestring
contentstring

Meetings

GET/api/external/meetingsmeetings:read

List meeting notes, or one with ?id.

Query parameters
FieldTypeNotes
idstring
limitinteger
POST/api/external/meetingsmeetings:write

Import a meeting (Plaud, Otter, Zapier, anything).

Body (JSON)
FieldTypeNotes
titlestring
transcriptstring
summarystring
action_itemsany
attendeesany
duration_secondsinteger
meeting_datestring
sourcestring
client_idinteger
workspace_idinteger
PATCH/api/external/meetingsmeetings:write

Update a meeting note (id plus any fields).

Body (JSON)
FieldTypeNotes
id requiredinteger
titlestring
transcriptstring
summarystring
action_itemsany
attendeesany
meeting_datestring
DELETE/api/external/meetingsmeetings:write

Delete a meeting note for good (no undo).

Query parameters
FieldTypeNotes
id requiredstring

Calendar

GET/api/external/calendarcalendar:read

Events in a range (start, end), free slots on a day (mode=free-slots) or the agenda (mode=agenda).

Query parameters
FieldTypeNotes
modeevents | free-slots | agenda
startstring
endstring
calendarIdstring
datestringYYYY-MM-DD
duration_minutesinteger
work_startstring
work_endstring

Users

GET/api/external/usersusers:read

The people who log in and the team roster.

Query parameters
FieldTypeNotes
emailstringExact, any case.
qstring
includestringclients, agents, inactive (comma separated; clients needs crm:read).
GET/api/external/users/{id}users:read

One person by id, u_<login id>, login id or email.

Query parameters
FieldTypeNotes
id requiredstring
includestring

Workspaces

GET/api/external/workspacesworkspaces:read

Workspaces with counts.

Tools

GET/api/external/toolsper tool

The agent tools this key's scopes reach.

Agent tools

The same 190 tools Plodder's agents use, one route each. Send the arguments as a JSON body; the answer is {"ok": true, "result": ...}. GET /api/external/tools lists the ones your key's scopes reach.

curl -X POST https://app.useplodder.com/api/external/tools/add_task_comment \
  -H "Authorization: Bearer ctrl_your_key" \
  -H "Content-Type: application/json" \
  -d '{"task_id": 4412, "comment": "Sent the proposal."}'

Tasks 14

add_task_commentComment on a task

POST/api/external/tools/add_task_comment

Scopes: tasks:write

Add a comment to a task thread. It shows as written through your AI client, not as you typing it.

FieldTypeNotes
task_id requirednumber or string
comment requiredstring
agenda_snapshotsAgenda snapshotsasks for approval

POST/api/external/tools/agenda_snapshots

Scopes: tasks:read, tasks:write

Daily snapshots of every task with its status (/api/agendas). Owner only: snapshots are one table by date. Actions: - list: Dates that have a snapshot. - get: The snapshot for a date (YYYY-MM-DD). - save: Save today's snapshot from your workspaces' tasks (replaces today's).

FieldTypeNotes
action requiredlist | get | saveWhat to do.
datestringYYYY-MM-DD
auto_scheduleAuto-schedulingasks for approval

POST/api/external/tools/auto_schedule

Scopes: tasks:read, tasks:write

The owner's auto-scheduler: work-hours schedules (blocks = [{day 0-6, start "09:00", end "17:00"}]), flexible hours for one date, rescheduling now, and the task timer (start/stop). Actions: - list_schedules: Every work-hours schedule. - create_schedule: A new schedule (name, blocks, color, is_default). - update_schedule: Change a schedule (schedule_id, name, blocks, color, is_default). - delete_schedule: Delete a schedule. (waits for approval: delete) - get_flexible_hours: The flexible hours set for one date (YYYY-MM-DD). - set_flexible_hours: Different hours for one date (date, blocks). - clear_flexible_hours: Back to the normal schedule for that date. (waits for approval: delete) - reschedule: Run the auto-scheduler now (repacks auto-scheduled tasks around the calendar). - toggle_task_timer: Start the timer on a task (status in progress), or stop it when it is running.

FieldTypeNotes
action requiredlist_schedules | create_schedule | update_schedule | delete_schedule | get_flexiWhat to do.
schedule_idnumber
namestring
blocksarray of object
colorstring
is_defaultboolean
datestringYYYY-MM-DD.
task_idnumber or string
complete_taskComplete a task

POST/api/external/tools/complete_task

Scopes: tasks:write

Mark a task done. Pass a short result note (20+ characters) when the task was created by an AI agent; it is required there and saved to the task thread.

FieldTypeNotes
task_id requirednumber or string
resultstringWhat was done.
create_taskCreate a task

POST/api/external/tools/create_task

Scopes: tasks:write

Create a task inside a project. Every task needs a project: call list_projects first if you do not know the id. Assignee defaults to the project default, else you.

FieldTypeNotes
title requiredstringTask title.
project_id requirednumber or stringProject id or public id (required).
descriptionstringPlain text or simple HTML.
statusbacklog | todo | in_progress | blocked | review | done | cancelled | archivedDefault todo.
priorityurgent | high | medium | low
assigneestringTeam member id, user_id, email or name (list_team_members), "ai-<agent id>" to give it to an agent (it starts working on it), or "none".
due_datestringYYYY-MM-DD.
start_datestringYYYY-MM-DD.
duration_minutesnumber
parent_task_idnumberMake this a subtask.
delete_taskDelete a taskasks for approval

POST/api/external/tools/delete_task

Scopes: tasks:write

Delete a task. Needs your approval in Plodder before it happens (unless you changed that in Settings > AI agents).

FieldTypeNotes
task_id requirednumber or string
get_taskGet a taskread only

POST/api/external/tools/get_task

Scopes: tasks:read

Full detail for one task: description, subtasks and recent comments/activity.

FieldTypeNotes
task_id requirednumber or stringTask id or public id.
list_tasksList tasksread only

POST/api/external/tools/list_tasks

Scopes: tasks:read

List tasks you can see, newest first. Filter by workspace, project, status, assignee, due dates or text. Open tasks only unless include_done is true.

FieldTypeNotes
workspace_idnumberOnly this workspace. Default: every workspace you belong to.
project_idnumber or stringOnly this project (id or public id).
statusbacklog | todo | in_progress | blocked | review | done | cancelled | archived
assigneestringTeam member name (partial match), id, user_id or email. Use "me" for yourself.
due_beforestringYYYY-MM-DD, inclusive.
due_afterstringYYYY-MM-DD, inclusive.
querystringText to match in title or description.
include_donebooleanInclude done, cancelled and archived tasks.
limitnumberMax results (default 50, max 200).
saved_viewsSaved viewsasks for approval

POST/api/external/tools/saved_views

Scopes: tasks:read, tasks:write

Your saved list views on Home, Drive and Search (filters, sort, grouping saved under a name). Only you see them. config is the list settings object the app saves. Home: { status: all|unread|read, types: [tasks|email|chat|notifications|files|projects|agents], group?: date|type|none, sort?: latest|oldest|unread|name }. Search: { q, scope, group?: type|date|none, sort?: relevance|updated|oldest|name }. Actions: - list: Your saved views on a surface. - create: Save a view (surface, name, config). - update: Rename it, replace its config, or make it the default (is_default). - delete: Delete one of your saved views. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | deleteWhat to do.
surfacehome | drive | search
view_idnumber
namestring
configobject
is_defaultboolean
status_updatesStatus updatesasks for approval

POST/api/external/tools/status_updates

Scopes: tasks:read, tasks:write

Status updates posted on a task or a project (/api/status-updates). Give task_id or project_id. Actions: - list: Updates on a task or project, newest first. - create: Post an update (content) on a task or project. - delete: Delete an update (update_id). (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | deleteWhat to do.
task_idnumber
project_idnumber
contentstring
update_idnumber
task_actionsTask actionsasks for approval

POST/api/external/tools/task_actions

Scopes: tasks:read, tasks:write

More task actions, as you: bulk changes over many tasks, copy a task, recurring series (edit or delete one occurrence or the whole series), scheduled work blocks (chunks), possible duplicates, and GitHub pull requests on a task. For one task's fields use update_task. Actions: - bulk: Change many tasks at once (task_ids, bulk, value). (may wait for approval) - copy: Copy a task (task_id): same project, stage, assignee, priority and description, status todo. - recurrence: A recurring task's series (task_id, series, changes): detach and change one occurrence, edit_all, delete_one, delete_all. (may wait for approval) - complete_chunk: Mark one scheduled work block done or not done (task_id, chunk_start, completed). - lock_chunk: Move and pin a scheduled work block (task_id, old_chunk_start, new_chunk_start, new_chunk_end); the rest reschedules around it. - duplicates: Possible duplicates of a task (task_id). - dismiss_duplicate: Say two tasks are not duplicates (task_id, other_task_id). - pulls: GitHub pull requests linked to a task, ones that look related, and your open ones to pick from (task_id). - link_pull: Link a GitHub pull request to a task (task_id, url, title). - unlink_pull: Unlink a pull request from a task (task_id, url).

FieldTypeNotes
action requiredbulk | copy | recurrence | complete_chunk | lock_chunk | duplicates | dismiss_duWhat to do.
task_idsarray of number
bulkset_priority | set_status | set_assignee | set_project | complete | deletebulk: what to do to every task.
valueanybulk: the new priority / status / assignee (team member public id or null) / project id.
cancel_reasonstring
task_idnumber
seriesdetach | edit_all | delete_one | delete_allrecurrence: detach = change only this occurrence.
changesobjectrecurrence: task fields to change.
chunk_startnumberepoch seconds of the work block
completedboolean
old_chunk_startnumber
new_chunk_startnumber
new_chunk_endnumber
other_task_idnumber
urlstringa GitHub pull request link
titlestring
fieldsobjectAny other body fields the action documents.
task_viewsTask board viewsasks for approval

POST/api/external/tools/task_views

Scopes: tasks:read, tasks:write

The named views on the task board (list, kanban, gantt, dashboard, workload) with their saved settings. Everyone on the board shares them, the same as in the app. Actions: - list: Every task view. - create: A new view (name, view_type, config). - update: Change name, view_type, config or sort_order. - delete: Delete a view. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | deleteWhat to do.
view_idnumber
namestring
view_typelist | kanban | gantt | dashboard | workload
configobject
sort_ordernumber
time_trackingTime trackingasks for approval

POST/api/external/tools/time_tracking

Scopes: tasks:read, tasks:write

Plodder time tracking from the Mac collector, as you (/api/ctrl-flow/*): classify sessions and apps to businesses and projects (the review queue), log a session's time to a task, privacy rules, retention, and maintenance backfills. Pairing a new Mac happens in the app. Actions: - classify: One review / attribution change (op + fields). merge_sessions and merge_entities wait for approval. (may wait for approval) - log_time: Log a session's business time to a task (session_id, business_id, task_id or new_task_title, project_id?, note?). reverse=true takes it back off. - backfill: Re-derive tracked data (backfill: default | localAiSessionIds | fleetFlags | fleetDispatch | reviewSweep | businessSeconds | reconcile; limit?, max_seconds?, days?). - delete_range: Delete tracked activity in a range (start + end ISO, or the last `days`). (waits for approval: delete) - retention: Keep `days` of tracked activity and delete what is older now. (waits for approval: delete) - privacy_rules: Privacy rules (what the collector never records). - add_privacy_rule: A privacy rule (kind, value, rule_action block|allow, default block). - remove_privacy_rule: Remove a privacy rule (rule_id). (waits for approval: delete) - devices: Paired Mac collectors. - revoke_device: Revoke a Mac collector (device_id); its token stops working. (waits for approval: delete)

FieldTypeNotes
action requiredclassify | log_time | backfill | delete_range | retention | privacy_rules | add_What to do.
oplabel_entity | attach_entity_business | attach_entity_project | attach_session_bclassify: which change. Its fields (sessionId, entityId, businessId, projectId, label, keywords, kind, value, reviewId, sourceSessionId, targetSessionId, sourceEntityId, targetEntityId, keyword) go in `fields`.
session_idnumber
business_idnumber
project_idnumber
task_idnumber
new_task_titlestring
notestring
reversebooleanlog_time: take a logged entry back off the task.
backfilldefault | localAiSessionIds | fleetFlags | fleetDispatch | reviewSweep | busines
limitnumber
max_secondsnumber
daysnumber
startstringISO date-time.
endstringISO date-time.
rule_idnumber
kindstringprivacy rule kind (app, domain, title, ...).
valuestring
rule_actionblock | allow
device_idnumber
fieldsobjectAny other body fields the action documents.
update_taskUpdate a task

POST/api/external/tools/update_task

Scopes: tasks:write

Change a task: title, description, status, priority, assignee, dates, duration, or move it to another project. Only the fields you pass change.

FieldTypeNotes
task_id requirednumber or string
titlestring
descriptionstring
statusbacklog | todo | in_progress | blocked | review | done | cancelled | archived
priorityurgent | high | medium | low
assigneestringTeam member id, user_id, email or name (list_team_members), "ai-<agent id>" to give it to an agent (it starts working on it), or "none" to unassign.
due_datestring or nullYYYY-MM-DD, or null to clear.
start_datestring or null
duration_minutesnumber
project_idnumber or stringMove to this project.
resultstringWhat was done. Required when marking a task created by an AI agent done (20+ characters).

Projects 5

create_projectCreate a project

POST/api/external/tools/create_project

Scopes: projects:write

Create a project with the standard Todo, In Progress and Done stages.

FieldTypeNotes
name requiredstring
workspace_idnumberWorkspace id (from list_workspaces). Defaults to your primary workspace.
colorstringHex colour, optional.
get_projectGet a projectread only

POST/api/external/tools/get_project

Scopes: projects:read

One project with its stages, task counts and open tasks.

FieldTypeNotes
project_id requirednumber or string
list_projectsList projectsread only

POST/api/external/tools/list_projects

Scopes: projects:read

List projects in your workspaces (or one workspace). Archived ones are left out unless include_archived is true.

FieldTypeNotes
workspace_idnumberOnly this workspace. Default: all of yours.
querystringMatch in the project name.
include_archivedboolean
project_actionsProject actionsasks for approval

POST/api/external/tools/project_actions

Scopes: projects:read, projects:write

Project settings, copies, stages and the project's comment box, as you. For tasks in a project use create_task / list_tasks. Actions: - update: Change a project (project_id, set). archived 1 archives it, 0 brings it back. - delete: Delete a project (it goes to Trash with its stages and tasks). (waits for approval: delete) - copy: Copy a project with its stages, tasks and docs (project_id, name). - comments: The project's comment box. - comment: Post in the project's comment box (project_id, body). - delete_comment: Delete your own project comment (comment_id). (waits for approval: delete) - stages: The project's stages in order. - add_stage: Add a stage (project_id, name, color). - update_stage: Change a stage (stage_id, set: {name, color, is_active, ...}). - reorder_stages: Put the stages in this order (project_id, stage_ids). - delete_stage: Delete a stage (stage_id); its tasks move to reassign_to, or lose their stage. (waits for approval: delete) - apply_template: Add a project template's stages and tasks to a project (project_id, template_id).

FieldTypeNotes
action requiredupdate | delete | copy | comments | comment | delete_comment | stages | add_stagWhat to do.
project_idnumber
namestring
setobjectupdate: project fields (name, description, color, status, priority, start_date, due_date, folder_id, archived 1|0, ...).
bodystringcomment: the text (@Claude or an agent handle runs that agent).
comment_idnumber
stage_idnumber
colorstring
stage_idsarray of number
reassign_tonumberdelete_stage: move its tasks to this stage.
template_idnumber
fieldsobjectAny other body fields the action documents.
templatesTemplatesasks for approval

POST/api/external/tools/templates

Scopes: projects:read, projects:write

Project templates, task templates and doc templates, as you: list, create, change, delete, and use them. Actions: - list_project: Project templates. - create_project: A project template (name, description, set {stages, default_tasks, roles, text_variables} as JSON strings), or from_project_id. - update_project: Change a project template (template_id, set). - delete_project: Delete a project template (template_id). (waits for approval: delete) - list_task: Task templates (workspace_id optional). - create_task: A task template (name, set {default_title, default_priority, default_duration_minutes, default_status, description, subtasks}). - use_task: Create the task(s) from a task template (template_id, project_id, stage_id, workspace_id). - delete_task: Delete a task template (template_id). (waits for approval: delete) - list_doc: Doc templates you can use (built-in and your workspaces'). - get_doc: One doc template with its blocks. - save_doc: Save a doc as a doc template (doc_id, name, description, set {category}). - update_doc: Change a doc template (template_id, set {name, description, category, icon}, or set {duplicate: true}). - delete_doc: Delete a doc template (template_id). (waits for approval: delete) - use_doc: A new doc from a doc template (template_id, title, workspace_id or project_id).

FieldTypeNotes
action requiredlist_project | create_project | update_project | delete_project | list_task | crWhat to do.
kindproject | task | doc
template_idnumber
namestring
descriptionstring
from_project_idnumbercreate a project template from this project.
doc_idstringsave this doc as a doc template.
workspace_idnumber
project_idnumber
stage_idnumber
titlestring
setobjectupdate: fields (project: name, description, stages, default_tasks, roles, text_variables; doc: name, description, category, icon).
fieldsobjectAny other body fields the action documents.

Docs and databases 24

add_database_rowAdd a database row

POST/api/external/tools/add_database_row

Scopes: docs:write

Add a row to a database. values maps column names (from list_database_rows) to values.

FieldTypeNotes
database requiredstringDatabase id or sheet:<id>.
values requiredobjectColumn name -> value.
append_to_docAppend to a doc

POST/api/external/tools/append_to_doc

Scopes: docs:write

Add markdown to the end of a doc without touching what is there.

FieldTypeNotes
doc_id requirednumber or string
content requiredstringMarkdown to append.
code_filesCode filesasks for approval

POST/api/external/tools/code_files

Scopes: docs:read, docs:write

Read and write code files in Drive, as you: files made in the code editor (id) and code-type uploads (.js .ts .py .json .css .html .md ..., drive_file). Edit with a find and replace (edit) or write the whole text (write). Actions: - list: Code files you can open, newest first. - get: A code file: title, type, revision, content, where it sits in Drive. - create: A new code file: title (with extension sets the language), file_type, content, workspace_id or folder_id. - write: Replace the whole content (base_rev from get; force=true overwrites a newer change). - edit: Replace old_text with new_text (exactly once unless all=true). - rename: Change the title (an extension also sets the language). - set_type: Change the language (file_type, an extension like "py"). - move: Move in Drive: workspace_id and/or folder_id. - trash: Move to Drive Trash. (waits for approval: delete) - drive_get: A code-type Drive upload (drive_file): content and its sha256. - drive_write: Save a Drive upload's text: content (base_sha from drive_get; force=true overwrites), or old_text/new_text.

FieldTypeNotes
action requiredlist | get | create | write | edit | rename | set_type | move | trash | drive_geWhat to do.
idstringCode file id or public id.
drive_filestringDrive file id (an uploaded code file).
titlestring
file_typestring
contentstring
old_textstring
new_textstring
allboolean
base_revnumber
base_shastring
forceboolean
workspace_idnumber
folder_idnumber
create_docCreate a doc

POST/api/external/tools/create_doc

Scopes: docs:write

Create a doc from markdown (headings, lists, checklists, code, bold/italic/links; $$ LaTeX $$ or a ```math fence for a math block; ![caption](file.mp4) or ![video](link) for a video block; a ```poll fence with the question line and "- option" lines, flags multi / anonymous / closed, for a poll people vote on).

FieldTypeNotes
title requiredstring
contentstringMarkdown.
workspace_idnumberWorkspace id (from list_workspaces). Defaults to your primary workspace.
project_idnumberAttach to a project.
database_adminDatabase structure and sharingasks for approval

POST/api/external/tools/database_admin

Scopes: docs:read, docs:write

Change a database's structure, as you: the same operations as the database grid (op = create_sheet {name, workspace_id}, rename_sheet {name}, add_column {name, type}, rename_column {column_name, new_name}, delete_column {column_name}, and the grid's other ops; pass their fields in fields), plus sharing with an email. Rows: add_database_row / update_database_row / delete_database_row. Actions: - change: Run one grid operation (op, database_id, fields): create_sheet, rename_sheet, add_column, rename_column, delete_column, reorder_columns, update_sheet, update_sheet_labels, update_settings, set_column_required {column_name, required} (a required column must hold a value in every row), import_csv, set_link_access, delete_sheet. Deletes and opening link access wait for approval. (may wait for approval) - shares: Who the database is shared with by email. - share: Share with an email (role, notify). (waits for approval: external) - unshare: Remove an email's access.

FieldTypeNotes
action requiredchange | shares | share | unshareWhat to do.
database_idstring
opstringThe grid operation (the database API's action).
emailstring
roleviewer | editor
notifyboolean
fieldsobjectAny other body fields the action documents.
delete_database_rowDelete a database rowasks for approval

POST/api/external/tools/delete_database_row

Scopes: docs:write

Delete one row of a database. Needs the user's approval unless they allowed deletes.

FieldTypeNotes
database requiredstringDatabase id or sheet:<id>.
row_id requirednumber
designDesign filesasks for approval

POST/api/external/tools/design

Scopes: docs:read, docs:write

Read and edit design files, as you. Items: pages {t:"page", name, bg, modes: {<collection id>: <mode id>}}, color/text styles {t:"style", kind}, variable collections {t:"vars", name, modes: [{id, name}]}, variables {t:"var", coll, name, type: color|number|string|boolean, values: {<mode id>: value}}, and nodes {t: frame|group|rect|ellipse|polygon|star|path|text|instance|boolean, parent: page or container id, name, x, y, w, h, fills: [{type:"solid", color:"#hex"}], strokes, strokeWidth, effects: [], text nodes {text, style}}. Bind a node property to a variable with bind: {fill|stroke|opacity|radius|strokeWidth|w|h|gap|padding|text|visible|fontSize: <variable id>} (the value is written on save). Frames take layout grids: grids: [{type: columns|rows|grid, count, size, gutter, margin, align: stretch|start|center|end, color, opacity}] and modes like pages. Get a design first to see its pages and node shapes, then add nodes with the same fields. Actions: - list: Designs you can open, newest first. - get: The design: title, your access, and every item as JSON. - create: A new design (title, workspace_id or folder_id), filed in Drive. - rename: Change the title. - add: Add items: a list of objects (an id is made when missing). - update: Change items by id: a list of {id, ...fields to change}. - remove: Remove items by id (ids). Undo is in the editor's history. - replace: Replace the whole design content (content = {items: [...]}). - trash: Move the design to Trash. (waits for approval: delete)

FieldTypeNotes
action requiredlist | get | create | rename | add | update | remove | replace | trashWhat to do.
idstringdesign id or public id.
titlestring
workspace_idnumber
folder_idnumber
itemsarray of objectadd / update: the items.
idsarray of stringremove: ids.
contentobjectreplace: the whole document.
design_libraryDesign librariesasks for approval

POST/api/external/tools/design_library

Scopes: docs:read, docs:write

Team libraries for design files, as you: publish a design file's components, colour and text styles and variables; use another file's library in a design file (its items are copied in on a hidden page); take newer versions; stop using one (anything still used stays as the file's own). Actions: - list: Libraries you can use: src (the publishing file), name, version, counts, mine. - get: One library's current version (src) with its items. - publish: Publish (or publish the next version of) the design file id; description optional. - unpublish: Unpublish the design file id's library (files using it keep their copies). - use: Make the design file id use the library src (copies its items in). - update: Take the newest version of every library the design file id uses (or only lib, a lib item id). - stop_using: Stop using a library in the design file id (lib = the lib item id from get on the design).

FieldTypeNotes
action requiredlist | get | publish | unpublish | use | update | stop_usingWhat to do.
idstringDesign file id or public id.
srcstringThe library: the publishing design file's public id.
libstringA lib item id inside the design file.
descriptionstring
discussion_actionsDiscussion actionsasks for approval

POST/api/external/tools/discussion_actions

Scopes: docs:write

Change comments in an item's discussion, as you: edit your message, resolve or reopen a thread, react with an emoji, delete a message. item = <type>:<id>. Read and post with read_discussion / post_discussion. Actions: - edit: Edit your message (message_id, content). - resolve: Resolve (resolved true) or reopen a thread (thread_root_id). - react: Toggle an emoji reaction (message_id, emoji). - delete: Delete a message (message_id). (waits for approval: delete)

FieldTypeNotes
action requirededit | resolve | react | deleteWhat to do.
itemstring
message_idnumber
contentstring
thread_root_idnumber
resolvedboolean
emojistring
fieldsobjectAny other body fields the action documents.
doc_actionsDoc actionsasks for approval

POST/api/external/tools/doc_actions

Scopes: docs:read, docs:write

More doc actions, as you: delete, who wrote each block (blame), polls (results, vote, close), block comments (add, resolve, delete), publish to the web, share with someone by email, and synced blocks. Read and write a doc's text with get_doc / update_doc. Actions: - delete: Delete a doc (to Trash). (waits for approval: delete) - polls: The doc's polls with results: question, options, votes per option, who voted (unless anonymous), your vote, closed. - vote: Vote in a doc poll as you (poll_id from get_doc's ```poll id=..., vote: option numbers from 0; [] withdraws). - close_poll: Close (closed: true) or reopen (closed: false) a doc poll. - blame: Who last changed each block of the doc and when ({blocks: {block_id: {name, user_id, source, at}}}), from its version history. - comments: A doc's block comments, threaded. - comment: Comment on a doc block (doc_id, content, block_id, parent_comment_id to reply). @Claude or an agent handle runs that agent. - resolve_comment: Resolve a block comment (comment_id). - delete_comment: Delete a block comment (comment_id). (waits for approval: delete) - publish: Publish the doc on a public web page (returns its slug). (waits for approval: external) - unpublish: Take the public page down. - shares: Who the doc is shared with by email. - share: Share the doc with an email (role viewer|editor; notify emails them, default true). (waits for approval: external) - unshare: Remove an email's access. - create_synced_block: A synced block (content shown live in several docs): blocks, workspace_id. Insert it in a doc with the returned id. - update_synced_block: Change a synced block everywhere it is shown (block, blocks, rev from its last read).

FieldTypeNotes
action requireddelete | polls | vote | close_poll | blame | comments | comment | resolve_commenWhat to do.
doc_idstringDoc id or public id.
contentstring
block_idstringcomment: the block it is on.
parent_comment_idnumber
comment_idnumber
emailstring
roleviewer | editor
notifyboolean
blockstringsynced block id
blocksstringsynced block content: a JSON string of blocks.
revnumber
workspace_idnumber
poll_idstringpolls / vote / close_poll: the id in get_doc's ```poll id=... line.
votearray of numbervote: the option numbers you pick (0 = first).
closedboolean
fieldsobjectAny other body fields the action documents.
get_database_rowRead a database rowread only

POST/api/external/tools/get_database_row

Scopes: docs:read

One database row with every column (formulas computed, relations as titles), its notes, and its database. Rows are items too: sheet_row:<id> works with get_properties, set_tags, read_discussion, post_discussion and read_activity.

FieldTypeNotes
row_id requiredstringRow id or sheet_row:<id>.
get_docRead a docread only

POST/api/external/tools/get_doc

Scopes: docs:read

Read a doc as markdown-style text, with its word_count, characters and reading_minutes. checklists lists each checklist (2+ items in a row) with its done/total progress and the filter that shows items (all, open, done).

FieldTypeNotes
doc_id requirednumber or stringDoc id or public id.
illustrationIllustrationsasks for approval

POST/api/external/tools/illustration

Scopes: docs:read, docs:write

Read and edit illustrations (vector artwork on artboards), as you. Same document as design files: artboards are top-level frames on a page; draw with path nodes {t:"path", paths: [{pts: [{x, y, i?: [dx, dy], o?: [dx, dy]}], closed}], fills, strokes, strokeWidth}, shapes and text. Items: pages {t:"page", name, bg, modes: {<collection id>: <mode id>}}, color/text styles {t:"style", kind}, variable collections {t:"vars", name, modes: [{id, name}]}, variables {t:"var", coll, name, type: color|number|string|boolean, values: {<mode id>: value}}, and nodes {t: frame|group|rect|ellipse|polygon|star|path|text|instance|boolean, parent: page or container id, name, x, y, w, h, fills: [{type:"solid", color:"#hex"}], strokes, strokeWidth, effects: [], text nodes {text, style}}. Bind a node property to a variable with bind: {fill|stroke|opacity|radius|strokeWidth|w|h|gap|padding|text|visible|fontSize: <variable id>} (the value is written on save). Frames take layout grids: grids: [{type: columns|rows|grid, count, size, gutter, margin, align: stretch|start|center|end, color, opacity}] and modes like pages. Actions: - list: Illustrations you can open, newest first. - get: The illustration: title, your access, and every item as JSON. - create: A new illustration (title, workspace_id or folder_id), filed in Drive. - rename: Change the title. - add: Add items: a list of objects (an id is made when missing). - update: Change items by id: a list of {id, ...fields to change}. - remove: Remove items by id (ids). Undo is in the editor's history. - replace: Replace the whole illustration content (content = {items: [...]}). - trash: Move the illustration to Trash. (waits for approval: delete)

FieldTypeNotes
action requiredlist | get | create | rename | add | update | remove | replace | trashWhat to do.
idstringillustration id or public id.
titlestring
workspace_idnumber
folder_idnumber
itemsarray of objectadd / update: the items.
idsarray of stringremove: ids.
contentobjectreplace: the whole document.
imagesImage editorasks for approval

POST/api/external/tools/images

Scopes: docs:read, docs:write

Layered image projects (the image editor), as you: list, create, open a Drive image for editing, read and change layers (name, visibility, opacity, position, order, text of text layers, remove), versions, and Remove background. Painting, filters and selections are in the editor in the browser. Actions: - list: Image projects you can open, newest first. - get: Size, access, where it sits, the Drive image it came from, and its layers. - create: A blank image: title, width, height, background (default white), workspace_id or folder_id. - open_drive_image: Open a Drive image (drive_file) as a layered project (reuses the one made before). - update_layers: Change layers: layers [{id, name?, visible?, opacity?, x?, y?, w?, h?, blend?, text?, locked?}]. - move_layer: Move a layer (layer_id) to index (0 = bottom) within its group. - remove_layer: Remove a layer (layer_id). (waits for approval: delete) - remove_background: Remove the background of a pixel layer (layer_id): with the user's OpenAI key the result is added as a new layer above (the original is hidden, not lost); without one, the answer explains the in-browser path. (may wait for approval) - rename: Change the title. - move: Move in Drive: workspace_id and/or folder_id. - versions: Earlier saves of the project, and of the Drive image it came from. - restore_version: Make an earlier project save current (version_id), or of the Drive original (original=true). - trash: Move to Drive Trash. (waits for approval: delete)

FieldTypeNotes
action requiredlist | get | create | open_drive_image | update_layers | move_layer | remove_layWhat to do.
idstringImage project id or public id.
drive_filestring
titlestring
widthnumber
heightnumber
backgroundboolean
layersarray of object
layer_idstring
indexnumber
version_idnumber
originalboolean
workspace_idnumber
folder_idnumber
list_database_rowsRead a databaseread only

POST/api/external/tools/list_database_rows

Scopes: docs:read

The columns and rows of a database (sheet). Find databases with list_items types ["sheet"]. Optionally filter rows by text.

FieldTypeNotes
database requiredstringDatabase id or sheet:<id> ref.
textstringOnly rows containing this text.
limitnumberMax rows (default 100, max 500).
list_docsList docsread only

POST/api/external/tools/list_docs

Scopes: docs:read

List docs in your workspaces, optionally by project or a text search on title and content.

FieldTypeNotes
workspace_idnumber
project_idnumber
querystring
limitnumberDefault 50.
list_tagsList tagsread only

POST/api/external/tools/list_tags

Scopes: docs:read

Tags, in two separate sets: scope "crm" (people, businesses, deals, conversations, bookings, forms, workflow tag steps) and scope "work" (tasks, projects, docs, files, everything else). The same name can exist in both. No scope = both, each with its scope.

FieldTypeNotes
scopecrm | workWhich set. Omit for both.
presentationsPresentationsasks for approval

POST/api/external/tools/presentations

Scopes: docs:read, docs:write

Read and build slide decks, as you. Layouts: title, title-content, section, two-content, title-only, blank. A slide from fields: {layout, title, subtitle, body (one line per paragraph, "- " for bullets, indent two spaces per level), notes}. get_slide returns the raw elements (text, image, table) for fine edits with set_elements. Actions: - list: Presentations you can open, newest first. - get: Title, access, theme name and every slide's title, text and notes. - get_slide: One slide (slide_id or slide number) as raw JSON. - create: A new deck: title, slides [{layout, title, subtitle, body, notes}], theme (name), workspace_id or folder_id. - add_slide: Add a slide from fields (fields) at position (1-based; default the end). - update_slide: Change a slide's layout, title, subtitle, body or notes (fields), or hide it (hidden). - set_elements: Replace a slide's elements with raw JSON (elements), for layouts the fields cannot express. - move_slide: Move a slide to position (1-based). - delete_slide: Remove a slide. (waits for approval: delete) - rename: Change the title. - move: Move in Drive: workspace_id and/or folder_id. - versions: Saved .pptx versions (exports, imports). - trash: Move to Drive Trash. (waits for approval: delete) - list_items: A slide's items like the Selection pane: id, kind, name, hidden, locked, group, box (front first). - update_items: Selection pane changes on a slide: items [{id, name, hidden, locked, x, y, w, h}], order (ids front first) to restack. - group: Group items (ids) so they select and move together. - ungroup: Ungroup: every group touching ids comes apart. - set_animations: Replace a slide's animations, in play order: animations [{element (item id), class entrance|emphasis|exit, effect, trigger click|with|after, duration_ms, delay_ms, direction left|right|up|down (fly, float, wipe), repeat}]. Effects: entrance:appear, entrance:fade, entrance:fly, entrance:float, entrance:split, entrance:wipe, entrance:zoom, entrance:growTurn, entrance:bounce, entrance:swivel, emphasis:pulse, emphasis:teeter, emphasis:spin, emphasis:growShrink, emphasis:transparency, exit:disappear, exit:fade, exit:fly, exit:float, exit:split, exit:wipe, exit:zoom, exit:shrinkTurn. Empty list removes them. - set_transition: Set a slide's transition (or every slide's with all_slides): transition {type none|fade|push|wipe|cover|uncover|split|zoom|cut|dissolve, duration_ms, direction (push, wipe, cover, uncover), after_ms (move on by itself), no_click}; null removes it. - add_chart: Add a native chart: chart {type bar|stacked|line|area|stacked-area|pie|doughnut|scatter|radar, title, legend, categories [labels], series [{name, values}]}, optional x/y/w/h (points, slide 960x540). update with element_id to change an existing chart. - add_equation: Add an equation from LaTeX (latex, size), optional x/y; element_id changes an existing one. - add_diagram: Add a SmartArt-style diagram: diagram {type list|process|cycle|hierarchy, text (one line per shape; indent two spaces for a child in a hierarchy)}, optional x/y/w/h; element_id (any shape of it) redraws an existing diagram. - get_master: The slide master: graphics, background, title/body text styles, and per layout its graphics, background, placeholder boxes and hide flag. - set_master: Replace the slide master (same JSON as get_master: {els, bg, title {font,size,color,bold,italic}, body, layouts {<layout>: {els, bg, boxes, hideMaster}}}); null removes it. Slides whose placeholders follow the master move and restyle with it. - set_slide_options: Slide flags: hide_background_graphics (hide the master graphics on this slide). - find: Find text like the editor's find bar: query, match_case, whole_word, include_notes (default true), optional slide / slide_id to look on one slide. Returns each match (slide, item id or notes, table cell, context). - replace_text: Find and replace across the deck (text boxes, shapes, table cells and, unless include_notes is false, speaker notes): query, replacement, match_case, whole_word, optional slide / slide_id. The new text keeps the formatting where each match starts. Returns how many changed.

FieldTypeNotes
action requiredlist | get | get_slide | create | add_slide | update_slide | set_elements | moveWhat to do.
idstringPresentation id or public id.
titlestring
themestringcreate: Office, Paper, Night, Slate, Forest, Ocean, Sunset, Mono.
slidesarray of object
fieldsobject{layout, title, subtitle, body, notes}
elementsarray of object
slide_idstring
slidenumber1-based slide number.
positionnumber
hiddenboolean
workspace_idnumber
folder_idnumber
itemsarray of objectupdate_items: [{id, name, hidden, locked, x, y, w, h}]
orderarray of stringupdate_items: item ids front first.
idsarray of string
animationsarray of object
transitionobject or null
all_slidesboolean
chartobject
diagramobject
latexstring
sizenumber
element_idstring
masterobject or null
hide_background_graphicsboolean
querystringfind / replace_text: the text to look for.
replacementstringreplace_text: the new text (may be empty).
match_caseboolean
whole_wordboolean
include_notesbooleanfind / replace_text: look in speaker notes too (default true).
xnumber
ynumber
wnumber
hnumber
query_databaseQuery a databaseread only

POST/api/external/tools/query_database

Scopes: docs:read

Answer a question from a database's rows: filter, group, aggregate, sort and limit, computed by the app over the rows the user can see (formula and rollup columns are filled in, relation cells are titles). Returns the result table and the equivalent SQL. Leave out group_by and metrics to list rows; give metrics without group_by for one number; give group_by (plus bucket for a date column) for a breakdown. chart is a display hint for the app (bar for categories, line for time, pie for parts of a whole, table for lists); it does not change the result. Column names must match the database (see list_database_rows).

FieldTypeNotes
database requiredstringDatabase id or sheet:<id>.
filtersarray of object
group_bystringColumn to group by. Multi-select rows count once per label.
bucketday | week | month | quarter | yearDate bucket when group_by is a date column.
metricsarray of object
columnsarray of stringColumns to show when listing rows.
sortobject
limitnumberMax result rows (default 50 for groups, 100 for rows, max 500).
chartbar | line | pie | tableHow the app should draw this answer.
titlestringShort chart title.
spreadsheetsSpreadsheetsasks for approval

POST/api/external/tools/spreadsheets

Scopes: docs:read, docs:write

Read and write spreadsheets (the grid editor, not databases), as you. Ranges are A1 notation ("B2", "A1:D20"); sheet is the tab name (default the first). Values are written like typing: numbers, "12%", "$1,200", dates, TRUE/FALSE, and "=SUM(A1:A5)" formulas. read returns computed values, the formulas behind them and the formatted text. Actions: - list: Spreadsheets you can open, newest first. - get: Title, access, sheets with their used ranges, named ranges. - read: Cells in range (default the used range) on sheet: values, formulas, text. - write: Write values (rows: a 2D list) starting at cell (default A1) on sheet. Empty string clears a cell; null leaves it. - format: Style a range: style {b, i, u, fc, bg, fs, ha: left|center|right, nf: number format like "#,##0.00" or "0%", wrap}. - evaluate: Compute a formula against the workbook without saving it (formula, sheet). - create: A new spreadsheet (title, workspace_id or folder_id); rows fills the first sheet. - add_sheet: Add a sheet tab (name). - rename_sheet: Rename a sheet tab (sheet, name). - delete_sheet: Remove a sheet tab and its cells (sheet). (waits for approval: delete) - rename: Change the spreadsheet title. - trash: Move the spreadsheet to Trash. (waits for approval: delete) - conditional_formats: The sheet's conditional formatting rules in priority order (earlier wins), each {id, range, kind, v1, v2, style | scale}. - add_conditional_format: Add a conditional formatting rule on sheet: rule {range (A1), kind: gt|gte|lt|lte|eq|ne|between|notbetween|contains|notcontains|begins|ends|blank|notblank|error|top|bottom|above_avg|below_avg|dup|unique|scale, v1, v2 (between), style {bg, fc (#RRGGBB), b, i, st} or for kind scale: scale {min, mid?, max} colours}. top / bottom take v1 = a count or "10%". - charts: The sheet's charts, each {id, kind, range, title, one_axis, cell (top-left anchor), w, h}. - add_chart: Add a chart on sheet from range (first column = categories, first row = series names): chart {range, kind: bar|stacked|percent-stacked|percent-bar|line|area|stacked-area|percent-area|combo|pie|doughnut|scatter|radar|stock, title?, cell? (anchor, default right of the data), w?, h?, one_axis? (combo: the line shares the left axis)}. combo = columns for every series but the last, which is a line on its own right axis; percent-* = 100% stacks. - set_charts: Replace the sheet's charts with charts (same shape as add_chart plus id; keep ids to keep charts; [] removes them). Use it to change a chart type, range or title, or delete one. - dropdowns: The sheet's in-cell dropdowns (data validation lists): each {id, range, list | source, allow_other, choices}, plus invalid: cells whose entry is not a choice. - set_dropdown: Put an in-cell dropdown on range: list (choices, a list or "a, b, c") or source (a range of cells like F2:F9 or 'Lists'!A2:A20); allow_other true keeps other entries and flags them (default: refused in the editor). remove true takes dropdowns off range. A cell has one dropdown: a new one replaces what was there. - goal_seek: Goal seek on sheet: find the number for changing_cell (a value cell) that makes set_cell (a formula) equal to_value, then write it (one save). dry_run true only reports it. - set_conditional_formats: Replace the sheet's rules with rules (same shape as add; keep ids to keep rules; [] removes them all). Use it to edit, reorder or delete rules.

FieldTypeNotes
action requiredlist | get | read | write | format | evaluate | create | add_sheet | rename_sheeWhat to do.
idstringSpreadsheet id or public id.
sheetstringSheet tab name.
rangestringA1 range.
cellstringwrite: the top-left cell (default A1).
rowsarray of array of anywrite / create: rows of cell values.
styleobject
formulastring
namestring
titlestring
workspace_idnumber
folder_idnumber
ruleobjectadd_conditional_format: one rule.
chartobjectadd_chart: one chart.
chartsarray of objectset_charts: every chart (images are kept).
listanyset_dropdown: the choices (array of strings, or one comma-separated string).
sourcestringset_dropdown: a range holding the choices instead of list.
allow_otherbooleanset_dropdown: keep entries that are not a choice (flagged).
removebooleanset_dropdown: remove dropdowns from range.
set_cellstringgoal_seek: the formula cell (A1).
to_valuenumbergoal_seek: the target value for set_cell.
changing_cellstringgoal_seek: the input cell to change (A1).
dry_runbooleangoal_seek: report the answer without writing it.
rulesarray of objectset_conditional_formats: every rule, in priority order.
update_database_rowUpdate a database row

POST/api/external/tools/update_database_row

Scopes: docs:write

Change cells of one row. Only the columns you pass change.

FieldTypeNotes
database requiredstringDatabase id or sheet:<id>.
row_id requirednumber
values requiredobjectColumn name -> value.
update_docUpdate a doc

POST/api/external/tools/update_doc

Scopes: docs:write

Rename a doc, replace its whole content with new markdown, move it into a project (project_id, or null to take it out), and/or turn checklist items into tasks (checklist_to_tasks). The old version is kept in version history.

FieldTypeNotes
doc_id requirednumber or string
titlestring
contentstringMarkdown that replaces the body.
project_idnumber or string or nullMove the doc into this project (same workspace), or null to take it out of its project.
checklist_filterobjectSet which items a checklist shows: {index (from get_doc checklists), filter: all | open | done}.
checklist_to_tasksobjectTurn open checklist items into tasks in the doc's project (or project_id); each item becomes that task's live card in the doc. items: item texts (exact or how they start), or all: true for every open item.
whiteboardWhiteboardsasks for approval

POST/api/external/tools/whiteboard

Scopes: docs:read, docs:write

Read and draw on whiteboards, as you. Element kinds: rect, ellipse, diamond {stroke, fill, strokeWidth, text}, sticky {fill: yellow|orange|pink|purple|blue|teal|green|gray, text}, text {text, fontSize, color}, pen {points: [[x,y,pressure]]}, arrow / line {start: {x,y,bind?: {id, anchor: center|n|e|s|w}}, end, text}, image {src: a Drive raw path}, card {ref: {type, id}} (a live CTRL item). Every element has x, y, w, h. Colors: ink, gray, red, orange, yellow, green, teal, blue, purple, pink, none. Actions: - list: Whiteboards you can open, newest first. - get: The whiteboard: title, your access, and every element as JSON. - create: A new whiteboard (title, workspace_id or folder_id), filed in Drive. - rename: Change the title. - add: Add elements: a list of objects (an id is made when missing). - update: Change elements by id: a list of {id, ...fields to change}. - remove: Remove elements by id (ids). Undo is in the editor's history. - replace: Replace the whole whiteboard content (content = {elements: [...]}). - trash: Move the whiteboard to Trash. (waits for approval: delete)

FieldTypeNotes
action requiredlist | get | create | rename | add | update | remove | replace | trashWhat to do.
idstringwhiteboard id or public id.
titlestring
workspace_idnumber
folder_idnumber
elementsarray of objectadd / update: the elements.
idsarray of stringremove: ids.
contentobjectreplace: the whole document.
word_docsWord documentsasks for approval

POST/api/external/tools/word_docs

Scopes: docs:read, docs:write

Read and write Word documents (.docx), as you: docs made in Plodder (id) or .docx files in Drive (drive_file). Content is simple markdown: # / ## / ### headings, - bullets, 1. numbered lines, > quotes, **bold**, *italic*, [link text](https://...) links. Every save keeps the replaced copy as a version. Actions: - list: Word docs you can open, newest first. - get: Title, access, where it sits, and the document text. - create: A new Word doc: title, content (markdown), workspace_id or folder_id. - append: Add paragraphs (content) at the end. - write: Replace the whole body with content (headers, footers and styles are kept). - replace_text: Replace old_text with new_text where it sits inside one run of text (all=true for every match). - rename: Change the title (Plodder docs). - move: Move in Drive: workspace_id and/or folder_id (Plodder docs). - versions: Earlier saved versions. - restore_version: Make an earlier version current (version_id); what it replaces is kept as a version. - trash: Move to Drive Trash (Plodder docs). (waits for approval: delete)

FieldTypeNotes
action requiredlist | get | create | append | write | replace_text | rename | move | versions |What to do.
idstringWord doc id or public id.
drive_filestringA .docx file id in Drive.
titlestring
contentstringMarkdown-style text.
old_textstring
new_textstring
allboolean
version_idnumber
workspace_idnumber
folder_idnumber
max_charsnumber

Meetings 3

get_meetingGet a meetingread only

POST/api/external/tools/get_meeting

Scopes: meetings:read

One meeting: summary, action items, attendees, and the transcript if include_transcript is true.

FieldTypeNotes
meeting_id requirednumber
include_transcriptboolean
list_meetingsList meetingsread only

POST/api/external/tools/list_meetings

Scopes: meetings:read

Recorded meetings with their AI summaries, newest first.

FieldTypeNotes
workspace_idnumber
querystringMatch in title or summary.
limitnumberDefault 25.
meetings_adminMeeting links and notesasks for approval

POST/api/external/tools/meetings_admin

Scopes: meetings:read, meetings:write

Make a meeting link (Plodder call, Google Meet or Zoom) for an event, re-run meeting-notes processing on a transcript, and set a recording's client (owner) (/api/meetings/*). Read meetings with list_meetings and get_meeting. Actions: - create_link: A meeting link (topic, start_time, duration, provider default zoom). Invites nobody by itself. - queue_status: Meeting-notes queue (owner). - process: Queue a transcript for meeting-notes processing (transcript_id, mode). Owner. - set_client: Set a recording's client by name (transcript_id, client, null clears). Owner.

FieldTypeNotes
action requiredcreate_link | queue_status | process | set_clientWhat to do.
topicstring
start_timestringISO date-time.
durationnumberMinutes.
providerctrlflow | google_meet | zoom
transcript_idnumber
modeprocess | reprocess
clientstring or null
fieldsobjectAny other body fields the action documents.

CRM 26

clients_adminClients and businessesasks for approval

POST/api/external/tools/clients_admin

Scopes: crm:read, crm:write

Create and delete client profiles and businesses, and manage a client's businesses, as you (/api/clients, /api/businesses, /api/clients/businesses). Change fields with update_client and update_business; list with list_clients and list_businesses. Actions: - create_client: A new client profile (name, workspace_id?, set?). - delete_client: Delete a client profile. (waits for approval: delete) - create_business: A new business (name, website?, client_id?, workspace_id?, set?). It is backed by a CRM company. - delete_business: Delete a business. (waits for approval: delete) - client_businesses: A client's businesses. - add_client_business: Add a business to a client (client_id, name, website?, set?). - update_client_business: Change one of a client's businesses (business_id, set). - remove_client_business: Delete one of a client's businesses (business_id). (waits for approval: delete)

FieldTypeNotes
action requiredcreate_client | delete_client | create_business | delete_business | client_businWhat to do.
client_idnumber
business_idnumber
workspace_idnumber
namestring
websitestring
setobjectOther profile / business fields.
fieldsobjectAny other body fields the action documents.
crm_assignCRM round robinasks for approval

POST/api/external/tools/crm_assign

Scopes: crm:read, crm:write

Round-robin rules that hand new deals and leads to teammates in turn, as you (/api/crm/assign). Members are team keys (deal_owner values). Actions: - list: Every rule. - save: Create, or change with rule_id: fields = {scope: pipeline|source, pipeline_id?, source_kind? form|booking|any, source_ref?, members: [..], away?: [..], enabled?}. - delete: Delete a rule. (waits for approval: delete)

FieldTypeNotes
action requiredlist | save | deleteWhat to do.
rule_idnumber
fieldsobject
crm_bulk_actionsCRM bulk actionsasks for approval

POST/api/external/tools/crm_bulk_actions

Scopes: crm:read, crm:write, messages:send

Bulk actions on people (CRM > Bulk actions), as you: add / remove a tag, add to / remove from a workflow, email, text or delete a selection, a People filter or a smart list, now, at a set time, or in batches (N people every M minutes), with the log (counts, progress, errors) and pause / resume / cancel. Each person goes through the same rules as the app's own buttons (consent, Do not contact, Mailjet opted-in only, workflow rules, Recently deleted for 30 days). The people are fixed when it is made. Actions: - list: Bulk actions, newest first: kind, label, status (scheduled, running, paused, done, cancelled, failed), total, done, ok, skipped, failed, next batch, errors. - get: One bulk action (bulk_id). - create: kind tag_add | tag_remove | workflow_add | workflow_remove | email | sms | delete | instantly_add; who: contact_ids, filter (People filter) or segment_id; params: { tag } | { workflow_id } | instantly_add { campaign_id, custom? [{ field, as }] } | email { subject, body, via gmail | mailjet, account_id (Gmail), format rich | html | text, from_email?, from_name?, reply_to?, track? } | sms { body }; when now | at | batches, start_at, batch_size, batch_every_min. (may wait for approval) - pause: Stop a running or scheduled bulk action (bulk_id) until resume. - resume: Carry on (bulk_id): the batch that fell due goes now, the spacing after it stays. (may wait for approval) - cancel: Cancel (bulk_id): the people not reached yet are left as they are.

FieldTypeNotes
action requiredlist | get | create | pause | resume | cancelWhat to do.
bulk_idnumber
kindtag_add | tag_remove | workflow_add | workflow_remove | email | sms | delete | i
contact_idsarray of number
filterobjectA People filter (crm_contacts filter_fields).
segment_idnumber
paramsobject
whennow | at | batches
start_atstring or number
batch_sizenumber
batch_every_minnumber
crm_companiesCRM companiesasks for approval

POST/api/external/tools/crm_companies

Scopes: crm:read, crm:write

Create, change, merge and delete CRM companies (businesses), as you (POST/PATCH/DELETE /api/crm/companies), and find them with the relational filter engine (query, filter_fields: deals, people, payments, tags, custom fields). List and read them with crm_list_companies and crm_get_company. Actions: - create: A new company from a domain (domain, optional name, stage_id). You own it. An existing domain returns that company (existed=true). - update: Change fields: fields = {name, stage_id, deal_owner, revenue, hidden, email_sync, notes, client_id, business_id}. - add_domain: Add a domain (value). - remove_domain: Remove a domain (value). - add_email: List a full email address on it (value). - remove_email: Remove a listed address (value). - add_address: An address lists it, a domain adds the domain (value). - enrich: Look its domain up again (name, icon). - refresh: Re-read its recent mail from your connected mailboxes. - merge: Merge company from_id into company_id (from_id is removed). (waits for approval: delete) - delete: Delete the company. (waits for approval: delete) - link_business: Link (or make) the CRM company for a business (business_id). - link_client: Link company_id (or null to unlink) to a client profile (client_id). - convert_to_client: Make company_id a client (optional workspace_id). - mark_churned: Mark company_id churned (PATCH /api/crm/companies/:id { churn }): churned_on (YYYY-MM-DD, default today), optional reason. Its won recurring deals churn from the same day (they stop counting in MRR), unless a deal also covers a business that has not churned. Fires the Client churned workflow trigger. - reactivate: Reactivate a churned company_id: clears the churn and reactivates the deals it churned (back in MRR). Fires Client reactivated. - query: Find businesses with the same engine as the CRM list: filter (the crm_contacts filter schema; field keys from action filter_fields), q (search), owner ("" | none | an owner key), stage ("" | none | open | closed | a stage id), activity (followup | recent), hidden (only | include), columns (field keys to return per row), sort (a field key) + dir, limit (<= 500), offset. Returns total and rows {id, name, values}. - filter_fields: Every business filter field and column (key, label, group, type, operators, options with their values), incl. custom fields f:<id> and the people fields p:<key> (a business matches when any of its people does).

FieldTypeNotes
action requiredcreate | update | add_domain | remove_domain | add_email | remove_email | add_adWhat to do.
filterobjectquery: { mode: and|or, items: [{ field, op, value? }] }.
qstringsearch: businesses by name, domains, industry, location, their people (name, emails, phones), tag names, text custom fields; deals by title, source, person (name, emails, phones), businesses, tag names, text custom fields
ownerstring
stagestring
activitystring
hiddenonly | include
pipelinestring
columnsarray of string
sortstring
dirasc | desc
offsetnumber
limitnumber
company_idnumber
domainstringcreate: the company domain, like acme.com.
namestring
stage_idstring
valuestringThe domain, email or address for the add_/remove_ actions.
fieldsobjectupdate: the fields to change.
from_idnumbermerge: the company that goes away.
business_idnumber
client_idnumber
workspace_idnumber
churned_onstringmark_churned: the churn day, YYYY-MM-DD (default today).
reasonstringmark_churned: why (optional).
crm_contactsCRM peopleasks for approval

POST/api/external/tools/crm_contacts

Scopes: crm:read, crm:write

Create, change, merge and delete people in the CRM, set do-not-contact flags and lead source, find duplicates, and SEARCH people with the smart-list filter engine (the People list, segments, smart lists and workflow filters run the same SQL), as you (/api/crm/contacts, /api/crm/contacts/query, /api/crm/duplicates). Filter schema: filter = { mode: "and"|"or", items: [ { field, op, value? } | a nested group (one level) ] }. field = a key from action filter_fields (contact info, tags, custom fields f:<id>, source / UTM, consent, SMS, email, calls, conversations, pipelines, calendars, forms, workflows, speed to lead, payments, business, activity). op by type: text contains|not_contains|is|is_not|empty|not_empty; number / money eq|ne|gt|gte|lt|lte|empty|not_empty; date last_days|older_days|next_days (value = days)|before|after|on (value = YYYY-MM-DD)|empty|not_empty; select / multi / person any|none|all|empty|not_empty (value = array of option values from filter_fields); bool true|false. Related-record fields (deal stage, workflow, form, calendar...) mean "has one that matches" for any and "has none that matches" for none. Actions: - search: People matching a filter (filter, q, owner, columns = extra field keys to return, sort = a field key, dir asc|desc, limit <= 500, offset). Returns total + the page. - filter_fields: Every people filter field (key, label, group, type, operators, options with their values) and the GHL filters that are not available. - get: One person with company, consent and lead source. - create: A new person (email, optional name, title, company_id). You own them; lead source "manual". - update: fields = {name, title, phone, notes, hidden, deal_owner, lead_source, lead_medium, lead_campaign, dnc_email, dnc_sms, dnc_call, unsubscribed, consent_reason, address_street, address_city, address_region, address_postal, address_country, timezone (IANA, like America/Vancouver: texting hours, pathways and the dialer use it), birthday (YYYY-MM-DD, or MM-DD with no year: the Birthday trigger reads it), website, email_label, phone_label}. - channels: Every email and phone of a person (contact_id), primary first, with labels. Sends use the primary; matching (forms, texts, payments, leads, replies), search, filters and duplicates use them all. - add_channel: Add an email or phone: contact_id, channel (email|phone), value, label (work|home|mobile|personal|other or your own), primary (true = make it the primary now). A person with no real primary gets it as the primary. A value another person has is refused (merge them instead). - remove_channel: Remove an email or phone (contact_id, channel, value). Removing the primary promotes the next one; their only email stays (change it instead). - make_primary: Make one of their emails or phones the primary (contact_id, channel, value); the old primary becomes an extra. - label_channel: Label an email or phone (contact_id, channel, value, label; empty clears). - matches: What is tied to a person (contact_id) through any of their emails: bookings (invitee email), payments (with the buyer email the provider gave) and payment customer records. Payments and closing calls (commissions) match by these emails. - changes: The change log of a person (contact_id): who changed which field, old -> new, when (90 days, newest first). field (e.g. email, timezone, f:<custom field id>, tags) and limit (<= 500) optional. - set_consent: Do-not-contact flags for one or many people: contact_ids + fields {dnc_email?, dnc_sms?, dnc_call?, unsubscribed?, consent_reason?}. - delete: Delete the person. They go to Recently deleted for 30 days (restore brings them back with their deals, tags, fields and timeline); their workflow runs end. Returns batch. (waits for approval: delete) - delete_many: Delete several people (contact_ids, at most 500) to Recently deleted. Returns batch: restore with that batch undoes it. (waits for approval: delete) - deleted: Recently deleted (last 30 days): people (id, name, email, deleted_at, deleted_by, days_left) and deals. q filters by name / email / title. - restore: Restore deleted people: contact_ids, or batch (from a delete). Someone added again with the same email at the same business since is not restored (the reason says so). - duplicates: Groups of companies or people that look like duplicates. - merge: Merge duplicates: kind company|person, into (kept), from (ids that go away, max 50). A person merged from another company keeps that company as one of their businesses. (waits for approval: delete) - businesses: Every business the person is part of (primary first, with their role there). - add_business: Add the person to a business (company_id, optional role). Their primary stays. - remove_business: Take the person out of a business (company_id). Not their primary: set another primary first. Their deals stay theirs (the business stays on them as recorded). - set_primary_business: Make one business (company_id) their primary; the old primary stays one of their businesses. - set_business_role: Their role at a business (company_id, role; empty clears).

FieldTypeNotes
action requiredsearch | filter_fields | get | create | update | channels | add_channel | removeWhat to do.
contact_idnumber
rolestringadd_business / set_business_role: their role there, like Owner.
contact_idsarray of number
batchstringrestore: the batch a delete returned (undo).
channelemail | phoneadd_channel / remove_channel / make_primary / label_channel
valuestringThe email address or phone number.
labelstring
primaryboolean
fieldstringchanges: only this field.
emailstring
namestring
titlestring
company_idnumber
fieldsobject
kindcompany | person
intonumber
fromarray of number
filterobjectsearch: { mode: and|or, items: [{ field, op, value }] }
qstringsearch: text in name, any email or phone (digits match too), business, job title, tag names, text custom fields, deal names
ownerstringsearch: an owner key, or none
columnsarray of stringsearch: field keys to return per person
sortstring
dirasc | desc
limitnumber
offsetnumber
crm_dataCRM data and settingsasks for approval

POST/api/external/tools/crm_data

Scopes: crm:read, crm:write

Bulk edits, CSV import, sync from email, the company stages and the team activity report, as you (/api/crm/bulk, import, sync, settings, report). Actions: - bulk_edit: Set the same fields on many records: object people|deals|companies, ids, set = {field: value}. People: lead_source, lead_medium, lead_campaign, title, deal_owner, dnc_email, dnc_sms, dnc_call, unsubscribed, consent_reason. Deals: deal_owner, stage_id, status, lost_reason, close_date, source, probability, pipeline_id, recurring, currency. Companies: deal_owner, stage_id. Tags and custom fields: set_property. - import_preview: Plan a CSV import without saving: object companies|people|deals, csv, mapping? (one field key per column, "" skips), dedupe? skip|update|create. Shows the auto mapping and the first 50 rows. - import_run: Run the import (same inputs as import_preview). Max 5,000 rows, 5 MB. - sync_status: Email sync state per mailbox. - sync: Sync from email now (runs about 25 s, call again while a backfill is going). - settings: Company stages, closed and won stages, the workspace currency (settings.currency), the unknown-number lead setting and the speed to lead steps. - save_settings: Save stages: stages = [{id?, label, color}], closed_stage_ids?, won_stage_id? (max 50 stages); and / or unknown_number_lead = {on, pipeline_id, stage_id?} | null (texts / calls from unknown numbers make a lead); and / or speed_to_lead = {amber_min, red_min} | null (minutes before a waiting lead turns amber / red and alerts its owner; null = 5 / 15); and / or currency = USD | CAD | EUR | GBP | AUD | NZD | MXN | null (workspace currency: new deals and payments without one start in it, Reports show totals in it; null = USD). - report: Activity per teammate (calls, texts, emails, meetings, deals) for from..to (epoch s, default last 30 days, max 400). The workspace owner sees everyone.

FieldTypeNotes
action requiredbulk_edit | import_preview | import_run | sync_status | sync | settings | save_sWhat to do.
objectpeople | deals | companies
idsarray of number
setobject
csvstring
mappingarray of string
dedupeskip | update | create
stagesarray of object
closed_stage_idsarray of string
won_stage_idstring or null
unknown_number_leadobject or null
speed_to_leadobject or null
currencystring or nullsave_settings: workspace currency (ISO code) or null.
fromnumber
tonumber
crm_dealsCRM dealsasks for approval

POST/api/external/tools/crm_deals

Scopes: crm:read, crm:write

Deals in the CRM pipelines, as you (/api/crm/deals). Deals belong to people: every deal has a contact_id. One deal can cover several of their businesses: company_ids (primary first; company_id = the primary). Values are integer cents. Status follows the stage (the won stage = won). Pipelines and stages come from crm_pipelines. Actions: - list: Deals, optionally by pipeline_id, pipeline_kind (leads|sales: every pipeline of that kind), company_id (deals that cover that business), contact_id, person_id (their deals, plus older deals with no person at their businesses), status (open|won|lost|abandoned), waiting (true = open leads no person has texted, called or emailed yet), with the open forecast. Each deal has speed to lead: lead_started_at, first_response_at, first_response_channel (sms|call|email|logged_call), speed_to_lead_seconds, waiting. - speed_to_lead: Speed to lead numbers: leads that started in from..to (epoch s, default the last 24 h), scope me|team (default team), optional pipeline_id. Returns summary {leads, responded, waiting, median_seconds, avg_seconds, under_amber, under_amber_pct, oldest_waiting_seconds}, the same for every waiting lead, and thresholds {amber_min, red_min}. Only a person's own text, call, email or logged call counts as a response; workflows, notifications, agents (you), API sends and bulk sends never do. - get: One deal with its line items and stage history. - create: A new deal: fields = {title, value_cents, currency, recurring, close_date, probability, pipeline_id, stage_id, status, lost_reason, deal_owner, company_id, company_ids, contact_id, source, value_from_lines, notes}. You own it unless deal_owner is set. A deal belongs to a person: contact_id is required. company_ids = every business the deal covers, primary first ([] = none); company_id = one business; neither = all of the person's businesses. A business they are not part of adds them to it. - update: Change a deal: fields as in create (moving stage_id moves status; status won|lost moves the stage; status abandoned sets it aside in its stage, out of the open forecast, until it moves or is reopened with status open). contact_id cannot be cleared; company_ids replaces the business list (company_id = just that one; null or [] = no business). - set_lines: Replace every line item: lines = [{product_id?, name?, qty?, price_cents?, discount_pct?, recurring?}]. - delete: Delete the deal. It stays in Recently deleted for 30 days (restore puts it back). (waits for approval: delete) - deleted: Deals deleted in the last 30 days (merged ones are not listed). q filters by title. - restore: Restore deleted deals: deal_ids. Merged deals and deals whose pipeline was deleted are refused (the reason says so). - merge: Fold deal_id into into_id (kept): notes, line items, history, tasks, links, tags and fields move; deal_id is removed. (waits for approval: delete) - mark_churned: Mark a won recurring deal_id churned (PATCH /api/crm/deals/:id { churn }): churned_on (YYYY-MM-DD, default today), optional reason. It stops counting in MRR from that day. One-time deals are refused. Its business is not churned. - reactivate: Reactivate a churned deal_id (back in MRR). - query: Find deals with the same engine as the CRM list: filter (the crm_contacts filter schema; field keys from action filter_fields), q (search), owner ("" | none | an owner key), pipeline (id, blank = every pipeline), status (open | won | lost; leave it out for all), stage (a stage id), columns (field keys to return per row), sort (a field key) + dir, limit (<= 500), offset. Returns total and rows {id, name, values}. - filter_fields: Every deal filter field and column (key, label, group, type, operators, options with their values), incl. custom fields f:<id> and the person fields p:<key> (the deal's person: tags, texts, calls, bookings, forms, workflows, payments...).

FieldTypeNotes
action requiredlist | speed_to_lead | get | create | update | set_lines | delete | deleted | reWhat to do.
filterobjectquery: { mode: and|or, items: [{ field, op, value? }] }.
qstringsearch: businesses by name, domains, industry, location, their people (name, emails, phones), tag names, text custom fields; deals by title, source, person (name, emails, phones), businesses, tag names, text custom fields
ownerstring
stagestring
activitystring
hiddenonly | include
pipelinestring
columnsarray of string
sortstring
dirasc | desc
offsetnumber
limitnumber
deal_idnumber
deal_idsarray of numberrestore: the deleted deals to put back.
into_idnumbermerge: the deal that is kept.
person_idnumberlist: every deal of this person (plus older deals with no person at their businesses).
pipeline_idnumber
pipeline_kindleads | saleslist: only deals in leads pipelines or in sales pipelines.
company_idnumber
contact_idnumber
statusopen | won | lost | abandoned
waitingbooleanlist: only open leads with no response by a person yet.
scopeme | teamspeed_to_lead: my deals or the whole CRM.
fromnumberspeed_to_lead: epoch seconds.
tonumberspeed_to_lead: epoch seconds.
fieldsobject
linesarray of object
churned_onstringmark_churned: the churn day, YYYY-MM-DD (default today).
reasonstringmark_churned: why (optional).
crm_field_categoriesCRM field categoriesasks for approval

POST/api/external/tools/crm_field_categories

Scopes: crm:read, crm:write

Custom field categories on CRM records (the field cards on person, business and deal pages, like a Forms card), as you: list (entity_type crm_contact | crm_company | crm_deal) gives the categories in order and which field (property definition id) sits in which; create, rename, reorder, delete (its fields go back to General), and place_field to move a field into a category (category_id null = General). Actions: - list: Categories and field placements (entity_type, default crm_contact). - create: New category (name, entity_type?). - rename: Rename (category_id, name). - reorder: Order the categories (order: ids first to last). - place_field: Put a field in a category (definition_id, category_id or null for General, sort_order?). - delete: Delete a category (category_id); its fields go back to General. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | rename | reorder | place_field | deleteWhat to do.
entity_typecrm_contact | crm_company | crm_deal
category_idnumber or null
namestring
orderarray of numberreorder: category ids, first to last.
definition_idnumberplace_field: the field (property definition id).
sort_ordernumberplace_field: position inside the category.
fieldsobjectAny other body fields the action documents.
crm_forecastDeal forecastasks for approval

POST/api/external/tools/crm_forecast

Scopes: crm:read, crm:write

The deal forecast (CRM > Deals > Forecast): open deals by expected close month or quarter as commit (win chance >= commit_min), best case (>= best_min, commit included) and pipeline (every open deal), weighted by win chance (the deal's own, else its stage's), what was won per period, by pipeline or owner, and the deals that need attention: past due (close date passed, still open), stale (no change for stale_days), at risk (stale or past due; high = both), missing close date or value. One currency at a time (the most used, or currency). Leads pipelines are left out unless pipeline = all or a leads pipeline id. Actions: - get: The forecast: period (month | quarter), periods (1-12), group (none | pipeline | owner), pipeline (id, sales = every sales pipeline, all), owner (teammate key | none), currency, tz. - settings: The forecast rules: commit_min, best_min (win chance %), stale_days. - set_settings: Change the rules: commit_min?, best_min? (<= commit_min), stale_days?.

FieldTypeNotes
action requiredget | settings | set_settingsWhat to do.
periodmonth | quarter
periodsnumber
groupnone | pipeline | owner
pipelinestring
ownerstring
currencystring
tzstring
commit_minnumber
best_minnumber
stale_daysnumber
crm_get_companyCRM: get a companyread only

POST/api/external/tools/crm_get_company

Scopes: crm:read

One CRM company with its contacts.

FieldTypeNotes
company_id requirednumber
crm_list_companiesCRM: list companiesread only

POST/api/external/tools/crm_list_companies

Scopes: crm:read

Companies in your CRM (built from your email), with stage and deal owner.

FieldTypeNotes
querystring
stage_idstring
limitnumber
crm_list_contactsCRM: list contactsread only

POST/api/external/tools/crm_list_contacts

Scopes: crm:read

People in your CRM, optionally for one company or matching text.

FieldTypeNotes
company_idnumber
querystring
limitnumber
crm_objectsCRM custom objectsasks for approval

POST/api/external/tools/crm_objects

Scopes: crm:read, crm:write

Custom objects (CRM > Objects), GHL style: your own record types next to people, businesses and deals (Properties, Vehicles, Policies...). A type has a name, plural, icon, fields (data_type: string, long_text, number, currency, percent, date, boolean, select, multi_select, email, phone, url, person) and link labels. Records have a name, owner (teammate key), notes and values ({ field key | field id | field name: value }; selects take option labels or ids; null clears). Records link many-to-many (with a label) to people (contact), businesses (company), deals (deal) and other records (object). query takes the CRM smart-list filter { mode: "and" | "or", items: [{ field, op, value }] } where field = name, owner, created_at, updated_at, people, businesses, deals, people_count, businesses_count, deals_count, records_count, assoc_label or f:<field id>. Creating / changing a record fires the Object record created / changed workflow triggers and the object.* webhooks. Actions: - list_types: Every object type with its fields (id, key, data_type, options) and record count. - get_type: One type (type_id) with its smart lists. - create_type: New type: name, plural?, icon?, description?, labels? (link labels), fields? [{ name, data_type, options?, required? }]. - update_type: Change a type (type_id): name, plural, icon, description, labels. - delete_type: Delete a type and all its records (type_id). (waits for approval: delete) - add_field: Add a field (type_id, name, data_type, options?, required?). - update_field: Rename a field, change its options or required (field_id, name?, options?, required?, sort_order?). A field keeps its type. - delete_field: Delete a field and its values (field_id). (waits for approval: delete) - query: Records of a type (type_id): filter?, q?, owner?, sort? (name, created_at, updated_at, f:<id>, people_count...), dir?, limit? (<= 1000), offset?. Returns records with values by field id and linked names. - get: One record (record_id) with its type and every link. - create: New record: type_id, name, values?, owner?, notes?, associations? [{ target_type, target_id, label? }]. - update: Change a record (record_id): name?, values? (merged), owner?, notes?. - delete: Delete a record (record_id). (waits for approval: delete) - associate: Link a record (record_id) to target_type contact | company | deal | object, target_id, label?. Again = changes the label. - unassociate: Remove a link: association_id, or record_id + target_type + target_id. - related: Records linked to a person / business / deal / record (target_type, target_id), grouped by type. - import: Import CSV text into a type (type_id, csv, mapping? { header: name | owner | notes | f:<id> | person_email | business_domain | "" }, update_existing? default true, label?). - views: Smart lists of a type (type_id) with live counts. - save_view: Save a smart list (type_id, name, config { filter, q?, owner?, sort?, dir? }); with view_id it updates that one. - delete_view: Delete a smart list (view_id). Records stay.

FieldTypeNotes
action requiredlist_types | get_type | create_type | update_type | delete_type | add_field | upWhat to do.
type_idnumber
field_idnumber
record_idnumber
view_idnumber
association_idnumber
namestring
pluralstring
iconstring
descriptionstring
labelsarray of string
fieldsarray of object[{ name, data_type, options?, required? }]
data_typestring
optionsarray of anyOption labels, or { id?, label, color? }
requiredboolean
sort_ordernumber
valuesobject{ field key | id | name: value }
ownerstring
notesstring
associationsarray of object
target_typecontact | company | deal | object
target_idnumber
labelstring
filterobject
qstring
sortstring
dirasc | desc
limitnumber
offsetnumber
csvstring
mappingobject
update_existingboolean
configobject
crm_pipelinesCRM pipelinesasks for approval

POST/api/external/tools/crm_pipelines

Scopes: crm:read, crm:write

Deal pipelines and their stages, as you (/api/crm/pipelines). Pipeline 0 is the default one (its stages are the company stages, always kind sales). A stage is {id?, label, color?, probability?}. LEADS ARE DEALS (GHL style): a pipeline is kind leads or sales; a leads pipeline's won_handoff {mode: move|create, pipeline_id, stage_id?} runs when a deal enters its won stage (move = the same deal goes to that pipeline + stage with its history; create = a new linked deal there). One open deal per person per pipeline for leads made by forms, calendars and unknown numbers (forms tool op lead_pipeline, calendars tool set_lead_pipeline, set_unknown_number_lead here). A workflow with Create / update deal can do the same. Actions: - list: Every pipeline with its stages, kind and won_handoff. - create: A new pipeline (name, kind leads|sales default sales, optional stages: leads start New, Contacted, Qualified, Booked, Won (handed off), Lost; optional won_handoff). - update: Change a pipeline: pipeline_id + any of name, stages, closed_stage_ids, won_stage_id, kind, won_handoff (null clears), access, card_fields. - set_access: Who can see a pipeline and its deals (pipeline_id, access = {mode: everyone | users | owner, users: team member keys, agent ids ai-<id>, or "api" for API keys}). owner = only the CRM owner signed in; agents and API keys do not see it. Lists, boards, filters, reports, the API and agents follow it. - set_card_fields: The fields its board cards show (pipeline_id, card_fields = up to 4 of value, win_chance, close_date, days_in_stage, source, person, business, owner, created, recurring, phone, f:<deal custom field id>; null = the standard card). - copy: Copy a pipeline (pipeline_id, name optional): the same stages, closed / won stages, kind, access and card fields; no deals and no automations. - reorder: New order: ids = every pipeline id (0 included). - delete: Delete a pipeline; its deals move to move_to (default 0). (waits for approval: delete) - unknown_number_lead: The setting "New texts / calls from unknown numbers create a lead": {on, pipeline_id, stage_id} or null. - set_unknown_number_lead: Set it: setting = {on, pipeline_id, stage_id?} or null to clear.

FieldTypeNotes
action requiredlist | create | update | set_access | set_card_fields | copy | reorder | delete What to do.
pipeline_idnumber
namestring
stagesarray of object
closed_stage_idsarray of string
won_stage_idstring or null
idsarray of number
move_tonumber
kindleads | sales
won_handoffobject or null{mode: move|create, pipeline_id, stage_id?}; null clears.
settingobject or nullset_unknown_number_lead: {on, pipeline_id, stage_id?} or null.
accessobject{ mode: everyone | users | owner, users?: string[] }
card_fieldsarray or null
crm_productsCRM productsasks for approval

POST/api/external/tools/crm_products

Scopes: crm:read, crm:write

The product list deal line items pick from, as you (/api/crm/products). Prices are integer cents. Actions: - list: Products (include_archived to see archived ones). - save: Create a product, or change one with product_id: fields = {name, description?, price_cents, currency?, recurring? none|monthly|yearly, archived?}. Archive instead of deleting.

FieldTypeNotes
action requiredlist | saveWhat to do.
product_idnumber
fieldsobject
include_archivedboolean
crm_tasksCRM tasksasks for approval

POST/api/external/tools/crm_tasks

Scopes: crm:read, crm:write

CRM tasks are normal tasks linked to a deal, person or company. Make the task with create_task, then link it here (/api/crm/tasks). Actions: - mine: Open tasks assigned to you that are linked to a CRM record, by due date. - link: Link task_id to records: links = [{type: crm_deal|crm_contact|crm_company, id}], remind_at? (epoch s, null clears).

FieldTypeNotes
action requiredmine | linkWhat to do.
task_idnumber
linksarray of object
remind_atnumber or null
crm_update_companyCRM: update a company

POST/api/external/tools/crm_update_company

Scopes: crm:write

Change a CRM company: name, stage, revenue, notes, or hide it.

FieldTypeNotes
company_id requirednumber
namestring
stage_idstringStage id from crm_list_companies stages.
revenuenumber
notesstring
hiddenboolean
crm_update_contactCRM: update a contact

POST/api/external/tools/crm_update_contact

Scopes: crm:write

Change a CRM contact: name, title, phone or notes.

FieldTypeNotes
contact_id requirednumber
namestring
titlestring
phonestring
notesstring
crm_viewsCRM views and segmentsasks for approval

POST/api/external/tools/crm_views

Scopes: crm:read, crm:write

Saved CRM views (companies, people or pipeline, with filters in config) and segments (views with config.segment = true, the audiences for crm_send), and SMART LISTS (views with config.segment = true and config.smart = true: people lists use config.filter = the crm_contacts filter schema, config.psort / pdir = sort field key and direction; businesses (kind companies) and deals (kind pipeline) lists use config.filter with the crm_companies / crm_deals filter_fields keys, config.xsort / xdir, and for deals config.pipeline + config.status; list columns are each person's own setting, not part of the list), as you (/api/crm/views, /api/crm/segments, /api/crm/smart-lists). Actions: - list: Saved views. - segments: Segments with live counts. - smart_lists: Smart lists (people, businesses, deals) with live counts and their kind, and the starter lists you can add. - add_starters: Make starter smart lists (keys, default all): no_open_30, no_phone, textable, no_showed, upcoming_week, waiting_reply, unworked_7, clients, dnd. Already made ones are returned, not duplicated. - tag_list: Add (or with remove: true, take off) a CRM tag on everyone in a smart list (view_id, tag). - segment_people: Who is in a segment right now (view_id). - create: A new view: name, kind companies|people|pipeline, config (filters, columns, sort; segment: true makes it a segment). - update: Change a view (view_id, name?, config?). - set_consent: A smart list / segment's consent basis (view_id, consent: opt_in | customers | cold | not_set). Cold lists are refused by Mailjet bulk sends, and people added to a workflow from one skip its Mailjet marketing steps (Gmail one to one only). - delete: Delete a view. (waits for approval: delete)

FieldTypeNotes
action requiredlist | segments | smart_lists | add_starters | tag_list | segment_people | creatWhat to do.
view_idnumber
namestring
kindcompanies | people | pipeline
configobject
limitnumber
keysarray of string
tagstring
removeboolean
consentopt_in | customers | cold | not_set
get_businessGet a businessread only

POST/api/external/tools/get_business

Scopes: crm:read

One business profile: context, offer, audience, location, budgets, channels.

FieldTypeNotes
business_id requirednumber or stringId or slug.
get_clientGet a clientread only

POST/api/external/tools/get_client

Scopes: crm:read

One client profile (context, goals, offer, audience, channels) and its businesses.

FieldTypeNotes
client_id requirednumber or stringId or slug.
list_businessesList businessesread only

POST/api/external/tools/list_businesses

Scopes: crm:read

Businesses (a client can have several) in your workspaces.

FieldTypeNotes
client_idnumber or string
querystring
list_clientsList clientsread only

POST/api/external/tools/list_clients

Scopes: crm:read

Clients in your workspaces with their status and industry: the Clients roster with its search, filters and sort (D 10-09).

FieldTypeNotes
querystringSearch: name, slug, industry, contacts, notes and linked business names.
whereobject or stringThe roster filter panel: {mode: and|or, items: [{field, op, value}]}. Fields: name, contact, industry, businesses (text: is, contains, ...), status (select: active|onboarding|paused|churned, ops any|none), crm_status (current|past|not_in_crm), business_count (number), created, updated (date: last_days, before, after, ...).
sortname | contact | status | crm_status | industry | businesses | business_count |
dirasc | desc
metaMeta (Facebook and Instagram)asks for approval

POST/api/external/tools/meta

Scopes: crm:read, crm:write

Meta lead ads, Messenger / Instagram DMs and comments, Conversions API and Custom Audiences, as you. Pages the connected token reaches (with the linked Instagram account), which of leads / messages / comments each page sends here (turning any on subscribes the page to the Plodder app), lead forms with their field mapping (question key -> a target: email | phone | name | first_name | last_name | title | extra_email | extra_phone | website | timezone | birthday | notes | address_street | address_city | address_region | address_postal | address_country | business_name (find or make the business by name, link the person) | business_website | business_phone | deal_value | deal_title (lead pipeline on) | f:<person custom field id> | b:<business custom field id> | skip), answer rules per question (an answer is / contains a value -> add tags and / or move the lead deal to a stage), the workspace default mapping (question key / label patterns, applied to newly found forms), a Test lead dry run, and the lead pipeline ({ on, pipeline_id, stage_id?, title? }: every lead makes a deal there and starts the speed to lead clock), recent leads, the ad account for Custom Audiences, and the Conversions API pixel per workspace (workspace_id 0 = default). Workflows use the Facebook lead form submitted, Facebook / Instagram comment and DM received triggers and the Send Meta conversion, Meta audience and Send FB/IG DM steps (crm_automations). Actions: - status: Connection, pages, lead forms (questions, mapping, pipeline, on), Conversions API settings, the last 10 leads, the webhook URL. - leads: Recent leads (limit?): form, campaign, ad set, ad, person, deal, status (done | failed | skipped), via (webhook | poll). - ad_accounts: Ad accounts the token reaches. - audiences: Customer list Custom Audiences of the picked ad account. - available_pages: Facebook Pages the connected account reaches: picked (in this CRM), elsewhere (another Plodder account has it). No tokens. - sync: Re-read the pages the token manages (and the forms of pages with leads on). - sync_forms: Re-read one page's lead forms (page_id). - poll: Check every live lead form for leads the webhook missed (each lead lands once). - pick_pages: Keep exactly these Pages (page_ids, from available_pages) after Continue with Facebook: picked ones are added with switches off, the rest are unsubscribed and removed. - check_health: Check the Meta token and every page now: health (ok | expiring | missing | broken), expiry, missing permissions, still subscribed. Status shows the last check; a daily job alerts the owner. - set_page: Turn a page's leads_on / messages_on / comments_on on or off (page_id). Any on subscribes the page to the Plodder Meta app; all off unsubscribes it. - set_form: A lead form (form_id): on?, mapping? ({ question key: target }), rules? ({ question key: [{ op: is | contains, value, tags: [], stage_id? }] }, null clears), lead_pipeline? (object or null). Status lists each form's questions (with multiple-choice options), its unmapped count (questions added after the last save) and the targets (custom fields as f:<id> / b:<id>). - default_mapping: The workspace default lead form mapping: rules [{ by: key | label, pattern (* wildcard; label = contains), target }], auto (apply to newly found forms). - set_default_mapping: Save the default mapping: rules?, auto?, apply_now? (also fill forms whose mapping was never saved). - copy_mapping: Copy the targets and answer rules of another form (from_form_id) onto form_id: same question key, else the same label. - new_field: Make a person custom field from a question (form_id, question_key, name?, type? text | number | date | select (select gets the question choices), category_id? = a person field card) and map the question to it. - test_lead: Dry run (nothing saved, Meta not called): a fake lead (sample answers, or answers { question key: value }, platform? facebook | instagram) through the form's mapping, rules and pipeline. Returns the person (found or new, built-ins, extra emails / phones, notes, custom fields), the business (link or create), tags, the deal (pipeline, stage, title, value), the attribution and warnings. - set_ad_account: The ad account for Custom Audiences (ad_account_id, act_123...; empty clears). - set_capi: Conversions API for a workspace (workspace_id?, 0 = default): pixel_id (dataset id), test_event_code (empty clears). The access token is set in Settings by a person.

FieldTypeNotes
action requiredstatus | leads | ad_accounts | audiences | available_pages | sync | sync_forms |What to do.
page_idstring
page_idsarray of stringpick_pages: the Facebook Page ids to keep.
form_idstring
leads_onboolean
messages_onboolean
comments_onboolean
onbooleanset_form: the form feeds the CRM.
mappingobjectset_form: { question key: target }.
rulesanyset_form: { question key: [{ op, value, tags, stage_id? }] } (null clears). set_default_mapping: [{ by, pattern, target }].
autobooleanset_default_mapping: apply to newly found forms.
apply_nowbooleanset_default_mapping: also fill forms never mapped.
from_form_idstringcopy_mapping: the form to copy from.
question_keystringnew_field: the question.
namestringnew_field: the field name (default: the question).
typestringnew_field: text | number | date | select.
category_idnumbernew_field: the person field card.
answersobjecttest_lead: { question key: answer } (others get sample answers).
platformstringtest_lead: facebook | instagram.
lead_pipelineanyset_form: { on, pipeline_id, stage_id?, title? } or null to turn off.
ad_account_idstring
workspace_idnumber
pixel_idstring
test_event_codestring
limitnumber
update_businessUpdate a business

POST/api/external/tools/update_business

Scopes: crm:write

Update fields on a business profile. Only the fields you pass change.

FieldTypeNotes
business_id requirednumber or string
namestring
industrystring
statusstring
contextstring
brand_voicestring
goalsstring
target_audiencestring
servicesstring
offerstring
offer_detailsstring
locationstring
targeting_areastring
websitestring
instagram_handlestring
tiktok_handlestring
facebook_pagestring
monthly_budgetnumber
update_clientUpdate a client

POST/api/external/tools/update_client

Scopes: crm:write

Update fields on a client profile. Only the fields you pass change.

FieldTypeNotes
client_id requirednumber or string
namestring
industrystring
statusstring
contextstring
notesstring
brand_voicestring
goalsstring
target_audiencestring
servicesstring
locationstring
offerstring
offer_detailsstring
websitestring
instagram_handlestring
tiktok_handlestring
facebook_pagestring
monthly_budgetnumber

Calendars and bookings 12

calendar_eventsCalendar events (more)asks for approval

POST/api/external/tools/calendar_events

Scopes: bookings:read, bookings:write

More on the owner's Google calendar: search events, the full create (repeat rules, out of office, visibility, travel time, which calendar, project), change a repeat rule, move an event, and sync now. Basic create/update/delete: create_calendar_event, update_calendar_event, delete_calendar_event. Actions: - search: Find events by words (mode title | description | exact). - create: Create an event with any field. Guests get invitations, so with guests it waits for approval. (may wait for approval) - set_recurrence: Set or clear the repeat rule on an event (whole series). Google emails guests about it, so an event with guests waits for approval. (may wait for approval) - move: Move an event to new_start / new_end (ISO). notify_guests emails the guests, so it waits for approval. (may wait for approval) - sync: Pull every connected Google calendar now (and the calendar sync links).

FieldTypeNotes
action requiredsearch | create | set_recurrence | move | syncWhat to do.
titlestring
start_timestringISO 8601 with offset; all-day: YYYY-MM-DD.
end_timestring
all_dayboolean
descriptionstring
locationstring
guestsarray of string
conferencingnone | meet | zoom
busy_statusbusy | free | tentative | out_of_office
visibilitydefault | public | private
recurrencearray of stringRepeat rules, e.g. ["RRULE:FREQ=WEEKLY;BYDAY=MO"]; [] stops repeating.
travel_time_beforenumber
travel_time_afternumber
calendar_idstring
project_idnumber
timezonestring
auto_declineall | new | noneOut of office: decline new or all invites.
decline_messagestring
qstring
modetitle | description | exact
event_idstring
new_startstring
new_endstring
notify_guestsboolean
calendar_oooOut of officeasks for approval

POST/api/external/tools/calendar_ooo

Scopes: bookings:read, bookings:write

Out of office: your auto-decline settings, marking yourself away (shows in Team out of office), and who on the team is away. For an out-of-office event on the Google calendar, use calendar_events create with busy_status out_of_office. Actions: - get: Your out-of-office settings and your upcoming away periods. - team: Who is away between start and end (default last 7 days to next 30). - settings: auto_decline (all | new | none), message, show_team. - add: Mark yourself away: start, end, title, all_day. - remove: Remove one of your away periods (ooo_id; the owner can remove anyone's). (waits for approval: delete)

FieldTypeNotes
action requiredget | team | settings | add | removeWhat to do.
startstring or number
endstring or number
titlestring
all_dayboolean
auto_declineall | new | none
messagestring
show_teamboolean
ooo_idnumber
calendarsCalendars (Automations)asks for approval

POST/api/external/tools/calendars

Scopes: bookings:read, bookings:write

Booking calendars in Automations > Calendars, beyond the page settings (create, rename, durations, hosts, type and limits are the booking_links tool). Types (booking_links booking_mode): single = personal, round_robin, collective (every host free), group = class or event (capacity seats). Open times come from, most specific first: a date override for a host, a date override for the calendar (holidays included), the host's own weekly hours, the calendar's weekly hours (custom_hours), the host's work schedule; minus their Google busy times and their other bookings. Weekly hours look like {"1":[{"start":"09:00","end":"17:00"}]} (0 = Sunday). Notification content uses custom values ({{contact.first_name}}, {{booking.start}}, {{booking.location}}, {{calendar.name}}, {{booking.reschedule_url}} in the confirmation). Text messages go only to guests who ticked "Text me" and respect STOP and Do not text. Actions: - list: Every calendar with type, hosts, bookings this week and upcoming. - get: One calendar: settings, hosts with their own hours, upcoming date overrides, notifications, look, public URL (calendar_id). - availability: Open times on a date as the public page shows them (calendar_id, date YYYY-MM-DD, duration?, exclude_booking_id? when moving one). - set_host_hours: A host's own weekly hours on this calendar (calendar_id, team_member_id, hours: object, or null to follow the calendar). - set_override: Close a date or give it custom hours, for the calendar or one host (calendar_id, date, closed?, hours? [{start,end}], team_member_id?, label?). Replaces that date. - delete_override: Remove a date override (calendar_id, override_id). (waits for approval: delete) - add_holidays: Close a year's public holidays (calendar_id, region us|ca, year?). - get_notifications: The notification matrix (calendar_id): events confirm (Booked, unconfirmed), confirmed (Booked, confirmed), reschedule, cancel, reminders[], follow_up; channels email + sms (guest) and in_app (the host's app notification), each {on, subject, body}; per event team_copy (host heads-up email). WhatsApp: no sender yet, never sent. - set_notifications: Change the matrix, merged over what is saved (calendar_id, notifications: { confirm|confirmed|reschedule|cancel: { email|sms|in_app: {on, subject, body}, team_copy }, reminders: [{ minutes, email, sms, in_app }], follow_up: { minutes after the end, after showed|any, email, sms, in_app }, reply_to }). Each cell sends once per booking. (waits for approval: external) - get_settings: The calendar settings (GHL parity): booking form, widget order, sticky contacts, prefill, consent box, guests, confirmation page, Meta pixel / Google tag, auto-confirm, payments (stored, no provider yet), owner assignment, guest cancel / reschedule policy, Google invite emails, invite notes. Plus payment_provider and form_problem (calendar_id). - set_settings: Change calendar settings, merged (calendar_id, settings). settings = { form_id (a form with its public link on, no screener or booking steps; null = default form), widget_order time_first|form_first, sticky_contacts, prefill_from_url, consent {on, required, text}, guests {on, max 1-10}, confirmation {mode message|redirect, message (custom values: {{contact.first_name}}, {{booking.start}}, {{calendar.name}}), redirect_url https, append_params}, tracking {meta_pixel_id, google_tag_id}, auto_confirm, payments {on, amount, currency, collect full|deposit, deposit_amount, hold_minutes 30-1440} (charged at booking through Stripe Checkout once Stripe is connected; on stays off while it is not), assign_owner {on, skip_if_assigned}, policy {allow_reschedule, allow_cancel} (cut-offs: cancel_cutoff_minutes / reschedule_cutoff_minutes), send_invites (Google invite + update emails to attendees), invite_notes {on, template with {{contact.phone}} {{contact.email}} {{reschedule_link}} {{cancellation_link}}}, recurring {on, frequencies [weekly, biweekly, monthly], max_count 2-52, allow_until} (guests may book a repeating series; each occurrence is its own booking; off while payments are on) }. Merged over what is saved. (waits for approval: external) - get_theme: The calendar's public page look (calendar_id). - set_theme: Change the public page look, merged (calendar_id, theme: { only the keys to change }), or theme null for the workspace default. Theme keys: mode light|dark|custom, background #hex (page colour in custom mode), brand #hex, text #hex or "" (auto), font system|inter|dm-sans|manrope|plus-jakarta|work-sans|lora|merriweather, heading_font "" (same as font) or a font key, radius sharp|soft|round, button filled|outline, button_text #hex or "" (auto), button_label up to 40 characters or "" (default label), button_shape auto (follows radius)|square|pill, button_width auto|full, button_size s|m|l, field_style outlined|filled|underline, field_bg / field_border / label_color #hex or "" (auto), show_card true|false, card_bg #hex or "" (auto), card_width auto|narrow|medium|wide, card_shadow none|soft|strong, card_border true|false, text_size s|m|l, align left|center (header and intro), page_fill solid|gradient, gradient_from / gradient_to #hex or "" (auto), gradient_angle 0-360, page_image / logo_url / cover_url (https or /uploads/ path, "" for none), page_overlay 0-80 (darkens page_image), logo_size s|m|l, logo_position left|center; forms: form_layout page|one, progress none|bar|steps, question_numbers true|false, required_color red|brand; calendars: booking_layout month|list, show_host true|false, slot_style outline|filled. A bad value is ignored and the current one stays. (waits for approval: external) - bookings: Bookings on a calendar with appt_status and needs_status (calendar_id, scope upcoming|past|cancelled|needs). - notices: What was sent for one booking (calendar_id, booking_id). - cancel_booking: Cancel a booking: removes the calendar event and sends the cancel notice (calendar_id, booking_id). (waits for approval: send email) - reschedule_booking: Move a booking to an open time on the same calendar (calendar_id, booking_id, start YYYY-MM-DDTHH:MM). (waits for approval: send email) - book: Book a time on a calendar for someone, once or repeating (calendar_id, name, email, phone?, start and end as the availability slots give them, notes?, recurrence? { frequency weekly|biweekly|monthly, count 2-52 | until YYYY-MM-DD } when the calendar recurring setting is on, skip_conflicts? to book the open dates when some are taken; without it a series with taken dates answers needs_confirm + conflicts). Same path as the public page: calendar event, CRM person, notices. (waits for approval: send email) - series: The repeating series a booking belongs to: how often, how many, and every booking in it with its status (calendar_id, booking_id). - cancel_series: Cancel a repeating booking: this one, this and the following ones, or every upcoming one (calendar_id, booking_id, series_scope this|following|all). One cancel notice goes to the guest. (waits for approval: send email) - external_calendars: Your Outlook / iCloud calendar accounts (each person connects their own in Settings > Calendars): which calendars block booking times (busy), which one gets booking events (write), and the status (ok, reconnect, error). - set_external_calendars: Pick an Outlook / iCloud account's busy calendars (busy: calendar ids) and the calendar booking events are written to (write: a calendar id, or null for none) (connection_id). - check_external_calendar: Read an Outlook / iCloud account again: refresh the token and its calendars, set the status (connection_id). - disconnect_external_calendar: Forget an Outlook / iCloud account (connection_id). Events already written stay on that calendar. (waits for approval: delete) - move_series: Move a repeating booking: this one, this and the following ones, or every upcoming one, each by the same amount as this one moves (calendar_id, booking_id, series_scope, start YYYY-MM-DDTHH:MM). Dates whose new time is taken stay and are listed in failed. (waits for approval: send email) - get_lead_pipeline: The calendar's CRM lead setting (calendar_id): {on, pipeline_id, stage_id, booked_stage_id, showed_stage_id, no_show_stage_id} or null. - set_lead_pipeline: Lead pipelines (calendar_id, setting = {on, pipeline_id, stage_id?, booked_stage_id?, showed_stage_id?, no_show_stage_id?} or null): on = a booking finds or makes the person and adds a deal in that CRM pipeline at stage_id, or, when they already have an open deal there, moves it to booked_stage_id (if set) and logs the booking. showed / no-show marks move it to those stages. One open deal per person per pipeline. A workflow with Create / update deal can do the same. - set_outcome: Mark a booking showed or no_show (or null to clear); fires the Showed / No-show workflow triggers (calendar_id, booking_id, outcome). (waits for approval: send email) - get_booking_status: One booking with its status (booked, confirmed, showed, no_show, cancelled, invalid), needs_status (ended and still booked / confirmed), calendar, guest, answers, source, and its status history incl. Rescheduled markers (booking_id; calendar_id optional). - set_booking_status: Set a booking's status (booking_id, status booked|confirmed|showed|no_show|cancelled|invalid, note?). The same path as the app: fires the status trigger (Appointment confirmed / showed / no-show / cancelled / invalid) and Appointment status changed once; cancelled removes the calendar event and sends the calendar's cancel notice; showed / no-show move the calendar's lead deal. A cancelled booking cannot be reopened. (waits for approval: send email) - needs_status: Past bookings still Booked / Confirmed (the meeting ended with no outcome), newest first (calendar_id optional). - event_crm: A calendar event's CRM links (people, businesses, deals, the client pages it shows on), its booking + status when it is one of our bookings, and guest suggestions matched by email (event_id, event_calendar_id?). - link_event: Link a calendar event to CRM records: a person (contact_id) and, in the same go, businesses (company_ids, e.g. the person's businesses), and / or a deal (deal_id). Clients' pages get the event too (event_id, event_calendar_id?). - unlink_event: Remove one CRM link from a calendar event (event_id, event_calendar_id?, link_type crm_contact|crm_company|crm_deal|client|business, link_id). - get_default_theme: The workspace default look that calendars and forms without their own follow. - set_default_theme: Change the workspace default look (theme, merged; same keys as set_theme: mode light|dark|custom, background #hex (page colour in custom mode), brand #hex, text #hex or "" (auto), font system|inter|dm-sans|manrope|plus-jakarta|work-sans|lora|merriweather, heading_font "" (same as font) or a font key, radius sharp|soft|round, button filled|outline, button_text #hex or "" (auto), button_label up to 40 characters or "" (default label), button_shape auto (follows radius)|square|pill, button_width auto|full, button_size s|m|l, field_style outlined|filled|underline, field_bg / field_border / label_color #hex or "" (auto), show_card true|false, card_bg #hex or "" (auto), card_width auto|narrow|medium|wide, card_shadow none|soft|strong, card_border true|false, text_size s|m|l, align left|center (header and intro), page_fill solid|gradient, gradient_from / gradient_to #hex or "" (auto), gradient_angle 0-360, page_image / logo_url / cover_url (https or /uploads/ path, "" for none), page_overlay 0-80 (darkens page_image), logo_size s|m|l, logo_position left|center; forms: form_layout page|one, progress none|bar|steps, question_numbers true|false, required_color red|brand; calendars: booking_layout month|list, show_host true|false, slot_style outline|filled. A bad value is ignored and the current one stays.) (waits for approval: external) - get_form_theme: A form's public look (form_id). - set_form_theme: Change a form's public look, merged (form_id, theme: the set_theme keys, incl. the form ones: form_layout, progress, question_numbers, required_color, button_label), or theme null for the default. (waits for approval: external) - list_email_templates: Your email templates. - save_email_template: Create or change an email template (template_id?, name, subject, body with custom values). - delete_email_template: Delete an email template (template_id). (waits for approval: delete)

FieldTypeNotes
action requiredlist | get | availability | set_host_hours | set_override | delete_override | adWhat to do.
calendar_idnumber
team_member_idnumber
hoursobject or array or null
datestring
closedboolean
labelstring
override_idnumber
regionus | ca
yearnumber
durationnumber
exclude_booking_idnumber
notificationsobject
settingsobjectset_settings: the calendar settings to change (merged).
themeobject or null
scopeupcoming | past | cancelled | needs
booking_idnumber
startstring
endstringbook: the slot end (from availability).
emailstringbook: the guest's email.
phonestringbook: the guest's phone (optional).
notesstringbook: notes for the booking.
recurrenceobjectbook: { frequency: weekly|biweekly|monthly, count: 2-52 } or { frequency, until: YYYY-MM-DD }.
skip_conflictsbooleanbook: book the open dates of a series when some are taken.
series_scopethis | following | allcancel_series / move_series: which bookings of the series.
connection_idnumberAn Outlook / iCloud account id (external_calendars).
busyarray of stringset_external_calendars: calendar ids that block booking times.
writestring or nullset_external_calendars: the calendar id booking events go to, or null.
outcomestring or null
form_idstringThe form id or public id.
statusbooked | confirmed | showed | no_show | cancelled | invalid
notestring
event_idstringCalendar event id (or "<eventId>|<calendarId>").
event_calendar_idstringThe Google calendar id the event is on.
contact_idnumber
company_idsarray of number
deal_idnumber
link_typecrm_contact | crm_company | crm_deal | client | business
link_idnumber
settingobject or nullset_lead_pipeline: the lead setting, or null to turn it off.
template_idnumber
namestring
subjectstring
bodystring
create_calendar_eventCreate a calendar eventasks for approval

POST/api/external/tools/create_calendar_event

Scopes: bookings:write

Add an event to your Google calendar. An event with guests sends them invitations, so it waits for your approval in Plodder first. An event with no guests is created right away.

FieldTypeNotes
title requiredstring
start_time requiredstringISO 8601 with offset, e.g. 2026-10-08T16:00:00-07:00. For all-day: YYYY-MM-DD.
end_time requiredstringISO 8601. For all-day: the next day YYYY-MM-DD.
all_dayboolean
descriptionstring
locationstring
guestsarray of stringEmail addresses to invite. Needs approval.
conferencingnone | meet | zoomAdd a video call.
busy_statusbusy | free
timezonestringIANA zone, e.g. America/Vancouver.
delete_calendar_eventDelete a calendar eventasks for approval

POST/api/external/tools/delete_calendar_event

Scopes: bookings:write

Delete an event from your Google calendar (a repeating event: this occurrence, or every one with all_occurrences). Waits for your approval unless you allowed deletes; an event with guests emails them a cancellation, so it also follows the external-actions setting.

FieldTypeNotes
event_id requiredstring
calendar_idstring
all_occurrencesbooleanDelete the whole series.
google_calendarsCalendar settingsasks for approval

POST/api/external/tools/google_calendars

Scopes: bookings:write

Settings for each connected Google calendar in the app (see list_calendars for ids): shown or hidden, default busy or free, whether it blocks auto-scheduling, color, and the primary calendar new events go to. App-side only; nothing changes in Google. Actions: - set: visible, default_busy_status (busy | free), use_for_conflicts. Changes reshuffle auto-scheduled tasks. - set_color: color (hex). - set_primary: Make this the calendar new events go to.

FieldTypeNotes
action requiredset | set_color | set_primaryWhat to do.
calendar_id requiredstring
visibleboolean
default_busy_statusbusy | free
use_for_conflictsboolean
colorstring
list_calendar_eventsList calendar eventsread only

POST/api/external/tools/list_calendar_events

Scopes: bookings:read

Events on your connected Google calendars between two dates (default: today through the next 7 days). Times are ISO 8601.

FieldTypeNotes
startstringISO date or datetime. Default now.
endstringISO date or datetime. Default start + 7 days.
querystringMatch in title, location or description.
include_hiddenbooleanInclude calendars hidden in the app.
limitnumberDefault 100.
list_calendarsList calendarsread only

POST/api/external/tools/list_calendars

Scopes: bookings:read

Your connected Google calendars: id, name, primary, shown in the app, used for conflicts. Pass a calendar_id to create_calendar_event-style tools when an event is not on the primary calendar.

No arguments.

update_calendar_eventUpdate a calendar eventasks for approval

POST/api/external/tools/update_calendar_event

Scopes: bookings:write

Change an event on your Google calendar: title, time, description, location, busy or free, guests. Only the fields you pass change; a repeating event changes this one occurrence. When the event has guests (or you add some) Google emails them the change, so it waits for your approval first.

FieldTypeNotes
event_id requiredstringFrom list_calendar_events.
calendar_idstringFrom list_calendar_events.
titlestring
start_timestringISO 8601 with offset. Pass end_time too (or the old end is kept).
end_timestring
all_dayboolean
descriptionstring
locationstring
busy_statusbusy | free
guestsarray of stringThe full guest list after the change (email addresses).

Forms 1

formsFormsasks for approval

POST/api/external/tools/forms

Scopes: forms:read, forms:write

Build forms, read their responses and answer them, as you. A form writes its answers into a database (one row per response). Find forms with list_items types ["form"]. Question types: short, paragraph, email, phone, url, choice, checkboxes, dropdown, checkbox, number, date, datetime, person, relation. Actions: - get: The form: questions (layout sections), settings, columns, counts, status. - create: A new form (name, optional workspace_id); with database_id it asks that database's columns, or returns the form that database already has (the database page's Form button). - edit: One builder change: op = meta {name, description} | add_question {type, label, sectionId?, afterQuestionId?, relationSheetId?} | add_existing {columnId} | rename_question {questionId, name} | set_type {questionId, type, convert?} | set_options {questionId, options:[..]} | remove_question {questionId, deleteColumn?} | add_section {kind: questions|gate|booking, bookingLinkId?} | layout {layout} | settings {settings} | public_link {enabled} | lead_pipeline {lead_pipeline: {on, pipeline_id, stage_id?, title? (custom values, default "{{form.name}}: {{contact.name}}"), value_question? (a question id whose number answer is the deal value)} or null}: on = each submission finds or makes the person from the email / phone answer and adds a deal in that CRM pipeline unless they already have an open one there (then the submission is logged on it); lead source from the page UTM. Put the op's fields in `fields`. (may wait for approval) - trash: Move the form to Trash. (waits for approval: delete) - responses: Every response (the linked database rows) with column names. - stats: Public link traffic (same numbers as the Responses tab): views (each visitor once a day), starts (first touch), submits (public link responses), start_rate and conversion (submits / views, 0..1), per-day series. days = only the last N days. - questions: What a respondent sees: sections and questions with their ids, for answer. - answer: Submit a response as you: answers = {questionId: value}. preview=true checks without saving.

FieldTypeNotes
action requiredget | create | edit | trash | responses | stats | questions | answerWhat to do.
form_idstringForm id or public id.
namestring
workspace_idnumber
database_idstringcreate: a database to build the form on.
opmeta | layout | settings | public_link | lead_pipeline | add_question | add_exisedit: which builder change.
fieldsobjectedit: the op's fields.
answersobjectanswer: {questionId: value}.
previewboolean
daysnumberstats: only the last N days (omit for all time).

Messages 25

chat_channel_bookmarksChannel bookmarksasks for approval

POST/api/external/tools/chat_channel_bookmarks

Scopes: messages:read, messages:write

The links bar at the top of a chat channel that everyone in it sees: list, add, remove, reorder. Actions: - list: The channel's bookmarks. - add: Add one: title, and a url or a message_id. - remove: Remove one (bookmark_id). (waits for approval: delete) - reorder: ordered_ids = bookmark ids in order.

FieldTypeNotes
action requiredlist | add | remove | reorderWhat to do.
channel_idnumber
bookmark_idnumber
titlestring
urlstring
message_idnumber
ordered_idsarray of number
chat_channelsChat channelsasks for approval

POST/api/external/tools/chat_channels

Scopes: messages:read, messages:write

Create and manage Plodder chat channels and DMs as you. Read and post with read_chat_messages and post_chat_message; list them with list_chat_channels. Members: chat_members; join links: chat_invites. Actions: - get: One channel: name, topic, type, members, your notification level, starred. - create: A new channel (name, optional description, workspace_id, private). You join it. - update: Change name, description, topic or type (public|private). Members only. - archive: Archive (delete) the channel. Members only; the default channel cannot be archived. (waits for approval: delete) - unarchive: Bring an archived channel back. Members only. - reorder: Sidebar order: ordered_ids = channel ids in order (channels you are in). - star: Star the channel for yourself. - unstar: Unstar it. - list_starred: Your starred channel ids. - set_notifications: Your notification level for the channel: level = all | mentions | nothing. - mark_read: Mark the channel read for you. - open_dm: Find or open a DM: user_ids (people who share a workspace with you), or with = a teammate's name, a bot's @username, or "botfather". Posts nothing. - open_bot_dm: Find or open the DM with one of your own bots (bot_id).

FieldTypeNotes
action requiredget | create | update | archive | unarchive | reorder | star | unstar | list_staWhat to do.
channel_idnumber
namestring
descriptionstring
topicstring
typepublic | private
privatebooleancreate: a private channel.
workspace_idnumber
ordered_idsarray of number
levelall | mentions | nothing
user_idsarray of numberopen_dm: the other people (you are added).
withstringopen_dm: a name, @bot username, or botfather.
bot_idnumber
chat_invitesChat join linksasks for approval

POST/api/external/tools/chat_invites

Scopes: messages:read, messages:write

Join links for a chat channel: anyone with the link can join, so making one waits for approval. Actions: - list: The channel's join links: url, uses, max uses, expiry. - create: A new join link (max_uses 1-1000 or none, expires_in_days 1-90, default 7). (waits for approval: external) - revoke: Turn a link off (invite_id).

FieldTypeNotes
action requiredlist | create | revokeWhat to do.
channel_id requirednumber
invite_idnumber
max_usesnumber
expires_in_daysnumber
chat_labelsChat sidebar labelsasks for approval

POST/api/external/tools/chat_labels

Scopes: messages:read, messages:write

Your own chat sidebar labels (groups of channels and DMs). A label with a rule is a smart label: rule = {kind: name|unread|dms|channels|private|clients|workspace, value?}. Actions: - list: Your labels and which channel sits under which label. - create: A new label (name, optional rule). - update: Rename, change the rule, or collapse (label_id). - reorder: ordered_ids = label ids in order. - delete: Delete a label; its channels go back to Channels / DMs. (waits for approval: delete) - assign: Move a channel under a label (channel_id, label_id; label_id null = back to default).

FieldTypeNotes
action requiredlist | create | update | reorder | delete | assignWhat to do.
label_idnumber or null
namestring
ruleobject
collapsedboolean
ordered_idsarray of number
channel_idnumber
chat_membersChat channel membersasks for approval

POST/api/external/tools/chat_members

Scopes: messages:read, messages:write

Who is in a chat channel, and adding or removing people and agents, as you. Same access as the channel: anyone in a public channel, members of a private one. Actions: - list: Members with names and roles. - add: Add a person (user_id) or an agent (agent_id), optional role. Adding a guest from outside the channel's workspace waits for approval. (may wait for approval) - remove: Remove a person (user_id) or an agent (agent_id). Waits for approval. (waits for approval: delete)

FieldTypeNotes
action requiredlist | add | removeWhat to do.
channel_id requirednumber
user_idnumber
agent_idstring
rolemember | admin
chat_messagesChat message actionsasks for approval

POST/api/external/tools/chat_messages

Scopes: messages:read, messages:write

Everything you do to chat messages besides posting: edit or delete your own, reactions, pins, your bookmarks, scheduled messages and reminders, as you. Actions: - edit: Change the text of your own message (message_id, text). Everyone in the channel sees the edit. (waits for approval: post chat) - delete: Delete a message: your own, or any as a channel admin or owner. (waits for approval: delete) - react: Add an emoji reaction (message_id, emoji). - unreact: Remove your reaction. - pin: Pin a message in its channel. - unpin: Unpin it. - list_pins: Pinned messages in a channel (channel_id). - bookmark: Save a message to your bookmarks. - unbookmark: Remove it from your bookmarks. - list_bookmarks: Your bookmarked messages. - schedule: Schedule a message (channel_id, text, at = ISO time or epoch seconds in the future). It posts at that time. (waits for approval: post chat) - list_scheduled: Your scheduled messages that have not gone out. - cancel_scheduled: Cancel one of your scheduled messages (message_id). Nothing was posted yet. - remind: Remind you about a message later (message_id, at). Only you see it. - list_reminders: Your open reminders (due_only for the ones due now). - dismiss_reminder: Dismiss one of your reminders (reminder_id).

FieldTypeNotes
action requirededit | delete | react | unreact | pin | unpin | list_pins | bookmark | unbookmarWhat to do.
message_idnumber
channel_idnumber
textstring
emojistring
atstring or numberISO time or epoch seconds.
reminder_idnumber
due_onlyboolean
chat_pollsChat pollsasks for approval

POST/api/external/tools/chat_polls

Scopes: messages:read, messages:write

Polls in chat: ask one (it posts in the channel), read results, vote, close or reopen. Actions: - create: Post a poll (channel_id, question, options 2-10, multi, anonymous). (waits for approval: post chat) - get: A poll with its tally and (unless anonymous) who voted what. - vote: Your vote: options = option indexes (0-based); an empty list withdraws your vote. - close: Close the poll (the person who asked, or the owner). - reopen: Reopen it.

FieldTypeNotes
action requiredcreate | get | vote | close | reopenWhat to do.
channel_idnumber
poll_idnumber
questionstring
optionsarray of string or numbercreate: option texts; vote: option indexes.
multiboolean
anonymousboolean
crm_conversationsCRM Conversationsasks for approval

POST/api/external/tools/crm_conversations

Scopes: messages:read, messages:send, messages:write

CRM Conversations (the team inbox of texts, email and Facebook / Instagram DMs), as you: saved views, the inbox with every filter, messages scheduled to send later, and response times. Scheduled texts keep texting hours (in the person's time zone): a text scheduled outside them goes at the start of the next window and note says so. A DM must go inside Meta's 24-hour window. Response times: with the target on, a message from a person that waits longer than N minutes of business time alerts the assignee (else the person's owner) and / or you, once. To reply now use the phone tool (reply, with cc / bcc for email). Actions: - threads: Threads in a box with filters ({ box?: team | mine | unassigned | unread | done | scheduled, q?, tag? (tag option id), owner? (owner key | none), pipeline? (id), stage?, channel? sms | email | messenger | instagram, assignee? (team member key | none), unread? true, last? them | us }) and the count in every box. - views: Saved inbox views (id, name, config). - save_view: Save a view: name, config = { box?: team | mine | unassigned | unread | done | scheduled, q?, tag? (tag option id), owner? (owner key | none), pipeline? (id), stage?, channel? sms | email | messenger | instagram, assignee? (team member key | none), unread? true, last? them | us }. - update_view: Rename a view or change its filters: view_id, name?, config?. - delete_view: Delete a saved view (view_id). The conversations stay. - scheduled: Scheduled messages, soonest first: contact_id? (one person), status? scheduled (default) | sent | failed | cancelled | all. - schedule: Schedule a message: contact_id, channel sms | email | messenger | instagram, body, send_at (ISO date-time or epoch seconds), email: subject? (else Re: their newest thread), account_id? (mailbox), cc?, bcc? (lists or comma separated). (may wait for approval) - update_scheduled: Change a waiting message (scheduled_id): body?, subject?, send_at?, cc?, bcc?, channel?. (may wait for approval) - send_scheduled_now: Send a waiting message now (scheduled_id); a text outside texting hours still waits for the window. (may wait for approval) - cancel_scheduled: Cancel a waiting message (scheduled_id). - settings: Response-time target, business hours and texting hours, with first-response stats over the last 30 days. - set_settings: Change them: settings = { sla_on?, sla_minutes?, notify? assignee | owner | both, business? { tz, days [0 Sun..6 Sat], start "09:00", end "17:00" }, texting_start?, texting_end?, texting_tz? }. - response_stats: First response over the last N days (days, default 30): answered, waiting, overdue, avg / median seconds, avg business seconds, % within target.

FieldTypeNotes
action requiredthreads | views | save_view | update_view | delete_view | scheduled | schedule |What to do.
boxteam | mine | unassigned | unread | done | scheduled
qstring
tagnumber
ownerstring
pipelinenumber
stagestring
channelsms | email | messenger | instagram
assigneestring
unreadboolean
lastthem | us
view_idnumber
namestring
configobject
contact_idnumber
statusstring
scheduled_idnumber
bodystring
subjectstring
account_idnumber
ccarray or string
bccarray or string
send_atstring or numberISO date-time (with offset) or epoch seconds
settingsobject
daysnumber
crm_sendCRM sendasks for approval

POST/api/external/tools/crm_send

Scopes: messages:read, messages:send

Email or text CRM people one by one (merge fields {{first_name}}, {{name}}, {{company}}, {{first_name|there}}), as you (/api/crm/send). Do-not-contact flags and missing addresses are skipped. At most 200 people per send. Email goes via gmail (your connected mailbox, account_id: personal, one to one) or via mailjet (bulk / marketing: a verified sender from_email or your default, Reply-to your Gmail, unsubscribe link + mailing address footer added, OPTED-IN PEOPLE ONLY: lists flagged cold are refused, people tagged cold / no-consent and the suppression list are skipped). Texts from your Twilio number. format: text (default), rich or html (sanitized). The audience can be a people filter (the People list filter schema) as well as ids or a segment / smart list. Actions: - preview: Dry run: who gets it and who is skipped and why. Nothing is sent. - send: Send it: channel email|sms, the audience (contact_ids, company_ids, deal_ids, segment_id or filter), via (gmail | mailjet), account_id (gmail), from_email / from_name / reply_to / track (mailjet), subject (email), body, format. (waits for approval: send email)

FieldTypeNotes
action requiredpreview | sendWhat to do.
channelemail | sms
contact_idsarray of number
company_idsarray of number
deal_idsarray of number
segment_idnumber
filterobjectPeople filter: { mode: and|or, items: [{ field, op, value }] } (crm_views smart list schema).
viagmail | mailjet
account_idnumberMailbox id to send email from (list_email_threads shows accounts).
from_emailstringMailjet: a verified sender (mailjet status lists them).
from_namestring
reply_tostring
trackbooleanMailjet: count opens and clicks.
formattext | rich | html
subjectstring
bodystring
draft_emailDraft an email or reply

POST/api/external/tools/draft_email

Scopes: messages:write

Save a Gmail draft (new email, or a reply when thread_id is set). Nothing is sent; you can review it in Gmail or Plodder Email.

FieldTypeNotes
account_idnumberSending account. Default: your first connected account.
thread_idstringReply in this thread. Recipients and subject come from the newest message unless you pass them.
reply_allbooleanWith thread_id: cc everyone on the last message.
toarray of string
ccarray of string
bccarray of string
subjectstring
body requiredstringPlain text body.
draft_idstringUpdate this existing draft instead of creating one.
email_campaignsEmail campaignsasks for approval

POST/api/external/tools/email_campaigns

Scopes: messages:read, messages:send, messages:write

Email campaigns through Mailjet (Email > Campaigns), as you: one email to an audience of OPTED-IN people (smart lists / segments, tags, people, a People filter; minus excluded smart lists and tags). People without an address, with do not email / unsubscribed, tagged cold / no-consent, or on the suppression list (bounced, complained, unsubscribed) are skipped with the reason; a smart list flagged cold is refused. Send now, schedule at a wall clock time in a time zone, or batches (batch.size people every batch.every_min minutes). Every email carries the unsubscribe link and your mailing address; links are click tracked per link; opens come from Mailjet. Stats: sent, delivered, opened, clicked (per link), bounced, unsubscribed, complained; recipients filterable by event; add those people to a tag or a workflow; resend to the ones who did not open after N hours (optionally a new subject). audience = { segment_ids?: number[], tag_ids?: number[] (tag option ids, crm_contacts filter_fields "tags"), contact_ids?: number[], filter?: People filter }; exclusions = { segment_ids?, tag_ids? }. A/B test: ab = { on, variants: [{ subject, body? }] (versions B and C; A is the campaign itself), test_pct 10-50 (share of people in the test, split evenly), metric open | click, wait_hours 1-72 }; the winner goes to everyone else after the wait (get shows per version results and the winner). Invalid, throwaway and no-mail-server addresses are skipped (the address check, email_domains validate). A client's own From address works once their sending domain is verified (email_domains). Actions: - list: Every campaign, newest first, with status, counts (total, sent, skipped, failed), delivered, opened and clicked. - get: One campaign (campaign_id) with stats, clicks per link and its resends. - create: A draft: name, subject, body (HTML for rich / html, merge fields {{first_name|there}}, {{name}}, {{company}}, {{unsubscribe_link}}, {{workspace.mailing_address}}), format (rich | html | text), from_email (a verified Mailjet sender, else your default), from_name, reply_to, track (opens and clicks, default true), audience, exclusions, batch, send_local + timezone. - update: Change a draft or scheduled campaign (same fields as create). After it starts only the name changes. - duplicate: Copy a campaign into a new draft (campaign_id). - delete: Delete a draft, sent or cancelled campaign (campaign_id). (waits for approval: delete) - preview: The email exactly as a send builds it, nothing sent: subject, body, format (rich | html | text), contact_id? (one person on the list; else sample values). Returns subject, html, text, person and a warning when the mailing address is missing. - preview_audience: Who it would reach: audience + exclusions (or campaign_id of a resend). Returns total, sendable, skipped reasons with counts, a sample. - test: Send the campaign (campaign_id; subject / body override optional) to yourself only, subject prefixed [Test]. (waits for approval: send email) - send: Send now (campaign_id). Batches go out on their schedule. (waits for approval: send email) - schedule: Schedule (campaign_id, send_local "YYYY-MM-DDTHH:mm", timezone e.g. America/Vancouver). (waits for approval: send email) - unschedule: A scheduled campaign back to draft (campaign_id). - pause: Stop sending (campaign_id). Nothing more goes out until resume. - resume: Carry on (campaign_id). Batches that fell due while paused go now, the rest keep their spacing. (waits for approval: send email) - cancel: Cancel (campaign_id): everyone not sent yet is skipped. - resend_unopened: Resend to people who did not open it: campaign_id, after_hours (1 to 720, from when it started), subject (optional new subject), name. Creates a scheduled campaign. (waits for approval: send email) - recipients: Recipients (campaign_id), filter event = sent | delivered | opened | clicked | bounced | unsubscribed | complained | not_opened | skipped | failed | queued, q, limit (<= 1000), offset. - add_to: Give the people behind an event (campaign_id, event) a tag (tag = the tag name) or add them to a workflow (workflow_id; it must be published and on). (may wait for approval)

FieldTypeNotes
action requiredlist | get | create | update | duplicate | delete | preview | preview_audience |What to do.
campaign_idnumber
namestring
subjectstring
bodystring
formatrich | html | text
from_emailstring
from_namestring
reply_tostring
trackboolean
audienceobject{ segment_ids?, tag_ids?, contact_ids?, filter? }
exclusionsobject{ segment_ids?, tag_ids? }
batchobject{ size: people per batch (0 = all at once), every_min: minutes between batches }
send_localstringYYYY-MM-DDTHH:mm, wall clock time in timezone
timezonestring
abobject or nullA/B test: { on, variants: [{ subject, body? }], test_pct, metric open | click, wait_hours }
after_hoursnumber
eventsent | delivered | opened | clicked | bounced | unsubscribed | complained | not_
qstring
limitnumber
offsetnumber
tagstring
workflow_idnumber
contact_idnumberpreview: one person on the list
email_domainsSending domains and address checksasks for approval

POST/api/external/tools/email_domains

Scopes: messages:read, messages:write

Each client's own sending domain for Mailjet email (Settings > Email > Sending domains), as you: add a domain (it becomes a Mailjet domain sender; the DNS records to add come back: SPF include, DKIM key, ownership token), check DNS (SPF / DKIM status and errors; verified when both are OK), set who it belongs to (business_id = a client, null = your own company) and label. A domain has several senders (hello@, news@, support@ ... each with its own name and Reply-to, one the default; the Mailjet domain sender already covers every address, so a sender needs no Mailjet step): senders / add_sender / update_sender / remove_sender. Every sender of a verified domain shows in campaign, workflow and CRM From pickers, grouped by domain. validate: check an address (email) or people (contact_ids): syntax, a mail server for the domain (MX, cached 30 days), throwaway domains; the result (valid | invalid | no_mx | disposable | unknown) is flagged on each person and campaigns / bulk sends skip invalid, no_mx and disposable. Actions: - list: Every sending domain with its records, SPF / DKIM status, client and default From. - add: Add a domain: domain (client.com), business_id? (the client), label?, default_from? (address or local part on the domain), default_name?. - update: Change a domain (domain_id): label, business_id; default_from / default_name set the default sender (made when new). - senders: The domain's senders (domain_id): address, display_name, reply_to, is_default. - add_sender: Add a sender (domain_id, local_part = the part before the @, like news; display_name?, reply_to?, is_default?). Unique per domain; the first one is the default. - update_sender: Change a sender (domain_id, sender_id): display_name, reply_to, is_default: true makes it the default. - remove_sender: Remove a sender (domain_id, sender_id); when it was the default, the oldest one left becomes the default. (waits for approval: delete) - check: Ask Mailjet to check its DNS now (domain_id). - remove: Take a domain off the list (domain_id); the Mailjet sender stays on the account. (waits for approval: delete) - validate: Check an address (email) or people's primary addresses (contact_ids, <= 2000); fresh = skip the 30-day cache.

FieldTypeNotes
action requiredlist | add | update | senders | add_sender | update_sender | remove_sender | cheWhat to do.
domain_idnumber
domainstring
business_idnumber or null
labelstring
default_fromstring
default_namestring
sender_idnumber
local_partstring
display_namestring
reply_tostring
is_defaultboolean
emailstring
contact_idsarray of number
freshboolean
get_email_threadRead an email threadread only

POST/api/external/tools/get_email_thread

Scopes: messages:read

Every message in a Gmail thread as plain text.

FieldTypeNotes
thread_id requiredstring
account_id requirednumberFrom list_email_threads.
list_chat_channelsList chat channelsread only

POST/api/external/tools/list_chat_channels

Scopes: messages:read

Plodder chat channels and DMs you can read.

FieldTypeNotes
include_dmsbooleanDefault true.
list_email_labelsList email labelsread only

POST/api/external/tools/list_email_labels

Scopes: messages:read

The Gmail labels of your connected accounts (system labels like INBOX and your own), with unread counts. Use the names with update_email_thread.

FieldTypeNotes
account_idnumberOne account. Default: all of yours.
list_email_threadsList email threadsread only

POST/api/external/tools/list_email_threads

Scopes: messages:read

Gmail threads from your connected accounts. Filter by folder (inbox, starred, sent, drafts, all, spam, trash), unread only, or a Gmail search query (from:, to:, subject:, label:, has:attachment, newer_than:7d).

FieldTypeNotes
folderinbox | starred | sent | calendar | drafts | archived | all | spam | trashDefault inbox. calendar = threads with invites, archived = out of the inbox.
unread_onlyboolean
querystringGmail search syntax.
account_idnumberOne account. Default: all of yours merged.
limitnumberDefault 20, max 50.
page_tokenstringnext_page_token from a previous call.
list_inboxList inboxread only

POST/api/external/tools/list_inbox

Scopes: messages:read

Your Plodder inbox: notifications (assignments, mentions, leads...), recent task activity in your workspaces, and AI actions waiting for your approval.

FieldTypeNotes
unread_onlyboolean
limitnumberPer section. Default 25.
mail_organizeEmail organizingasks for approval

POST/api/external/tools/mail_organize

Scopes: messages:read, messages:write

Organize email threads in your own mailboxes, as you: file a thread to a client, snooze it or set a follow-up reminder, shared tags, create or delete a Gmail label, delete a draft, share a thread into a chat channel. Gmail writes are dry runs while sending is off on the server. Read, archive, star or label a thread with update_email_thread. Actions: - client_links: Clients a thread is filed to (account_id + thread_id), or counts per client with neither. - file_to_client: File a thread to a client (account_id, thread_id, client_id). - unfile_from_client: Take a thread off a client. - reminders: Live reminders (snoozed and follow-ups), optionally for one thread. - remind: Snooze a thread or set a follow-up (account_id, thread_id, kind, due_at at least a minute out). - reminder_seen: Clear the "back in your inbox" marker on a thread. - cancel_reminder: Unsnooze (back to the inbox now) or cancel a follow-up (reminder_id). - tags: Tags used on your mail with counts. - set_tags: Set a thread's shared tags (account_id, thread_id, tag_ids; subject optional). - create_label: Create a Gmail label in a mailbox (account_id, name). - delete_label: Delete a Gmail label you made (account_id, label_id from list_email_labels). Gmail takes it off every thread; the email stays. (waits for approval: delete) - delete_draft: Delete a Gmail draft (account_id, draft_id). (waits for approval: delete) - share_to_chat: Post a thread as a link card in a chat channel or DM (account_id, thread_id, channel_id, note). (waits for approval: post chat)

FieldTypeNotes
action requiredclient_links | file_to_client | unfile_from_client | reminders | remind | remindWhat to do.
account_idnumberYour mailbox id (list_email_threads / list_email_labels show it).
thread_idstringGmail thread id.
client_idnumber
kindsnooze | followupremind: snooze (back in the inbox at due_at) or followup (nudge if nobody replied).
due_atstring or numberremind: ISO time or epoch ms.
reminder_idnumber
tag_idsarray of numberset_tags: the thread's full tag list (option ids); [] clears.
subjectstring
namestring
draft_idstring
label_idstringdelete_label: Gmail label id (Label_...).
channel_idnumber
notestring
fieldsobjectAny other body fields the action documents.
mail_scheduledScheduled emailasks for approval

POST/api/external/tools/mail_scheduled

Scopes: messages:read, messages:send, messages:write

Email waiting to send (scheduled, or in the undo window), as you: list, open, reschedule or edit, cancel, or send now. Schedule a new one with send_email. Actions: - list: Everything waiting to send. - get: One scheduled email with its content. - reschedule: Move it (send_at) and/or replace its content (input). - cancel: Cancel it; nothing is sent (answers with its content). - send_now: Send it now. (waits for approval: send email)

FieldTypeNotes
action requiredlist | get | reschedule | cancel | send_nowWhat to do.
scheduled_idnumber
send_atstring or numberreschedule: ISO time or epoch ms.
inputobjectreschedule: the whole email (same shape get returns as input) to replace its content.
fieldsobjectAny other body fields the action documents.
mail_settingsEmail settingsasks for approval

POST/api/external/tools/mail_settings

Scopes: messages:read, messages:write

Your email settings, as you: undo-send seconds, signatures (and the one set in Gmail), split inbox, blocked senders, Important rules (always or never important by address or domain), and mailbox sync (status, force sync). Actions: - get: Your email settings. - set: Change settings: undo_seconds, signature_html, signature_on, signature_replies, split_inbox, or account_id + mailbox_signature_html. - sync_status: How a mailbox's sync stands (account_id): phase backfill / resync / live, status, emails copied, and the Gmail total while copying. - force_sync: Force sync a mailbox (account_id): a live one re-reads everything from Gmail, a stuck one retries now. - gmail_signature: The signature set in Gmail for a mailbox (account_id), to copy in with set (mailbox_signature_html). - list_blocked: Senders you blocked. - block: Block senders (addresses); their inbox mail goes to Trash. (waits for approval: delete) - unblock: Unblock one sender (address). - list_rules: Your Important rules. - set_rule: Always (important true) or never (false) important for an address or domain (kind, pattern). - delete_rule: Delete an Important rule (rule_id, or kind + pattern). (waits for approval: delete)

FieldTypeNotes
action requiredget | set | sync_status | force_sync | gmail_signature | list_blocked | block | What to do.
undo_secondsnumber
signature_htmlstring
signature_onboolean
signature_repliesbooleanset: the signature also goes on replies and forwards (false = new emails only).
split_inboxboolean
account_idnumberYour mailbox id (list_email_threads / list_email_labels show it).
mailbox_signature_htmlstringset: one mailbox's own signature (with account_id); "" removes it.
addressesarray of string
addressstring
kindaddress | domain
patternstring
importantboolean
rule_idnumber
fieldsobjectAny other body fields the action documents.
mailjetMailjet and email editorasks for approval

POST/api/external/tools/mailjet

Scopes: messages:read, messages:send, messages:write

Mailjet (bulk / marketing email) and the email editor, as you. Verified senders, your default From name / address / Reply-to, the event webhook (opens, clicks, bounces, spam, unsubscribes feed the CRM timeline, workflow stats and the suppression list), plus preview and test of an email body exactly as a workflow step or CRM bulk send would build it (custom values, sanitized HTML, the marketing footer: unsubscribe link + {{workspace.mailing_address}}). Marketing sends are for opted-in contacts only. Actions: - status: Connected?, verified senders, your defaults, your connected Gmail (default Reply-to), mailing address, last 30 days (sent, opened, clicked, bounced, spam, unsub); the webhook URL and what Mailjet has registered (app owner only). refresh?: true skips the 10 minute sender cache. - save_settings: Your default marketing sender: from_email (must be a verified Mailjet sender), from_name, reply_to (empty = your connected Gmail). - register_webhook: Point Mailjet's event webhooks (sent, open, click, bounce, spam, blocked, unsub) at this app (app owner only). - preview: Build an email without sending: context (workflow | crm), subject, body, format (rich | html | text), from (mailbox | system) for workflows or via (gmail | mailjet) for crm, mailjet_kind (marketing | transactional), from_email?, from_name?, reply_to?, account_id?, unsubscribe?, contact_id? (else sample data), workflow_id? / workspace_id? (custom values). Returns subject, html, text, from, warnings, error. - send_test: Send that email to yourself only (subject prefixed [Test]) through the path it would use. Same fields as preview. (waits for approval: send email)

FieldTypeNotes
action requiredstatus | save_settings | register_webhook | preview | send_testWhat to do.
refreshboolean
contextworkflow | crm
subjectstring
bodystringPlain text, or HTML for rich / html (sanitized: no scripts, styles blocks, forms or event handlers). Custom values like {{contact.first_name|there}}, {{unsubscribe_link}}, {{workspace.mailing_address}}.
formatrich | html | text
frommailbox | system
viagmail | mailjet
mailjet_kindmarketing | transactional
from_emailstring
from_namestring
reply_tostringEmpty = your connected Gmail; "none" = no Reply-to.
account_idnumber
unsubscribeboolean
coldboolean
contact_idnumber
workflow_idnumber
workspace_idnumber
post_chat_messagePost a chat messageasks for approval

POST/api/external/tools/post_chat_message

Scopes: messages:write

Post a message to a Plodder channel or DM as you. By default it waits for your approval in the Plodder Inbox and posts when you approve.

FieldTypeNotes
channel_id requirednumber
text requiredstring
thread_parent_idnumberReply in this thread.
read_chat_messagesRead chat messagesread only

POST/api/external/tools/read_chat_messages

Scopes: messages:read

Recent messages in a channel, oldest first.

FieldTypeNotes
channel_id requirednumber
limitnumberDefault 30, max 100.
before_idnumberPage back from this message id.
thread_idnumberRead one thread instead: the first message (thread_parent_id) and its replies.
send_emailSend an emailasks for approval

POST/api/external/tools/send_email

Scopes: messages:send

Send an email or reply from your Gmail. By default this does NOT send right away: it creates an approval request in your Plodder Inbox, and the email goes out when you approve it there. Pass draft_id to send an existing draft.

FieldTypeNotes
account_idnumberSending account. Default: your first connected account.
thread_idstringReply in this thread. Recipients and subject come from the newest message unless you pass them.
reply_allbooleanWith thread_id: cc everyone on the last message.
toarray of string
ccarray of string
bccarray of string
subjectstring
body requiredstringPlain text body.
draft_idstringSend this saved draft.
update_email_threadUpdate an email threadasks for approval

POST/api/external/tools/update_email_thread

Scopes: messages:write

Mark a Gmail thread read or unread, archive it, move it back to the inbox, star it, trash it, or add and remove labels by name (list_email_labels). Trashing waits for approval like every delete.

FieldTypeNotes
thread_id requiredstring
account_id requirednumberFrom list_email_threads.
actionread | unread | archive | inbox | star | unstar | trash | untrash | spam | notsp
add_labelsarray of stringLabel names (or ids) to add.
remove_labelsarray of stringLabel names (or ids) to remove.

Calls 6

crm_activityCRM activityasks for approval

POST/api/external/tools/crm_activity

Scopes: calls:write, crm:read, crm:write

A CRM record's timeline, logging a call made outside the app, and the discussion comments on a company or person, as you (/api/crm/calls, /api/crm/comments). Actions: - timeline: Forms, bookings, meetings, signatures, deal moves, logged calls and sends for one company_id, contact_id or deal_id. - log_call: Log a call on a contact_id, company_id or deal_id: outcome connected|no-answer|voicemail|busy|wrong-number, duration_min?, notes?, at? (epoch s), direction? in|out. - comments: Discussion on a company_id or contact_id. - comment: Post a comment (company_id or contact_id, body, parent_id? to reply). @agent mentions get a reply. - edit_comment: Edit your own comment (comment_id, body). - delete_comment: Delete your own comment. (waits for approval: delete)

FieldTypeNotes
action requiredtimeline | log_call | comments | comment | edit_comment | delete_commentWhat to do.
company_idnumber
contact_idnumber
deal_idnumber
outcomeconnected | no-answer | voicemail | busy | wrong-number
duration_minnumber
notesstring
atnumber
directionin | out
comment_idnumber
parent_idnumber
bodystring
dialerPower dialerasks for approval

POST/api/external/tools/dialer

Scopes: calls:read, calls:write

The power dialer, read and set up (agents never place calls): sessions with live stats (dials, connects, talk time, sets, per hour) and the current / next people; call scripts with custom values ({{contact.first_name}}, {{company.name}}, {{user.first_name}}); the disposition list every call uses (No answer, Left voicemail, Interested, Booked, DNC request...) and what each does (move the lead stage, tags, workflow, task, lead status, Do not call, call back, book); voicemail drops (list, rename, delete; recording or uploading audio is done in the app); dialer settings (calling hours by the person's time zone, auto-advance, answering machine detection, caller ID local presence and daily cap, recording notice); set_disposition logs a disposition on any call (its side effects run once per call). Ringless voicemail is not offered: it counts as a call and needs consent. Actions: - sessions: Dialer sessions, newest first, with stats. - session: One session (session_id): stats, counts, skipped by reason, the current person card and call, the next three. - end_session: End a session (session_id): frees everyone it still holds. - set_disposition: Log a disposition on a call (call_id, key, note?, callback_at?). Changing it later is fine; each disposition's side effects run once per call. - dispositions: The disposition list (archived too with fields.all = true). - save_disposition: Create or update a disposition (id to update; label, connect, set, kind, actions, archived). - reorder_dispositions: Order the dispositions (order: ids; the first nine are the 1-9 keys). - archive_disposition: Archive a disposition (id). Calls keep their label. (waits for approval: delete) - scripts: Call scripts and the custom values they can use. - save_script: Create or update a script (id to update; name, body, pipeline_id = the default for that pipeline). - delete_script: Delete a script (id). (waits for approval: delete) - drops: Voicemail drops (recorded messages) with their length. - rename_drop: Rename a voicemail drop (id, name). - delete_drop: Delete a voicemail drop (id). (waits for approval: delete) - settings: Dialer settings. - update_settings: Change dialer settings (settings: any of the keys).

FieldTypeNotes
action requiredsessions | session | end_session | set_disposition | dispositions | save_disposiWhat to do.
session_idnumber
call_idnumber
keystringset_disposition: the disposition key from dispositions (e.g. interested).
notestring
callback_atnumberset_disposition with a Call back disposition: epoch seconds.
idnumbersave_script / save_disposition / rename_drop / delete_*: the row id (omit to create).
namestring
bodystringsave_script: the script text with custom values.
pipeline_idnumber or nullsave_script: the default script for this pipeline.
labelstringsave_disposition: the button name.
connectbooleansave_disposition: counts as reaching the person.
setbooleansave_disposition: counts as an appointment set.
kindno_answer | voicemail | busy | bad_number | contact | dnc
actionsobjectsave_disposition: { stage?: {pipeline_id, stage_id}, add_tags?, remove_tags?, workflow_id?, task?: {title, due_in_days}, lead_status?: won|lost, dnc?, callback?, book? }
archivedboolean
orderarray of numberreorder_dispositions: ids, first = hotkey 1.
settingsobjectupdate_settings: { start, end (HH:MM local), saturday, sunday, default_tz, skip_called_today, auto_advance_sec, amd, amd_drop_id, record, record_notice, local_presence, number_daily_cap, sort, script_id }
fieldsobjectAny other body fields the action documents.
get_callGet a video callread only

POST/api/external/tools/get_call

Scopes: calls:read

One Plodder video call: summary, action items (with their task ids), who was there, the related item, the in-call chat, and the transcript when include_transcript is true.

FieldTypeNotes
call_id requiredstringThe 12-character call id from list_calls or a /calls/<id> link.
include_transcriptboolean
list_callsList video callsread only

POST/api/external/tools/list_calls

Scopes: calls:read

Plodder video calls you can see, newest first: title, when, how long, who was there, and whether a summary exists. Filter by tab (all, missed, unattended, live), by a chat channel, or by the item a call was about (entity_type + entity_id, e.g. task 812).

FieldTypeNotes
taball | missed | unattended | live
channel_idnumber
entity_typestringtask, project, crm_company, crm_contact, client ...
entity_idstring
querystringMatch in the title.
limitnumberDefault 25.
phonePhoneasks for approval

POST/api/external/tools/phone

Scopes: calls:read, calls:write, messages:read, messages:send, messages:write

Your business phone (Twilio), as you: text people, call them (rings your cell first), read and assign threads, triage people known only by number, AI reply drafts, templates and the phone inbox. CRM Conversations: inbox_threads lists a box (team, mine, unassigned, unread, done) with filters, thread gives one thread with its person, company, owner, tags and open deal, mark_done / reopen / mark_unread. Texts and calls wait for approval. Read a thread with action messages, or the whole conversation (texts + linked email + activity) with conversation; reply on either channel with reply, or by text with send_text. Actions: - conversations: Text threads (scope team or mine) and recent calls. - messages: Texts with a contact (contact_id) or a company (company_id), and whether they opted out. - send_text: Text a contact (contact_id) or a number (to): text, media. (waits for approval: external) - mark_thread_read: Mark a contact's text thread read. - assign: Assign a text thread (contact_id, assignee; null clears). - inbox_threads: CRM Conversations: threads in a box (team, mine = assigned to you or people you own, unassigned, unread, done) with search, tag_id, owner, pipeline_id, stage_id; and the count in every box. - thread: One CRM conversation (contact_id): the person, company, owner, assignee, tags, open deal, done, and whether texting is blocked. Read the texts with messages. - conversation: The whole CRM conversation with a person (contact_id), GHL style: texts, their email from your own and shared mailboxes (only mail with their address), and activity rows (bookings, forms, calls, deal moves, tags, notes, tasks) in time order; default_channel is where they last wrote in; reply gives the email thread a reply lands in. - reply: Reply in a CRM conversation (contact_id, channel sms | email | messenger | instagram, text; email: subject? to start a new thread, account_id? mailbox, cc? / bcc? addresses). To send later use crm_conversations schedule. Email lands in their newest thread with Re: and your signature; messenger / instagram go in their DM thread (24-hour window). Waits for approval like send_text / send_email. (may wait for approval) - mark_done: Mark a conversation done (contact_id): it leaves the open boxes until a newer text comes in. - reopen: Reopen a done conversation (contact_id). - mark_unread: Mark a conversation unread again (contact_id): its newest incoming text. - draft_reply: An AI draft of the next text to a contact (never sent). - calls: Calls with a contact or company, or one call (call_id). - call: Call a contact or number: rings your cell first, then connects them. (waits for approval: external) - hold: Hold or resume a live call (call_id, hold). - hang_up: Hang up a live call (call_id). - transfer: Transfer a connected call (call_id) to a teammate or a number (transfer_to), cold or warm (mode). The customer waits on hold music while it rings. Rings someone outside the app, so it waits for approval. (waits for approval: external) - transfer_state: The transfer going on a call (call_id): ringing, talking (warm, answered), completed, cancelled, no-answer. - complete_transfer: Warm transfer: you leave and the customer is connected to the person you transferred to (call_id). - cancel_transfer: Warm transfer called off: the person you rang leaves, the customer comes off hold (call_id). - mark_call_read: Mark a call (missed call, voicemail) read. - add_contact: Add a person known by phone (phone, name, company_id); returns contact_id. - move_contact: Move a person (and their texts and calls) to another company (contact_id, company_id). - inbox: Unread texts, missed calls and voicemails. - mark_inbox_read: Mark inbox items read (items from inbox, or all=true). - templates: Your text templates. - save_template: Create or update a template (template_id to update, name, body). - delete_template: Delete a template. (waits for approval: delete)

FieldTypeNotes
action requiredconversations | messages | send_text | mark_thread_read | assign | inbox_threadsWhat to do.
contact_idnumber
company_idnumber
tostringA full number (+1 604 555 0123) when there is no contact.
channelsms | email | messenger | instagramreply: which channel (messenger / instagram: their Facebook or Instagram DM thread, only inside the 24-hour window after their last message).
subjectstringreply (email): subject for a new thread.
account_idnumberreply (email): the mailbox to send from.
ccarray or stringreply (email): CC addresses (list or comma separated).
bccarray or stringreply (email): BCC addresses.
textstring
mediaarray of stringsend_text: media tokens.
call_idnumber
holdboolean
transfer_toobjecttransfer: { kind: "member", id: team member id } or { kind: "number", phone }.
modecold | warmtransfer: cold = you leave at once; warm = you talk to them first, then complete_transfer.
assigneestring or nullassign: team member id or name; null clears.
phonestring
namestring
hintstring
template_idnumber
bodystringsave_template: the text (merge fields {{first_name}}, {{company}}, {{my_name}}).
allboolean
itemsarray of objectmark_inbox_read: [{kind, id, contact_id}] from inbox.
scopeteam | mine
boxteam | mine | unassigned | unread | doneinbox_threads: which box (default team).
searchstringinbox_threads: name, company, number or text.
tag_idnumberinbox_threads: a tag option id.
ownerstringinbox_threads: an owner (team member id) or none.
pipeline_idnumberinbox_threads: open deal in this pipeline (0 = the default).
stage_idstringinbox_threads: open deal in this stage (with pipeline_id).
fieldsobjectAny other body fields the action documents.
video_callsVideo callsasks for approval

POST/api/external/tools/video_calls

Scopes: calls:read, calls:write

Plodder video calls and scheduled call meetings (/api/calls*). Joining with camera and microphone happens in the app; here: start a call room, ring teammates, chat, guest links, admit guests, mute or remove people, recording, meetings, and the calls switch. Read calls with list_calls and get_call. Actions: - start: Start (or join) the live call of a channel, an item, or a quick call (channel_id | entity | title), ringing user_ids. People are notified. (waits for approval: post chat) - ring: Ring teammates into a live call (call_id, user_ids). (waits for approval: post chat) - chat: A call's chat. - post_chat: Post in a call's chat (call_id, body). (waits for approval: post chat) - guest_link: A join link for people without an account (call_id). (waits for approval: external) - admit_guest: Let a waiting guest in, or turn them away (call_id, guest_id, admit). Hosts. (waits for approval: external) - participant: Mute or remove someone (call_id, identity, participant_action mute|remove). Hosts. Remove waits for approval. (may wait for approval) - recording: Start or stop recording (call_id, recording start|stop). Starting waits for approval. (may wait for approval) - meetings: Call meetings you organize or are invited to. - create_meeting: A scheduled call meeting (title, description?, scheduled_start/end epoch s, lobby_enabled?, invite_user_ids?, invitee_emails?, channel_id?, entity?). Inviting teammates notifies them; inviting emails waits for approval. (may wait for approval) - update_meeting: Change a meeting you organize (meeting_id + title, scheduled_start/end, lobby_enabled, invite_user_ids, invitee_emails, cancelled). Cancelling waits for approval. (may wait for approval) - join_meeting: Open a meeting from its link token (token): the call it runs in. The media join happens in the app. - settings: The calls switch and server (owner). - set_settings: Turn calls on or off (enabled), point at a server (server_url, waits for approval) or test the connection (test). LiveKit keys are entered by the owner in the app. (may wait for approval)

FieldTypeNotes
action requiredstart | ring | chat | post_chat | guest_link | admit_guest | participant | recorWhat to do.
call_idstringThe call's public id.
channel_idnumber
entityobject{type, id} of the item the call is about.
titlestring
user_idsarray of number
bodystring
guest_idnumber
admitboolean
identitystring
participant_actionmute | remove
recordingstart | stop
meeting_idnumber
descriptionstring
scheduled_startnumber
scheduled_endnumber
lobby_enabledboolean
invite_user_idsarray of number
invitee_emailsarray of string
cancelledboolean
tokenstringjoin_meeting: the meeting link token.
enabledboolean
server_urlstring
testboolean
fieldsobjectAny other body fields the action documents.

Automations and agents 26

agent_itemsAgents on items (mention, send to agent, sessions)asks for approval

POST/api/external/tools/agent_items

Scopes: automations:read, automations:write

Agents on any item (task, project, doc, CRM person or business, client, business, meeting, database row, file ...). mention: post a comment as you that @mentions agents, and they run on the item (its content plus the discussion) and reply in the same thread. dispatch: start an agent conversation with the item and its discussion as context (Send to agent); returns the conversation. prompt: the item and every discussion thread as a markdown prompt (Copy as prompt). sessions: agent conversations, mention runs and assigned work on the item. Items: "task:12", "doc:7", "crm_contact:40", "client:3" (ids or public ids). Agents: id, "ai-<id>" or @handle (list them with agent_work action agents). Actions: - mention: Mention agents on an item: item, agent (one) or agents (list), text (what you ask), thread_id? (reply inside a discussion thread). - dispatch: Send an item to an agent: item, agent? (default: your built-in agent), prompt? (what to do; default: work on it). - prompt: The item as a prompt with its discussion threads: item. - sessions: Agent sessions on an item: item.

FieldTypeNotes
action requiredmention | dispatch | prompt | sessionsWhat to do.
itemstring
agentstring or number
agentsarray of string or number
textstring
promptstring
thread_idnumber
agent_mcp_serversOutside MCP serversasks for approval

POST/api/external/tools/agent_mcp_servers

Scopes: automations:read, automations:write

Outside MCP servers your agents can use (Settings > Agents > MCP servers). Adding one or turning one on gives agents new tools, so it waits for approval (external). Auth headers and OAuth sign-in are entered by the person in the app. Actions: - list: Servers and their tools. - add: Add a server (url, name?). Connects and lists its tools. (waits for approval: external) - update: Rename (name) or turn on/off (enabled). Turning on waits for approval. (may wait for approval) - refresh: Reconnect and list its tools again. - delete: Remove a server. (waits for approval: delete)

FieldTypeNotes
action requiredlist | add | update | refresh | deleteWhat to do.
server_idnumber
urlstring
namestring
enabledboolean
agent_memoryAgent memoryasks for approval

POST/api/external/tools/agent_memory

Scopes: automations:read, automations:write

The memory notes your agents read and write (Settings > AI > Memory, /api/ai-agents/memory). Actions: - list: Every note. - add: Add a note by hand (content). - delete: Delete a note (note_id). (waits for approval: delete) - clear: Delete every note. (waits for approval: delete)

FieldTypeNotes
action requiredlist | add | delete | clearWhat to do.
note_idnumber
contentstring
agent_runnersPaired Macsasks for approval

POST/api/external/tools/agent_runners

Scopes: automations:read, automations:write

Macs paired to run agents on their CLIs (Settings > Agents > Runtimes). Pairing a new Mac runs a command on that Mac, so it is done in the app. Actions: - list: Paired Macs, online state and CLIs. - rename: Rename a Mac (device_id, name). - unpair: Unpair a Mac; its token stops working at once. (waits for approval: delete)

FieldTypeNotes
action requiredlist | rename | unpairWhat to do.
device_idnumber
namestring
agent_runsAgent runs and routinesasks for approval

POST/api/external/tools/agent_runs

Scopes: automations:write

Run a routine now, delete a routine, or stop a run (/api/ai-agents/routines/[id], /run, /api/ai-agents/runs/[id]/stop). Create and change routines with create_routine and update_routine. Actions: - run_routine: Run a routine now (routine_id). Starts in the background. A run started this way cannot start further runs, and at most 6 can be started per 10 minutes. - delete_routine: Delete a routine (routine_id). (waits for approval: delete) - stop_run: Stop a running agent run (run_id).

FieldTypeNotes
action requiredrun_routine | delete_routine | stop_runWhat to do.
routine_idnumber
run_idnumber
agent_skillsAgent skills and instructionsasks for approval

POST/api/external/tools/agent_skills

Scopes: automations:read, automations:write

Skills (reusable instructions an agent loads with /slug) and your AI instructions every built-in agent reads (/api/ai-agents/skills, /api/ai-agents/instructions). Read one with read_skill, list with list_skills. Actions: - get: One skill (skill_id). - create: A new skill: name, instructions, slug?, description?, share? private|team. - duplicate: Copy a skill (skill_id) to edit it (built-in ones too). - copy_installed: Copy an installed (legacy) skill in (installed_id). Owner only. - update: Change a skill you made (skill_id + any of name, slug, description, instructions, share). - delete: Delete a skill you made. (waits for approval: delete) - instructions: Your AI instructions. - set_instructions: Replace your AI instructions (text).

FieldTypeNotes
action requiredget | create | duplicate | copy_installed | update | delete | instructions | setWhat to do.
skill_idnumber
installed_idnumber
namestring
slugstring
descriptionstring
instructionsstring
shareprivate | team
textstring
agent_threadsAgent conversationsasks for approval

POST/api/external/tools/agent_threads

Scopes: automations:read, automations:write

Rename, archive, compact or delete your agent conversations (/api/ai-agents/threads/[id]), and read how full a conversation's context is and what its agent may do. Actions: - rename: New title (thread_id, title). - compact: Compact now: fold every turn but the last exchange into the running summary the agent reads instead of them (/api/ai-agents/threads/[id]/compact). Returns the new context size. - context: Context size (tokens used of the model window, what is summarized) and the agent's permissions for this conversation. - archive: Archive it. - unarchive: Bring it back. - mark_read: Mark it read. - delete: Delete the conversation for good. (waits for approval: delete)

FieldTypeNotes
action requiredrename | compact | context | archive | unarchive | mark_read | deleteWhat to do.
thread_id requirednumber
titlestring
agent_workAgent work (assign to an agent)asks for approval

POST/api/external/tools/agent_work

Scopes: automations:read, automations:write

Hand a task, project or doc to an agent as work it owns, and manage that work (Agents > Queue). assign: the agent gets the item with its full context, moves a task to In progress, posts its plan, progress and result as comments, asks questions as comments (the item shows Waiting on you), then moves the task to Review (or Done when finish = done or the task says so) and gives it back to the person who assigned it. Setting a task or project assignee to "ai-<agent id>" does the same. Items: "task:12", "project:4", "doc:7" (ids or public ids). Agents: id, "ai-<id>" or @handle. Actions: - list: The queue: work you assigned or that runs as you. status (open | closed | queued | running | waiting | paused | review | done | stopped | error), agent, item. - get: One piece of work: id. - agents: The agents you can assign work to (their assignee values). - assign: Give an item to an agent: item, agent, note? (instructions), finish? (review | done), start? (false = hold it until resume; default: the agent's "start right away" setting). - stop: Stop work (ends it and hands the item back): id. - pause: Pause work (a live run stops; resume picks it up): id. - resume: Resume paused work, or try again on finished / failed / stopped work with note?: id. - answer: Answer the agent's question on waiting work: id, note.

FieldTypeNotes
action requiredlist | get | agents | assign | stop | pause | resume | answerWhat to do.
idnumber
itemstring
agentstring or number
notestring
finishreview | done
statusstring
limitnumber
startboolean
agents_adminAgentsasks for approval

POST/api/external/tools/agents_admin

Scopes: automations:read, automations:write

Create, change and delete AI agents like the agent editor (/api/ai-agents). List them with list_agents. fields: name, handle, description, avatar, color, instructions, model, share, channel_scope, channel_ids, use_memory, auto_start, policy, auto_accept, allowed_tools, connections, connections_scope, runtime. Changing policy, auto_accept, allowed_tools, connections, connections_scope, runtime (what an agent may do, or whether it skips approvals) always waits for the person's approval (external), on any agent. Actions: - get: One agent with its settings. - create: A new agent: fields = {name, instructions?, model?, ...}. (may wait for approval) - update: Change an agent you made (agent_id, fields). (may wait for approval) - delete: Delete an agent you made. (waits for approval: delete)

FieldTypeNotes
action requiredget | create | update | deleteWhat to do.
agent_idnumber
fieldsobject
botsChat botsasks for approval

POST/api/external/tools/bots

Scopes: automations:read, automations:write

Bot accounts that let an outside program post in chat (Settings > Bots). The bot token is shown only in the app; an outside program gets it with a pairing code. Actions: - list: Your bots. - create: A new bot for a runtime agent (agent_id, display_name, username?, description?). Get it running with pair. - update: Change display_name, description, avatar_url, webhook_url. A webhook URL sends chat to an outside address (waits for approval). (may wait for approval) - pair: A 10-minute pairing code an outside program trades for the bot token. (waits for approval: external) - delete: Revoke the bot. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | pair | deleteWhat to do.
bot_idnumber
agent_idstring
display_namestring
usernamestring
descriptionstring
avatar_urlstring or null
webhook_urlstring or null
coding_sessionsCoding sessionsasks for approval

POST/api/external/tools/coding_sessions

Scopes: automations:read, automations:write

Code mode: a coding agent working on a GitHub repository in a sandbox or a hosted runtime (Cursor, Codex cloud, Claude Code), as you (/api/ai-agents/coding*). A turn runs in the background; read progress with get. Review notes are the comments on a session's Changes. Pull requests themselves: github_pulls. Actions: - get: A session (session_id, or thread_id of its conversation) with its change sets. - start: A new coding conversation and its first turn: prompt, repository (owner/name or URL), branch? (default main), kind? (runtime), agent_id?, size?. - turn: The next turn of a session (session_id, prompt). - stop: Stop the session's runtime (session_id). remove=true also deletes the sandbox (waits for approval: delete). (may wait for approval) - link_pr: Link a pull request by hand (session_id, pr_url); its diff is read into Changes. - changes: The diff of a change set (session_id, set_id? default latest), as file paths with added/removed line counts and hunks. - notes: Review notes on the session's changes. - add_note: A review note: file_path, body, line?, side? L|R. - resolve_note: Mark a note resolved or not (note_id, resolved). - delete_note: Delete your own note (note_id). (waits for approval: delete) - runtimes: Which coding runtimes are ready for you, and the Codex environment. - set_codex_environment: Pick the Codex cloud environment (environment_id, environment_label?). The Cursor API key is entered by you in Settings > Coding agents. - clear_codex_environment: Forget the Codex environment choice. - link_task: The task a session works on (session_id, task: id, CTRL-TASK-<id> or task link; empty to unlink). The session shows on the task and its pull request counts as the task's. - task_pull_requests: Pull requests linked to a task (task), through coding sessions or a reference in their description, with state. - preferences: Your coding preferences: track work with tasks, open pull requests. - set_preferences: Change coding preferences (create_tasks?, open_pull_requests?).

FieldTypeNotes
action requiredget | start | turn | stop | link_pr | changes | notes | add_note | resolve_note What to do.
session_idnumber
thread_idnumber
taskstring
create_tasksboolean
open_pull_requestsboolean
promptstring
repositorystring
branchstring
kindstring
agent_idnumber
sizestring
removeboolean
pr_urlstring
set_idnumber
note_idnumber
file_pathstring
bodystring
linenumber
sideL | R
resolvedboolean
environment_idstring
environment_labelstring
conversation_turnConversation turnasks for approval

POST/api/external/tools/conversation_turn

Scopes: automations:write

Act in the conversation you are answering right now (only inside a Conversation AI turn). Save what they told you, move along the pathway, reply, send a photo from the media library, offer real times and book one, update the CRM, hand off to a person, end, and score the thread. Nothing is sent from here: your reply goes out after the guard rails, with human pacing (or as a draft for a person to approve). Actions: - set_vars: Save answers: vars = { name: value } (the variables the current step asks for; numbers as numbers, yes / no as yes or no). - go_to: Move to a way forward listed in the context (target = its node id, or "return" to go back after a global step). Call it BEFORE reply when their message fits a way forward; the result tells you what to do at the new step. - reply: The message to send them (text). One reply per turn; keep it short on texts. - offer_times: Real open times on the playbook calendar (or the step's). Present them plainly. - book: Book one offered time: slot_id (s1, s2...) and confirmed = true only after they said yes to that exact time. Books once. - send_media: Send one photo / short video from the media library listed under PHOTOS (media_id). It goes out right after your reply text; at most the playbook's limit per conversation, never the same one twice. Say something natural about it in your reply. - tag: Add a tag (tag), or remove it (remove = true). - update_field: Set a person field: field (name | email | phone | title | lead_source | notes | f:<custom field id>), value. - move_stage: Move their open deal (or make one): pipeline_id, stage_id. - hand_off: A person takes over (reason): they asked for a person, you cannot answer, anything sensitive. You may reply one short line that someone will follow up. - end: End the conversation: outcome = qualified | disqualified | booked | not_now | other (message optional, your last line). - score: Every turn: level = hot | warm | cold, reason = one short line. - note: A note on the timeline for the team (text). - call_tool: Call a tool the current step lists (name = the tool, input = { field: value } per its input). Its answer comes back here and fills variables.

FieldTypeNotes
action requiredset_vars | go_to | reply | offer_times | book | send_media | tag | update_field What to do.
varsobjectset_vars: { variable: value }.
targetstring
textstring
slot_idstring
confirmedboolean
tagstring
removeboolean
fieldstring
valuestring
pipeline_idnumber
stage_idstring
reasonstring
outcomestring
messagestring
levelstring
namestring
inputobjectcall_tool: the tool input.
media_idnumbersend_media: the photo id from PHOTOS.
create_routineSchedule a routineasks for approval

POST/api/external/tools/create_routine

Scopes: automations:write

Schedule work for later: a routine runs the instructions as an agent (or a bare model) on a cron schedule, or once at run_at (or say it in words with schedule), and reports to the user's Inbox or a chat channel. To follow up yourself, leave agent_id out (your own default agent). Use list_agents to delegate to another agent. Do not create a routine from inside a routine run unless the user asked for it, and never one per run.

FieldTypeNotes
name requiredstring
instructions requiredstringWhat the agent should do each time it runs.
cronstringRepeat on this 5-field cron schedule, for example "0 9 * * 1-5" (9am on weekdays).
run_atstringRun once at this ISO date-time (with offset), then turn off. Use instead of cron.
timezonestringIANA zone for cron, default America/Vancouver.
schedulestringThe schedule in words instead of cron / run_at, read in the routine's time zone: "every weekday at 9", "mondays and thursdays 4pm", "every 2 hours", "monthly on the 15th" (repeat), or "tomorrow 3pm", "next fri 9am", "in 2h" (once).
agent_idnumberRun as this agent (list_agents). Default: your default agent.
modelstringRun on this model with no agent setup instead.
channel_idnumberPost results in this chat channel instead of the Inbox.
crm_automationsAutomationsasks for approval

POST/api/external/tools/crm_automations

Scopes: automations:read, automations:write

Workflows (CTRL Automations: triggers, emails, texts, waits, branches, CRM steps), as you (/api/automations). A graph is { nodes: [{ id, type, x, y, config }], edges: [{ from, port, to }] }; call `catalog` for node types, ports and config fields, and `options` for the forms, pipelines, mailboxes and templates to pick from. Edits change the draft; `publish` makes it live. Custom values in text: {{contact.first_name}}, {{company.name}}, {{deal.value}}, {{form.answer.<question>}}, {{booking.start}}, {{workspace.<key>}}, {{values.<saved>}}, fallback {{contact.first_name|there}}. Actions: - list: Your workflows with status, counts and folder_id, plus your folders. - get: One workflow: draft graph, settings, problems blocking publish, per-step counts, webhook URL (workflow_id). - catalog: Node types with their ports and config fields, trigger events, condition operators, starter templates. - options: Lists for pickers: forms, booking links, pipelines + stages, mailboxes, project templates, workspaces, projects, team, workflows, segments, fields, tags, custom values (workspace_id?, form_id?). - create: A new draft: name, template? (booking_reminders | client_onboarding | lead_follow_up | cold_outreach), graph?, settings?, workspace_id?, folder_id?. - update: Change the draft (Custom code steps are read-only for agents and API keys: only the account owner edits them in the app): workflow_id, name?, description?, graph?, settings? (allow_reentry, stop_on_reply, stop_on_booking, stop_on_bounce, send_window {days, start_hour, end_hour}, timezone, mailbox_daily_cap, mailbox_spacing_sec, allow_multiple_deals (once per deal instead of once per person), default_mailbox_id, default_from_email, default_from_name, default_reply_to, default_sms_number (the default sender for steps that leave it empty)), workspace_id?. - publish: Publish the draft as a new version and turn the workflow on (workflow_id, note?). (may wait for approval) - pause: Pause: no new people, everyone held where they are (workflow_id). - resume: Resume a paused workflow (workflow_id). (may wait for approval) - delete: Delete a workflow; people still in it are removed (workflow_id). (waits for approval: delete) - versions: Published versions (workflow_id). - restore_version: Load an old version into the draft (workflow_id, version). - enroll: Add people by hand: workflow_id, contact_ids and / or segment_id (max 2,000). (may wait for approval) - remove: Take people out: workflow_id, contact_ids or enrollment_ids. - contact_workflows: The workflows one person is in or was in (contact_id): name, state (active | waiting_until | waiting_reply | waiting | finished | removed | exited | failed), until, current step. Add with enroll, take out with remove. - enrollments: Who is in it: workflow_id, status? (active | completed | exited | removed | failed), limit?, offset?. - runs: Run history with each step's input and output: workflow_id, enrollment_id?, node_id?, contact_id?, limit?; plus send / open / reply counts per step and A/B subject. - test_step: Run one step on sample data, nothing sent or written: workflow_id, node_id, contact_id? (a real person) or sample? ({ contact: {...}, form: { answer: {...} } }). - values: Workspace custom values ({{workspace.key}}): workspace_id. - set_value: Add or change a workspace custom value: workspace_id, label, key?, value. - delete_value: Remove a workspace custom value: workspace_id, key. - bookings: Your recent and upcoming bookings with their showed / no-show mark. - booking_outcome: Mark a booking showed or no_show (or null to clear): booking_id, outcome. Starts the showed / no-show triggers. (may wait for approval) - folders: Your workflow folders: id, name, parent_id (null = top level), workflows in each. - create_folder: A new folder: name, parent_id? (a folder to nest it in). - update_folder: Rename a folder or move it under another one: folder_id, name?, parent_id? (null = top level). - delete_folder: Delete a folder (folder_id). Its workflows move to No folder and its subfolders move up; no workflow is deleted. (waits for approval: delete) - move: Put a workflow in a folder: workflow_id, folder_id (null = No folder). - connections: Slack / Google Sheets connections the Send Slack message and Add Google Sheets row steps post to (workspace_id?): id, kind, name, a hint of the URL (never the URL). Also the Apps Script to paste into a sheet. - save_connection: Add a connection or change one: kind (slack | sheets), name, url (Slack incoming webhook or Apps Script /exec URL), workspace_id; id? to rename or replace the URL. - delete_connection: Remove a connection (connection_id). Steps using it skip until another is picked. (waits for approval: delete) - scoring: Contact scoring: every named score (profiles: id, name, first, rules [{ event, value, points }], decay { points, days }), the events a rule can use and the presets (forms, emails, booked, lead, blank). The first score is the default (People Score column, {{contact.score}}). - create_score: A new named score: name?, preset? (forms | emails | booked | lead | blank: starting rules), rules? [{ event, value?, points }], decay? { points, days }. - set_scoring: Replace one score's rules and decay, or rename it: profile_id? (default the first score), name?, rules [{ event, value?, points }] (e.g. email_opened +1, booking_created +10, booking_showed +20, booking_no_show -10), decay? { points, days } (points 0 = off). - delete_score: Delete a named score (profile_id) with its rules, every person's value and its history. The next score becomes the default. (waits for approval: delete) - contact_scores: One person's value in every score (contact_id). - adjust_score: Move one person's score: contact_id, profile_id? (default the first score), points (+ or -), or set (the new score), reason?. Fires Contact score changed. - score_history: One person's score changes, newest first (contact_id, profile_id? for one score). - suppressions: The unsubscribe / bounce list automations never send to. - unsuppress: Take an address off the suppression list: channel (email | sms), address. (waits for approval: send email)

FieldTypeNotes
action requiredlist | get | catalog | options | create | update | publish | pause | resume | deWhat to do.
workflow_idnumber
folder_idnumber or null
parent_idnumber or null
namestring
descriptionstring
templatestring
graphobject{ nodes, edges }
settingsobject
workspace_idnumber
form_idnumber
notestring
versionnumber
contact_idsarray of number
enrollment_idsarray of number
segment_idnumber
statusstring
enrollment_idnumber
node_idstring
contact_idnumber
sampleobject
limitnumber
offsetnumber
labelstring
keystring
valuestring
booking_idnumber
outcomestring or null
channelemail | sms
addressstring
connection_idnumber
rulesarray of object
profile_idnumber
presetforms | emails | booked | lead | blank
decayobject
pointsnumber
setnumber
reasonstring
idnumber
kindslack | sheets
urlstring
get_routineRead a routineread only

POST/api/external/tools/get_routine

Scopes: automations:read

One routine with its full instructions, triggers and its recent runs.

FieldTypeNotes
routine_id requirednumber
github_pullsGitHub pull requestsasks for approval

POST/api/external/tools/github_pulls

Scopes: automations:read, automations:write

Reviews: your GitHub pull requests, read live through your own GitHub link (/api/github/pulls). Comments, reviews (approve / request changes) and merges are posted as you on GitHub, so they wait for your approval; a merge always does. Actions: - list: Pull requests: scope all|authored|assigned|involving|review_requests, state open|closed|all, repository?, author?, label?, q?, priority? (urgent|high|medium|low|none), linked? (agent|ticket|customer), sort? (recently_updated|priority). Each carries links: coding sessions, tasks, customers, priority and origin. - get: One pull request (repo owner/name, number) with changed files and the conversation. - repositories: Repositories you can hand a coding agent. - comment: Comment on the pull request (body). (waits for approval: external) - review: Submit a review: event APPROVE|REQUEST_CHANGES|COMMENT, body?. (waits for approval: external) - merge: Merge it (method merge|squash|rebase, default squash). Always waits for approval. (waits for approval: external)

FieldTypeNotes
action requiredlist | get | repositories | comment | review | mergeWhat to do.
repostringowner/name.
numbernumber
bodystring
eventAPPROVE | REQUEST_CHANGES | COMMENT
methodmerge | squash | rebase
scopeall | authored | assigned | involving | review_requests
stateopen | closed | all
repositoryarray of string
authorarray of string
labelarray of string
qstring
limitnumber
priorityarray of urgent | high | medium | low | none
linkedarray of agent | ticket | customer
sortrecently_updated | least_recently_updated | newest | oldest | priority
installed_skillsInstalled skill libraryasks for approval

POST/api/external/tools/installed_skills

Scopes: automations:read, automations:write

The installed skill library (/api/skills): list, turn on or off, give to a runtime agent, delete, install from GitHub. Owner only. Agent skills in the agent editor are agent_skills. Actions: - list: Every installed skill. - get: One skill (skill_id) and the agents that have it. - set_enabled: Turn a skill on or off (skill_id, enabled). - assign: Give a skill to a runtime agent or take it away (skill_id, agent_id, enabled). - delete: Delete an installed skill (skill_id). (waits for approval: delete) - install_from_github: Install a skill from a GitHub URL (github_url). Downloads outside code. (waits for approval: external)

FieldTypeNotes
action requiredlist | get | set_enabled | assign | delete | install_from_githubWhat to do.
skill_idnumber
agent_idstring
enabledboolean
github_urlstring
knowledgeKnowledge baseasks for approval

POST/api/external/tools/knowledge

Scopes: automations:read, automations:write

Workspace knowledge entries (text notes and links) agents can read (/api/knowledge). Actions: - list: Entries in a workspace (workspace_id?) or every workspace you are in. - create: A new entry: title, type? text|url, content?, url?, workspace_id?, private?. - update: Change an entry (entry_id + fields). - delete: Delete an entry. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | deleteWhat to do.
entry_idnumber
workspace_idnumber
titlestring
typestring
contentstring
urlstring
privateboolean
fieldsobject
list_agentsList agentsread only

POST/api/external/tools/list_agents

Scopes: automations:read

The agents you can use or delegate to (yours and the team's shared ones): id, @handle, what each is for, its model.

No arguments.

list_routinesList routinesread only

POST/api/external/tools/list_routines

Scopes: automations:read

Your routines (scheduled or event-triggered agent work): name, schedule, the agent it runs as, next and last run. Filter by text or enabled state.

FieldTypeNotes
textstringName or instructions contain this.
enabledbooleanOnly enabled (true) or paused (false) routines.
list_skillsList skillsread only

POST/api/external/tools/list_skills

Scopes: automations:read

Saved skills (reusable agent instructions): yours, the team's shared ones and the built-in ones. Read one with read_skill and follow it when the user's request matches.

FieldTypeNotes
textstringName or description contains this.
memoriesMemory browserasks for approval

POST/api/external/tools/memories

Scopes: automations:read, automations:write

The long-term memory store behind the memory browser (/api/memories): search and delete. Owner only. Agent notes live in agent_memory. Actions: - browse: Search memories (q, sector semantic/episodic, source, client, page). 50 a page, with counts by source and sector. - delete: Delete a memory (memory_id). (waits for approval: delete)

FieldTypeNotes
action requiredbrowse | deleteWhat to do.
qstring
sectorstring
sourcestring
clientstring
pagenumber
memory_idnumber
pathwaysPathways (Conversation AI)asks for approval

POST/api/external/tools/pathways

Scopes: automations:read, automations:write, messages:send

Conversation AI as you, agent-centric (D 10-10): each AI agent runs jobs (a job = a playbook row with the agent_id: one pathway plus its trigger, audience and channels), owns its pathways, and keeps one set of conversation settings for all of its jobs (texting style, voice, knowledge, guard rails, hand-off, photos per conversation: agent_settings / update_agent_settings). Templates (built-in for leads, appointments, payments, clients, support; plus saved ones and Bland imports): templates, template, use_template (an independent copy on an agent plus an off job), save_template. Underneath: playbooks (which agent answers leads on SMS, email, Messenger / Instagram DMs and comments, and how: engagement rules, knowledge, personality, audience lock, channels, segments in priority order, guard rails, hand-off rules, qualifying, booking care, outreach, A/B, outcomes), pathways (node graphs the agent follows: draft, staging and live versions, Bland JSON import, starters), the kill switch and auto-pause limits, channel shortcuts (prebuilt Hand to agent workflows), conversations and the agent side of a CRM thread (suggested replies, take over / hand back / end), learned voice examples. Workflows use the Hand to agent and Agent: start conversation steps and the Agent booked a call / handed off / Pathway ended / Lead qualified triggers (crm_automations). Actions: - overview: Playbooks (with what blocks each from going on), pathways, settings, shortcuts, counts, starters. - pickers: Agents, smart lists, calendars, pipelines, team, workflows, person fields for the editors. - playbook: One playbook (playbook_id) with its problems and voice examples. - create_playbook: New playbook (set: { name, agent_id, ...config }); made off. - update_playbook: Change a playbook (playbook_id, set: { name?, agent_id?, on?, is_default?, scope?, scope_confirmed?, audience_list_ids?, channels?, mode?, outreach?, engagement? (incl. texting style: always_split, split_chance 0-100, max_parts, typo_rate off | rare | sometimes, typo_fix, lowercase, casual, reply delays), knowledge?, personality? (incl. voice_source none | me | teammate | custom, voice_member = team key, voice_samples = pasted lines), guards?, handoff?, qualify?, booking?, pathway_ids?, ab_playbook_id?, ab_split?, outcome_fields?, instructions?, media_max? (photos per conversation), preset? = "super_human" (casual, lowercase-ish, 2-3 texts back to back, typos sometimes, your voice, short, replies after 30-150 s) }). Nested objects merge. (may wait for approval) - delete_playbook: Delete a playbook (playbook_id) with no open conversations. (waits for approval: delete) - reorder_playbooks: Priority order (ids): the first whose rules fit answers. - pathway: One pathway (pathway_id): draft graph, problems, versions, playbooks using it, saved tests. - create_pathway: New pathway: name, agent_id (the agent it belongs to; without one it is a template, and a Bland import always is), and starter (index from overview) or import_json (a Bland pathway export) or graph. - agent_home: One agent's Conversation AI home (agent_id): its jobs (with problems), its pathways, shared settings, counts, 30 day results, recent conversations. - create_job: A new job on an agent (agent_id, set: { name, pathway_id? }): made off with the agent's shared settings. Change it with update_playbook (playbook_id = the job id). - agent_settings: The agent's shared conversation settings (agent_id). - update_agent_settings: Change the agent's shared settings (agent_id, set: { engagement?, personality?, knowledge?, guards?, handoff?, media_max?, learn_from_edits? }, preset? = "super_human", job_ids? to copy to only those jobs). Saved on the agent and copied to its jobs. Nested objects merge. - rebuild_agent_voice: Rebuild the agent's voice profile from real outbound messages of its voice source (agent_id); goes on the agent and every job. - agent_media: An agent's media library (agent_id): its photos, its jobs' and the shared ones. - templates: Every template: saved ones (id) and built-in ones (key "builtin:<key>"), with category (leads, appointments, payments, clients, support), suggested trigger and texting style, outcomes, node count. - template: One template with its graph and problems (key: "builtin:<key>" or a saved template id). - use_template: Copy a template into an agent (key, agent_id, name?, job? default true): an independent pathway on the agent plus an off job with the suggested trigger (channels, outreach). Later template edits never reach the copy. - save_template: Save as template (from_pathway_id = an agent's pathway, or import_json = a Bland export, or graph; name?, set: { description?, category?, trigger?, style? }). An independent copy. - update_template: Change a saved template's name, description, category, trigger or style (template_id, set). Edit its graph with save_pathway (pathway_id = template_id). - delete_template: Delete a saved template (template_id). Copies already on agents stay. (waits for approval: delete) - save_pathway: Save the draft (pathway_id, set: { name?, description?, graph?, require_tests? }). - publish_pathway: Publish the draft as a new version: stage = staging (test first) or live (conversations use it). (may wait for approval) - set_live_version: Make a version live (pathway_id, version): promote staging or roll back. (waits for approval: send email) - duplicate_pathway: Copy a pathway (pathway_id) as a new draft. - delete_pathway: Delete a pathway (pathway_id) no playbook uses. (waits for approval: delete) - settings: Kill switch, auto-pause limits (opt-outs / complaints a day), channel shortcuts. - set_settings: paused (true stops every agent at once; false lets them go again), reason, optout_limit, complaint_limit. (may wait for approval) - set_shortcut: Channel shortcut (channel: sms | email | messenger | instagram | comments | missed_call): on, playbook_id?, agent_id?, segment_id? (only people in that smart list), pipeline_id + stage_id?. (may wait for approval) - conversations: Conversations (state: open | active | human | handed_off | ended, playbook_id?, agent_id?, q?). - thread: The agent side of one person's thread (contact_id): conversation, log, pending suggested replies. - take_over: A person takes the conversation (conversation_id): the agent stops. - hand_back: Give the conversation back to the agent (conversation_id). (waits for approval: send email) - end_conversation: End a conversation (conversation_id, outcome: qualified | disqualified | booked | not_now | other). - send_draft: Send the agent's suggested reply (draft_id, text? edited). Goes out paced, as the agent. (waits for approval: send email) - discard_draft: Drop a suggested reply (draft_id). - voice_examples: Learned voice examples of a playbook (playbook_id): drafts a person edited. - voice_profile: The texting-voice profile of a playbook (playbook_id): source, style facts and the guidance the agent writes to. - rebuild_voice: Rebuild the voice profile from real outbound messages (playbook_id): the voice source's sent texts and DMs (me / a teammate) or the pasted examples (custom). Keeps style facts only. - media_library: Photos / short videos the agent may send (playbook_id: that playbook's + the shared ones; none = all): id, title, when to send, tags, type, size. - add_media: Add to the media library: agent_id (every job of that agent) or playbook_id (one job); omit both or set.shared = true for every agent, set: { title, when (when the agent should send it), tags? }, and the file: drive_file (a Drive file id / public id of an image or MP4) or data_base64 + filename + mime (image/jpeg|png|gif|webp, video/mp4|quicktime; 25 MB). - update_media: Change a media item (media_id, set: { title?, when?, tags?, playbook_id? (null = every playbook) }). - delete_media: Take an item out of the media library (media_id); the Drive file stays. (waits for approval: delete) - delete_voice_example: Forget one voice example (example_id). (waits for approval: delete) - test_chat: One test turn (nothing sent, nothing written): playbook_id? and / or pathway_id, test_version? (draft | staging | live), message, test_state? (the state from the last turn), lead? ({ name, email, phone, tags, fields }). Returns the reply as it would go (parts and delays), the node, variables, trace and the state for the next turn. - tests: Saved tests of a pathway (pathway_id) with their last runs. - save_test: Save a node test (pathway_id, test_id? to change one, set: { name?, node_id?, message, vars?, expect: { node?, var?, value?, goal? }, variations? (0-5 paraphrases) }). - delete_test: Delete a saved test (test_id). (waits for approval: delete) - run_test: Run one saved test (test_id). - run_suite: Run every saved test of a pathway (pathway_id). - results: Results per playbook, pathway and A/B side over days? (default 30): conversations, replied, booked, showed, hand-offs, opt-outs. - campaigns: Agent text campaigns with their stats. - campaign: One campaign (campaign_id): settings, stats, people. - preview_audience: Who an audience is now (set: { segment_ids?, tags?, contact_ids?, exclude_segment_ids? }). - create_campaign: New draft campaign (set: { name, playbook_id, audience, opener: { mode: agent | fixed, text }, pacing: { per_hour, daily_cap } }). - update_campaign: Change a campaign (campaign_id, set); audience / playbook / opener only while a draft. - start_campaign: Start or resume (campaign_id): texts go out by the drip (consent, texting hours, caps). (waits for approval: send email) - pause_campaign: Pause (campaign_id). - stop_campaign: Stop for good (campaign_id); people not reached yet are skipped. - delete_campaign: Delete a draft, stopped or finished campaign (campaign_id). (waits for approval: delete)

FieldTypeNotes
action requiredoverview | pickers | playbook | create_playbook | update_playbook | delete_playbWhat to do.
playbook_idnumber
pathway_idnumber
test_idnumber
campaign_idnumber
daysnumber
messagestring
test_stateobject
leadobject
test_versionstring
conversation_idnumber
draft_idnumber
example_idnumber
contact_idnumber
setobjectFields to set.
idsarray of number
namestring
starternumber
import_jsonanyA Bland pathway export (object or JSON text).
graphobject
stagestring
notestring
versionnumber
pausedboolean
reasonstring
optout_limitnumber
complaint_limitnumber
channelstring
onboolean
agent_idnumber
segment_idnumber
pipeline_idnumber
stage_idstring
statestring
qstring
outcomestring
textstring
template_idnumber
keystringTemplate key: "builtin:<key>" or a saved template id
from_pathway_idnumber
jobboolean
presetstring
job_idsarray of number
media_idnumber
drive_filestring
data_base64string
filenamestring
mimestring
read_skillRead a skillread only

POST/api/external/tools/read_skill

Scopes: automations:read

The full instructions of one skill, by id or /command.

FieldTypeNotes
skill requiredstringSkill id or its /command.
runtime_agent_skillsRuntime agent skillsasks for approval

POST/api/external/tools/runtime_agent_skills

Scopes: automations:read, automations:write

Skills on the runtime agents (/api/agents/skills). Owner only. Running one is not offered here: it starts a CLI on the server; use agent_runs for agent runs. Actions: - list: Skills of one runtime agent (agent_id), or all. - create: A new skill: agent_id, name, and any of description, type, trigger_type, trigger_config, prompt, enabled, mode, visibility. - update: Change a skill (skill_id + fields). - delete: Delete a skill (skill_id). (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | deleteWhat to do.
skill_idnumber
agent_idstring
namestring
descriptionstring
typestring
trigger_typestring
trigger_configstring
promptstring
enabledboolean
modestring
visibilitystring
update_routineChange a routineasks for approval

POST/api/external/tools/update_routine

Scopes: automations:write

Pause or resume a routine, or change its name, instructions, schedule (cron, run_at, or schedule in words) or agent. Only the fields you pass change. Read it with get_routine first.

FieldTypeNotes
routine_id requirednumber
enabledbooleanfalse pauses it, true resumes it.
namestring
instructionsstring
cronstringRepeat on this 5-field cron schedule, for example "0 9 * * 1-5" (9am on weekdays).
run_atstringRun once at this ISO date-time (with offset), then turn off. Use instead of cron.
timezonestringIANA zone for cron, default America/Vancouver.
schedulestringThe schedule in words instead of cron / run_at, read in the routine's time zone: "every weekday at 9", "mondays and thursdays 4pm", "every 2 hours", "monthly on the 15th" (repeat), or "tomorrow 3pm", "next fri 9am", "in 2h" (once).
agent_idnumber

Reports 2

my_activityMy activityread onlyasks for approval

POST/api/external/tools/my_activity

Scopes: reports:read

What you did in the app: the My activity page (your actions over the last days, grouped by item), the year graph (actions per day), or your latest actions. Actions: - summary: Your actions in the last `days` (1-31, default 7) with the items they touched. - graph: Actions per local day for the past year (tz_offset_min = your getTimezoneOffset). - recent: Your latest actions (limit).

FieldTypeNotes
action requiredsummary | graph | recentWhat to do.
daysnumber
tz_offset_minnumber
limitnumber
reportsReports (CRM > Reports)asks for approval

POST/api/external/tools/reports

Scopes: reports:read, reports:write

Custom report dashboards like GHL / HubSpot custom reports: a grid of widgets over CRM and activity data, with a dashboard date range, compare-to-previous and filters (owner, pipeline, pipeline_kind leads|sales, business, tag, lead_source). Answer a numbers question by calling action "run" with a widget config, e.g. revenue this month: config {"title":"Revenue","visual":"number","source":"revenue","metric":"sum","field":"value"} with filters {"range":{"preset":"this_month"},"compare":true}. Config: source (deals | revenue | people | businesses | bookings = calendar calls | phone_calls | texts | emails | logged_calls | forms | tasks | workflow_runs), metric (count | sum | avg | median | min | max | unique (field) | daily_avg | rate | mrr | velocity (deals) | formula), field (number field for sum/avg/min/max, e.g. value in cents, talk_time in seconds), rate (preset: win_rate, close_rate, show_rate, no_show_rate, cancel_rate, answer_rate, connect_rate, done_rate, completion_rate) or rate_num/rate_den filter lists, group_by ("time" or a field such as owner, stage, pipeline, pipeline_kind, business, tag, lead_source, calendar, form, result, direction, status), interval (day | week | month | quarter), breakdown (second field: one series per value), filters [{field, op: eq|neq|in|nin|gt|gte|lt|lte|contains|empty|not_empty|is_true|is_false, value}], range override {preset: today|yesterday|this_week|last_week|this_month|last_month|this_quarter|last_quarter|ytd|last_year|last_7|last_30|last_90|last_12_months|all|custom, from, to}, visual (number | line | bar | area | donut | table | funnel | leaderboard | goal), funnel {mode: cohort (default: follows the same people; breakdown?: a step-1 field to split by; orientation?: horizontal) | steps (counts each step on its own), steps:[{label, source, metric?, filters?, time_field?}]} or {mode: pipeline, pipeline_id, pipeline_kind?: leads} (stage conversion, days in stage, lost reasons), formula = an equation {vars: {A: {source, metric?, field?, rate?, filters?, time_field?, label?} | {source: "ad_spend"} (the dashboard's ad spend, cents), B: ..., up to H}, expr: "(A - B) / C * 100" (numbers, A-H, + - * /, parentheses, unary minus; dividing by zero gives null), format?: count|number|money|duration|percent} with metric "formula"; works as a number, over time (per bucket) and grouped by a field every variable has (group_by); the first kind {op, a, b} still works as "A op B". custom_metric (a saved metric id, see metric_list) with metric "formula" runs that saved equation (edit it once, every widget follows; a deleted one shows a removed note), goal (target in the metric's units: cents, seconds, 0..1), currency (default: the workspace currency, crm_data save_settings currency; other currencies are listed apart, never added in), color, limit, sort, retention (churn_rate on businesses | revenue_churn | expansion | contraction | nrr on revenue: churn and NRR over the range, number or line / bar; MRR leaves out deals from their churn day). Money is in cents. Revenue = won deals' value in the period of their close date; add filter {field: "pipeline_kind", op: "eq", value: "sales"} for true revenue (a leads pipeline's won stage is a handoff to sales, not money). MRR = monthly value of won recurring deals won before the period ends (yearly / 12). Show rate = showed / booked calls whose time has passed. Action "catalog" lists every field. Results only count records the caller can see. Actions: - list: Your dashboards and those shared with you, plus the templates. - get: One dashboard with its widgets, filters and grid positions (dashboard_id). - library: The metrics library: ~70 ready metrics by area (revenue, leads, calls, messaging, forms, workflows, tasks), each a widget config. Run one with run (config) or add it with add_metric. - add_metric: Add a library metric to a dashboard as a widget (dashboard_id, metric_key, position?). - catalog: Sources with their date fields, fields (type, groupable), rate presets and which dashboard filters apply. Includes what the workspace made: custom fields (cf_<id>) on people / businesses / deals, contact scores (score_<id>, score_<id>_band) on people, and one source per custom object (obj_<id>, fields of_<id>). A deleted custom field or object shows a removed note instead of numbers. - options: Values for filters you can use: owners, pipelines, stages, businesses, tags, lead sources, calendars, forms, workflows. - metric_list: Saved custom metrics: named equations ("Cost per showed call", "Profit") every dashboard can use (widget config {metric: "formula", custom_metric: id}). - metric_create: Save an equation as a named custom metric (name, formula {vars, expr, format?}). Variables can use custom fields, contact scores, custom objects and ad spend ({source: "ad_spend"}). - metric_update: Change a saved custom metric (metric_id, name?, formula?); every widget using it follows. - metric_delete: Delete a saved custom metric (metric_id); widgets using it show "This metric was removed." (waits for approval: delete) - run: Run a widget config and return its numbers plus a one-line answer (config, filters?: dashboard filters {range, compare, owner, pipeline, business, tag, lead_source}, tz?). - run_widget: Run a saved widget under its dashboard filters (dashboard_id, widget_id, filters? to override, tz?). - run_dashboard: Run every widget on a dashboard (dashboard_id, filters?, tz?): one answer line per widget. - create: New dashboard, blank or from a template (name?, template?: sales_overview | calls | funnels | funnel | monthly_revenue, description?, shared?, workspace_id?, filters?). - update: Rename, describe, set dashboard filters, or share (dashboard_id, name?, description?, filters?, shared?: private | view | edit, workspace_id?). Sharing is owner only. - duplicate: Your own private copy of a dashboard (dashboard_id, name?). - delete: Delete a dashboard you own (dashboard_id). (waits for approval: delete) - add_widget: Add a widget (dashboard_id, config, position? {x, y, w, h} on the 12-column grid; default: the next free spot). - update_widget: Change a widget's config or position (dashboard_id, widget_id, config?, position?). config replaces the whole config. - delete_widget: Remove a widget (dashboard_id, widget_id). (waits for approval: delete) - set_layout: Move / resize several widgets at once (dashboard_id, positions: [{id, x, y, w, h}]). - list_report: One page of a list report, the Appointments / Calls / Texts / Emails / Attribution tabs of CRM > Reports (kind, range?: preset or custom with from/to (default last_30), filters?: appointments {date_field: start|booked, calendar, status: booked|confirmed|showed|no_show|cancelled|invalid|needs, host (team member id or none), source, medium, campaign, pipeline, contact (person id: their meetings), company (business id: the meetings of its people), when: upcoming|past (not cancelled) or any (with range all, bookings ahead count too: the Calendars > Bookings table)}; calls {direction: in|out, user (user id), outcome: answered|missed|voicemail|no_answer|not_returned, number, contact}; texts {direction, user, origin: manual|automated, status: delivered|sent|failed|pending|received|replied, contact}; emails (every email the app sent a person since 10-09: compose, CRM send, workflows, calendar, documents) {origin: user|automation|agent|api, user (user id), source: compose|crm|workflow|calendar|document, provider: gmail|mailjet, status: sent|delivered|opened|clicked|replied|bounced|failed|spam, contact}; attribution {source, medium, campaign ((none) = blank), booked|showed|won: yes|no}, where? the filter panel conditions: {mode: and|or, items: [{field, op, value}]} (one nested group allowed) on the fields of the kind from list_report_options (where_fields: key, type, options; ops by type: select any|none|empty|not_empty with value a list, multi also all, text is|is_not|contains|not_contains|starts_with|ends_with|empty|not_empty, number / money gt|gte|lt|lte|eq|ne|between, date last_days|next_days|older_days|before|after|on|between|today|this_week|this_month|..., bool true|false; e.g. appointments person tag, business stage, booked on, lead source), q? search, sort?, dir?, page?, page_size? (max 200), tz?). Returns rows, total, the totals tiles and, for attribution, the summary by source and by campaign (leads, booked, showed, won, won value in sales pipelines, cash collected from payments, ad spend). action list_report_options gives the filter values. - list_report_options: Values for the list report filters (calendars, hosts, users, pipelines, lead sources, mediums, campaigns, tags, business stages, dispositions) and where_fields: per kind, the fields the where conditions take. - export_list_report: The whole filtered list as CSV text (same arguments as list_report, plus columns?: list of column keys; at most 50,000 rows). Formula-like cells are prefixed with an apostrophe.

FieldTypeNotes
action requiredlist | get | library | add_metric | catalog | options | metric_list | metric_creWhat to do.
dashboard_idnumber
metric_idnumbermetric_update / metric_delete: a saved custom metric id (metric_list).
formulaobjectmetric_create / metric_update: {vars: {A: {...}, B: {...}}, expr: "A / B", format?}.
widget_idnumber
namestring
descriptionstring
templatesales_overview | calls | funnels | funnel | monthly_revenue
sharedprivate | view | edit
workspace_idnumber or null
configobjectA widget config (see the tool description).
filtersobjectDashboard filters: {range: {preset, from?, to?}, compare?, owner?, pipeline?, pipeline_kind?: leads|sales, business?, tag?, lead_source?}.
positionobject{x, y, w, h} in grid steps (12 columns, rows of 40px).
positionsarray of object
metric_keystringA key from action library (e.g. revenue, speed_to_lead, velocity, show_rate, cpl).
tzstringIANA time zone for ranges and buckets (default the dashboard's, else UTC).
kindappointments | calls | texts | emails | attributionlist_report / export_list_report: which list.
rangestringlist_report: date range preset (today, this_week, this_month, last_month, last_7, last_30, last_90, ytd, all, custom with from / to).
fromstringlist_report custom range start, YYYY-MM-DD.
tostringlist_report custom range end (inclusive), YYYY-MM-DD.
qstringlist_report search (name, email, number, message).
sortstringlist_report: a column key to sort by.
dirasc | desc
pagenumber
page_sizenumber
columnsarray of stringexport_list_report: column keys to include (default all).
whereobject or stringlist_report / export_list_report: the filter panel conditions {mode, items: [{field, op, value}]} (fields: list_report_options where_fields).

Files 4

driveDrive and foldersasks for approval

POST/api/external/tools/drive

Scopes: files:read, files:write

Organize Drive and the sidebar, as you: folders (create, rename, colour, delete), move items between folders and projects, rename, trash, restore and delete forever, save a chat/task/mail attachment into Drive, extract a .zip, and the project/stage/task Trash. kind: doc | sheet | folder | file (move also takes mail_thread | channel). Actions: - folders: Folders in a workspace. - create_folder: A folder (workspace_id, name, color, parent_id). - update_folder: Change a folder (folder_id, set). - color_folder_tree: Give a folder and everything in it one colour (folder_id, color). - delete_folder: Delete a folder. (waits for approval: delete) - sidebar_move: Move a project, doc, folder or database into a folder or project in the sidebar (type, id, target_folder_id or target_project_id, sort_order). - move: Move Drive items (items, target). - rename: Rename one Drive item (items: [one], name). - trash: Move Drive items to Trash (items). (waits for approval: delete) - restore: Bring Drive items back from Trash (items). - extract_zip: Extract a .zip in Drive next to it (items: [{kind: "file", id}]): a new folder named after the zip with its folders and files. Links, system files and blocked types are skipped; oversized or zip-bomb archives are refused. - delete_forever: Delete Drive items that are already in Trash, for good (items). (waits for approval: delete) - save_attachment: Copy an attachment into Drive (source attachment with attachment, url with url, or mail with mail), to target. - work_trash: Deleted projects, stages and tasks. - restore_work: Restore deleted projects, stages or tasks (project_ids, stage_ids, task_ids). - purge_work: Delete deleted projects, stages or tasks for good (project_ids, stage_ids, task_ids). (waits for approval: delete)

FieldTypeNotes
action requiredfolders | create_folder | update_folder | color_folder_tree | delete_folder | siWhat to do.
folder_idnumber
namestring
colorstring
parent_idnumber
workspace_idnumber
setobjectupdate_folder: fields (name, color, parent_id, sort_order, ...).
itemsarray of object[{kind, id}]
targetobject{folderId?, workspaceId?}
typestringsidebar_move: project | doc | folder | database; trash: project | stage | task.
idnumber
target_folder_idnumber
target_project_idnumber
sort_ordernumber
sourceattachment | url | mail
attachmentstringsave_attachment: msg:<id> | task:<id>
urlstring
mailobjectsave_attachment from mail: {account, message, id, name, type}
project_idsarray of number
stage_idsarray of number
task_idsarray of number
fieldsobjectAny other body fields the action documents.
importsImportsasks for approval

POST/api/external/tools/imports

Scopes: files:read, files:write

Import jobs from other tools (/api/import/jobs). File imports (Notion export, Slack, CSV) are uploaded by the person in the app; here: a GitHub import (options.repo) through your GitHub link, and every job's preview, options, start and cancel. API tokens (Notion, Linear) are pasted by the person. Actions: - list: Your imports, newest first. - get: One import with its preview. - create: A new import that previews first (source, workspace_id, options). Nothing is written until start. - set_options: Change an import's options; the preview runs again (job_id, options). - start: Run the import the preview showed (again = update, never duplicate). - cancel: Stop a running import after its current item; what was written stays.

FieldTypeNotes
action requiredlist | get | create | set_options | start | cancelWhat to do.
job_idnumber
sourcestringcreate: github.
workspace_idnumber
optionsobjectcreate / set_options: source options (repo, picked items, people mapping, filters).
fieldsobjectAny other body fields the action documents.
read_fileRead a fileread only

POST/api/external/tools/read_file

Scopes: files:read

The text of a file in Drive (text, markdown, code, csv, json, pdf, docx) plus its name, type and size. Find files with list_items types ["file"] or search. Images, audio and video have no text.

FieldTypeNotes
file requiredstringFile id, public id, or file:<id>.
max_charsnumberReturn at most this many characters (default 20000, max 100000).
save_fileSave a file to Drive

POST/api/external/tools/save_file

Scopes: files:write

Save text you wrote (a report, a CSV export, notes, code) as a new file in Drive, in a folder or a workspace root, or in the user's own space. The file name's extension sets the type (.md, .txt, .csv, .json). For a rich document the team edits, use create_doc instead.

FieldTypeNotes
name requiredstringFile name with extension, for example "October report.md".
content requiredstringThe file's text.
folder_idnumberDrive folder id (list_items types ["folder"]).
workspace_idnumberWorkspace root, when no folder is given. Default: your own space.

E-sign 2

documentsDocuments and contractsasks for approval

POST/api/external/tools/documents

Scopes: esign:read, esign:write

Document templates (contracts, proposals, NDAs) filled with custom values ({{contact.full_name}}, {{business.name}}, {{deal.value}}, {{date.today}}, {{custom_values.key}}, any CRM custom field key, {{input.key}} fill-ins), turned into a PDF on a person or deal, and sent for signature by email. Template kinds: pdf (fields placed on an uploaded PDF: kind merge {text}, input {key,label,default}, signature/initials/date/name/text/checkbox {role}; rect 0..1 of the page, origin top-left) or written (a Word document: edit it with word_docs; signer blocks in the text: {{sign:client}}, {{initials:client}}, {{date:client}}, {{text:client:Label}}, {{check:client}}). Roles: [{key, label, type: contact|teammate|email}]. Actions: - templates: List templates (type contract|proposal|agreement|other, query) and the starters. - get_template: One template with its fields, roles, fill-ins and settings. - create_template: New template: kind pdf with file (a Drive PDF), kind written (blank Word document) or file = a .docx, or starter (service_agreement | proposal | mutual_nda). name, type, workspace_id. - update_template: Change a template: set {name?, type?, fields?, roles?, settings? {order, doc_name, subject, message, expires_days, remind_days}, inputs? [{key,label,default}]}. - duplicate_template: Copy a template. - delete_template: Remove a template (documents made from it stay). (waits for approval: delete) - options: The values you can use in templates (incl. Custom values) and who can countersign. - preview: Check a template for a person (contact_id / deal_id, or the sample person): empty values, signer fields, pages, warnings. Nothing is stored. - check_values: Which values are empty for this person, and the fill-ins the template asks for. - generate: Make the PDF for a person / deal (template, contact_id, deal_id, inputs {key: value}). Saved in Drive (Documents folder) and on their record; not sent. - send: Send for signature: template (or document = a draft), contact_id, deal_id, inputs, countersign_user_id, order client_first|company_first|parallel, subject, message, expires_days, remind_days, role_emails {role: email}, pay_on_sign {amount?, currency?, description?} (Stripe: the client pays right after signing; amount empty = the deal's value). The contact gets an email link with a code check. (waits for approval: external) - documents: Documents for a person, deal or template (contact_id, deal_id, template, status), with status and signers. - status: One document: status, each signer, links to the PDF and the signed copy. - cancel: Cancel a sent document (its signing links stop working). (waits for approval: external)

FieldTypeNotes
action requiredtemplates | get_template | create_template | update_template | duplicate_templatWhat to do.
pay_on_signobject or booleansend: collect a payment when the client signs { amount?, currency?, description? }.
templatestringTemplate id or public id.
documentstringDocument id or public id.
kindpdf | written
typecontract | proposal | agreement | other
namestring
filestringDrive file id or public id (a PDF or .docx).
starterservice_agreement | proposal | mutual_nda
workspace_idnumber
querystring
setobjectupdate_template changes.
contact_idnumber
deal_idnumber
inputsobjectFill-in values {key: text}; text may use {{values}}.
countersign_user_idnumber
orderclient_first | company_first | parallel
subjectstring
messagestring
expires_daysnumber
remind_daysnumber
role_emailsobject
statusstring
pdfPDF annotate and signasks for approval

POST/api/external/tools/pdf

Scopes: esign:read, esign:write, files:read, files:write

Marks and signature requests on a PDF in Drive, as you. Coordinates are 0..1 of the displayed page, origin top-left. Mark data: {kind:"highlight", rects:[{x,y,w,h}], color: yellow|green|blue|pink|purple, quote} | {kind:"ink", strokes:[[[x,y],...]], color: black|blue|red|green, width} | {kind:"text", rect, text, color, size} | {kind:"signature", rect, image: PNG data URL}. Read the text of a PDF with read_file; a finished request has signedFileId (read it with read_file). Actions: - marks: Every mark on the file and whether you can edit. - add_mark: Add a mark: page (1-based) and data. - update_mark: Change a mark's data (mark_id). - delete_mark: Remove a mark (mark_id). (waits for approval: delete) - export: Save a copy with every mark flattened into a new Drive file next to the original. - outline: The PDF's outline (bookmarks / table of contents) as a tree: [{title, page, items}], like the viewer's Outline panel; [] when it has none. - requests: Signature requests on the file; options=true also lists who you can ask (teammates, portals, CRM people). - request_signatures: Ask people to sign: signers [{signerUserId | portalSlug | email (+name) | crmContactId, fields?: [{id, page, kind: signature|initials|date|name, rect}]}], message, order sequential|parallel, expiresDays, autoRemindDays. Teammates only runs at once; portals and emails reach outside people. (may wait for approval) - remind: Remind a teammate signer (request_id; once an hour). - cancel_request: Cancel the whole envelope (request_id). (waits for approval: external) - my_requests: Requests waiting on you to sign. - view_request: A request made to you: the file, marks and fields to fill. - sign: Sign a request made to you (request_id). Fields are filled with your saved signature (signature_id, default the newest) plus your name and today, or pass values [{id, image|text}]. (waits for approval: external) - decline: Decline a request made to you (request_id, reason). (waits for approval: external) - signatures: Your saved signatures (ids and kinds). - save_signature: Save a signature picture: kind draw|type|upload, image (PNG data URL). - delete_signature: Delete a saved signature (signature_id). (waits for approval: delete)

FieldTypeNotes
action requiredmarks | add_mark | update_mark | delete_mark | export | outline | requests | reqWhat to do.
filestringDrive file id, public id or file:<id> (a PDF).
pagenumber
dataobjectMark data (see description).
mark_idnumber
optionsboolean
signersarray of object
messagestring
ordersequential | parallel
expiresDaysnumber
autoRemindDaysnumber
request_idnumber
signature_idnumber
valuesarray of object
placementsarray of objectsign without sender fields: [{page, data: signature or text mark}].
reasonstring
kinddraw | type | upload
imagestring
querystringrequests with options: filter who you can ask.

Payments 1

paymentsPayments (Stripe, Square, Whop, FanBasis)asks for approval

POST/api/external/tools/payments

Scopes: payments:read, payments:write

Get paid through the connected providers: Stripe (payment links, hosted invoices, subscriptions), Square (payment links, invoices), Whop (checkout links, monthly / yearly links), FanBasis (read only: collect in FanBasis, then record). provider picks one (default: the workspace default, else Stripe). Payments read from Square / Whop / FanBasis show up on their own (kind sale). The payments list with status (Paid, Open, Overdue, Failed, Refunded, Active...), refunds (Stripe, Square, Whop), cancel, resend, and record (a payment made outside: cash, e-transfer, the provider's own page). Amounts: amount in the currency (1500 or "1500.00"), or amount_cents, or lines [{name, qty, unit_cents}], or a deal_id (its line items, else its value). Currency: given, else the deal's, else the account's. Clients pay on the provider's pages; nothing here charges a card. Actions: - status: Which providers are connected (Stripe mode, account names, Square location, last sync, webhook set up) and the default. Never a key. - test_connection: Test a connected Square, Whop or FanBasis account (provider): its name and how many recent payments the key reads; FanBasis also returns the field names of 1 payment (keys only) and which ones the mapping found. Owner only. Never a key. - list: Payments, newest first (contact_id?, deal_id?, status?, kind?, provider?, limit?). - get: One payment (payment_id). - create_link: A Stripe payment link (single use) for an amount, lines or a deal. Returns the url to share. - create_invoice: A Stripe hosted invoice for a person (contact_id or a deal with a person), due_days (default 14) or due_date, send stripe | email | none. (may wait for approval) - create_subscription: A retainer: monthly / yearly (interval) for a person or deal, collect link (card on Stripe) or invoice. (waits for approval: money) - refund: Refund a paid payment (payment_id, amount? = all that is left, reason?). (waits for approval: money) - cancel: Stop a payment link, void an open invoice, or end a subscription (at_period_end?). (waits for approval: external) - resend: Send an open invoice again (via stripe | email). (waits for approval: external) - record: Record a payment made outside (cash, e-transfer, the provider's own page): contact_id or deal_id, amount, provider? (manual default), paid_at?. Marks it paid and fires Payment received once. Moves no money. (waits for approval: external)

FieldTypeNotes
action requiredstatus | test_connection | list | get | create_link | create_invoice | create_suWhat to do.
contact_idnumber
deal_idnumber
payment_idnumber
amountnumber or stringIn the currency, e.g. 1500 = $1,500.00.
amount_centsnumberMinor units (cents).
linesarray of object[{ name, qty, unit_cents }]
use_deal_linesbooleanWith deal_id: use its line items (default) or false for its value.
currencystringISO code. Default: the deal's, else the workspace currency (crm_data settings), else the provider account's (Square, Whop, FanBasis: the account's first).
descriptionstring
due_daysnumber
due_datestringYYYY-MM-DD
sendstripe | email | noneInvoices: Stripe emails it, our billing email, or none (just the link).
intervalmonth | year
collectlink | invoiceSubscriptions: link = the client enters a card on Stripe; invoice = Stripe emails an invoice each period.
statusstring
kindlink | invoice | subscription | checkout
limitnumber
reasonrequested_by_customer | duplicate | fraudulent
at_period_endboolean
viastripe | email
idem_keystringOptional: the same key returns the same payment.
providerstripe | square | whop | fanbasis | manualWhich provider makes it (create_*), filters list, or names where a recorded payment was paid (manual = cash / bank / other).
paid_atstringrecord: when it was paid (YYYY-MM-DD), default now.

Commissions 1

commissionsCommissions (closers and setters)asks for approval

POST/api/external/tools/commissions

Scopes: commissions:read, commissions:write

Pay closers and setters (CRM > Commissions). Payees are team members (they see their own lines) or outside people, with roles closer / setter and rates (percent and / or flat per close) over the workspace default. Basis: cash collected (each payment received counts in its month, the default) or deal value when won. Who is paid on a payment: a Closer / Setter picked on the deal wins, else the payment provider's own seller (Whop affiliate, FanBasis rep, Square team member, Stripe metadata) matched to a payee by the payee's provider ids or email (or a Plodder user it names: their email, or in Stripe metadata their user id), else the host of the buyer's closing call (their latest booking, matched by any of their emails, not cancelled or a no-show, before the payment and within the window in settings closing_calls), else the deal owner. Payments whose buyer email matches no CRM person are listed by list_no_person (link_person ties them). A provider seller that matches no payee is listed by list_needs_payee and its payments make no line until link_seller / create_payee_for_seller. Each payment is its own line with a mark: pending (expected, never payable), received, part_refunded, refunded, cancelled; a won deal's unpaid balance is one pending line. Refunds claw back in the month they happen (only what was counted). Months are statements: draft until finalized (lines locked), then sent to QuickBooks Online as a bill per payee; Paid comes back from QuickBooks. Money is in cents in the workspace currency. period = YYYY-MM, a month name, or "last month". Actions: - overview: The month (period): per payee earned, adjustments, payable, paid, owed and status, plus totals. Brings the ledger up to date first. - list_payees: The sales team with roles, own rules (null = default) and QuickBooks vendor. - get_payee: One payee (payee_id): rules in effect, lines (period or the last 12 months), statements, months. - create_payee: Add a payee: member_key (a team member) or name + email? (an outside person), contact_id?, roles?, rules?, notes?, provider_refs?. - update_payee: Change a payee (payee_id): name, email, contact_id, roles, rules (null = default), active, notes, provider_refs (their ids at Stripe / Square / Whop / FanBasis). - remove_payee: Remove a payee (payee_id): gone if they never earned, else made inactive (history stays). (waits for approval: delete) - get_deal_roles: Closer and Setter on a deal (deal_id); closer from_owner = the deal owner's payee. - set_deal_roles: Set a deal's closer_payee_id and / or setter_payee_id (null clears; closer cleared = the deal owner). - list_lines: Ledger lines (payee_id?, period? (or "open" = pending and cancelled lines), deal_id?, status?). Each has status (the payment mark), provider, payment_ref and attribution (deal, provider, booking, owner) with attribution_note for a booking ("from booking <calendar> on <date>"). - list_no_person: Paid payments whose buyer email matches no CRM person (email, provider, payments, amount_cents, payment_ids). - link_person: Tie every payment with this buyer email (email) to a person (contact_id): the email becomes one of their addresses, then the ledger syncs. - list_needs_payee: Payment provider sellers that match no payee (provider, role, ref, name, email, payments, amount_cents). Their payments make no line until linked. - link_seller: Link a provider seller (provider, ref) to a payee (payee_id): the ref becomes one of the payee's provider ids, then the ledger syncs and their payments make their lines. - create_payee_for_seller: Make a payee from a provider seller (provider, ref, name?, email?, role?, member_key?) with that provider id, then sync. - add_adjustment: A bonus or deduction for a payee (payee_id, period, amount, note). Refused when that month is finalized. - remove_adjustment: Remove an adjustment (line_id) while its month is a draft. (waits for approval: delete) - sync: Bring the ledger up to date now (it also runs every 10 minutes). - recalculate: Rebuild a month's automatic lines after a rate change (period). Draft months only; adjustments stay. - list_statements: Statements (period?, payee_id?). - generate_statements: Draft statements for a month (period), one per payee with lines (all: every active payee too). - finalize_statement: Finalize a statement (statement_id): locks its lines and freezes the totals. Without statement_id: every draft of the period. - reopen_statement: Unlock a finalized statement (statement_id), only before it is a bill in QuickBooks. - get_settings: The workspace default rules, time zone, first month counted, currency and QuickBooks bill settings. - update_settings: Change settings (settings: { rules?, timezone?, start_period?, qbo_account_id?, qbo_account_name?, qbo_line_mode?, qbo_due_days? }). - quickbooks_status: Is QuickBooks connected (company, sandbox or production, home currency, last error). Never a token. - list_vendors: QuickBooks vendors (q? name contains). - list_accounts: QuickBooks expense accounts (for qbo_account_id). - link_vendor: Link a payee (payee_id) to a QuickBooks vendor (vendor_id; null unlinks). - create_vendor: Make a QuickBooks vendor from a payee's name and email (payee_id) and link it (an existing vendor with that name is linked instead). (waits for approval: external) - send_to_quickbooks: Send a finalized statement (statement_id) to QuickBooks as a bill for the payee (a second send updates the same unpaid bill). (waits for approval: money)

FieldTypeNotes
action requiredoverview | list_payees | get_payee | create_payee | update_payee | remove_payee What to do.
periodstringYYYY-MM, a month name (september) or "last month". Default: this month.
payee_idnumber
deal_idnumber
statement_idnumber
line_idnumber
member_keystringcreate_payee: a team member: their id from list_team_members, their user_id or their email. Their login sees their own commissions.
namestring
emailstring
contact_idnumberOptional CRM person for the payee.
rolesarray of closer | setter
rulesobject{ basis?: cash | won, closer?: { pct, flat_cents }, setter?: { pct, flat_cents }, pipelines?: [ids] | null, product?: "contains" }. On a payee: only what differs from the default (null = all default).
activeboolean
notesstring
closer_payee_idnumber or nullset_deal_roles: null = the deal owner's payee.
setter_payee_idnumber or null
amountnumber or stringAdjustment in the currency: 250 = bonus, -100 = deduction.
amount_centsnumber
notestring
allbooleangenerate_statements: also a statement for active payees with no lines.
vendor_idstring or nulllink_vendor: a QuickBooks vendor id (null unlinks).
qstringlist_vendors: name contains.
settingsobjectupdate_settings: { rules?, timezone?, start_period?, qbo_account_id?, qbo_account_name?, qbo_line_mode?: summary | detail, qbo_due_days?, provider_closer?: { stripe?, square?, whop?, fanbasis?: boolean }, closing_calls?: { on?, window_days? (1-365, default 60), closing_calendars?: calendar ids | null (null = every calendar), setting_calendars?: calendar ids | null (their host is the setter) } }
statuspending | received | part_refunded | refunded | cancelledlist_lines: only lines with this payment mark.
providerstripe | square | whop | fanbasislink_seller / create_payee_for_seller: the provider of the seller.
refstringlink_seller / create_payee_for_seller: the seller's id, username or email at the provider (from list_needs_payee).
rolecloser | settercreate_payee_for_seller: their role (default closer).
provider_refsarray of objectcreate_payee / update_payee: the payee's ids at each provider (replaces the list on update).

Instantly 1

instantlyInstantly (cold email)asks for approval

POST/api/external/tools/instantly

Scopes: instantly:read, instantly:write, messages:send

Cold email runs through Instantly. status: connected workspace, webhook, settings (lead pipeline for Interested, skips, stop triggers), 30 day campaign totals. campaigns: the workspace's campaigns (id, name, status). push: add CRM people (contact_ids, segment_id = a smart list or segment, filter = a People filter, company_ids, deal_ids) to an Instantly campaign (campaign_id) with their name, business, website, phone and custom variables (custom: [{ field: "title" | "address_city" | "f:<custom field id>", as: "variable_name" }]); people with no email, unsubscribed, Do not email, a bounced address or already in another active Instantly campaign are left out and reported. dry_run: true shows the report without adding anyone. stop: take a person (contact_id) out of their Instantly campaigns. sync: read the daily campaign numbers now (sent, replies, interested, booked). Actions: - status: Connection, webhook, settings and 30 day campaign totals. Never the key. - campaigns: The Instantly campaigns (id, name, status), active first. - push: Add people to an Instantly campaign (campaign_id + who). Instantly then emails them on its schedule. (may wait for approval) - stop: Take a person (contact_id) out of every Instantly campaign Plodder knows them in. (waits for approval: external) - sync: Read the daily campaign numbers from Instantly now.

FieldTypeNotes
action requiredstatus | campaigns | push | stop | syncWhat to do.
campaign_idstringInstantly campaign id (from campaigns).
contact_idsarray of number
company_idsarray of number
deal_idsarray of number
segment_idnumberA smart list or segment (CRM saved view) id.
filterobjectA People filter (as the CRM sends it).
customarray of object[{ field, as }] CRM fields sent as Instantly custom variables.
dry_runboolean
contact_idnumber

Users 2

get_userGet a userread only

POST/api/external/tools/get_user

Scopes: users:read

One person who works in the app, by their id (team id), user_id (numeric login id), email (any case) or, when only one person has it, their exact name. Returns id, user_id, name, email, role, type, active. Fails naming the ref when nobody or more than one person matches.

FieldTypeNotes
ref requiredstringid, user_id, email or exact name.
list_team_membersList team membersread only

POST/api/external/tools/list_team_members

Scopes: users:read

The people who work in the app (owner, teammates, closers) and the team roster: id (their team id, the one to pass anywhere a person is taken), user_id (numeric login id, null when they do not log in), name, email, role (owner | team | client), type, active. Anywhere a person is taken (task assignee, deal owner, payee member_key, booking host, round robin members) you can pass the id, the user_id or the email.

FieldTypeNotes
include_agentsbooleanInclude agent team members (default false).
include_inactivebooleanInclude inactive roster rows (default false).
qstringOnly people whose name, email or id contains this.

Admin 23

appsConnected appsasks for approval

POST/api/external/tools/apps

Scopes: admin:read, admin:write

Your Composio apps (Settings > AI > Connections: Gmail, Slack, GitHub, Notion and more). Connecting an app is your own sign-in in the browser: connect_link returns the link to open. Your agents use connected apps through their tools. Actions: - connected: Apps you connected and their accounts. - search: Find an app to connect (q). - connect_link: A sign-in link for an app (slug, alias? for a second account). Give it to the person to open; nothing is connected until they finish. - check: After the person signed in: the app's accounts now (slug).

FieldTypeNotes
action requiredconnected | search | connect_link | checkWhat to do.
qstring
slugstringApp slug, like gmail or github.
aliasstring
billingBillingread onlyasks for approval

POST/api/external/tools/billing

Scopes: admin:read

Settings > Billing, read only: plan, seats, this month's AI allowance and credits, and (for workspace owners and admins) invoices and the credit ledger. Changing the plan, seats, auto reload or the card stays with the person in the browser. Actions: - overview: Plan, status, seats, credit position, scheduled plan notices (renewal, cancellation, trial end, failed payment) and the workspaces you can see billing for (workspace_id?). - preview: Billing lab: the account, AI position and notices Settings > Billing shows in a state (workspace_id?, state: free | pro | renewing | cancel_scheduled | trialing | trial_last_days | past_due | usage_high | out_of_credits | reload_paused | unlimited). Changes nothing; owners and admins. - invoices: Recent invoices and credit ledger (owners and admins). - unsettled: Owner only: finished AI runs that owe a workspace money and are not on the bill yet (settled by ctrlflow-core every few minutes).

FieldTypeNotes
action requiredoverview | preview | invoices | unsettledWhat to do.
workspace_idnumber
statestring
calendar_teamTeam calendarsasks for approval

POST/api/external/tools/calendar_team

Scopes: admin:read, admin:write

Teammates' calendars, read only: what each person shares (busy blocks by default, event details if they chose, nothing if they turned it off; private events are always just Busy), team availability for find-a-time, and your own sharing setting. Never changes Google permissions. Actions: - view: Teammates and their shared events between start and end (default this week; 62 days at most). user_ids narrows it. - availability: Busy blocks of teammates (emails and/or user_ids) between start and end (31 days at most), plus free_slots of duration_minutes for everyone. - get_sharing: What teammates can see of your calendar: busy_only | all | none. - set_sharing: Set what teammates can see of your calendar: sharing busy_only (default) | all | none.

FieldTypeNotes
action requiredview | availability | get_sharing | set_sharingWhat to do.
startstring or number
endstring or number
user_idsarray of number
emailsarray of string
duration_minutesnumber
sharingbusy_only | all | none
chat_share_itemsShare linked items with a channelasks for approval

POST/api/external/tools/chat_share_items

Scopes: admin:read, admin:write

Before posting a message that links docs, tasks, files or forms, check which channel members cannot open them, then give those members view access (the same grant as the Share dialog). Only items you can manage can be shared. Actions: - check: Items linked in `content` (entity chips or app links) that some channel members cannot open: type, id, title, missing members, can_share. - share: Give every channel member who cannot open these items view access. items = [{type, id}].

FieldTypeNotes
action requiredcheck | shareWhat to do.
channel_id requirednumber
contentstringcheck: the message text.
itemsarray of objectshare: the items.
data_cleanupData cleanup (Trash and retention)asks for approval

POST/api/external/tools/data_cleanup

Scopes: admin:read, admin:write

A workspace's Drive housekeeping (Settings > Workspace > Data cleanup): Empty Trash after 30 days (items 30+ days in Trash deleted for good; folders and forms stay) and Move untouched items to Trash after N days (plain uploads and plain docs nobody changed or opened; never favorites, linked records, generated or signed files, task/project docs, CRM, payments, commissions, e-sign). Both off by default; the first run after turning one on only lists what it would do, deleting starts 24 h later. Only the workspace owner changes them; turning one on or lowering the days waits for approval. Actions: - get: Settings, the last run of each job (dry or real, with counts and a sample), whether you can change them, whether the background service runs. - preview: What a job would do right now (job, retention_days?). Nothing is written. - set: Change the settings (trash_purge?, retention_days?). Owner only. Turning a job on or lowering the days waits for approval; turning off does not. (may wait for approval)

FieldTypeNotes
action requiredget | preview | setWhat to do.
workspace_idnumber
trash_purgebooleanset: Empty Trash after 30 days on/off.
retention_daysnumber or nullset: 30-3650 days, or null / 0 for off. preview: days to check (default the saved setting).
jobtrash_purge | retentionpreview: which job.
fieldsobjectAny other body fields the action documents.
database_questionsDatabase SQL and saved questionsasks for approval

POST/api/external/tools/database_questions

Scopes: admin:read, admin:write

Read a database with SQL and keep questions, as you. sql runs ONE read-only SELECT over one database (database_id) and only its rows you can see: FROM the database's name (or FROM this); no joins, subqueries, writes or other tables; up to 500 rows, 3 seconds. Supported: WHERE with = <> < > LIKE ILIKE IN BETWEEN IS NULL, 'label' = ANY("Multi select"), GROUP BY (a multi-select groups once per label; date_trunc('month', "Date") for day/week/month/quarter/year), HAVING, count/sum/avg/min/max (DISTINCT), ORDER BY, LIMIT, OFFSET, lower/upper/length/trim/coalesce/round/abs. Quote names with spaces: "Deal value". Text compares ignore case. A saved question is a named SELECT that re-runs live each time it is opened (in the database's Ask panel and as a doc question block). The query_database tool answers without SQL. Actions: - sql: Run a read-only SELECT (database_id, sql) and get its columns and rows. - list: Saved questions you can see (database_id to limit to one database, query to filter by name). - run: Run a saved question live (question_id): its rows, chart and any error. - save: Save a question (database_id, name, sql, chart). The SQL must run. - update: Rename a question or change its SQL or chart (question_id, name / sql / chart). - delete: Delete a saved question (question_id). (waits for approval: delete)

FieldTypeNotes
action requiredsql | list | run | save | update | deleteWhat to do.
database_idstringDatabase id, public id or sheet:<id>.
question_idnumberA saved question (question:<id>).
sqlstring
namestringsave / update: the question's name.
charttable | bar | line | pieHow the question is drawn.
querystringlist: filter by name.
fieldsobjectAny other body fields the action documents.
favoritesFavoritesasks for approval

POST/api/external/tools/favorites

Scopes: admin:read, admin:write

Your favorites (the starred items in the palette and lists). Items are "type:id" refs, e.g. "task:12", "doc:abc". Actions: - list: Your favorites with titles and links. - add: Favorite items (refs). - remove: Unfavorite items (refs).

FieldTypeNotes
action requiredlist | add | removeWhat to do.
refsarray of string
home_feedHome feedread only

POST/api/external/tools/home_feed

Scopes: admin:read

Your Home sidebar as one list, built on the server: task activity, Important email, chat mentions, replies and DMs, notifications, things you opened lately and agent conversations. Events about one thing fold into one row (unread while any is), newest first, with date groups. signal marks rows someone is waiting on you for.

FieldTypeNotes
statusall | unread | read
typesarray of tasks | email | chat | notifications | files | projects | agents
tz_offset_minnumberMinutes east of UTC for the date groups (default 0).
limitnumberRows, default 50, max 200.
invitationsInvitationsasks for approval

POST/api/external/tools/invitations

Scopes: admin:read, admin:write

Email invitations to join a workspace (people who are not users yet). Sending one emails an outside person, so it waits for approval. Actions: - list: Invitations for a workspace. - send: Invite someone by email (email, name?, role admin|member|client). Owners and admins. (waits for approval: external) - revoke: Revoke a pending invitation (invitation_id). (waits for approval: delete)

FieldTypeNotes
action requiredlist | send | revokeWhat to do.
workspace_idnumber
emailstring
namestring
roleadmin | member | client
invitation_idnumber
fieldsobjectAny other body fields the action documents.
list_pending_approvalsList approval requestsread only

POST/api/external/tools/list_pending_approvals

Scopes: admin:read

Actions that needed your approval (send email, post to chat, delete, invites) and what happened to them: pending, executed, rejected or failed. Use it to check whether something you queued went out.

FieldTypeNotes
statuspending | executed | rejected | failed | allDefault all.
limitnumber
list_workspacesList workspacesread only

POST/api/external/tools/list_workspaces

Scopes: admin:read

The workspaces you belong to. Other tools take workspace_id from here; your primary one is the default.

No arguments.

my_settingsMy profile and settingsasks for approval

POST/api/external/tools/my_settings

Scopes: admin:read, admin:write

Your profile (name, bio, pronouns, display role), your app settings (rail, ai_default_model, accent) and the interactive tutorial progress. Actions: - profile: Your profile. - update_profile: Change your profile (name, bio, pronouns, display_role). - setting: One app setting (key). - set_setting: Save one app setting (key, value). - tutorial: Tutorial progress. - set_tutorial: Mark a tutorial lesson done or not (lesson, done?), or reset=true.

FieldTypeNotes
action requiredprofile | update_profile | setting | set_setting | tutorial | set_tutorialWhat to do.
namestring
biostring
pronounsstring
display_rolestring
keyrail | ai_default_model | accent
valueany
lessonmove | select | create | palette | mention
doneboolean
resetboolean
fieldsobjectAny other body fields the action documents.
notification_settingsNotification settingsasks for approval

POST/api/external/tools/notification_settings

Scopes: admin:read, admin:write

How you get notified: per-kind channels (in app, email, push), snooze everything, mute one item (any type, incl. a chat channel), and the daily or weekly email digest. Actions: - get: Your per-kind preferences, snooze, and digest settings. - set_pref: One kind: in_app, email, push on or off. - snooze: Hold every notification until `until` (ISO or epoch seconds; max 30 days). - resume: End the snooze now. - mute_status: Is this item muted (type, id)? - mute: Mute an item (type, id), optional until; a chat channel muted with no end also goes to Nothing. - unmute: Unmute it (a chat channel goes back to All). - set_digest: Digest: frequency off | daily | weekly, send_hour 0-23, weekday 0-6, timezone. - test_digest: Email yourself your digest now (one every 5 minutes). (waits for approval: send email)

FieldTypeNotes
action requiredget | set_pref | snooze | resume | mute_status | mute | unmute | set_digest | teWhat to do.
kindnew_lead | inbound_reply | mention | assignment | appointment_booked | appointme
in_appboolean
emailboolean
pushboolean
untilstring or number
typestring
idstring or number
frequencyoff | daily | weekly
send_hournumber
weekdaynumber
timezonestring
notificationsNotificationsasks for approval

POST/api/external/tools/notifications

Scopes: admin:read, admin:write

Your notification feed (bell and Inbox) and its state: unseen, seen, done. Keys look like "u:12" (yours) or "w:3" (workspace bell, owner). Actions: - list: Your feed, newest first (filter all | active | unseen, limit), with the unseen count. - set_state: op = seen | done | reopen on keys, or all=true. - mark_read: Mark your notifications read: ids, or none for all. - mark_workspace_read: Owner: mark the workspace bell read (ids, or all=true). - mark_task_activity_read: Mark task activity in the Inbox read (activity ids, or all=true).

FieldTypeNotes
action requiredlist | set_state | mark_read | mark_workspace_read | mark_task_activity_readWhat to do.
filterall | active | unseen
limitnumber
opseen | done | reopen
keysarray of string
idsarray of number
allboolean
phone_setupPhone setupasks for approval

POST/api/external/tools/phone_setup

Scopes: admin:read, admin:write

Phone settings and numbers, as you: forwarding to your cell, ring time, recording, voicemail greeting, auto replies, browser calling, the numbers on your Twilio account (buy, use, repair webhooks, default, give a number to a teammate), call flows (flows, save_flow, number_flow, delete_flow: business hours, menus, ring groups, voicemail), call tracking numbers per ad source (tracking, save_tracking_source, tracking_number, tracking_swap_target for the website number swap, delete_tracking_source), and the US A2P 10DLC texting registration (a2p: stage, answers, what is blocked; a2p_save answers; a2p_submit; a2p_check; a2p_link one made in the Twilio Console; a2p_attach numbers; a2p_reset). Buying a number and submitting the registration charge your Twilio account, so they wait for approval. Connecting Twilio (credentials) stays in Settings > Phone. Actions: - get: Your phone account settings and numbers in use. - set: Change settings (settings object). - setup_browser_calling: Create (or redo) the Twilio API key and app that browser calling uses. Waits for approval (makes a credential on the Twilio account). (waits for approval: external) - disconnect: Forget the Twilio credentials (texts and calls stay). (waits for approval: delete) - numbers: Every number on your Twilio account. - search_numbers: Numbers you could buy (country, area_code, contains, type), with the monthly price. - buy_number: Buy a number (phone_number from search_numbers). This COSTS MONEY: Twilio bills it every month. (waits for approval: external) - use_number: Point a number already on your Twilio account here (sid). - default_number: Texts and calls go out from this number (sid). - repair_number: Set a number's SMS and voice webhooks back to Plodder (sid; numbers with needs_repair). - assign_number: Give a number to a teammate (sid, assignee team member id; null = everyone). Texts in threads assigned to them go out from it. - a2p: The US texting registration (A2P 10DLC): stage (draft, profile_review, brand_review, campaign_review, approved, rejected), the answers, errors / warnings before submit, reasons Twilio gave, and what is blocked until it is approved. - a2p_save: Save registration answers (brand and / or campaign objects; partial is fine). Only while it is a draft or Twilio asked for changes. - a2p_submit: Send the registration to Twilio (or resubmit the step Twilio rejected). This COSTS MONEY: Twilio charges brand and campaign fees plus a monthly campaign fee. (waits for approval: external) - a2p_check: Read the registration status from Twilio now (and take the next step when one is due). - a2p_link: Track a registration already made in the Twilio Console (finds the brand and its campaign). - a2p_attach: Add every US number in use to the registered campaign. - a2p_reset: Start the registration over here (nothing is deleted at Twilio; the answers stay). (waits for approval: delete) - flows: Call flows: business hours, menus (press 1, 2, 3), ring groups (all at once or round robin), voicemail; each with its steps, problems and the numbers that follow it. - save_flow: Create or update a call flow (flow object). Numbers can only follow a flow without problems. - number_flow: A number (sid) follows a call flow (flow_id; null = ring the app, then the cell, then voicemail). - delete_flow: Delete a call flow (flow_id). Its numbers and tracking sources ring the business line again. (waits for approval: delete) - tracking: Call tracking: the ad sources with their numbers, route (business line, forward, call flow), calls per source over 30 days, and the website number swap (key, number replaced, script tag). - save_tracking_source: Create or update a tracking source (source object). Calls and texts to its numbers credit the person to it (lead source, first / last touch) and can tag them. - tracking_number: Put one number in use here on a tracking source (sid, source_id; null takes it off). - tracking_swap_target: Set the number written on the website that the swap script replaces with a tracking number (target; empty turns the swap off). - delete_tracking_source: Delete a tracking source (source_id). Its numbers become plain lines; calls already tracked keep the name. (waits for approval: delete)

FieldTypeNotes
action requiredget | set | setup_browser_calling | disconnect | numbers | search_numbers | buy_What to do.
settingsobjectset: cell_phone, call_cell_first, forward_unanswered, ring_seconds, record_calls, record_notice, voicemail_greeting, help_reply, a2p.
countryUS | CA
area_codestring
containsstring
typeLocal | TollFree
phone_numberstringbuy_number: a number from search_numbers.
sidstringA number's Twilio sid.
assigneestring or nullassign_number: team member id (from the team list); null = everyone.
brandobjecta2p_save: business answers: legal_name, business_type (Sole Proprietorship | Partnership | Limited Liability Corporation | Co-operative | Non-profit Corporation | Corporation), company_type (private | public | non-profit | government), stock_exchange, stock_ticker, industry (e.g. PROFESSIONAL_SERVICES, CONSTRUCTION, REAL_ESTATE, HEALTHCARE, RETAIL), tax_id (EIN or BN), website, social, street, city, region, postal_code, country (US | CA), email, rep_first_name, rep_last_name, rep_email, rep_phone, rep_title, rep_position (Director | GM | VP | CEO | CFO | General Counsel | Other), brand_type (LOW_VOLUME_STANDARD | STANDARD).
sourceobjectsave_tracking_source: id (to update), name (e.g. "Meta ads - Eco Spa"), utm_source / utm_medium / utm_campaign (what the person is credited with), match_sources (utm_source values that pick it on the website swap), match_referrers (sites, e.g. facebook.com), is_default (visitors nothing else matches), route (business | forward | flow), forward_to (number), flow_id, tag (put on callers), numbers (sids in its pool).
source_idnumber or nullA tracking source id (tracking_number: null takes the number off its source).
flowobjectsave_flow: id (to update), name, steps (ordered; each { id, type: hours | greeting | menu | ring | voicemail | hangup, label, ... }: hours { source: calendar | custom, link_id, hours {"1":[{start,end}]}, timezone, holidays: none | us | ca, open, closed }, greeting { say | audio, next }, menu { say | audio, options [{ digit, label, goto }], timeout, retries, invalid, no_input }, ring { targets [{ kind: member, id } | { kind: number, phone } | { kind: me } | { kind: my_cell }], mode: simultaneous | round_robin, seconds, no_answer }, voicemail { say | audio }, hangup { say }; a goto is a step id, "" for the next step, "end" to hang up), numbers (sids that follow it).
flow_idnumber or nullA call flow id (number_flow: null = default ringing).
targetstringtracking_swap_target: the number written on the website that the swap script replaces (empty turns it off).
campaignobjecta2p_save: campaign answers: use_case (LOW_VOLUME | MIXED | CUSTOMER_CARE | ACCOUNT_NOTIFICATION | MARKETING), description, message_flow (how people opt in), samples (2 to 5 texts), has_links, has_phone, opt_in_message, opt_out_message, help_message, opt_in_keywords.
fieldsobjectAny other body fields the action documents.
property_adminProperties and tags adminasks for approval

POST/api/external/tools/property_admin

Scopes: admin:read, admin:write

Manage properties (custom fields) and tags, as you: create, rename and archive property definitions, their options, the tag lists (CRM tags and Work tags, separate sets: create with scope, rename, recolour, merge within a set, delete), restore an archived property, and clear one value on an item. Set values with set_property / set_tags. Actions: - definitions: Definitions that apply to a type (target type in property, workspace_id). - create_definition: A property (display_name, data_type, target_types, ref_entity_type, workspace_id or personal). - update_definition: Rename or retarget a property (id, display_name, target_types, sort_order). - archive_definition: Archive a property (id); restore brings it back. (waits for approval: delete) - restore_definition: Bring an archived property back (id). - options: A property's options (property; stage needs project_id; tags take scope crm|work). - add_option: Add an option (property, label, color; tags take scope crm|work). - update_option: Change an option (property, id, label, color, sort_order). - delete_option: Remove an option (property, id). (waits for approval: delete) - tags: Tags with usage counts. scope crm|work picks one set (CRM tags: people, businesses, deals, conversations, bookings, forms; Work tags: everything else); omit for both. - create_tag: A tag (label, color, scope crm|work; default work). The same name may exist once per scope. - update_tag: Rename or recolour a tag everywhere it is used (id, label, color). - merge_tags: Fold one tag into another (from, into). (waits for approval: delete) - delete_tag: Remove a tag from every item and list (id). (waits for approval: delete) - clear_value: Clear one property on an item (item, property).

FieldTypeNotes
action requireddefinitions | create_definition | update_definition | archive_definition | restoWhat to do.
idstringDefinition id, option id or tag id.
display_namestring
data_typestringtext, number, select, multi_select, date, checkbox, url, email, person, relation, ...
target_typesarray of string
ref_entity_typestring
workspace_idnumber
personalboolean
sort_ordernumber
propertystringoptions: the property id or system key (status, stage, tags, ...).
project_idnumber
labelstring
colorstring
fromnumber
intonumber
scopecrm | workTags: CRM tags (people, businesses, deals, conversations, bookings, forms) or Work tags (everything else).
itemstringclear_value: <type>:<id>
fieldsobjectAny other body fields the action documents.
recent_itemsRecently openedasks for approval

POST/api/external/tools/recent_items

Scopes: admin:write

Tell the app you opened an item, so it rises in your "recently viewed" and "frequent" sorts (list_items sort viewed / frecency). Actions: - record_open: Record that you opened item type + id (only items you can see).

FieldTypeNotes
action requiredrecord_openWhat to do.
type requiredstringItem type: task, doc, project, form, sheet, file, ...
id requiredstring or number
referralsReferral invite linksasks for approval

POST/api/external/tools/referrals

Scopes: admin:read, admin:write

Invite links people outside the app use to sign up into a workspace (Settings > Referrals). Owners and admins make them; anyone can turn off a link they made. Actions: - list: Invite links and who joined through them (workspace_id?). - create: A new invite link (workspace_id?, max_uses?, ttl_hours?, recipient_email? = only that address can use it, note?, free_months? = free months of a paid plan at their first Checkout, owners/admins, up to the owner's cap). (waits for approval: external) - turn_off: Turn a link off (link_id).

FieldTypeNotes
action requiredlist | create | turn_offWhat to do.
workspace_idnumber
max_usesnumber
ttl_hoursnumber
link_idnumber
recipient_emailstring
notestring
free_monthsnumber
sharingSharingasks for approval

POST/api/external/tools/sharing

Scopes: admin:read, admin:write

The Share dialog for any item, as you: who has access, give or remove access for a teammate, an email or a whole workspace, anyone-with-the-link access (docs, databases), and share links with an expiry. item = <type>:<id> (task:12, doc:abc, project:4, ...). Levels: none, view, comment, edit, manage. Actions: - get: Who has access and how. - set: Give or change access (principal, level; level none removes). An email principal can get an email (notify). (may wait for approval) - set_general: Anyone with the link (docs, databases): none, view or edit. (may wait for approval) - create_link: A share link (level, expires); people who open it get that level after signing in. (waits for approval: external) - update_link: Change a share link (link_id, level, expires, enabled). (may wait for approval) - disable_link: Turn a share link off (link_id).

FieldTypeNotes
action requiredget | set | set_general | create_link | update_link | disable_linkWhat to do.
itemstring
principalobject{type: user|email|workspace, id | email}
levelstring
notifyboolean
generalnone | view | edit
link_idnumber
expiresstring"7d", an ISO date, or null for never.
enabledboolean
fieldsobjectAny other body fields the action documents.
team_directoryTeam directoryasks for approval

POST/api/external/tools/team_directory

Scopes: admin:read, admin:write

The team roster used for assignees (/api/team). Owner only for changes. Setting a teammate's role or permissions waits for approval. Actions: - list: Teammates with their workspaces. - create: A new teammate (name, email?, role?, workspace_ids?). With role or permissions it waits for approval. (may wait for approval) - update: Change a teammate (member_id, set). Changing role or permissions waits for approval. (may wait for approval) - delete: Remove a teammate. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | deleteWhat to do.
member_idnumber
namestring
emailstring
rolestring
permissionsanyPermission list.
workspace_idsarray of number
setobject
include_inactiveboolean
fieldsobjectAny other body fields the action documents.
webhooksWebhooks and API keysasks for approval

POST/api/external/tools/webhooks

Scopes: admin:read, admin:write, webhooks:read, webhooks:write

Outgoing webhooks that POST app events (CRM, bookings, forms, texts, email, calls, workflows, e-sign, speed to lead, tasks) to an outside URL, signed with HMAC-SHA256, retried for 6 hours, with a delivery log (Settings > Integrations, owner only). Making one, or changing its URL, events or turning it on, waits for approval. Signing secrets are shown to the person in Settings, never here. API keys: list them and revoke one (with approval); new keys are made by the person in Settings. Actions: - list: Webhooks (status, failures, pending retries) and the events you can send. - events: Every event with its area and when it fires. - log: A webhook's delivery log, newest first (webhook_id, limit?): event, attempt, status code, time taken, response snippet. - create: A webhook (name, url, events? default all). Only public URLs. (waits for approval: external) - update: Change a webhook (webhook_id, set). (may wait for approval) - test: Post a sample event to the webhook now (webhook_id, event?). Returns the status code and response. (waits for approval: external) - resend: Post one delivery again now (delivery_id from the log). (waits for approval: external) - delete: Delete a webhook. (waits for approval: delete) - list_keys: API keys: name, scopes, last used (never the key). - revoke_key: Revoke an API key (key_id). Anything using it stops working. (waits for approval: delete)

FieldTypeNotes
action requiredlist | events | log | create | update | test | resend | delete | list_keys | revWhat to do.
webhook_idnumber
namestring
urlstring
eventsarray of stringEvent names (see events), "family.*" or "*".
setobjectupdate: name, url, events, active.
eventstringtest: the sample event to send (default webhook.test).
delivery_idnumber
key_idnumber
limitnumber
fieldsobjectAny other body fields the action documents.
workspace_settingsWorkspace labels, statuses and fieldsasks for approval

POST/api/external/tools/workspace_settings

Scopes: admin:read, admin:write

A workspace's task labels, statuses and custom fields, team settings (members can invite, share link defaults, task codes), and the global labels (/api/workspaces/labels, statuses, custom-fields, team-settings, /api/labels). Actions: - labels: Workspace labels. - add_label: A workspace label (name, color?). - update_label: Change a label (id, set {name, color, sort_order}). - delete_label: Delete a label (id). (waits for approval: delete) - statuses: Workspace statuses. - add_status: A workspace status (name, color?). - update_status: Change a status (id, set {name, color, sort_order}). - delete_status: Delete a status (id). (waits for approval: delete) - fields: Workspace custom fields. - add_field: A custom field (name, field_type?, options?). - update_field: Change a custom field (id, set). - delete_field: Delete a custom field (id). (waits for approval: delete) - set_task_field: Set a custom field on a task (task_id, field_id, value). - team_settings: Team settings: the team name, members can invite, the level and expiry new share links start at, the task code prefix (ENG in ENG-42), project prefixes, the GitHub autolink template. - set_team_settings: Change team settings (team_name?, members_can_invite?, share_link_level? view|comment|edit, share_link_expiry? 1d|7d|30d|never, task_prefix? letters, blank = default). Owners and admins. (may wait for approval) - set_project_prefix: A project's own task code prefix (project_id, project_prefix; blank = use the workspace prefix). Owners and admins. - task_code: A task's short code (ENG-42) and git branch name (task_id). - global_labels: Global labels. - add_global_label: A global label (name, color?). - delete_global_label: Delete a global label (id). (waits for approval: delete)

FieldTypeNotes
action requiredlabels | add_label | update_label | delete_label | statuses | add_status | updatWhat to do.
workspace_idnumber
idnumberThe label, status or field id.
namestring
colorstring
field_typestringtext, number, date, select, ...
optionsanyselect options.
setobject
task_idnumber
field_idnumber
valueany
team_namestringset_team_settings: the team (workspace) name.
members_can_inviteboolean
share_link_levelview | comment | edit
share_link_expiry1d | 7d | 30d | never
task_prefixstring
project_idnumber
project_prefixstring
fieldsobjectAny other body fields the action documents.
workspacesWorkspaces and teamasks for approval

POST/api/external/tools/workspaces

Scopes: admin:read, admin:write

Workspaces and who is in them, as you (/api/workspaces, /api/workspaces/[id]/roles, /invite, /primary). Team roles: owner, admin, member, guest. Changing anyone's role waits for approval. Actions: - list: Your workspaces. - create: A new workspace (name, color?, copy_from_id?). You own it. - update: Change a workspace you own (workspace_id, set). - delete: Delete a workspace you own. (waits for approval: delete) - set_primary: Make a workspace you own your primary one. - team: The team with roles, your role and whether you can manage it. - add_to_team: Add an existing Plodder user to the team (email, role). Waits for approval. (waits for approval: external) - set_role: Change someone's role (user_id, role). Any role change (raising or lowering, yours included) waits for approval. (may wait for approval) - remove_from_team: Take someone off the team (user_id). (waits for approval: delete) - members: Workspace members (people). - add_member: Add an existing user as a member by email (email, role?). Owners and admins. Waits for approval. (waits for approval: external) - remove_member: Remove a member (user_id). Owners and admins. (waits for approval: delete)

FieldTypeNotes
action requiredlist | create | update | delete | set_primary | team | add_to_team | set_role | What to do.
workspace_idnumber
namestring
colorstring
copy_from_idnumbercreate: copy settings from this workspace.
setobjectupdate: workspace fields (name, color, ...).
emailstring
roleowner | admin | member | guest
user_idnumber
fieldsobjectAny other body fields the action documents.

ctrl-flow 7

fetchFetch an itemread only

POST/api/external/tools/fetch

Scopes: ctrl-flow:read

Get the full content of an item by the id search returned: task:<id>, project:<id>, doc:<id>, meeting:<id>, client:<id>, or email:<account_id>:<thread_id>.

FieldTypeNotes
id requiredstringFor example task:123 or doc:45.
get_propertiesRead propertiesread only

POST/api/external/tools/get_properties

Scopes: ctrl-flow:read

Every property of an item with its current value (status, priority, assignee, dates, tags, deal stage, custom fields), and for select properties the allowed options.

FieldTypeNotes
item requiredstringAn item as type:id, for example task:123, doc:45, project:7, crm_company:3, sheet_row:88, meeting:12 or mail_thread:<account>-<thread>. list_items and search return these.
with_optionsbooleanInclude the options of select properties (default true).
list_itemsList itemsread only

POST/api/external/tools/list_items

Scopes: ctrl-flow:read

List anything the user can see across Plodder (tasks, projects, docs, databases, channels, meetings, clients, businesses, CRM companies and contacts, calendar events, email threads, agent conversations, recordings, bookings), newest first. Filter by type, title text, project, tag names or a date window. Returns item refs (type:id) for get_properties, read_discussion, read_activity and link_items.

FieldTypeNotes
typesarray of task | project | doc | sheet | channel | meeting | client | business | crm_compaOnly these kinds. Default: everything except CRM contacts.
textstringTitle contains these words.
project_idsarray of numberOnly items in these projects (tasks, docs).
tagsarray of stringTag names (from list_tags). Items with any of them.
updated_afterstringISO date or datetime: changed on or after this.
sortupdated | created | viewed | frecencyupdated (default), created, viewed (recently opened by the user) or frecency.
favoritesbooleanOnly the user's favourites.
limitnumberMax results (default 25, max 100).
cursorstringThe cursor from a previous page.
read_activityRead activityread only

POST/api/external/tools/read_activity

Scopes: ctrl-flow:read

The history of an item (created, edited fields with before and after, comments, sends, status changes), newest first. Without an item: the user's own recent actions across the app.

FieldTypeNotes
itemstringAn item as type:id, for example task:123, doc:45, project:7, crm_company:3, sheet_row:88, meeting:12 or mail_thread:<account>-<thread>. list_items and search return these.
limitnumberMax events (default 30).
read_discussionRead commentsread only

POST/api/external/tools/read_discussion

Scopes: ctrl-flow:read

The comment threads on an item (tasks, docs, projects, database rows, CRM companies and contacts, meetings, clients, email threads, files and more). For a chat channel it returns the latest messages, for a chat message its thread.

FieldTypeNotes
item requiredstringAn item as type:id, for example task:123, doc:45, project:7, crm_company:3, sheet_row:88, meeting:12 or mail_thread:<account>-<thread>. list_items and search return these.
limitnumberNewest threads to return (default 30).

* 5

post_discussionComment on an itemasks for approval

POST/api/external/tools/post_discussion

Scopes: *

Post a comment on an item, or reply in one of its threads (thread_id from read_discussion). Comments stay inside Plodder; people @mentioned are notified there. On a chat channel or chat message this posts in the channel (a message: in its thread), which waits for approval like every chat post.

FieldTypeNotes
item requiredstringAn item as type:id, for example task:123, doc:45, project:7, crm_company:3, sheet_row:88, meeting:12 or mail_thread:<account>-<thread>. list_items and search return these.
text requiredstringThe comment (markdown).
thread_idnumberReply in this thread instead of starting a new one.
set_propertySet a property

POST/api/external/tools/set_property

Scopes: *

Set (or clear with null) one property of an item, or of up to 50 items at once with items: a task's status, priority, assignee, due date or stage, a company's deal stage, a custom field. Name the property by name or key (get_properties lists them). Select values take the option label; dates take YYYY-MM-DD; people take the team member name; references take type:id.

FieldTypeNotes
itemstringAn item as type:id, for example task:123, doc:45, project:7, crm_company:3, sheet_row:88, meeting:12 or mail_thread:<account>-<thread>. list_items and search return these.
itemsarray of stringSeveral items (type:id) to set the same value on, instead of item. Max 50.
property requiredstringProperty name or key, for example status, Priority, Deal stage, due_date.
valueanyThe new value: a string, number, boolean, a list for multi-value properties, or null to clear.
set_tagsTag an item

POST/api/external/tools/set_tags

Scopes: *

Add or remove tags on an item. Tags come from the item's own set (CRM tags for people, businesses, deals, conversations, bookings and forms; Work tags for everything else); new names are created in that set. Returns the item's tags after the change.

FieldTypeNotes
item requiredstringAn item as type:id, for example task:123, doc:45, project:7, crm_company:3, sheet_row:88, meeting:12 or mail_thread:<account>-<thread>. list_items and search return these.
addarray of stringTag names to add.
removearray of stringTag names to remove.

Webhooks

Add a webhook in Settings, Integrations and API, Webhooks: your URL and the events you want. Plodder sends a signed POST for each one and retries up to 5 times. Subscribe to one event, a family like contact.*, or everything with *.

Payload

POST <your URL>
Content-Type: application/json
X-CtrlFlow-Event: deal.stage_changed
X-CtrlFlow-Delivery: 8812
X-CtrlFlow-Signature: t=1791504000,v1=<hex HMAC-SHA256 of "t.body">

{
  "id": "evt_3f1c...",
  "event": "deal.stage_changed",
  "created_at": "2026-10-08T17:20:00.000Z",
  "workspace": { "id": 1 },
  "owner": { "id": 1 },
  "data": {
    "deal": { "id": 77, "title": "Heat pump install", "stage_id": "proposal" },
    "changes": { "stage_id": { "from": "qualified", "to": "proposal" } }
  }
}

Check the signature

import crypto from 'node:crypto'

// rawBody: the request body as a string, before JSON.parse
function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')))
  const t = Number(parts.t)
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false // 5 minute window
  const want = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
  return want.length === parts.v1.length &&
    crypto.timingSafeEqual(Buffer.from(want), Buffer.from(parts.v1))
}

Answer with a 2xx quickly and do the work after. The same id can arrive more than once, so skip ids you have already handled.

Events

CRM

contact.createdA person is added to the CRM (app, form, import, agent, API).
contact.updatedA person's fields change. data.changes has { field: { from, to } }.
contact.deletedA person is deleted (they stay in Recently deleted for 30 days).
contact.restoredA deleted person is restored from Recently deleted.
contact.tag_addedA tag is put on a person. data.tag names it.
contact.tag_removedA tag comes off a person.
business.createdA business is added to the CRM.
business.updatedA business's fields change.
business.stage_changedA business moves to another stage.
deal.createdA deal is created.
deal.updatedA deal's fields change.
deal.stage_changedA deal moves to another stage or pipeline.
deal.wonA deal is marked won.
deal.lostA deal is marked lost.
deal.status_changedA deal turns open, won, lost or abandoned. data.status.
bulk_action.finishedA bulk action on people (tag, workflow, email, text, delete) finished, stopped or was cancelled. data.bulk_action: kind, status, total, ok, skipped, failed.
deal.staleAn open deal had no stage or field change for 14 days (once per stale stretch).
contact.dnd_changedDo not email / text / call or unsubscribed turns on or off (also STOP / START). data.dnd.
contact.score_changedA person's score moves (a scoring rule, a workflow step, decay). data.score.from / to / delta, profile_id and profile (the score's name).
contact.repliedA person texts or emails in (any channel). data.channel.
deal.deletedA deal is deleted.
deal.restoredA deleted deal is restored from Recently deleted.
deal.mergedA deal is merged into another. data.merged_into is the one kept.
note.addedA note or comment is added on a person, business or deal.
client.createdA client is made (Make client on a business, or a new client).
client.churnedA business is marked churned. data.churned_on and data.reason; its recurring deals churn with it.
client.reactivatedA churned business is reactivated.
deal.churnedA recurring deal is marked churned (it stops counting in MRR from data.churned_on).
deal.reactivatedA churned deal is reactivated (back in MRR).

Conversations

conversation.response_overdueA message from a person waited longer than the response-time target (business hours). data.contact_id, data.channel, data.waiting_since, data.target_minutes.
conversation.scheduled_sentA text, email or DM scheduled from a conversation went out. data.scheduled.
conversation.scheduled_failedA scheduled message could not go (consent, STOP, Meta's 24-hour window, mailbox). data.scheduled.error.

Email

email.domain_verifiedA client sending domain passed Mailjet's SPF and DKIM check. data.domain.
email.campaign_winnerAn email campaign's A/B test picked its winner and sends it to everyone else. data.winner, data.results per version.

Speed to lead

lead.waiting_amberA new lead has had no text, call or email for the amber time.
lead.waiting_redA new lead has had no reply for the red time.
lead.respondedSomeone answered a lead for the first time.

Bookings

booking.createdSomeone books a time on a booking calendar.
booking.rescheduledA booking moves to a new time.
booking.cancelledA booking is cancelled.
booking.confirmedA booking is confirmed (the guest's Confirm link, or by hand).
booking.showedA booking is marked showed.
booking.no_showA booking is marked no-show.
booking.invalidA booking is marked invalid.
booking.status_changedAny booking status change. data.from and data.status.
booking.series_createdSomeone books a repeating series (weekly, every 2 weeks, monthly). data.series, data.bookings (each is also a booking.created), data.skipped dates.
booking.calendar_sync_brokenA connected Outlook or iCloud calendar stops answering (signed out, password changed). data.connection, data.error, data.reconnect.
booking.series_cancelledThis and the following, or every upcoming booking of a series is cancelled at once. data.scope, data.cancelled booking ids.

Forms

form.submittedA form is submitted. data.answers holds the answers by question.
form.abandonedSomeone typed an email on a public form and left it unsent for 30 minutes.

Messages

sms.receivedA text comes in on one of your numbers.
sms.failedA text we sent failed or was not delivered. data.sms.error.
sms.sentA text goes out (you, a workflow, an agent).
phone.number_addedA Twilio number is bought or put to use in Plodder (webhooks set on it). data.number.
phone.a2p_changedThe A2P 10DLC registration moves stage (in review, approved, changes asked). data.registration.stage, reasons.
phone.call_transferredA call is transferred from the call bar (cold or warm). data.transfer.mode, label.
phone.tracking_callSomeone calls a tracking number (Settings > Phone > Tracking numbers). data.source names the ad source; data.website_visit is the visit when the number came from the website swap.
email.receivedEmail from a CRM person arrives in a connected mailbox.
email.sentThe app sends an email (you, scheduled, a workflow, an agent).
email.openedA workflow email is opened (first open).
email.repliedSomeone replies to a workflow email.
email.deliveredMailjet confirms an email reached the person's mail server.
email.clickedA person clicks a link in an email we sent (first click per link). data.email.url.
email.bouncedAn email to a person bounces. data.email.hard is true for a hard bounce.
email.unsubscribedA person unsubscribes (our link, the one-click header, or Mailjet).
email.campaign_sentAn email campaign finishes sending. data.campaign has the counts (sent, skipped, failed).

Custom objects

object.record_createdA record of a custom object (CRM > Objects) is made: app, import, workflow, agent or API. data.record has its fields by key.
object.record_updatedA custom object record changes. data.changes has { field key: { from, to } }.
object.record_deletedA custom object record is deleted.
object.associatedA custom object record is linked to a person, business, deal or another record. data.association.

Facebook and Instagram

meta.lead_receivedA Meta lead ad (instant form) lead lands in the CRM. data.meta has the page, form, campaign, ad set and ad; data.form.answer the answers.
meta.dm_receivedA person messages your page on Messenger or your Instagram account. data.channel, data.message.
meta.commentA person comments on your page's posts or your Instagram media. data.comment.
meta.connection_brokenThe daily Meta check finds the token stopped working, expires within 7 days, or a page lost its token or app subscription (once per new problem). data.problems.

Conversation AI

conversation.bookedAn agent booked a time on a calendar in a conversation. data.booking_id, data.when, data.playbook.
conversation.handed_offAn agent handed a conversation to a person. data.reason, data.summary (two lines).
conversation.endedA conversation ended. data.outcome, data.summary, data.outcomes (post-conversation fields), data.tags (pathway tags), data.variables.
conversation.qualifiedThe qualifying answers passed. data.answers.
conversation.disqualifiedThe qualifying answers did not pass. data.answers.

Calls

call.startedA phone call starts (in or out).
call.completedA phone call ends after it was answered. duration, direction, recording_url.
call.missedA call ends unanswered (missed, busy, no answer, voicemail).
call.loggedA call is logged by hand on a CRM record.

Automations

workflow.enrolledA person enters a workflow.
workflow.completedA person reaches the end of a workflow.
workflow.failedA workflow stops on an error.
workflow.goal_reachedA person meets a workflow goal.

E-sign

signature.requestedA document is sent for signature (one event per signer).
signature.signedA signer signs.
signature.declinedA signer declines (the envelope closes).
signature.completedEvery signer has signed; the signed copy is ready.

Payments

payment.receivedA client pays (payment link, invoice, subscription invoice, booking, document). data.payment.
payment.failedA payment attempt fails (card declined, bank debit failed, renewal failed).
invoice.paidA Stripe invoice is paid (one-off or a subscription's).
invoice.overdueAn open invoice passes its due date (once per invoice).
subscription.startedA client starts a retainer / subscription.
subscription.cancelledA subscription ends.
subscription.renewedA subscription renewal invoice is paid.
refund.issuedA payment is refunded, fully or in part. data.payment.refund_cents.

Commissions

commission.pendingA deal is won or a payment is made but not paid yet: the matched closer / setter get a pending line (expected, not payable). data.commission.status = pending.
commission.earnedA closer or setter earns a commission line (a payment received or a deal won), or a refund claws one back (negative). data.commission.status, .provider, .payment_ref, .attribution.
commission.refundedA refund claws a commission back (negative line in the refund's month; the payment's line is marked Refunded / Part refunded). data.commission.
commission.statement_finalizedA payee's month is finalized (its lines are locked). data.statement.
commission.statement_sentA finalized month becomes a bill in QuickBooks Online. data.statement.qbo_bill_id.
commission.statement_paidQuickBooks shows the payee's bill paid (once per statement). data.statement.

Instantly

instantly.reply_receivedA lead replied to an Instantly campaign email. data.instantly.reply_text when Instantly sends it.
instantly.lead_interestedA lead is marked interested in Instantly (once per person per campaign). data.instantly.deal_id = the lead deal made.
instantly.lead_not_interestedA lead is marked not interested in Instantly.
instantly.meeting_bookedA lead is marked meeting booked in Instantly.
instantly.out_of_officeAn auto reply or out of office from a lead.
instantly.unsubscribedA lead unsubscribed in Instantly (the address is suppressed here too).
instantly.bouncedAn Instantly email bounced (the person is marked Do not email).
instantly.email_sentInstantly sent a campaign email to a person in the CRM.
instantly.email_openedA person opened an Instantly campaign email.
instantly.link_clickedA person clicked a tracked link in an Instantly campaign email.
instantly.lead_statusAny other Instantly lead label (neutral, closed, wrong person, a custom label) or campaign event. data.instantly.event_type.

Work

task.createdA task is created.
task.updatedA task changes.
task.completedA task is marked done.
task.reminderA task on a CRM record reaches its reminder time.
task.deletedA task is deleted.
task.agent_startedAn agent starts work it was assigned (a task, project or doc given to it). data.work, data.agent, data.assigned_by.
task.agent_finishedAn agent finishes assigned work and hands it back. data.work, data.agent, data.outcome (review | done), data.summary.
project.createdA project is created.
doc.createdA doc is created.
doc.updatedA doc is edited.

Webhooks

webhook.testSend test event in Settings, or the webhooks tool action test.

MCP server

Connect Claude, ChatGPT or any MCP client straight to your workspace. Add this server URL in the client and sign in with your Plodder account:

https://app.useplodder.com/mcp

The client gets the same tools as the API, limited to what your account can reach. The full spec is at openapi.json (OpenAPI 3.1).