# MCP server reference

Every tool PYLO's MCP server lists, generated from the server's own list.

PYLO runs a Model Context Protocol server, so Claude and other agents can read a workspace's figures and, with the right token, carry out setup actions. This reference is generated from the list of tools the server itself returns, so it always matches what an agent sees.

## Connecting

- Endpoint: `https://api.pylosystem.com/mcp`, streamable HTTP, JSON-RPC.
- Authentication: a PYLO API token sent as `Authorization: Bearer <token>`. An owner or admin creates one under Settings, then API tokens, with the MCP scope. The Claude plugin can sign in with OAuth instead; see [the Claude plugin](/docs/claude-plugin).
- A workspace token reads only its own workspace, and every tool refuses another. An agency token can read each workspace in its agency and names the one it wants with `workspaceId`.
- A member's own token lists different tools, which read only that member's own figures. They are listed at the end.

## Tools at a glance

| Tool | What it does |
|---|---|
| `list_workspaces` | Workspaces |
| `get_setup_status` | Setup status |
| `get_metric_definitions` | Metric definitions |
| `get_metric` | One metric |
| `get_call_kpis` | Call figures |
| `get_ticket_split` | High and low ticket |
| `get_booking_outcomes` | Cancellations and reschedules |
| `get_payment_kpis` | Payment figures |
| `get_funnel` | Funnel |
| `list_leads` | Leads |
| `get_lead_journey` | Lead journey |
| `list_calls` | Calls |
| `list_payments` | Payments |
| `get_commission` | Commission |
| `get_eod_compliance` | End of day compliance |
| `get_webinar` | Webinars |
| `get_integration_health` | Integration health |
| `list_flow_runs` | Flow runs |
| `list_audit_events` | Audit log |
| `get_data_trust` | Data trust |
| `list_reconciliation_items` | Reconciliation items |
| `get_source_coverage` | Source coverage |
| `get_registrant_reconciliation` | Registrant reconciliation |
| `list_events` | Events |
| `get_event` | An event |
| `get_link_audit` | Link audit |
| `get_deliverability` | Text deliverability |
| `get_cash_returned_by_reason` | Refunds by reason |
| `get_rep_activity` | Rep activity |
| `get_pickup_heatmap` | Pick-up heatmap |
| `list_cadence_violations` | Cadence violations |
| `get_ad_scorecard` | Ad scorecard |
| `get_kill_scale_list` | Kill or scale list |
| `get_content_scorecard` | Content scorecard |
| `get_posting_cadence` | Posting cadence |
| `get_booking_thread` | Booking thread |
| `get_show_rate_drivers` | Show-rate drivers |
| `list_unrecovered_no_shows` | Unrecovered no-shows |
| `get_receivables` | Money owed |
| `get_buyers` | Buyers |
| `get_cash_forecast` | Cash forecast |
| `list_risky_deals` | Risky deals |
| `get_financing_funnel` | Financing |
| `get_outcomes` | Outcomes |
| `list_vault_keys` | Keys held |
| `get_person` | One person |
| `list_duplicates` | Duplicate queue |
| `get_access_checklist` | Access checklist |
| `get_launch_plan` | Launch plan |
| `list_blocking_items` | What is blocking launch |
| `get_partner_usage` | Are students using Base44? |
| `list_at_risk_students` | Students at risk |
| `list_builds` | Build library |
| `get_build` | A build |
| `get_speed_to_lead` | Speed to lead |
| `get_price_book` | Price book |
| `list_price_drift` | Price drift |
| `list_change_log` | Change log |
| `compare_before_after` | Before and after |
| `get_target_plan` | Target plan |
| `get_pace` | Pace to target |
| `get_capacity` | Calendar capacity |
| `get_allocation_suggestions` | Lead allocation suggestions |
| `get_attribution` | Attribution |
| `get_call_analysis` | Call analysis |
| `get_objection_report` | Objection report |
| `get_segment_report` | Segment report |
| `get_statement` | Statement |
| `get_client_economics` | Client economics |
| `get_operator_pnl` | Operator P&L |
| `get_agency_status` | Agency status |
| `list_unlinked_recordings` | Unlinked recordings |
| `list_inbox` | Operator inbox |
| `plan_blueprint` | Plan a workspace |
| `get_plan` | A plan |
| `request_plan_approval` | Ask for approval |
| `apply_plan` | Apply a plan |
| `undo_plan` | Undo a plan |
| `get_approval_policy` | Approval policy |
| `set_approval_policy` | Change the approval policy |
| `grant_standing_approval` | Grant a standing approval |
| `revoke_standing_approval` | Revoke a standing approval |
| `plan_backfill` | Plan a registrant backfill |
| `plan_reenrol` | Plan a re-enrol |
| `plan_event_relaunch` | Plan an event relaunch |
| `create_connect_link` | Connect link |
| `create_key_drop` | Key drop |
| `get_key_drop_status` | Key drop status |
| `get_connect_status` | Connect status |
| `list_templates` | Templates |
| `get_template` | A template |
| `get_onboarding_intake` | What the onboarding call must give |
| `list_recipes` | Recipes |
| `get_recipe_runs` | Recipe runs |
| `set_recipe_shadow` | Put a recipe in shadow |
| `list_tags` | Tags |
| `save_template` | Save an agency template |
| `template_usage` | Who runs a template |
| `plan_template_update` | Plan a template update for its clients |
| `fulfilment_overview` | Fulfilment across clients |
| `get_form` | Application forms |
| `list_form_submissions` | Form submissions |
| `get_form_analytics` | Form analytics |
| `list_form_partials` | Form partials |
| `list_email_lists` | Email lists |
| `list_cohorts` | Cohorts |
| `list_students` | Students |
| `enroll_student` | Enroll a student |
| `tick_student_step` | Tick a student's step |
| `start_onboarding` | Start onboarding a client |
| `get_onboarding_run` | An onboarding run |
| `next_onboarding_step` | What to do next |
| `tick_onboarding_step` | Record a person's step |
| `confirm_access_item` | Confirm an access item |
| `list_onboarding_runs` | Onboarding runs |
| `set_flow_shadow` | Put flows in shadow |
| `set_workspace_mode` | Set parallel or live |
| `list_people` | People |
| `list_identity_suggestions` | People to confirm |
| `decide_identity_suggestion` | Decide a pair |
| `add_person_alias` | Add an alias |
| `get_attribution_report` | Attribution report |
| `get_parallel_scorecard` | Parallel scorecard |
| `plan_switch_to_live` | Plan pieces to live |
| `pause_writes` | Pause writes |
| `lift_write_pause` | Lift a write pause |
| `export_audit_events` | Export the audit log |
| `plan_launch` | Plan a launch |
| `test_vault_key` | Test a key |
| `plan_merge` | Plan a merge |
| `plan_access_checklist` | Plan an access checklist |
| `request_proxy_token` | Proxy token for a script |
| `run_test_lead` | Run a test lead |
| `get_test_run` | A test run |
| `void_call` | Void calls |
| `propose_form_draft` | Draft a form |
| `record_change` | Log a change |
| `set_target` | Set a target |
| `create_task` | Add an inbox task |
| `close_task` | Close an inbox task |
| `switch_workspace` | Switch workspace |
| `request_scope_upgrade` | Ask for more permissions |
| `get_my_day` | My day |
| `get_call_brief` | Brief for one of my calls |
| `get_eod_draft` | My end of day, from my logs |
| `get_call_list` | Who do I call next |
| `get_my_numbers` | My numbers against the team |
| `get_my_commission` | What have I earned |
| `get_my_standing` | How far am I from moving up |
| `log_disposition` | Log a dial's result |
| `score_lead` | Score a lead |
| `confirm_call` | Mark a call confirmed |
| `claim_lead` | Claim a lead |
| `release_lead` | Release a lead |
| `amend_form` | Change my filed form's words |
| `file_form` | File my form from here |
| `confirm_form` | Confirm my form with its code |
| `list_missing_forms` | Who missed a form |
| `get_team_board` | Team board |
| `list_score_outliers` | Lead score outliers |
| `get_rep_calls` | A rep's calls |
| `get_one_to_one_brief` | Prep a 1:1 |
| `get_tracksheet` | Weekly tracksheet |
| `list_number_checks` | Checks that keep the numbers honest |
| `get_team_access` | What access a rep has |
| `get_sales_ops_jobs` | Sales ops jobs |
| `save_one_to_one` | Record a 1:1 |
| `send_nudge` | Nudge whoever has not filed |
| `assign_call_list` | Give a call list to reps |
| `set_sales_ops_jobs` | Switch sales ops jobs on or off |
| `save_call_review` | Record a call review |
| `review_ramp_item` | Tick a ramp step |
| `plan_team_change` | Add, change or remove a rep |
| `get_tool_capabilities` | What PYLO can do in a tool |
| `get_tool_map` | Where things live in a tool |
| `plan_tool_task` | Plan a small task in a tool |
| `get_step_pack` | The steps for a browser line |
| `start_browser_run` | Start a browser run |
| `report_step` | Report a step |
| `finish_browser_run` | Finish a browser run and prove it |
| `record_step_pack` | Save a run as a draft pack |
| `browser_observe` | Read the hosted browser's page |
| `browser_act` | Act in the hosted browser |
| `create_browser_login_link` | Hosted browser sign-in link |
| `list_content_templates` | Content templates and the client's voice |
| `list_content` | Content items |
| `get_content_drift` | Does each tool still hold the approved copy |
| `save_content_draft` | Save a draft |
| `request_content_approval` | Ask a person to approve content |
| `register_asset` | Register a file |
| `save_voice_profile` | Save the client's voice |
| `plan_content_push` | Plan pushing approved content into the tools |
| `plan_webinar_run` | Start a webinar run |
| `answer_webinar_intake` | Answer the webinar intake |
| `get_webinar_run` | Where a webinar run stands |
| `tick_webinar_step` | Confirm a person's step |
| `get_live_board` | The live board |
| `get_webinar_report` | The post-webinar report |
| `run_webinar_test` | Tech test a webinar run |
| `set_up_registration_flow` | Set up a webinar run's registration flow |
| `plan_sequence` | Plan a sequence of timed sends |
| `plan_stack` | Recommend the client's stack |
| `plan_provision` | Plan the client's provisioning |
| `run_backend_test` | Run the end-to-end backend test |
| `run_tracking_check` | Check the funnel's tracking end to end |
| `get_provisioning` | The stack and provisioning |
| `preview_sequence` | Who gets what, when |
| `get_sequence_status` | How a sequence is going |
| `pause_sequence` | Pause a sequence |
| `resume_sequence` | Resume a sequence |
| `list_pipelines` | Pipelines and custom fields |
| `get_pipeline_board` | A pipeline board |
| `list_custom_fields` | Custom fields |
| `get_stage_history` | Stage moves |
| `plan_pipeline` | Plan pipeline changes |
| `list_views` | Saved views |
| `get_view_leads` | A view's leads |
| `get_lead_timeline` | A lead's timeline |
| `list_tasks` | Rep tasks |
| `get_routing` | Lead routing |
| `plan_routing` | Plan lead routing |
| `plan_saved_views` | Plan saved views |
| `get_booking_links` | Booking links |
| `plan_booking_links` | Plan booking links |
| `get_low_budget_answers` | Low budget answers |
| `plan_low_budget_answers` | Plan low budget answers |
| `plan_move_calls` | Plan moving booked calls to another closer |
| `plan_mark_test` | Plan marking leads as test |
| `get_discord_routing` | Discord routing |
| `plan_discord_routing` | Plan Discord routing |
| `plan_eod_cutoff` | Plan the EOD cutoff |
| `list_workflows` | Messaging workflows |
| `get_workflow` | One messaging workflow |
| `get_workflow_run` | A contact's path through a workflow |
| `list_senders` | List the senders |
| `list_suppression` | List the suppression list |
| `plan_senders` | Plan sender and pool changes |
| `get_number_bundles` | Read the number bundles |
| `plan_numbers` | Plan a bundle and a number outside the US |
| `get_outreach_domains` | Read the outreach domains |
| `plan_outreach_domain` | Plan an outreach domain |
| `get_messaging_health` | Messaging health |
| `get_wallet` | Credits (older name) |
| `get_credits` | Credits |
| `get_rate_card` | Messaging rate card |
| `list_conversations` | Messaging conversations |
| `get_conversation` | One messaging conversation |
| `list_chats` | Team chats |
| `get_chat_thread` | One team chat |
| `list_booking_event_types` | Booking event types |
| `get_booking_availability` | Booking availability |
| `list_bookings` | Native bookings |
| `plan_booking_event_type` | Plan a booking event type |
| `list_booking_partials` | Unfinished bookings |
| `list_webhooks` | Outgoing webhooks |
| `get_webhook_deliveries` | Webhook deliveries |
| `plan_webhook` | Plan an outgoing webhook |
| `create_webhook_drop` | Webhook address drop |
| `send_test_webhook` | Send a test webhook |
| `retry_webhook_delivery` | Send a webhook delivery again |
| `list_dialler_calls` | Dialler calls |
| `get_dial_queue` | Power dial queue |
| `get_dialler_setup` | Dialler set-up |
| `list_dnc` | Do-not-call list |
| `get_call_recording` | Call recording and notes |
| `get_call_transcript` | Call transcript |
| `list_call_recordings` | Call recordings |
| `get_recorder_settings` | Recorder settings |
| `list_pages` | Landing pages |
| `get_page_stats` | Landing page figures |
| `get_page_setup` | Landing page setup |
| `get_funnel_tracking` | Ads funnel tracker |
| `plan_page` | Plan a landing page |
| `plan_form_from_link` | Plan a form from a link |
| `plan_booking_event_from_link` | Plan an event type from a booking link |
| `plan_page_from_link` | Plan a landing page from a reference link |
| `plan_workflow` | Plan a messaging workflow |
| `list_broadcasts` | Messaging broadcasts |
| `get_broadcast` | One messaging broadcast |
| `list_message_templates` | Message templates |
| `get_message_template` | One message template |
| `list_contact_lists` | Contact lists |
| `plan_broadcast` | Plan a messaging broadcast |
| `list_procedures` | SOP procedures |
| `get_procedure` | An SOP procedure |
| `get_sop_coverage` | How much of the SOPs PYLO runs |
| `ask_sops` | Ask the SOPs |
| `run_procedure` | Run an SOP procedure |
| `save_procedure` | Save the agency's own procedure |
| `get_contact_checks` | A lead's checks before sending |
| `get_affiliate_funnel` | Affiliate funnel |
| `get_affiliate_overview` | Every affiliate funnel |
| `list_affiliate_sales` | Affiliate sales |
| `list_unmatched_signups` | Signups to link |
| `log_affiliate_sale` | Log an affiliate sale |
| `match_affiliate_sale` | Link a signup |
| `plan_affiliate_import` | Import the program's report |
| `set_portal_link` | Set the sales portal link |
| `plan_webinar_event` | Find or create a webinar session |
| `plan_attendance_import` | Import a webinar attendee file |
| `plan_webinarjam_import` | Import a WebinarJam session |
| `search_docs` | Search the help pages |
| `whats_new` | What is new in PYLO |
| `read_doc` | Read a help page |
| `explain_figure` | Explain a figure |
| `request_feature` | Send a feature request to the PYLO team |

## Reading tools

### `list_workspaces`

**Workspaces**

The workspaces this token can read, each with its id, name, currency and tier. Call this first with an agency token, to find the workspaceId every other tool takes. A workspace token gets its one workspace. A sign-in its person approved for several workspaces gets the one it is working in, plus canSwitchTo for switch_workspace; working as a closer, setter or SDR, it gets each one's id and name only.

No arguments.

### `get_setup_status`

**Setup status**

The setup steps for a workspace, each done, waiting, in progress or not started, with what finishes it and, when it is waiting, on what. A workspace in parallel is held to its parallel checklist (who the client is, their stack and the field mappings, with nobody on their team invited); the steps going live will need come back as goLive. Use it to see what is left. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_metric_definitions`

**Metric definitions**

What PYLO's metrics mean, from the metric registry: the definition, the numerator and the denominator by name, the exclusions and the period rule. Use it before quoting a figure, to say exactly what it counts. Pass metric for one, prefix for a family (rate., cash., calls.), or neither for every declared metric. Never returns a value: get_metric does. Refuses an id the registry has not declared.

| Argument | Type | Required | Description |
|---|---|---|---|
| `metric` | string | no | One registry id, for example rate.show. |
| `prefix` | string | no | Every declared id starting with this, for example rate. |

### `get_metric`

**One metric**

One metric for a period: the value, the numerator and denominator with their labels and counts, the exclusions and the period rule. A rate is a fraction, never a percentage. A figure PYLO cannot produce comes back as unavailable with the reason, never as zero. Use it to answer a question like "show rate, last 30 days". Refuses an id the registry has not declared. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `metric` | string | yes | The registry id, for example rate.show or cash.collected. |
| `eventId` | string | no | Only for one session's webinar figures (webinar.show_paid_real and the like): the session, from list_events. |
| `pipeline` | string | no | Only for the pipeline. figures and rate.pipeline_win: the pipeline's key, from list_pipelines. Default opportunity. |
| `stage` | string | no | Only for pipeline.entered: one stage's key. |
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_call_kpis`

**Call figures**

Every call figure for a period in one answer: booked, live, qualified, closed, no-shows, cancellations, reschedules and disqualifications, with the show rate, the booked to held, booked to cancelled and booked to rescheduled rates beside it, the close rate, the qualified close rate and the disqualification rate, each with both sides. For closes split into high and low ticket, use get_ticket_split. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_ticket_split`

**High and low ticket**

Closes, deposits and cash for a period split into high ticket and low ticket, and per program. A program's tier is the owner's choice, or its price against the workspace's threshold. Closes are calls marked closed won and deposits calls marked deposit, DM closes included; cash is payments that succeeded less refunds, in the workspace's currency. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_booking_outcomes`

**Cancellations and reschedules**

Of the calls booked into a period, how many were cancelled and, counted apart, how many were rescheduled, broken down by funnel, source, setter and closer. Every row carries both sides of both rates, for example 6 of 40 calls cancelled. A reschedule is never counted as a cancellation. A row labelled Not recorded holds the calls with no value for that breakdown, so each breakdown adds up to the workspace total. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_payment_kpis`

**Payment figures**

Cash collected, outstanding, after fees and by kind for a period, plus revenue booked, deals closed and the two averages, each in the workspace's currency. Use list_payments for the rows behind them. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_funnel`

**Funnel**

One funnel's stages for a period, with each stage's count and the conversion to the next, and whether each figure is counted, reported on an end-of-day form, or a gap PYLO cannot see, and what the funnel brought in (money): cash collected in the period from the funnel's leads and revenue booked on its closes, per currency, with cash per booked call and per close. Use it for "how much did the webinar bring in". Refuses a funnel PYLO does not have. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `funnel` | string: vsl, dm, free_community, webinar | no | Which funnel. Defaults to vsl. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_leads`

**Leads**

Leads created in a period, newest first, with their source, status, owners (the assigned setter and closer) and UTMs. For one lead's whole history use get_lead_journey. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_lead_journey`

**Lead journey**

Everything PYLO holds about one lead, in time order: how they arrived, every attribution touch, every call and its outcome, every payment with its currency, and every flow run. The tool to call in the thread of a booked call. Refuses without a leadId. A lead in another workspace is not found. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `leadId` | string | yes | The lead's PYLO id. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_calls`

**Calls**

Calls scheduled in a period, newest first, with outcome, the closer, setter and SDR slots, the booking link each was booked on (bookingLink, from 21 October 2026, so a check-in can be told from a sales call), and whether each was voided or filed as an internal booking. Voided calls are left out unless includeVoided is true. For figures rather than rows use get_call_kpis. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `includeVoided` | boolean | no | Include voided calls, each marked with its reason. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_payments`

**Payments**

Payments and instalments paid or due in a period, with status, whether each is the initial payment, and verification. Amounts are as stored, in their currency, never converted. Read only: PYLO has no tool that refunds, pays out or edits a payment. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_commission`

**Commission**

What each team member is owed for a period, in the workspace's currency, with every line behind it: the call, the slot held, the cash, the rate and the rule that set the rate. Read only: PYLO never pays anybody. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_eod_compliance`

**End of day compliance**

End-of-day reports filed against those expected, per team member and role, for a period. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_webinar`

**Webinars**

Webinar events with registrations, attendance, pitch and booking counts, and the show rate, booking rate and replay conversion rate, each with both sides. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `eventId` | string | no | One event, instead of every event in the period. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_integration_health`

**Integration health**

For each provider: whether it is connected, when PYLO last received data from it, what it can and cannot see, and what would fix it. Never returns a credential. Use it before trusting a figure that depends on a provider, or to find what an integration needs. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_flow_runs`

**Flow runs**

Runs of the workspace's flows (lead intake, booking, cancellation, outcome, payment, hand-off) in a period, newest first, with status and failures. Says so when flows are not built on this deployment. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `flow` | string | no | One flow, for example lead_intake. |
| `status` | string | no | Only runs in this status, for example failed. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_audit_events`

**Audit log**

Audit log entries in a period, newest first: who or which token changed what, before and after, the plan, who approved it and how, and how the write was made. Filter by planId, by tool (the tool touched, e.g. close, or a tool name in the action) and by method (api, snapshot, browser or person). export_audit_events returns the same as CSV. Says so when the audit log is not built on this deployment. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `planId` | string | no | Only writes made by this plan. |
| `tool` | string | no | Only writes to this tool, e.g. close, calendly, workspace_mode. |
| `method` | string: api, snapshot, browser, person | no | Only writes made this way. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_data_trust`

**Data trust**

Can this workspace's figures for a period be trusted? Every check (silent inbound streams against their four-week baseline, outcome filing, source coverage, cash reconciliation, connection identity) with its status, its reasons in plain sentences and the evidence behind them, and an overall trust flag: ok, or degraded with the reasons. Quote the reasons beside any figure from a degraded period. Days are UTC days. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_reconciliation_items`

**Reconciliation items**

Cash that does not reconcile in a period: collected payments with no deal behind them, and closed deals whose cash has no payment behind it, largest first, each with its currency. Also the open items waiting on the reconciliation screen. Both sides are PYLO's own records; the processors' ledgers are not read. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_source_coverage`

**Source coverage**

How many leads, bookings and closes in a period have a known source, by entry point (form, CRM, calendar, DM close form, import), with both counts. Use it to find where UTMs are being dropped. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_registrant_reconciliation`

**Registrant reconciliation**

For one event, every registrant in one class: tagged, in the SMS platform without the event's tag, not in the platform, not in the CRM, in the CRM with no opportunity, in the CRM but not in this event's pipeline stage, phone invalid (with the fix PYLO proposes), opted out, or duplicate, and registrant coverage with both sides. Placement is read from the CRM's own opportunities (Close or GoHighLevel), with each registrant's pipeline and stage. The latest kept reconciliation (daily, and 48, 24 and 4 hours before), or a fresh one. Says what each source could not tell. Refuses without an eventId. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `eventId` | string | yes | The webinar event (session) id. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_events`

**Events**

Every event (webinar session, challenge or launch) with its date, its join, replay, community and add-to-calendar links, its registration and confirmation pages, its tag, which event it relaunched, and when its post-event exit is due or was done. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_event`

**An event**

One event: its links, pages, CRM choice, SMS workflow and tags, its latest link audit, and its relaunch plans with the manual steps a person has ticked. Refuses without an eventId. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `eventId` | string | yes | The event id, from list_events. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_link_audit`

**Link audit**

Whether everything points at this event: the latest link audit, each place checked (the pages PYLO can read, and the GoHighLevel workflow and the host's emails through the latest browser run of their read step pack; with no run, listed as not readable rather than clean, naming the plan_tool_task capability that reads it), each stale or missing link with where it is and what it should be. Refuses without an eventId. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `eventId` | string | yes | The event id, from list_events. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_deliverability`

**Text deliverability**

Per sender number, the share of texts that failed over the last 7 days, by error class (unreachable, invalid number, opted out, other), and whether it is at the alert or the pause level. Failures on older sends are counted apart, so an old rate never passes for today's. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_cash_returned_by_reason`

**Refunds by reason**

Refunds dated in the period by the reason recorded on each (pack 09 Part 5: onboarding delay, didn't use it, expectations mismatch, financial hardship, dispute or chargeback, delivery issue, other, and any the workspace added), with how many and how much in each currency. Processor refunds arrive with no reason and sit in Not recorded, so the rows add up to the refunds cash collected nets. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_rep_activity`

**Rep activity**

Per rep per day: dials, connects (by call length, not the dialler's answered flag), pick-up rate, conversations over 3 minutes and talk time, with the EOD's reported dials beside the system's and the activity alerts, callbacks kept (the next call within the workspace's window of the promised time) and the leads that went dead with no connect. Give a teamMemberId for one rep. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `teamMemberId` | string | no | One rep's team member id. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_pickup_heatmap`

**Pick-up heatmap**

Dials and pick-up rate by London hour and weekday, and by the number each rep dialled from, with a number flagged as burned when it picks up at under half the rep's average on at least 20 dials. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_cadence_violations`

**Cadence violations**

Follow-ups to a lead that had not picked up sooner than the workspace's minimum gap, and leads called more times in a day than its rules allow, with the rules used. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_ad_scorecard`

**Ad scorecard**

Pack 09 3.7. Per ad in a period: spend, impressions, clicks, the leads whose utm_content is the ad's id or name, their booked calls and cash, cash return on spend and cost per booked call, each with its numerator and denominator. Also each hook's share of spend and the majority hook, and fatigue (frequency, and click-through against the ad's first 3 days). Money is per currency and never converted. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_kill_scale_list`

**Kill or scale list**

Pack 09 3.7. Which ads to scale (cash return above 4x) and which to kill (below 1x on meaningful spend, or cost per booked call more than twice the account's, including no bookings after 7 days), each with the reason and the spend a kill would recover. A list only: PYLO never pauses or edits an ad. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_content_scorecard`

**Content scorecard**

Pack 09 3.7. YouTube and Instagram posts in a period: views, outlier score against the channel average (2x or more is an outlier), and the buyers and cash each post converted, with how each buyer was tied to it (UTM, DM keyword, the buyer's own answer, first touch). Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_posting_cadence`

**Posting cadence**

Pack 09 3.7. Posts per channel per complete week against the workspace's commitment, the share of weeks that met it, and an alert for every committed week with nothing published. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_booking_thread`

**Booking thread**

One booking from first booked to its final state: each reschedule (who moved it and why), a cancellation with who cancelled and the reason, the pre-call touches, and the lead time. Give a threadId or any callId on it. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `threadId` | string | no | The booking thread's id. |
| `callId` | string | no | Any call on the thread. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_show_rate_drivers`

**Show-rate drivers**

Show rate with and without each driver (a setter confirming, the prospect replying, a group chat, a reminder, a setter booking it, booking within 3 days), counts on both sides, and "too few to compare" below the minimum sample. Also the booked to held, cancel, reschedule and no-show recovery rates. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_unrecovered_no_shows`

**Unrecovered no-shows**

No-shows in the period whose lead has not booked again since. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_receivables`

**Money owed**

Who owes what: every open instalment per currency, aged (not yet due, 1 to 7, 8 to 30, 31 to 60, 61 to 90 and over 90 days overdue, adding up to the total), by closer, plan type and deposit band; the default rate by plan type, deposit band, closer and funnel; the collection and refund rates for the period; and how many deals closed in it have money owed with no schedule. Every rate has both sides. Read only: PYLO never chases a payment. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_buyers`

**Buyers**

Every client the sales team closed, one row per person: what they were sold, cash collected before and after refunds, what is still owed and overdue, refunds, the next payment date, the closer and program, and flags for anything that does not add up (sold against collected plus owed plus refunded, a sale logged twice, two leads for one person, a possible duplicate). Also lists payments with no buyer, and how the totals line up with the dashboard's Revenue booked, Cash collected and Cash outstanding. Use it for "who bought, what did they pay, who still owes". Amounts are in the workspace's currency only. A closer or setter sees only their own buyers. Read only. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `period` | string: this_month, last_month, last_90_days, all_time | no | Which buyers, by the date of their first close. Defaults to all_time. |
| `sort` | string: closed, sold, collectedGross, collected, owed, overdue, refunded, name | no | Order of the rows, largest first for money. Defaults to closed (newest first). |
| `query` | string | no | Only buyers whose name, email or phone contains this. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_cash_forecast`

**Cash forecast**

Instalments scheduled in the next 30, 60 and 90 days, per currency, shown two ways: as scheduled, and at the workspace's historical collection rate for each plan type, with that rate's numerator and denominator. A plan type with too few instalments uses the workspace rate and says so. On Basic only the 30 day window is returned and planCap says why. Only payments in the workspace's currency are counted, and currencyScope says how many in other currencies were left out. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_risky_deals`

**Risky deals**

Deals closed in the period that carry a risk flag at close: a deposit below the threshold, money owed with no schedule, a first instalment more than 30 days out, or a payment method no processor verified. Each with who owes, what is owed and which flags. On Basic the first 10 are listed, with the total and planCap saying so. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_financing_funnel`

**Financing**

Financing applications made on calls in a period, per provider: applied, approved, declined and abandoned, the approved amount per currency, and the approval rate with both sides, plus whether declines have spiked in the last 7 days. Where the financing table is not there yet it says so with the reason rather than returning zeros. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_outcomes`

**Outcomes**

How the calls in a period ended, counted by outcome. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_vault_keys`

**Keys held**

The keys PYLO holds for the workspace's key-based tools, as metadata only: the tool, the account behind the key, whether its last test passed, when it was last used, when it expires and when it is due for rotation. Never a key or any part of one. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_person`

**One person**

Is this the same person? The person a dashboard lead, an email or an E.164 phone belongs to: every linked record (dashboard lead, Close lead, GoHighLevel contact) with which is primary, the open suggestions still waiting on a person's approval with their evidence, and whether a GoHighLevel contact is linked (why someone did not get their texts). Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `leadId` | string | no | A dashboard lead's id. |
| `email` | string | no | An email address. |
| `phone` | string | no | An E.164 phone, such as +447700900123. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_duplicates`

**Duplicate queue**

The workspace's duplicate queue from the last nightly scan: groups of records that look like one person, in one tool (a duplicate in the CRM) or across tools, each with its evidence (the shared email or phone, or a name plus one other signal, which is only ever a suggestion), a suggested primary and what approving it would do. Also the duplicate rate per tool and the cross-tool match rate. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `status` | string | no | open (default), linked or dismissed. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_access_checklist`

**Access checklist**

What the client still has to give the agency: each item on the workspace's access checklist with what the client does, how PYLO checks it, and its status (pending, claimed, verified, or failed with the reason). Also who is reminded, the reminders sent and when the next one goes, and the items longest outstanding. A ticked item no read can check shows as claimed, never verified. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_launch_plan`

**Launch plan**

A launch plan: every item with its owner, due day, what it waits on, the check that proves it and that check's latest reading, and whether it is open, claimed (ticked while its check fails) or done; with the items grouped by owner, the overdue ones, and the ones blocking launch. Checks are run as it is read. Without planKey, the workspace's next launch. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |
| `planKey` | string | no | The plan's key, e.g. webinar-relaunch. Leave it out for the next launch. |

### `list_blocking_items`

**What is blocking launch**

The items launch waits on that are not done, overdue first, each with its owner, due day and why it is open. Answers "what's left before launch?" and "who's holding it up?". Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |
| `planKey` | string | no | The plan's key. Leave it out for the next launch. |

### `get_partner_usage`

**Are students using Base44?**

A Base44 partner's students: activation to first build, the share active in the last 7 and 14 days against Base44's requirement where one is recorded, builds per student, and where students stop. Use is proof of a build or a visit to the student portal; Base44 does not expose its own usage figures. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_at_risk_students`

**Students at risk**

Students with no proof of a build three days after activating, or none and no portal visit for a week, each with why, for a setter or support to nudge. Answers "who's stuck on the foundation?". Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_builds`

**Build library**

The agency's Base44 build library as this workspace's portal uses it: each build's version, section, steps, what counts as proof, and a warning where it needs more than the students' plan runs. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_build`

**A build**

One build's spec: the walkthrough video, each step's prompt and checklist, the screenshots of the result, the proof definition and what it needs from the students' plan. The current version unless one is named. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |
| `key` | string | yes | The build's key, from list_builds. |
| `version` | number | no | An older version, when a proof names one. |

### `get_speed_to_lead`

**Speed to lead**

Leads that arrived recently and have no call yet, longest wait first, each with minutes waiting and a link to open it in PYLO. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `withinMinutes` | number | no | How far back to look, in minutes. Defaults to 120, capped at a week. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_price_book`

**Price book**

Each programme's versions: price, payment plan options, deposit rule, bonuses and the date each took effect, with the close rate while each was in force (both sides). Plus, for the period, the discount rate, pay in full share and price realisation, each with both sides. Says so when offer versions are not switched on. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_price_drift`

**Price drift**

Deals in a period whose price drifted: sold at an earlier version's price, or at a price different from the version in force with no reason recorded. Each with the list price, the price agreed and the version. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_change_log`

**Change log**

Dated changes in a workspace, newest first: price or offer, team, script, funnel or page, ad or social account restrictions, integration outages, launches and promos. Some PYLO records itself, the rest people and agents add. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `compare_before_after`

**Before and after**

Key figures in equal windows either side of a moment or a change log entry (14 days each by default): show rate, close rate, average cash per deal, discount rate, pay in full share and price realisation, each with both sides for both windows. A side under the minimum sample (20 by default) comes back as too few to compare, with its counts. It shows what changed alongside the entry, never what the entry caused. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `at` | string | no | The moment, YYYY-MM-DD or a timestamp. Or pass changeId. |
| `changeId` | string | no | A change log entry's id, whose date is the moment. |
| `days` | number | no | Days each side. Defaults to 14, capped at 90. |
| `minSample` | number | no | The smallest side worth a rate. Defaults to 20. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_target_plan`

**Target plan**

Works back from a cash target to the closes, held calls, bookings, leads and daily dials it needs, in a best, average and worst case from the last three months' rates. Every input rate comes with its numerator, denominator and month; where the workspace's own data is too thin, the workspace's stated rate is used and the plan says so. Uses the month's cash target, or the monthly cash goal, unless cashTarget is given. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `cashTarget` | number | no | A cash figure to plan for, instead of the month's target. |
| `month` | string | no | YYYY-MM. Defaults to this month. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_pace`

**Pace to target**

Actual to date against each target pro-rated for the month so far, with a projected finish and the rate behind it, for the workspace and for each closer and setter against their own target or personal goal. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_capacity`

**Calendar capacity**

How full the closers' calendars are over the next two weeks, from their real Calendly availability, how many weeks remain until they are full at the current booking growth, and whether to consider adding a closer (projected over the threshold, 85% by default, for two weeks). Says what is missing when availability cannot be read. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_allocation_suggestions`

**Lead allocation suggestions**

Closers ranked by cash per booked call and close rate over 90 days, and suggested priority changes under the workspace's rules. Suggestions only: routing stays in the calendar or the CRM. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_attribution`

**Attribution**

Leads and closes by campaign, with the close rate over LEADS, which is not comparable with the close rate over live calls. Covers the workspace's whole history, which the answer says in its notes. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_call_analysis`

**Call analysis**

One call's analysed fields (objections, stated budget, decision-maker, next step, phases and the rest), each with the quote and timestamp it rests on and whether a rep confirmed, edited or rejected it. Cash is never among them. Says so when call analysis is not built on this deployment. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `callId` | string | yes | The call. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_objection_report`

**Objection report**

Objections on analysed calls in a period: the share of calls raising each type, by closer, and a topic signal when one reaches 30% of 20 or more calls. Also next steps on no-close calls, median pitch and discovery minutes and the discount rate. Confirmed fields only unless includeUnconfirmed, and then labelled. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `closerId` | string | no | One closer's calls. |
| `funnel` | string | no | One lead source, for example vsl_funnel. |
| `includeUnconfirmed` | boolean | no | Count fields no rep has confirmed yet. The answer says how many. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_segment_report`

**Segment report**

Close rate, AOV and cash per booked call by stated budget band, decision-maker present and country, stated budget against what was paid, and each scorer's lead scores against outcomes. Cash from payments only. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `funnel` | string | no | One lead source, for example vsl_funnel. |
| `includeUnconfirmed` | boolean | no | Count fields no rep has confirmed yet. The answer says how many. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_statement`

**Statement**

A client workspace's statement for one month under its agency's deal terms: every line, the base and rate each is worked on, the amount, its currency, and whether an operator marked it sent or paid. PYLO works amounts out; it never invoices or moves money. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `month` | string | no | YYYY-MM. Defaults to this month. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_client_economics`

**Client economics**

What the agency has earned from one client workspace: income per month, lifetime, tenure, trend and any post-launch slide (a month under half of the peak before it). Per currency, never combined. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | First month, YYYY-MM. Defaults to twelve months ago. |
| `to` | string | no | Last month, YYYY-MM. Defaults to this month. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_operator_pnl`

**Operator P&L**

The agency's income by client and deal shape, less the agency's own costs, per month and currency. Needs an agency token; a workspace token is refused.

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | First month, YYYY-MM. Defaults to twelve months ago. |
| `to` | string | no | Last month, YYYY-MM. Defaults to this month. |

### `get_agency_status`

**Agency status**

Status for every workspace in this agency at once, each row naming its workspace: setup (steps done of all, and what is waiting), integration health (connected tools not receiving), data trust (ok or degraded, with reasons) and counts for the period (leads, calls and paid payments; voided and test leads left out). Needs an agency token, or in PYLO AI an operator of the open workspace's agency; it never reads another agency. A section PYLO could not read says why instead of a figure.

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceIds` | array | no | Only these workspaces, from list_workspaces. Leave out for every one. |

### `list_unlinked_recordings`

**Unlinked recordings**

Recordings from Fathom, Fireflies, Gong or Grain that PYLO could not place on a call, newest first, each with why and the calls that day it could belong to. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_inbox`

**Operator inbox**

The workspace's operator inbox: every open, claimed and draft task, each with its owner, due date, where it came from, the check that closes it and the evidence, and the tasks that closed themselves in the last seven days with what their check read. Every run's steps for a person or a browser run are here too, owned by whoever approved the plan and closed only by the step's proof. Use it for "what do I need to do today" and "what fixed itself". Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `search_docs`

**Search the help pages**

Searches PYLO's help pages at docs.pylosystem.com and returns the best matching pages, each with its title, url and summary. Use it for how-do-I questions, then read_doc the best one, and link the page in the answer.

| Argument | Type | Required | Description |
|---|---|---|---|
| `query` | string | yes | What the person is trying to do, in their words. |

### `whats_new`

**What is new in PYLO**

Every change to what an agent can do with PYLO, newest first, each with the tools to use. Tell the operator what they can now do. Optional since, YYYY-MM-DD, for changes after a day.

| Argument | Type | Required | Description |
|---|---|---|---|
| `since` | string | no | Optional. Only changes after this day, YYYY-MM-DD. |

### `read_doc`

**Read a help page**

Reads one of PYLO's help pages as markdown, by the url or path search_docs returned. Only pages on the help site can be read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `url` | string | yes | The page's url or path, from search_docs. |

### `explain_figure`

**Explain a figure**

What a figure means and where it is shown, from PYLO's metric registry: its definition, what it divides by, the benchmarks the knowledge base states beside it (and whether they are comparable), its caveats, why it can show as a dash, every screen and section it sits under, the help page that explains it, and whether its card on that screen has a Show explanation toggle. Use it for "what does this number mean", "why is this a dash" and "is this good". Name the metric by id, or the screen's route and section, or pass the member's words as query. Reads no workspace data.

| Argument | Type | Required | Description |
|---|---|---|---|
| `metric` | string | no | A metric id, e.g. rate.show. get_metric_definitions lists them. |
| `page` | string | no | The app route the member is on, e.g. /dashboard or /funnel. |
| `section` | string | no | The section heading on that screen, as it shows it, e.g. Sales activity. |
| `query` | string | no | The member's own words for the figure, when there is no id. |

### `request_feature`

**Send a feature request to the PYLO team**

When the operator asks for something PYLO's tools cannot do, first tell them PYLO cannot do it yet, then offer to send it to the PYLO team as a feature request. Call this only after they agree. request is what they wanted, in one or two sentences in their words; tried is which tools you tried, if any. Leave out lead names, emails, phone numbers and money figures. Tell them it was sent and that PYLO will let them know here when it is built.

| Argument | Type | Required | Description |
|---|---|---|---|
| `request` | string | yes | What the operator wanted PYLO to do, in one or two sentences. |
| `tried` | string | no | Optional. The PYLO tools you tried, and why they did not do it. |

## Action tools

These change PYLO, so each needs a token carrying its scope. A plan is shown before anything is applied.

### `plan_blueprint`

**Plan a workspace**

Plans a new or existing workspace from a template and the client's overrides, or from a whole blueprint, and returns every change (create, update, no-op or blocked with the reason) without doing any of it. A blueprint's deal_terms section records the client's deal terms in the operator ledger ([{ kind, starts_on, retainer_amount, share_pct, share_base, setup_fee_amount }]); terms are money, so a person approves that plan. Needs config:plan. Only an agency token can plan a new workspace.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `newWorkspace` | boolean | no | True to plan a new workspace. Otherwise pass workspaceId. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `template` | string | no | A template key, from the agency's templates. |
| `version` | number | no | The template version. Defaults to its latest. |
| `overrides` | object | no | The client's intake, merged over the template: workspace, team, rates, SMS bodies and the rest. |
| `blueprint` | object | no | A whole blueprint, instead of a template and overrides. |

### `get_plan`

**A plan**

A plan's state and every change in it, with each change's result once it is applied. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `planId` | string | yes | The plan's id, from plan_blueprint. |

### `request_plan_approval`

**Ask for approval**

Sends a plan to the workspace's owners and admins to approve in the app, and tells them and the agency's operators by push, Slack DM and email, with an inbox task. Asking again tells nobody twice. With chatCode true, PYLO instead sends a 6 digit code to the approver's own phone, email or Slack (the person you act for, when they may approve), with a message saying exactly what it approves: the plan's title, its changes and workspace, and for people and money the audience, count and first line. The code is never in this result. When the person types it to you, call apply_plan with approvalCode. It lasts 10 minutes, works once, and only for this version of this plan. Every plan is classed by PYLO (internal, reversible external, hard to reverse, people and money) and the workspace's approval policy says which classes need a person. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `planId` | string | yes | The plan's id, from plan_blueprint. |
| `chatCode` | boolean | no | Send a code to the approver instead of only asking in the app. |

### `apply_plan`

**Apply a plan**

Applies a plan a person has approved, with an idempotency key: the same key never applies twice. A plan older than a day, or one whose workspace changed since it was made, is refused: plan again. Needs config:apply, or config:plan with the approvalCode a person typed to you after request_plan_approval with chatCode. Whether a person must approve depends on the plan's class and the workspace's approval policy (get_approval_policy). Names any API tokens it issued but never returns their values. Pass sendRunId instead of planId to apply a send from plan_backfill or plan_reenrol: it messages real people, so above the workspace's recipient limit it is refused until a person confirms the count in the app. Pass relaunchId to apply a relaunch from plan_event_relaunch.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `planId` | string | no | The plan's id, from plan_blueprint. |
| `sendRunId` | string | no | A send from plan_backfill or plan_reenrol, instead of planId. |
| `relaunchId` | string | no | A relaunch from plan_event_relaunch, instead of planId. |
| `workspaceId` | string | no | With sendRunId or relaunchId: the workspace. An agency token must pass it. |
| `idempotencyKey` | string | yes | 8 to 200 characters, fresh per apply. Reuse it only to retry the same apply. |
| `approvalCode` | string | no | The code the approver typed to you, exactly as typed. Never guess one or reuse one from another plan. |

### `undo_plan`

**Undo a plan**

Makes the reverse of an applied plan from the before and after values it recorded, as a new plan. Nothing changes until that plan is approved and applied under the same policy as any other (apply_plan). Only internal and reversible plans can be undone. Anything the plan created is never deleted, and a change PYLO cannot put back is listed with its value before. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `planId` | string | yes | The plan's id, from plan_blueprint. |

### `get_approval_policy`

**Approval policy**

How plans in this workspace are approved, per class: internal, reversible external, hard to reverse, and people and money. Each is apply (config:apply is enough), chat_code (a person approves, in the app or by a code sent to them) or app (a person approves in the app only). Also the channels codes go out on, and the owner's standing approvals that are active or recent. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `set_approval_policy`

**Change the approval policy**

Asks the workspace's owner to change its approval policy. Called without code, PYLO sends the owner a code with the exact change; nothing changes yet. Called again with exactly the same change and the code the owner typed, it is made, as the owner. You cannot change it any other way. Only internal plans can be set to apply without a person. Leave workspaceId out with an agency token to set the agency's default. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `agencyDefault` | boolean | no | With an agency token: set the agency's default for every workspace instead of one workspace's. |
| `modes` | object | no | Class to mode, e.g. { "hard_to_reverse": "app" }. null clears a class back to the default. |
| `channels` | array | no | push, email, slack: where codes may go. |
| `code` | string | no | The owner's code, on the second call only. |

### `grant_standing_approval`

**Grant a standing approval**

Asks the workspace's owner to approve one class of small changes in advance: internal or reversible external only, for at most 14 days. Plans inside it apply without a code and each is listed in the owner's inbox. Called without code, PYLO sends the owner a code describing it; called again with the same request and the code they typed, it is granted as the owner. Hard to reverse changes and anything touching people or money are never covered. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `planClass` | string | yes | internal or reversible_external. |
| `days` | number | no | How long, in days, at most 14. Or endsAt. |
| `endsAt` | string | no | When it ends, as a date or time, at most 14 days away. |
| `note` | string | no | What it is for, e.g. "reminder timings and tags during launch week". |
| `code` | string | no | The owner's code, on the second call only. |

### `revoke_standing_approval`

**Revoke a standing approval**

Ends a standing approval now. Plans already applied under it stay applied; new ones need a person again. Taking permission away needs no code. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `standingApprovalId` | string | yes | From get_approval_policy. |

### `plan_backfill`

**Plan a registrant backfill**

Plans adding every fixable registrant of one event to the SMS platform with the event's tag, which starts the event's texts: those not in the platform, those without the tag, and those whose number PYLO can fix. Leaves out opted-out contacts, numbers it cannot fix, countries the workspace does not sell to, test contacts and duplicates, and says who and why. Send-affecting: apply it with apply_plan and sendRunId. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | yes | The webinar event (session), from list_events or get_webinar. |

### `plan_reenrol`

**Plan a re-enrol**

Plans re-enrolling returning registrants of one event who still carry an earlier event's tag, so the event's texts start for them again: this event's tag is removed and added back. It cannot remove anyone from a GoHighLevel workflow, and the plan says so. Send-affecting: apply it with apply_plan and sendRunId. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | yes | The webinar event (session). |

### `plan_event_relaunch`

**Plan an event relaunch**

Plans relaunching an event on a new date: the new event and its links in PYLO, the registration flow's new tag, and every step PYLO cannot make itself (the host session, the CRM choice and smart views, the SMS workflow's time and links, the calendar invite, the registration and confirmation pages) as a blocked manual step with the exact values. Apply it with apply_plan and relaunchId; a link audit runs after. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | yes | The event being relaunched, from list_events. |
| `startsAt` | string | yes | The new session's start, ISO 8601 with its offset. |
| `timezone` | string | no | The zone the session is advertised in, e.g. Europe/London. |
| `endsAt` | string | no | Optional. The new session's end. |
| `joinUrl` | string | no | The new join link (https). |
| `replayUrl` | string | no | Optional. Carries over when left out. |
| `communityUrl` | string | no | Optional. Carries over when left out. |
| `calendarUrl` | string | no | Optional. The add-to-calendar link. |
| `registrationUrl` | string | no | Optional. Carries over when left out. |
| `confirmationUrl` | string | no | Optional. Carries over when left out. |
| `crmChoice` | string | no | Optional. The new value of the CRM's event field. |
| `smsWorkflow` | string | no | Optional. The SMS workflow's name. Carries over when left out. |
| `hostSessionId` | string | no | Optional. The host session, when it already exists. |

### `create_connect_link`

**Connect link**

Creates one link the client opens to connect their own tools (OAuth or a write-only key field, never through the conversation). Returns the URL once. Needs connect:links.

Changes PYLO. Needs a token with the `connect:links` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `providers` | array | no | Provider keys to connect. Defaults to the plan's or the workspace's missing ones. |
| `optional` | array | no | Providers offered but not required. |
| `planId` | string | no | The plan the link belongs to, if any. |
| `expiresInDays` | number | no | 1 to 30. Defaults to 7. |
| `keys` | array | no | Pack 13: key-based tools whose keys to collect on a key-drop link (write-only fields, e.g. webinarjam, iclosed, brevo). Tools named in providers that only take a key land there too. Keys PYLO already holds and that pass are left off. |

### `create_key_drop`

**Key drop**

Makes a one-time drop for one tool's key in one workspace, lasting 15 minutes, and returns the ready command (pylo keys put <provider> --drop <id>) for the operator to run in their own terminal, plus a link to the same drop. The key goes straight into PYLO's vault, where saving that tool's key puts it, and is tested at once. Never ask for a key in the chat, and never pass one to any tool: a key in an argument is refused and flagged for rotation. fields takes the tool's non-secret fields only (a GoHighLevel location id, a Base44 app id). Needs connect:links.

Changes PYLO. Needs a token with the `connect:links` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `provider` | string | yes | The tool, e.g. close, ghl, calendly, webinarjam, everwebinar, iclosed, base44, brevo. |
| `fields` | object | no | Optional. The tool's non-secret fields, e.g. { "locationId": "..." } for GoHighLevel. Never a key. |

### `get_key_drop_status`

**Key drop status**

Whether a key drop's key has arrived and passed its test: received, tested ok or failed (with the reason), the account the tool named, and the scopes and expiry where the tool says. Never the key. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `dropId` | string | yes | The pykd_ id create_key_drop returned. |

### `get_connect_status`

**Connect status**

Each provider on a connect link: pending, connected, failed or unavailable, with the reason. Connected is read back from the connection itself. Needs connect:links.

Changes PYLO. Needs a token with the `connect:links` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `linkId` | string | yes | The link's id, from create_connect_link. |

### `list_templates`

**Templates**

Every template this agency can onboard a client from: PYLO's starter templates (vsl-call, webinar, dm-setter, free-community, outbound-sdr, challenge, each with a -ghl variant for GoHighLevel) and the agency's own, with their versions. Needs read.

Changes PYLO. Needs a token with the `read` scope.

No arguments.

### `get_template`

**A template**

One template's blueprint: the tools it needs, the CRM setup, flows, lead sources, the client's access checklist and targets, and what it leaves to the overrides. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | The template's key, from list_templates. |
| `version` | number | no | Optional. An older version. |

### `get_onboarding_intake`

**What the onboarding call must give**

For a template and the overrides drafted so far: every field the template leaves to the overrides, what to ask on the call for each, which are still missing, and every problem PYLO's own validation finds, before the operator is asked to confirm them. Also the agency's intake groups (signing, copy_inputs, offer_proof, build_decisions, buyers): each question, whether the operator answers it in the chat or the client by a link or form (and which tool), and, with a runId, what the run has already recorded, so nothing answered in an earlier conversation is asked again. Pass template and overrides, or a runId. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `template` | string | no | The template's key, from list_templates. |
| `overrides` | object | no | The overrides drafted so far. |
| `runId` | string | no | Or an onboarding run, to read its template and the intake answers it has recorded. |
| `group` | string: signing, copy_inputs, offer_proof, build_decisions, buyers | no | Optional. One intake group only. |

### `list_recipes`

**Recipes**

The workspace's recipes (a trigger, conditions and actions, in off, shadow or live) and its seven built-in flows, which run on the same events. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_recipe_runs`

**Recipe runs**

Each recipe's recent runs: shadow runs with what each action would have done, live runs with what each did and any error. Compare shadow with the zap a recipe replaces before a person moves it to live. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | no | Optional. One recipe's key. |

### `set_recipe_shadow`

**Put a recipe in shadow**

Moves a recipe that is off to shadow, where it logs what it would do and writes nothing. Never to live: a person does that. Recipes themselves are created by plan_blueprint with a recipes section. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | yes | The recipe's key, from list_recipes. |

### `list_tags`

**Tags**

The tags on people in this workspace and how many carry each, or one person's tags with leadId. Tags are set by recipes (add_tag) and pushed to the CRM where it supports them. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | no | Optional. One person's tags. |

### `save_template`

**Save an agency template**

Saves the agency's own template: a new version when the document changed, nothing when it did not. Saving under a starter's key (vsl-call, webinar...) forks it for this agency. Checked by every blueprint kind first. Clients on older versions keep them until plan_template_update plans the change. Needs config:plan and an agency token.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | Lower case letters, digits and hyphens. |
| `document` | object | yes | The whole template, as get_template returns it (format pylo-blueprint/1). |
| `description` | string | no | Optional. One line on what it is for. |

### `template_usage`

**Who runs a template**

Every client onboarded from a template, the version each runs (from its latest applied plan, or its onboarding run), and which are behind the current version. Needs read and an agency token.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | The template's key, from list_templates. |

### `plan_template_update`

**Plan a template update for its clients**

Plans the template's current version for each client on an older one: one plan per client, against its live state, with its own onboarding overrides. Nothing applies: each plan is approved and applied on its own. Up to 25 clients a call. Needs config:plan and an agency token.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | The template's key. |
| `workspaceIds` | array | no | Optional. Only these clients. |

### `fulfilment_overview`

**Fulfilment across clients**

Students across every client in the agency: active, at risk (with the top reasons), completed, refunded, and past their refund window. Counts only, no money. Needs read and an agency token.

Changes PYLO. Needs a token with the `read` scope.

No arguments.

### `get_form`

**Application forms**

The workspace's application forms, or one by key: its questions, logic, scoring (points, bands, pass mark, disqualifying answers), endings, where qualified and unqualified applicants go, whether it is published, and its link, iframe, script and popup snippets. Created and changed in the app or by plan_blueprint with a forms section. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | no | Optional. One form's key. |

### `list_form_submissions`

**Form submissions**

Recent applications: each one's answers, score, whether it qualified and why, where the applicant was sent, the lead it became and its UTMs and click ids. Newest first. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | no | Optional. One form's key. |
| `qualified` | boolean | no | Optional. Only qualified, or only unqualified. |
| `limit` | number | no | Up to 200. Default 50. |

### `get_form_analytics`

**Form analytics**

One form's views, starts, completions, the start and completion rates with both counts, the drop-off at each question, and the average and median time to finish, over 7, 30 or 90 days. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | yes | The form's key, from get_form. |
| `days` | number | no | 7, 30 or 90. Default 30. |

### `list_form_partials`

**Form partials**

People who started a form and stopped for 30 minutes or more without sending it: what they typed (name, email, phone, answers), where they stopped and their UTMs. Newest first. None of them is a lead. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | yes | The form's key, from get_form. |
| `days` | number | no | 7, 30 or 90. Default 30. |

### `list_email_lists`

**Email lists**

The lists (tags, in Kit) in each email tool connected to the workspace that PYLO can add people to: Brevo, Mailchimp, ActiveCampaign and Kit. A recipe's email_list action names one by tool and id, e.g. { type: "email_list", tool: "brevo", list: "12", list_name: "Webinar registrants" }, and adds the person on the trigger; the tool's own automation does any emailing. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `list_cohorts`

**Cohorts**

The workspace's cohorts, each with its start day. Created by plan_blueprint with a cohorts section. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `list_students`

**Students**

Buyers after the sale: each enrollment's cohort, the fulfilment checklist (joined the community, kickoff call booked, first win), instalments overdue and the refund window, with why a student is at risk. atRisk: true for only those. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `cohort` | string | no | Optional. One cohort's key. |
| `atRisk` | boolean | no | Only students at risk. |

### `enroll_student`

**Enroll a student**

Enrolls a buyer, into a cohort or the current one, with a refund window (14 days unless refundDays). A recipe's start_enrollment does the same on a won outcome or a paid payment. Needs data:write.

Changes PYLO. Needs a token with the `data:write` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | The buyer's lead id. |
| `cohort` | string | no | Optional. The cohort's key. |
| `refundDays` | number | no | Optional. 0 to 90. |

### `tick_student_step`

**Tick a student's step**

Records one fulfilment step for a student (joined_community, kickoff_booked or first_win), with who and when. Needs data:write.

Changes PYLO. Needs a token with the `data:write` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | The student's lead id. |
| `step` | string | yes | joined_community, kickoff_booked or first_win. |

### `start_onboarding`

**Start onboarding a client**

"I signed a client" starts here: the onboarding run from intake to live, the agency's 7-day arc through the client checklist's 20 items. Starts, or updates, the run for a client: a funnel template (list_templates) and its overrides. Once the operator has confirmed the overrides line by line, call it with confirmed: true and it makes the plan that creates the workspace with setup actions switched on, and returns it for a person to approve. It never applies anything. intake saves answers to the intake groups on the run (get_onboarding_intake lists them), kept for every later conversation. Pass workspaceId to onboard a workspace that already exists. Every later step is read with next_onboarding_step. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `runId` | string | no | The run to update, from an earlier call. Leave out to start one. |
| `template` | string | no | The funnel template's key, e.g. vsl-call, webinar, dm-setter. |
| `version` | number | no | Optional. A template version; the current one by default. |
| `overrides` | object | no | The template's overrides: at least { workspace: { name } }, then team, commission, SMS bodies and so on. |
| `funnel` | string | no | Optional. What the operator calls this funnel. |
| `confirmed` | boolean | no | True once the operator has confirmed every override. |
| `replan` | boolean | no | Make a fresh workspace plan, when the last one expired or went stale. |
| `workspaceId` | string | no | Optional. An existing workspace to onboard instead of creating one. |
| `intake` | object | no | Optional. Intake answers to keep on the run: { group: { field: answer } }, e.g. { signing: { contract_terms: "..." }, build_decisions: { geography: ["GB"] } }. |

### `get_onboarding_run`

**An onboarding run**

One client's onboarding run: the 7-day arc (the client checklist's 20 items, Day 0 to Day 7, each with its owner, due day, the tool that does it and the read that proves it, or a person's claim for a step only a person can do), the Day 7 go-live checks (funnel set up, software set up, sales team active, backend test and test lead passed, nothing blocking launch), the automation library mapped to PYLO flows and recipes with each one's state, the intake groups, and pack 11's technical steps (overrides, workspace, setup switch, connections, client access, tool setup, flows, test lead, launch). Everything is decided from live reads, never from what anyone said. Pass runId, or workspaceId. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `runId` | string | no | The run's id, from start_onboarding or list_onboarding_runs. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `next_onboarding_step`

**What to do next**

The one thing to do now in a client's onboarding, for an agent with no memory of it: the arc item, the tool that does it with its arguments filled in (plan_access_checklist, create_key_drop, plan_stack, plan_provision, save_content_draft, plan_sequence, plan_webinar_run, plan_team_change, run_backend_test and the rest), or, when the agent has nothing left to do, who it is waiting on and why. Also every person step still open, with its owner and due day, and the go-live checks. Call it after every step, and after any pause. Done when the go-live checks pass by a read. Pass runId, or workspaceId. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `runId` | string | no | The run's id. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `tick_onboarding_step`

**Record a person's step**

Records a person's word that a checklist item only a person can do happened (contract signed, expectations call held, client added to the chat, submissions reviewed, backstory call held, offer signed off, or the client's payment and processor application until their reads land), with who, when and a note (the signing tool's reference, the recording's link). Shown as claimed, never done. An item a read proves is refused: do the step and the run reads it. done false unticks it and keeps the record. The same tick shows on the workspace's client onboarding checklist. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `runId` | string | no | The run's id. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `item` | string | yes | The checklist item's key, from get_onboarding_run, e.g. contract_signed or backstory_call_held. |
| `done` | boolean | no | Optional. False to untick. |
| `note` | string | no | Optional. What the person said, or the proof's reference. Never a key or password. |

### `confirm_access_item`

**Confirm an access item**

Records that an item on the client's access checklist is done. An item PYLO can read (a tool connected, a key that works, a DNS record) is checked by its read now and verified only if the read passes. An item no read can reach (Google Workspace accounts, paying for the tools, A2P details sent) is confirmed by the operator and recorded as theirs, as the checklist's Confirm does. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | yes | The item's key, from get_access_checklist. |

### `list_onboarding_runs`

**Onboarding runs**

Every client the agency is onboarding: template, days in onboarding, steps done out of the total, and the next step with who owns it. Needs read, on an agency token.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `state` | string | no | active (default: active and live), live, or archived. |

### `set_flow_shadow`

**Put flows in shadow**

Moves flows that are off to shadow, where each logs on the lead's page exactly what it would have written, and writes nothing anywhere. It never moves a flow to live or back: a person does that on the flows screen after comparing shadow with the zap it replaces. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kinds` | array | yes | Flow kinds: lead_intake, booking, reschedule, cancellation, outcome, payment, hand_off. |

### `set_workspace_mode`

**Set parallel or live**

Parallel mode runs PYLO next to the client's current setup: it reads everything and writes nothing to the client's tools (CRM, email lists, webhooks, checkouts), whatever a token's scopes, and flows and recipes run in shadow. mode parallel applies now. mode live is hard to reverse, so it returns a plan that a person approves in the app (request_plan_approval); apply_plan refuses it until then. get_setup_status shows the mode. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `mode` | string | yes | parallel or live. |

### `list_people`

**People**

Everyone PYLO attributes records to in a workspace, with every email, name and tool user id each is known by and where each was seen. Filter for shadow people (made from the client's tools while the workspace is parallel, with no login and no seat), name only (no email yet), role guessed, or one source (base44, close, aircall, calendly). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `shadow` | boolean | no | Only shadow people (true) or only real members (false). |
| `nameOnly` | boolean | no | Only people known by a name alone. |
| `roleGuessed` | boolean | no | Only people whose role PYLO guessed. |
| `source` | string | no | Only people made from this tool, e.g. base44 or close. |

### `list_identity_suggestions`

**People to confirm**

Pairs PYLO thinks may be one person (the same first name, a near spelling, a name matching an email, a tool user's name), each with its evidence and how many end of day reports, dials, calls and sales each side holds. Nothing is merged until a person decides. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `decide_identity_suggestion`

**Decide a pair**

Accept merges the shadow side of a pair into the other: its reports, dials, calls, sales and aliases move across and it is switched off, all or nothing, and on a day both filed a report the survivor's is kept. Reject keeps them apart and the pair is never suggested again. Two real members cannot be merged. Ask the person before accepting. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `suggestionId` | string | yes | From list_identity_suggestions. |
| `decision` | string | yes | accept or reject. |
| `into` | string | no | When both are shadow people, which one survives. Optional. |

### `add_person_alias`

**Add an alias**

Tell PYLO another way a person is known: an email, a name as a tool writes it, or a tool's user id (with its provider). Records waiting for that person are attributed on the next read. Refuses, in words, an email or tool id someone else already holds; a name may belong to two people, and records using it then wait for a decision. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `teamMemberId` | string | yes | The person, from list_people. |
| `kind` | string | yes | email, name or tool_user. |
| `value` | string | yes | The email, the name, or the tool's user id. |
| `provider` | string | no | For a tool_user: the tool, e.g. close, aircall, calendly. |

### `get_attribution_report`

**Attribution report**

How much of each source's data PYLO has attributed to a person, and what is still waiting: per source, the records attributed and waiting with the share, how each was attributed (tool id, email, staff join, name, created), and the waiting records grouped by reason. Nothing is ever dropped: a record nobody can be found for waits and is counted. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_parallel_scorecard`

**Parallel scorecard**

While a workspace runs in parallel: PYLO's registrants, attendees, bookings, shows, closes and cash next to the client's current setup for the same period, read from the CRM's own records, the booking tool and the SMS platform. For each difference, the people on one side only with the likely reason. Cash is per currency, never added across currencies. A side PYLO cannot read says why, never zero. Also each piece's state and whether it has passed the 7-day shadow cutover. Defaults to the last 7 days. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 6 days before to. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |

### `plan_switch_to_live`

**Plan pieces to live**

Makes one plan per piece of a parallel workspace to go live (registration, crm, sms_platform, email_lists, automations, webhooks, checkouts, setup_actions, relaunch), each with what to turn off in the current setup first and its rollback plan. Follows the 7-day shadow cutover: refused until the workspace has run 7 days in parallel with fewer than 5 differences on the scorecard, unless a person decides to go early (acceptEarly with their reason). Each plan is hard to reverse, so a person approves it (request_plan_approval). Applies nothing. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `pieces` | array | no | The pieces to plan. Defaults to every piece not yet live. |
| `acceptEarly` | boolean | no | True only when a person has decided to go live before the protocol passed. |
| `reason` | string | no | With acceptEarly: the person's reason, in one sentence. It goes in each plan's title. |

### `pause_writes`

**Pause writes**

Stops every write to the client's tools and every scheduled send, for one workspace (scope workspace) or every workspace in the agency (scope agency, agency token only), at once, whatever any token or plan says. Reads keep running and tokens stay valid. The app shows a banner with the reason. Only an owner lifts it: in the app, or lift_write_pause with a code sent to them. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `scope` | string: workspace, agency | no | workspace (the default) or agency. |
| `reason` | string | yes | Why, in one sentence. The owner reads it on the banner. |

### `lift_write_pause`

**Lift a write pause**

Asks the owner to lift a write pause. Without code: sends a code to the workspace's owners (or the agency's operators for an agency pause), with a message saying what lifting it does; nothing changes yet. Call again with the code the owner types to you: the pause is lifted, as that owner. The agent cannot lift a pause any other way. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `scope` | string: workspace, agency | no | workspace (the default) or agency. |
| `pauseId` | string | no | Which pause, when there could be more than one. From pause_writes. |
| `code` | string | no | The code the owner typed, on the second call only. |

### `export_audit_events`

**Export the audit log**

The audit log for a period as CSV text, newest first: when, who (member, user or token), the scope, the action, the target, the plan, who approved it and how, and how the write was made. Filters as list_audit_events: planId, tool and method. Before and after are left out; list_audit_events shows them. Up to 5000 rows. Defaults to the last 30 days. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | Start of the period, YYYY-MM-DD. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `planId` | string | no | Only writes made by this plan. |
| `tool` | string | no | Only writes to this tool, e.g. close. |
| `method` | string: api, snapshot, browser, person | no | api, snapshot, browser or person. |
| `limit` | number | no | How many rows. Defaults to 1000, capped at 5000. |

### `plan_launch`

**Plan a launch**

Plans a workspace's launch from a template and a launch day, and returns every change (the plan and each item, with its owner and due day) without doing any of it. Planning again with a new day moves every due date and keeps the ticks. Templates: webinar-relaunch, webinar-run, client-launch (the three weeks after a client goes live), base44-partner-launch, vsl-dialler, or one in the agency's blueprint. For a whole webinar in days (intake, timeline, build, tests), use plan_webinar_run instead. Needs config:plan; apply it with apply_plan, or request_plan_approval.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `template` | string | yes | The launch template's key. |
| `launchOn` | string | yes | The launch day, YYYY-MM-DD. |
| `key` | string | no | The plan's key, to keep two launches apart. Defaults to the template's key. |
| `name` | string | no | What people call this launch. |
| `items` | array | no | Items to add, or to replace the template's by key: { key, title, owner, due, depends_on, blocking, check }. |

### `test_vault_key`

**Test a key**

One cheap read at the tool with the saved key, on PYLO's server: does it still work, and for which account. Records the result, notices a replaced key or a changed account, and returns what it found. Never the key. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `provider` | string | yes | The key's provider, from list_vault_keys. |

### `plan_merge`

**Plan a merge**

Plans approving duplicate groups from list_duplicates: each links its records as one person (the primary, and the rest secondary), merges a Close duplicate in Close with Close's own merge only where the deployment has switched that on (linking only is the default), and writes the person's CRM and SMS-platform ids onto the dashboard leads. Nothing in PYLO is deleted. Returns a plan; nothing happens until a person applies it with apply_plan or approves it in the app. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `groups` | array | yes | Each { group: id from list_duplicates, primary?: a member ref such as close:lead_abc }. |

### `plan_access_checklist`

**Plan an access checklist**

Plans the workspace's access checklist: the items the client gives the agency, each with what they do, how PYLO verifies it (connected, close_org_member, dns, url or manual) and an optional fallback, plus who is reminded and on what schedule (day 1, 3 and 5, then daily, by default). Returns a plan like plan_blueprint's; nothing changes until apply_plan. Existing items keep their status. With no items, they are generated from the workspace's stack (plan_stack): processor authorisation, registrar access or DNS records, Google Workspace accounts, the Business Manager partner invite and A2P details, a number never used on WhatsApp, each key through the key-drop link, and payment for every tool. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `items` | array | no | Each { key, tool, does, verify?: { method, ... }, fallback?: { after_days, does, verify? } }. Leave out to build them from the stack. |
| `stack` | object | no | Optional, with no items: a stack section; defaults to the stored one. |
| `keepsZaps` | boolean | no | Optional, with no items: the client keeps zaps of their own, so Zapier authorisation is asked for. |
| `contact` | object | no | { email, name? }: who the reminders go to. |
| `chasers` | object | no | { days?: [1,3,5], then_daily?: true, channel?: email \| workspace_chat \| off }. |

### `request_proxy_token`

**Proxy token for a script**

A short-lived token (15 minutes by default, 60 at most) an operator's own script uses to read (GET only) from Close or the GoHighLevel private integration through PYLO, which adds the key on its server. For scripts, not for agents: an agent reads through PYLO's tools. Shown once. Needs admin:tokens.

Changes PYLO. Needs a token with the `admin:tokens` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `provider` | string | yes | close or ghl_private. |
| `ttlMinutes` | number | no | Minutes it lasts, 1 to 60. Defaults to 15. |

### `run_test_lead`

**Run a test lead**

Starts a simulated test lead: PYLO drives its own intake and stops before anything reaches a person. Returns the run and its trace so far. Needs test:run. A live run files a real CRM lead and sends real messages, so a person confirms it by a code (DECISIONS #2): the first call with mode live sends a code to their own phone or inbox, and the same call with approvalCode starts it. The test lead is always the person who typed the code, with their own email; the booking is made on the agency's own sandbox calendar, never the client's (B9). A live run does not start in parallel mode.

Changes PYLO. Needs a token with the `test:run` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `mode` | string: simulated, live | no | Defaults to simulated. Live needs a person's code. |
| `approvalCode` | string | no | Live only: the code the person typed. Leave out to have one sent. |
| `funnel` | string: typeform, dms | no | Simulated only. Defaults to typeform. |
| `waitMinutes` | number | no | Live only: how long PYLO waits for the booking. |

### `get_test_run`

**A test run**

A test lead run's trace, step by step, each passed, failed or skipped with its timing and reason. Leave runId out for the latest. Needs test:run.

Changes PYLO. Needs a token with the `test:run` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | no | The run's id. Defaults to the latest. |

### `void_call`

**Void calls**

Voids calls that should not count (a test, a duplicate, spam), with a reason. Refused for a call with money collected or commission paid on it. A voided call can be restored in the app. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callIds` | array | yes | The calls, by id, from list_calls. |
| `reason` | string: test, duplicate, spam, other | yes | Why. |
| `note` | string | no | Required when the reason is other. |

### `propose_form_draft`

**Draft a form**

Proposes a post-call, DM close, past call or end of day form, filled in, for a member to review and file themselves. It never files the form, and it refuses any money figure: cash is for the member to enter. A post-call draft names its call. A closer, setter or SDR drafts only for themselves. Needs data:write.

Changes PYLO. Needs a token with the `data:write` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: post_call, dm_close, past_call, eod, affiliate_sale | yes | Which form. affiliate_sale is one signup on an affiliate funnel (pack 14). |
| `fields` | object | yes | The form's fields, by the names the form uses. No cash, revenue or price. |
| `callId` | string | no | The call, from list_calls. Required for a post-call draft. |
| `memberId` | string | no | Whose draft. Defaults to the call's closer, or to you. |
| `idempotencyKey` | string | no | Optional. The same key never drafts twice. |

### `record_change`

**Log a change**

Adds an entry to the workspace's change log (a new offer, a script change, a price test, a hire), so compare_before_after can measure what happened around it. Needs data:write.

Changes PYLO. Needs a token with the `data:write` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `type` | string: price_offer, team_change, script_change, funnel_page_change, ad_account_restriction, social_account_restriction, integration_outage, launch_promo, other | yes | What kind of change. |
| `title` | string | yes | What changed, in under 200 characters. |
| `note` | string | no | Anything else worth keeping. |
| `occurredAt` | string | no | When it happened, YYYY-MM-DD or a timestamp. Defaults to now. Never in the future. |

### `set_target`

**Set a target**

Sets a month's target for the workspace or one member: cash collected, closes or calls booked. Replaces that month's target for the same metric. Owners and admins only. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `metricId` | string: cash.collected, calls.closes, calls.booked | yes | Which metric. |
| `month` | string | yes | YYYY-MM. |
| `value` | number | yes | The target, zero or more. Cash in the workspace's currency. |
| `teamMemberId` | string | no | A member, for a member's target. Leave it out for the workspace's. |

### `create_task`

**Add an inbox task**

Adds a task to the workspace's operator inbox, with a link to where it came from. It opens under the operator; a task PYLO can check itself comes from its own alerts, not from here. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `title` | string | yes | What needs doing, in under 200 characters. |
| `detail` | string | no | Anything else worth knowing. |
| `link` | string | no | Where it came from: an app path or a url. |
| `dueOn` | string | no | YYYY-MM-DD. |
| `ownerAuthUserId` | string | no | Whose task. Leave it out for the workspace's list. |

### `close_task`

**Close an inbox task**

Closes an open task. A task with a check (every alert task has one) becomes claimed, and PYLO marks it done when the check passes; one without a check is done. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `taskId` | string | yes | The task, from list_inbox. |

### `switch_workspace`

**Switch workspace**

Moves this sign-in to another workspace the person ticked when they approved it, so every call after this one reads and acts there, as their own role in that workspace. list_workspaces shows the one you are in now and the ones you may switch to. Tell the person which workspace you are moving to. Not needed with an agency sign-in, which names a workspace per call. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | yes | The workspace to switch to, from list_workspaces' canSwitchTo. |

### `request_scope_upgrade`

**Ask for more permissions**

When a tool is refused for a scope this token does not carry (refused.scope names it), asks the person you act for to allow it. Returns a link to PYLO's own screen, good for an hour: give it to them. They see what this token holds, what you asked for and your reason, and when they approve, this same token carries the new scopes on your next call, with no reconnect. Nothing changes until they approve, and you cannot approve it yourself. Only for a token from signing in (OAuth); an API token is widened by issuing a new one. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `scopes` | array | yes | The scopes wanted, e.g. ["config:plan"]. read, config:plan, config:apply, connect:links, data:write, test:run, admin:tokens, browser:steps, content:draft, forms:self or team:manage. send:confirm is never a token scope. |
| `reason` | string | yes | Why, in a sentence the person will read, e.g. "to plan the webinar reminders you asked for". |

### `get_my_day`

**My day**

"What's on today?" Your own day: today's calls with their confirmation colour, forms you owe (oldest first), your end of day and its cutoff, callbacks you promised, deposits with no remainder scheduled (closers), what PYLO has counted for you so far today, and cash you reported that is still waiting for a payment to match it. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_call_brief`

**Brief for one of my calls**

"Setter notes and application for my 3pm." One of your own calls: the lead's application, the setter's note, the lead's journey (earlier calls, payments and deposits, UTMs) and where it came from. Refuses a call you are not on. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | One of your calls, from get_my_day. |

### `get_eod_draft`

**My end of day, from my logs**

Your end of day with every figure PYLO can count already filled in (calls, closes, cash, dials, pickups over 40 seconds, conversations over 3 minutes, talk time), where each comes from, and what only you can say. Ask the rep only for that, then file_form or propose_form_draft. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `date` | string | no | YYYY-MM-DD. Defaults to your report's day, in your time zone. |

### `get_call_list`

**Who do I call next**

One of your call lists: today, triage (new leads on the speed-to-lead clock), post_webinar, no_shows, recent_no_buy or deposits. Each lead says why it is listed, its last dial and call, and when the cadence rules next allow a call (now, a time, or dead). Triage also offers new leads nobody holds; claim one with claim_lead. Follow-up dates stay in the CRM. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `list` | string: today, triage, post_webinar, no_shows, recent_no_buy, deposits | no | Which list. Defaults to today. |

### `get_my_numbers`

**My numbers against the team**

Your figures for a period, each with its definition, beside the team's average and your rank among reps in your role. Nobody else's figures or names. Rates are fractions. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to the first of this month. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |

### `get_my_commission`

**What have I earned**

Your own commission lines for a period, as your payout breakdown shows them: earned, paid and pending, in the workspace's currency, and cash you reported from a chat that counts only once a payment matches it. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to the first of this month. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |

### `get_my_standing`

**How far am I from moving up**

Your level and its KPIs, the next level's KPIs beside this month's figures, your step on the ladder and your calendar priority. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `log_disposition`

**Log a dial's result**

"Log that as a voicemail." Sets the result of your latest dial to a lead in the last day. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callOrLeadId` | string | yes | One of your calls, or the lead you dialled. |
| `result` | string: voicemail, no_answer, busy, wrong_number, not_interested, callback, booked, connected, do_not_call, other | yes | What happened. |
| `callbackAt` | string | no | Optional, with callback. When to call back, ISO date and time: PYLO puts a call back task on your list for then. |

### `score_lead`

**Score a lead**

"Score the 2pm no-show a 2." Scores the lead on one of your calls, 1 to 5 in half steps: the lead's quality, not whether it closed. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | One of your calls. |
| `score` | number | yes | 1 to 5, in steps of 0.5. |

### `confirm_call`

**Mark a call confirmed**

"Mark my 4pm confirmed." Sets the traffic light on one of your calls: green confirmed, orange unsure, red not confirmed, or rescheduled. Written to PYLO's calls board only; nothing is written to the calendar tool. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | One of your calls. |
| `colour` | string: green, orange, red, rescheduled | yes | The light. |

### `claim_lead`

**Claim a lead**

"I've got this one." The first claim owns the lead, in place of an emoji on the Slack post. A lead another rep claimed is refused. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | The lead, from get_call_list. |
| `list` | string | no | Which list it came from, for the record. |

### `release_lead`

**Release a lead**

Gives back a lead you claimed, so another rep can take it. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | A lead you claimed. |

### `amend_form`

**Change my filed form's words**

Changes the words of one of your filed forms: a post-call form's notes, reasons, reason code, recording link and rating, or an end of day's written answers. Never the outcome, money or who was on the call: an owner changes those in the app. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: post_call, eod | yes | Which form. |
| `callId` | string | no | For a post-call form: the call. |
| `date` | string | no | For an end of day: its date, YYYY-MM-DD. |
| `fields` | object | yes | The fields to change, by the names the form uses. |

### `file_form`

**File my form from here**

"PCF for Jane: closed, split pay, objection was her spouse, score 4." Files your own post-call form or end of day, money included, once you confirm it. PYLO checks it with the app's own rules, then sends you a notice: your rep app shows the form and a six digit code. Type the code here (confirm_form) or tap once in the rep app. Money can be typed as 6,800 or 6800.50. Cash filed this way counts once a processor payment matches it. Only the call's closer files its form here; anyone else drafts it with propose_form_draft. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: post_call, eod | yes | Which form. |
| `callId` | string | no | For a post-call form: your call. |
| `date` | string | no | For an end of day: YYYY-MM-DD. Defaults to your report's day. |
| `fields` | object | yes | The form's fields by the names the form uses: outcome, cash_collected, revenue_generated, program_id, payment_plan, payment_method, call_rating, lead_quality_score, reason_code (budget, not_decision_maker, just_browsing, geography, timeline, other), notes and the reasons; for an end of day the role's questions (get_eod_draft lists them). |
| `draftId` | string | no | The draft this came from, if any. |

### `confirm_form`

**Confirm my form with its code**

Files a form file_form prepared, with the six digit code the rep read in their own rep app. A code confirms only that rep's own form, lasts 10 minutes and works once. Do not guess a code. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `formId` | string | yes | From file_form. |
| `code` | string | yes | The six digits the rep typed. |

### `list_missing_forms`

**Who missed a form**

"Who missed a form or an EOD yesterday?" Calls with no recorded outcome, end of day reports missing after the cutoff, and dials with no result, per person, with the deduction each would trigger under the workspace's sales ops settings. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `date` | string | no | YYYY-MM-DD. Defaults to yesterday. |

### `get_team_board`

**Team board**

"Rank the setters on pick-up, confirm and show, and flag anyone under 70% show." Each rep's dials, pickups, confirmations, shows (both show-rate definitions side by side), closes and cash for a period, sorted by the metric asked for. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to the first of this month. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |
| `metric` | string: pickup_rate, confirm_rate, show_rate, booked_to_held, close_rate, cash, sets, dials | no | Sort by this, best first. |

### `list_score_outliers`

**Lead score outliers**

"Whose lead scores are out of line?" Each scorer's average lead score against the team's, and how the leads they score 4 or more actually close; outliers flagged. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |

### `get_rep_calls`

**A rep's calls**

"Three of Sam's calls from this week." A rep's calls, newest first, with the recording link, the start of the transcript and the call analysis where it is on. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `memberId` | string | yes | The rep, from get_team_board. |
| `n` | number | no | How many, 1 to 20. Defaults to 3. |
| `filter` | string: recent, closed, no_close, no_show, recorded | no | Which calls. Defaults to recent. |

### `get_one_to_one_brief`

**Prep a 1:1**

"Prep my 1:1 with Sam." Their month and last seven days against the team's average, the open actions from earlier 1:1s, their ramp checks, and the calendar priority moves SOP 9-21 and 9-22 suggest. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `memberId` | string | yes | The rep. |

### `get_tracksheet`

**Weekly tracksheet**

"Last week's tracksheet." SOP 11-9's columns for one week: ad spend, clicks, applications, calls, shows, closes, revenue and collected, each with its cost where spend and cash share a currency. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `week` | string | no | The Monday it starts, YYYY-MM-DD. Defaults to last week. |

### `list_number_checks`

**Checks that keep the numbers honest**

Closes with no payment after the workspace's window, payments with no closed call, and end of day figures a rep changed from the logs. Flags only; nothing is changed. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |

### `get_team_access`

**What access a rep has**

Every access PYLO gave a rep in the client's tools, how it was given, and the read that proves it, with their ramp checks. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `memberId` | string | yes | The rep. |

### `get_sales_ops_jobs`

**Sales ops jobs**

The workspace's sales ops jobs (the day's call list, missed outcomes and their count, end of day checks, deposit chases, the leaderboard and the reports): on or off, their hour, and whether each has a channel. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `save_one_to_one`

**Record a 1:1**

Records a 1:1 with a rep: notes and action items, on their Development page. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `memberId` | string | yes | The rep. |
| `date` | string | no | YYYY-MM-DD. Defaults to today. |
| `notes` | string | no | What was said. |
| `actionItems` | array | no | The fixes agreed, one per item. |
| `managerId` | string | no | Who held it, when this token is not that person's own sign-in. |

### `send_nudge`

**Nudge whoever has not filed**

"Nudge whoever hasn't filed." A private reminder to each person, by Slack DM or on their phone: never named in a channel. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `memberIds` | array | yes | Who, from list_missing_forms. |
| `about` | string: missing_form, missing_eod, missing_disposition, other | no | What they owe. Defaults to missing_form. |
| `date` | string | no | The day it is about, YYYY-MM-DD. Defaults to today. |
| `note` | string | no | A sentence to add, about their own work only. |

### `assign_call_list`

**Give a call list to reps**

"Give the post-webinar list to Sam and Jo." Who works a call list and by what rule. The members named hold it; anyone else on it is taken off. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `list` | string: today, triage, post_webinar, no_shows, recent_no_buy, deposits | yes | Which list. |
| `memberIds` | array | yes | Closers, setters or SDRs. Empty takes everyone off. |
| `rule` | string: round_robin, split_evenly, first_claim | no | How leads are shared. Defaults to round_robin. |

### `set_sales_ops_jobs`

**Switch sales ops jobs on or off**

Turns the workspace's sales ops jobs on or off, sets their hour, and chooses the Slack channel each kind of post goes to (by name, e.g. daily-sales-ops, or id; PYLO's bot must be in it). The deduction amount and naming people in channels stay an owner's or admin's. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `jobs` | object | no | By job: {"missed_outcomes": {"enabled": true, "hour": 18}}. Jobs: morning_call_list, missed_outcomes, outcome_deductions, eod_check, leaderboard, deposit_reminders, reports, onboarding_reminders. |
| `channels` | object | no | By purpose, the Slack channel's name or id: {"daily_ops": "daily-sales-ops", "eod": "eod-reports"}. Purposes: daily_ops, outcomes, eod, leaderboard, deposits, reports, onboarding. |

### `save_call_review`

**Record a call review**

"Review Sam's 3pm: discovery 3, pitch 4, rushed the price drop." Records a review of one call, scored by stage (the nine closing stages, or the two setting ones), with notes and a Loom link, on the rep's Development page. SOP how-to-review-calls. A ramping closer's own reviews of recorded calls count toward their ramp: pass reviewerId for them. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | The call, from get_rep_calls. |
| `reviewType` | string: closing, setting | no | Defaults to closing. |
| `stageScores` | object | yes | Scores 1 to 5 by stage. Closing: intro_rapport, frame_setting, discovery, commitment_urgency, transition, pitch, temperature_check, price_drop, objection_handling. Setting: qualifying_correctly, following_process. |
| `notes` | string | no | What went well and what to fix. |
| `loomUrl` | string | no | A Loom of the review, https. |
| `reviewerId` | string | no | Who wrote it, when not this token's own person: a member of this workspace. |

### `review_ramp_item`

**Tick a ramp step**

"Ria's mock call was good, green light her." Approves (or sends back) a step on a rep's bootcamp that no read can see: a mock call, walking the prospect journey, a roleplay, a knowledge check. The ramp then shows it as claimed by a manager, never proved. Moving them up stays plan_team_change. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `memberId` | string | yes | The rep. |
| `item` | string | yes | The step: mock_calls, prospect_journey, or a bootcamp item's key (get_team_access lists the ramp). |
| `status` | string: approved, rejected | no | Defaults to approved. |

### `plan_team_change`

**Add, change or remove a rep**

One plan to add a rep everywhere (PYLO, their sign-in and agent, the CRM, the calendar, Slack channels, and a person's step with the exact values for every tool with no API), to change their role, level, pay, days off or calendar priority, or to remove them (end date, every access PYLO gave revoked and proved by a read, their work reassigned, never deleted). A person approves it. Needs team:manage and config:plan.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `op` | string: add, change, remove | yes | What to do. |
| `person` | object | no | add: { name, email, slackUserId? }. |
| `role` | string: closer, setter, sdr, ops, admin | no | add, or change: their role. |
| `level` | string | no | A level's name or id for their role. |
| `pay` | object | no | Rates as percent or fraction: { close, set, lowticket, total }, and effectiveFrom (YYYY-MM-DD; backdated needs the owner). |
| `startsOn` | string | no | add: their first day, YYYY-MM-DD. |
| `rampStartsOn` | string | no | When their ramp starts, YYYY-MM-DD. Defaults to startsOn. |
| `offDays` | array | no | Weekdays off, 0 Sunday to 6 Saturday. |
| `tools` | object | no | add: { slackChannels: [channel ids] (defaults to the team's own channels), closeRoleId, calendlyEventTypes: [names], bookingUrl (a setter's own UTM link points here), hubLinks: [{ name, url }] (posted in the welcome) }. |
| `channels` | array | no | add or change: how a setter or SDR sets, each dials or dms. A DM setter is a setter with ["dms"]: kept on the roster, their end of day asks DM figures. Defaults to dials. |
| `memberId` | string | no | change or remove: the rep. |
| `calendarPriority` | object | no | change: { to: lowest \| equal \| high, reason }. |
| `lastDay` | string | no | remove: their last working day, YYYY-MM-DD. |
| `reassignTo` | string | no | remove: the member who takes over their open CRM work. |

### `get_tool_capabilities`

**What PYLO can do in a tool**

For one tool (webinarjam, zoom, close, ghl, calendly, iclosed, slack, notion, google_drive, cloudflare, payments, meta, typeform, email_platform, base44, whatsapp, pylo), every capability PYLO knows, e.g. webinar.notifications.set or crm.smart_view.create: its methods in fallback order (api, snapshot, browser, person), whether PYLO has its own API writer or only the vendor does, what it needs (plan tier, vendor API access, admin rights, a founder decision), the step pack and where it may run, whether a secret shows on screen, rate limits, the read that proves it, its approval class, and whether it is refused by decision. Also whether the vendor allows automation. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `provider` | string | yes | The tool's key or a name for it, e.g. webinarjam, GoHighLevel, Close. |

### `get_tool_map`

**Where things live in a tool**

The map of a tool's screens: where each setting lives (the menu path, as the screen labels it), what it does and which plan tier has it, from the vendor's own help pages, with the source and the date it was read. Use it in explore mode to go straight to the right screen. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `tool` | string | yes | The tool, e.g. webinarjam. |
| `topic` | string | no | Optional. What you are looking for, e.g. replay, notifications, workflow wait. |

### `plan_tool_task`

**Plan a small task in a tool**

"Move the 1-hour reminder to 30 minutes", "turn on the replay chat", "add Sam to the round robin": one tool for any small task. Map the operator's words to capability ids (get_tool_capabilities) and pass them as capability, or pass goal in their words and PYLO offers candidates when it is not sure. PYLO picks the method (its own API writer, then a snapshot, then a step pack, then explore mode in your browser, then a person), fills the values it knows (the next webinar, the time zone), lists the questions still open, names the read that will prove it, and classes it for approval. With no open questions it makes the plan (one line, or a few); with questions it plans nothing yet: ask them and call again with the answers in params. Internal tasks (a push on booking, a morning digest, a target, EOD questions) name PYLO's own tool instead. Refused tasks (Meta spend, deleting in Close, a test booking, posting in WhatsApp groups) say why. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `tool` | string | no | The tool, e.g. webinarjam, close, ghl, calendly. Leave out to search every tool. |
| `goal` | string | no | The task in the operator's words. |
| `capability` | array | no | Optional. The capability id or ids, from get_tool_capabilities. Wins over goal. |
| `params` | object | no | Optional. Values by the capability's input names (e.g. webinar_name, session_start, field_name, choice). Never a key or password. |

### `get_step_pack`

**The steps for a browser line**

For a plan line whose method is browser: the step pack with its inputs filled from the plan (each step's goal, where, hints, value, check, gotchas and stops), the pack's version and whether a run has ever verified it, the stop rules, and the proof the run must produce. With no pack yet, the explore brief instead: the goal, the tool map and the proof. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `planId` | string | yes | From plan_tool_task. |
| `line` | number | yes | The line's position, as the plan lists it. |

### `start_browser_run`

**Start a browser run**

Starts running an approved plan line's steps. runner agent_browser is your own browser (Claude in Chrome, a browser tool), where the operator is already signed in: PYLO never holds a password. runner hosted_browser answers refused.hosted_browser_off while PYLO's hosted browser is switched off. The plan must be applied first. A workspace in parallel mode, or with writes paused, refuses a run that changes the tool. explore true runs without the pack and records the steps. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `planId` | string | yes | The applied plan. |
| `line` | number | yes | The line's position. |
| `runner` | string: agent_browser, hosted_browser | no | agent_browser (the default) or hosted_browser. |
| `explore` | boolean | no | Optional. Run in explore mode even though a pack exists, recording the steps. |
| `record` | boolean | no | Optional. Record a pack run too, for record_step_pack. |

### `report_step`

**Report a step**

After each step: the step's id, its result (done, drift, stopped or failed), and what the screen showed as text. Drift needs deviation: what the screen showed that the pack did not expect, and what you did instead; a pack that drifts twice goes to a person to re-record. stopped hands a login, code, CAPTCHA, terms, payment or identity step to the operator. Never include a key, password or code: a report that looks like it holds one is refused, not saved, and flagged for rotation. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | From start_browser_run. |
| `step` | string | yes | The pack step's id, or in explore mode a short id of your own (lower case, underscores). |
| `result` | string: done, drift, stopped, failed | yes | How the step went. |
| `observed` | string | yes | What the screen showed after the step, as text. Nothing personal about a lead. |
| `deviation` | string | no | For drift: what differed, and what you did instead. |
| `where` | string | no | Explore mode: the screen or URL pattern you were on. |
| `value` | string | no | Explore mode: the value you set. |
| `check` | string | no | Explore mode: what the screen shows once the step is done. |
| `goal` | string | no | Explore mode: what the step does, in plain words. |

### `finish_browser_run`

**Finish a browser run and prove it**

Runs the line's proof: PYLO's own API read where it has one, a fetch of the page, or the settings screen's read-back you pass as observed (reopen the screen after the run and read it). Only a passing proof marks the plan line done. A screenshot the operator confirmed (screenshotConfirmed true) leaves the line claimed, not done; a failed read leaves it pending with the reason. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | From start_browser_run. |
| `observed` | string | no | The settings screen's read-back after reopening it, as text. |
| `screenshotConfirmed` | boolean | no | Only when no read is possible and the operator confirmed a screenshot. Leaves the line claimed. |
| `pageUrl` | string | no | For a page line: the published page's https address. PYLO fetches it itself and looks for what the line names (the capture snippet, the pixel id). |

### `record_step_pack`

**Save a run as a draft pack**

Turns a run's reported steps (explore mode, or a pack run that drifted) into a draft step pack for a person to review, with the run's values turned back into inputs. A draft is never run and is never verified until a published version's run passes its proof. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | The run to record. |

### `browser_observe`

**Read the hosted browser's page**

PYLO's hosted browser only: the page as text and structure, with passwords and anything secret-shaped masked. Answers refused.hosted_browser_off while the hosted browser is switched off; use your own browser. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | A hosted run. |

### `browser_act`

**Act in the hosted browser**

PYLO's hosted browser only: click, type, select or navigate by a target hint. Never types a password or key. Answers refused.hosted_browser_off while the hosted browser is switched off. Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | A hosted run. |
| `action` | object | yes | { kind: click \| type \| select \| navigate, target, text, option, url }. |

### `create_browser_login_link`

**Hosted browser sign-in link**

PYLO's hosted browser only: a link where the operator signs in to a tool on the vendor's real page with their own password and code; PYLO keeps only the session. Answers refused.hosted_browser_off while the hosted browser is switched off (no stored sessions yet). Needs browser:steps.

Changes PYLO. Needs a token with the `browser:steps` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `tool` | string | yes | The tool to sign in to. |

### `list_content_templates`

**Content templates and the client's voice**

The copy frameworks to draft from, by purpose (a prefix: webinar lists every webinar one): the agency's own templates with their slots and required merge fields first, then PYLO's generic starters. Also the rule packs every draft is checked against, the agency's banned words, whether client sign-off is on, the client's voice profile, and the purposes only a person writes (the client's new opportunity, the brand sheets, the offer sign-off). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `purpose` | string | no | Optional. A purpose or its prefix, e.g. webinar.signup or webinar. |
| `kind` | string | no | Optional. email, sms, whatsapp_template, whatsapp_post, dm, page_section, calendar_invite, script, ad or story. |

### `list_content`

**Content items**

The workspace's content items: purpose, kind, status (draft, approved, pushed, retired), the current version and its checks, where approval stands (operator, and client for pages, scripts and ads) with the client's comments, and where each was pushed. With itemId, the copy itself and every version. Read a client's comments here, revise with save_content_draft, and ask again. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `itemId` | string | no | Optional. One item, with its copy and versions. |
| `eventId` | string | no | Optional. One event's content. |
| `purpose` | string | no | Optional. A purpose prefix. |

### `get_content_drift`

**Does each tool still hold the approved copy**

Reads each pushed item's copy back from its tool where PYLO can (Brevo templates, GoHighLevel custom values) and says per place: clean, drifted (someone edited it in the tool; both texts shown), missing, behind (a newer version is approved and not pushed), or put in by a browser run or a person (no API read). Changes nothing. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | no | Optional. One event's content. |
| `itemId` | string | no | Optional. One item. |

### `save_content_draft`

**Save a draft**

Stores copy you drafted, in the client's voice from the agency's template, as a new version of its item (found by purpose, key and event, or by itemId). Merge fields are PYLO's: {{first_name}}, {{last_name}}, {{email}}, {{phone}} for the tool to fill, and any other {{field}} declared in variables with its value in values. Then it is checked: merge fields, tracked links and the UTM naming convention, email hygiene, SMS length and opt-out, income claims and banned words, the webinar rules, the agency's house style where it has one, and what the client would never say. A failing check blocks approval until a new version fixes it. A key or password in the copy is refused and never stored. The same copy twice is one version. Needs content:draft.

Changes PYLO. Needs a token with the `content:draft` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `purpose` | string | no | What it is for, e.g. webinar.signup.plus25 or webinar.dayof.1h. From list_content_templates. |
| `kind` | string | no | email, sms, whatsapp_template, whatsapp_post, dm, page_section, calendar_invite, script, ad or story. |
| `body` | string | yes | The copy, with merge fields in PYLO's syntax. |
| `subject` | string | no | An email's subject. |
| `title` | string | no | Optional. The name a person sees. |
| `channel` | string | no | Optional. Where it is sent from, e.g. email, sms, meta. |
| `variables` | array | no | Optional. The fill fields the copy must use. Defaults to the template's. |
| `values` | object | no | Optional. { field: text } for the fill fields, e.g. whatsapp_link. Never a key. |
| `itemId` | string | no | Optional. The item to save a new version of. |
| `eventId` | string | no | Optional. The event it belongs to. |
| `key` | string | no | Optional. A variant's name when one purpose has several (ad variants). |

### `request_content_approval`

**Ask a person to approve content**

Asks for approval of content items at their current versions. The operator: PYLO sends a code to the approver's own phone, email or Slack, whose message names the set and its size; when they type it to you, call again with the same ids and code, and the whole set is approved at once. The client (pages, VSL or webinar scripts and ads): a link with a preview of each item, approved or sent back with a comment item by item. A draft failing a check cannot be sent. Never approve on the client's link yourself. Needs content:draft.

Changes PYLO. Needs a token with the `content:draft` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `ids` | array | yes | The content items, from save_content_draft or list_content. |
| `approver` | string: operator, client, both | no | Optional. Who is asked; both by default. |
| `code` | string | no | The code the operator typed to you, to approve the same set. |

### `register_asset`

**Register a file**

Records a deck, video, image or PDF the operator dropped: a file in the client's Drive folder (driveFileId) or an https address (url). PYLO keeps where it is, its kind and status, not a copy. Pushes refer to it by id. Needs content:draft.

Changes PYLO. Needs a token with the `content:draft` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: deck, video, image, pdf, other | yes | What it is. |
| `name` | string | yes | What the operator calls it, e.g. the webinar deck. |
| `driveFileId` | string | no | The Drive file's id (after /d/ in its address). |
| `url` | string | no | Or an https address where the file is. |
| `eventId` | string | no | Optional. The event it belongs to. |

### `save_voice_profile`

**Save the client's voice**

The client's voice, built from the sources the operator points to (the backstory call, a voice note, their posts): catchphrases, what they would never say (every draft is checked against it), how they come across, and samples. A new version when anything changed. Needs content:draft.

Changes PYLO. Needs a token with the `content:draft` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `catchphrases` | array | no | Things the client says. |
| `neverSays` | array | no | Words and phrases the client would never use. |
| `comesAcross` | string | no | How they come across, in a sentence or two. |
| `samples` | array | no | Samples: { kind (post, transcript, voice_note), text or url }. |
| `sources` | array | no | Where it came from, in words. |

### `plan_content_push`

**Plan pushing approved content into the tools**

One plan that writes each APPROVED item into its tool, with merge fields translated into that tool's syntax and the translated text on each line: Brevo email templates and GoHighLevel custom values by API (updated in place when pushed before); the WebinarJam host's reminder emails by its step pack; a GoHighLevel workflow step, a page section or another platform's template in your own browser (explore mode); a WhatsApp template by a person. Only approved versions are pushed, checked again when it applies. A workspace in parallel mode refuses the writes. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `ids` | array | yes | The approved content items. |
| `targets` | array | yes | Where each goes: { tool (brevo, ghl, webinarjam, whatsapp, a page builder), target? (email_template, custom_value, workflow_message, page_section), itemId? (all ids when left out), name? (template, custom value or webinar name), objectId?, sender? { email, name } for a new Brevo template, when? (WebinarJam send time), pageUrl?, workflowName?, stepName? }. |

### `plan_webinar_run`

**Start a webinar run**

"A webinar for this client in five days" as one run. Starts it and returns the intake the way get_onboarding_intake does: each field (when, who, host, offer, proof, traffic, channels, sales, replay, bump, assets) with the question to ask, the allowed values, what PYLO already knows and what is missing. Ask in small batches and save each with answer_webinar_intake. template names the agency's own template whose webinar section holds its private timeline and defaults; PYLO's starter timeline is generic. Only an owner's or admin's token can start one (B9). Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `startsAt` | string | no | Optional. The start with its offset, e.g. 2026-10-02T19:00:00+01:00. |
| `host` | string: webinarjam, zoom, zoom_aevent, everwebinar | no | Optional. The webinar host. |
| `eventId` | string | no | Optional. For a recurring webinar: the earlier session's event, from list_events. |
| `name` | string | no | Optional. The webinar's name; the session's date is added to it. |
| `template` | string | no | Optional. The agency template (save_template) whose webinar section to use. |

### `answer_webinar_intake`

**Answer the webinar intake**

Saves a batch of answers, checks each (and refuses what cannot be right: the same person presenting and moderating, a named case study without permission, money in another currency) and says what each changes: a bank holiday in the audience's countries, sales calls on a weekend, a promotion window too short for the traffic, a booking window over 3 days, a sending domain too new to use (so the host's own emails send instead). The five-day substitutions apply automatically and are listed; overrule keeps the original for any of them, restore undoes that. Once every answer is in, PYLO makes the run's build plan: the timeline dated from the start, every line resolved through the capability register (PYLO's API writer, a step pack, explore mode or a person), the content set, the sequences, the person steps and the read that proves each. Approve it under 3.1 (request_plan_approval with chatCode). Changing an answer later re-plans; moving the date moves every due time. Only an owner's or admin's token (B9). Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | From plan_webinar_run. |
| `answers` | object | no | Field: value, e.g. { starts_at, timezone, presenter, moderator, mechanisms: [..], price: { amount, currency } }. |
| `overrule` | array | no | Optional. Substitution keys to overrule (keep the original), e.g. sending_domain, booking_window. |
| `restore` | array | no | Optional. Substitution keys to apply again. |

### `get_webinar_run`

**Where a webinar run stands**

What is done, due, overdue, held (parallel mode), claimed or waiting, and on whom, with each step's due time in the copy's time zone, how it happens (API, step pack, content, sequence, a person or PYLO) and the read that proves it: no step is done on a claim. Also the intake answers, the substitutions in force, the guards from the SOPs' failure lists (presenter link, join link, catch-up, dated tags, quiet hours, SPF DKIM and DMARC, Zoom settings, purchase pixel, booking window, WhatsApp cap, stale links), the blockers, the tests and the next step with the call to make. With no runId, lists the workspace's runs. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | no | Optional. The run; leave out to list them. |

### `tick_webinar_step`

**Confirm a person's step**

Records that a person did a step only they can do (went live, rehearsed, posted in the WhatsApp group), on their word. A step with a read to prove it (a pushed page, a sequence, a plan line) is shown as claimed, not done, until the read passes. done false unticks it. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | The run. |
| `step` | string | yes | The step's key, from get_webinar_run. |
| `done` | boolean | no | Optional. False to untick. |
| `note` | string | no | Optional. What the person said. |

### `get_live_board`

**The live board**

On the day: registrations, bookings, applications and partial applications, head count where the host exposes it (after the attendance import otherwise), failed payments, and whether the setters triaged each booking within 5 minutes. Plus the moderator's notes: "NAME has booked for DATE and TIME" as bookings land, and who applied but did not book. Every count is from PYLO's own flow, calls, forms and payments; the tech test's registrant is left out. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | no | The session, from list_events or get_webinar_run. |
| `runId` | string | no | Optional. The run, instead of eventId. |

### `get_webinar_report`

**The post-webinar report**

The post-webinar report for one session, written without a spreadsheet: thirteen sections read top down (link CTR, opt-in rate, cost per registrant, real paid show rate, retention to pitch, book rate on the pitch room, cost per booked call paid direct, booked to call taken, close rate, cost per close, cash ROAS, per-ad ROAS, VIP take rate), each a declared metric with both sides and a null with the reason where PYLO cannot produce it. Splits registrants, attendees, show rate and bookings by organic, warm and cold. Tags every booking since the start by cohort (paid direct, organic direct, prior replay, old cohort replay, cold, next cohort): only paid and organic direct count for this session, and a booking 3 or more days after the start counts for the next. Benchmarks and the diagnosis come from the agency template's webinar section (report_benchmarks). The narrative is the agent's: draft it with save_content_draft (kind report, purpose webinar.report.narrative, this eventId). Test registrants are left out. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | no | The session, from list_events or get_webinar_run. |
| `runId` | string | no | Optional. The run, instead of eventId. |

### `run_webinar_test`

**Tech test a webinar run**

One registrant through the funnel, checked at every hop: the page and PYLO's flow, the host registration, the CRM lead and its opportunity's stage, the confirmation email and SMS, the calendar link's time zone, the WhatsApp link, the booking link's UTMs and checkout in test mode. simulated runs the flow in shadow and writes nothing. live needs a person: the first call sends a code to their own phone or inbox, and the same call with approvalCode runs it with THEIR OWN name and email, never anyone else's. No test booking is ever made (B9). In parallel mode a live test runs in shadow. The test registrant is left out of every count. Needs test:run.

Changes PYLO. Needs a token with the `test:run` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | The run. |
| `mode` | string: simulated, live | no | simulated (the default) or live. |
| `approvalCode` | string | no | live only: the code the person typed. Leave out to have one sent. |

### `set_up_registration_flow`

**Set up a webinar run's registration flow**

Plans PYLO's registration flow for the run (WebinarJam's registration, PYLO's record, the GoHighLevel contact with its dated tag, the Close lead, each retried until proved), replacing the signup automation: named for the webinar, linked to the WebinarJam webinar PYLO finds by that name through WebinarJam's API, the dated tag from the naming convention, the CRM legs from the intake, and only the registration page's origin may post to it. In shadow unless live is true: in shadow each leg records what it would have written and nothing reaches a client tool. Needs the host session to exist in WebinarJam first. The page's form posts through PYLO's capture snippet (the form carries data-pylo-registration with the flow's id), so there is no address or secret to paste: only the listed origins, rate limited, deduplicated by email, and nothing beyond the flow's own legs. The apply proves it with one test registration through that path, in shadow, read back; prove true runs the proof again. Needs config:plan and an owner or admin (B9).

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `runId` | string | yes | The run, from plan_webinar_run. |
| `pageUrls` | array | no | The registration page's https address (and any other page whose form posts to it). |
| `live` | boolean | no | Take the flow out of shadow. Hard to reverse: a person approves it by code, and parallel mode still holds its writes. |
| `prove` | boolean | no | Only prove the applied flow: one test registration through the capture snippet's path, in shadow, read back. |

### `plan_sequence`

**Plan a sequence of timed sends**

Reminders timed from the event, not rebuilt in every tool: a sequence of steps, each with an anchor (registration, event_start, booking, call_time, no_show, no_close, purchase), an offset (-1d, -1h, +15m), a channel, an audience (registered, attended, not_attended, booked, not_booked, bought, not_bought, or tag:<name>), quiet hours in the contact's own time zone, a catch-up rule for late joiners (send_if_missed, skip_if_missed, next_only) and via: the client's tool that sends it. With via { tool: "pylo", body, subject (email), sender?, pool? } PYLO sends the text or email itself at its time, from the sender the order picks (a pinned sender, the person who set it off so an "I called" text comes from the line that called, the lead's owner, the pool by the lead's country, else skipped and reported), through the same consent, cap and health checks as a workflow; a channel with no live sender is skipped and reported while the rest runs; on_reply stop (sales follow-ups) or continue (event reminders, the default with an event); STOP always ends texting; pools { sms, email } names a pool per channel (list_senders). For the client's own tools: at each step's time PYLO adds a GoHighLevel tag (or sets a field) or adds the person to an email list in Brevo, Mailchimp, ActiveCampaign or Kit, and the tool's own workflow sends at once; a Calendly step (via { tool: "calendly", event_type }) is timed and sent by Calendly's own workflow from the booking or the call, and PYLO writes nothing per person; a Close step (via { tool: "close", action: "subscribe", sequence: "seq_..." }) subscribes the lead to one of the client's own Close sequences, which sends its own emails, and PYLO reads the subscription back (a step without its sequence answers with the client's Close sequences to choose from); a person step reminds whoever posts it. Start from a starter (webinar_reminders with eventId, booking_reminders, pre_call_calendly, after_call for no-shows and no-closes, after_call_close for a Close client with no email platform), an agency template's sequences section, or a whole sequence; overrides change steps by key (steps: { h1: { offset: "-30m" } }, drop: ["m15"]). The first plan also has a line per workflow or automation the tool needs, run in your own browser or by a person. A sequence messages people, so a person approves it by chat code stating the audience, the count and the first line. Moving the event moves every step still ahead. Its forecast lists every send with its sender, time in the contact's zone and cost, and each one held or blocked by a gate (consent, frequency, sender cap, window, balance, sender health, reach, live switches) with the reason; anything its own settings would hold back is refused before anyone approves. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `template` | string | no | webinar_reminders, booking_reminders, pre_call_calendly, after_call, after_call_close, or an agency template's key whose blueprint has a sequences section. |
| `eventId` | string | no | The webinar it follows, from list_events. Needed for registration and event_start steps. |
| `overrides` | object | no | Changes to the template: steps by key (merged over the template's step; a new key adds a step), drop (step keys to leave out), name, quiet_hours { start, end } or null, time_zone (contact or workspace), suppress_tags. |
| `sequence` | object | no | Optional. A whole sequence instead of a template: { key, name, on_reply, pools, steps: [{ key, name, anchor, offset, channel, first_line, audience, catch_up, quiet, via: { tool, action, tag \| list \| field \| sequence, value } or { tool: "pylo", body, subject, sender, pool } }] }. |
| `sequenceKey` | string | no | Optional. Which sequence in an agency template, when it has more than one. |
| `key` | string | no | Optional. The sequence's key; defaults to the template and the event's date. Planning the same key again changes that sequence. |
| `name` | string | no | Optional. Its name on the Sequences page. |

### `plan_stack`

**Recommend the client's stack**

Runs the agency's decision rules over the intake and returns a recommended stack, a reason on every line: the funnel (no audience: DMs first; steady YouTube: a VSL; B2C with a teachable mechanism and a presenter: a webinar; B2B or done for you: never a webinar), checkout (under $2k direct, over $2k a call, never both), the CRM (none, GoHighLevel, Close or both, or keep a well-built one), messaging by market, the webinar host, the email platform and warm-up, the tracking store (PYLO), the scheduler, team chat, payments and the page builder. The operator confirms or overrides each line; an override needs a reason and is recorded with who and when. Lines PYLO cannot decide come back as questions and nothing is planned. Otherwise it makes an internal plan that stores the stack section. Answers not repeated come from the stored stack. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `answers` | object | yes | The intake: existing_crm { tool, well_built }, lead_flow (low, steady, high), closers, setters, dialers, audience (none, small, steady_youtube, large), market (b2c, b2b), done_for_you, teachable_mechanism, presenter, offer_price, offer_currency, geography (two-letter codes), calls_only, wants_timed_flows, all_in_one, webinar_mode (live, evergreen), new_domain, warm_platform (kit, activecampaign, beehiiv), email_platform, mirror (airtable, sheets), chat (slack, discord), scheduler (calendly, iclosed), payments (whop, stripe, fanbasis), page_builder, application_form (pylo, typeform), keeps_zaps. |
| `overrides` | object | no | Optional. The operator's choices over the recommendation: { slot: { choice, reason } }, slot being funnel, checkout, crm, scheduler, messaging, webinar_host, email_platform, tracking_store, application_form, chat, payments or page_builder. |

### `plan_provision`

**Plan the client's provisioning**

One plan in SOP 10-1's order (client identity, tool signups, the GoHighLevel sub-account, its fields and forms, Close, Calendly or iClosed, the application form, the domain and sending domain, phone numbers, WhatsApp, automations, Slack or Discord, Notion and Drive, payments, Meta, pages, the end-to-end test), with a method on every line from the capability register: PYLO's own API (Close fields, statuses, the pipeline and smart views; Calendly event types; Slack channels; SPF, DKIM and DMARC through Cloudflare, hard to reverse), a step pack or explore mode in your own browser, or a person, with the exact values to type. Paying, KYC, A2P identity, ID checks and buying a domain are person lines. A Notion workspace and Meta campaigns are refused. A line missing a value asks for it and the rest is planned. Built from the stored stack (plan_stack) and the agency's provision and naming sections, or the ones passed. Every write passes parallel mode's guard, and each line is done only when a read proves it. Each page line carries the exact capture snippet and pixel id to paste, and is proved when PYLO fetches the published page and finds them. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `params` | object | no | Values for the lines: business_email, business_phone, business_address, signup_mailbox, tool_plans { tool: plan }, domain, spf_include, dkim_selector, dkim_value, dmarc_report_to, buy_domain, phone_area, whatsapp_number, closer_emails, meeting_location, form_template, drive_template, share_with, offer_name, offer_price, offer_currency, ad_account_id, pixel_id, page_urls { page: https address }, no_pixel_pages (pages that never fire the pixel: the unqualified path, for pixel conditioning). Never a key or password. |
| `stack` | object | no | Optional. A stack section; defaults to the stored one. |
| `provision` | object | no | Optional. A provision section (snapshot, snapshot_fixes, signup_mailbox, tool_plans, close, ghl, event_types, invitee_questions, form_template, channel_sets, drive, phone, pages, email_auth, page_domain); defaults to the stored one, then PYLO's generic starter. |
| `naming` | object | no | Optional. A naming section: utm { source, medium, campaign, content }, dated_tag, event_name, campaign_name. |

### `run_backend_test`

**Run the end-to-end backend test**

SOP 10-14 in order. mode sandbox (the default) is sandbox-safe: an application (one lead, its funnel value and UTMs, no duplicate, routed as qualified), a booking (one call, on that lead, only one flow fired), a cancellation (reads as cancelled), the confirming form (confirmed, setter set), the post-call form (filed), and a booking on the DM calendar. PYLO's own handlers run on signed test payloads with every CRM push, Slack or Discord message and phone notification held back, and no meeting is booked in any calendar. Every assertion is a read, named on the result. Then only the records the test made (by its own test address) are voided, never deleted. mode live sends a test lead through the real form and waits for a booking on the agency's own sandbox calendar, never the client's (B9); it needs a person: the first call sends a code to their own phone or inbox, and the same call with approvalCode runs it with THEIR OWN email, never anyone else's. A live run files a real lead in the client's CRM, so it does not run in parallel mode. Needs test:run.

Changes PYLO. Needs a token with the `test:run` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `mode` | string: sandbox, live | no | sandbox (the default) or live. |
| `approvalCode` | string | no | live only: the code the person typed. Leave out to have one sent. |

### `run_tracking_check`

**Check the funnel's tracking end to end**

Day 7's tracking check, on one test lead a person made: they open the funnel's page through a tracked link in their own browser and apply with their own email (never a client's lead), stopping at the booking page without booking (B9). Then this reads, hop by hop: PYLO fetches each funnel page and finds the capture snippet and the pixel; the snippet is recording visits; the application arrived with its four UTMs; the page visit is joined to the lead; the lead's first touch matches; a qualified applicant was sent to the booking link with the UTMs on it. With no lead yet, it answers with the tracked link to open and records nothing. The result is kept for the go-live checks. Needs test:run.

Changes PYLO. Needs a token with the `test:run` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `email` | string | yes | The address the person applied with, their own. |
| `pageUrls` | object | no | Optional. { page: https address } for pages PYLO does not know the address of yet. |

### `get_provisioning`

**The stack and provisioning**

The workspace's stored stack with each line's reason and any override, its provision and naming sections, and the latest provisioning plan's lines in SOP 10-1 order, each with its method and proof state (verified, claimed, pending, blocked, failed, waiting on an answer, resolved to a PYLO tool, or refused). Also the tracking every funnel page carries: the exact capture snippet line, the marker PYLO looks for when it fetches a page, and the UTM convention. The same read as the Stack and Provisioning screen. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `preview_sequence`

**Who gets what, when**

For a sequence as of now: each step's time (after quiet hours) in each person's own time zone, who it goes to and who it skips and why (not in the audience, missed and skipped by its catch-up rule, quiet hours would land it after the start, suppressed, a duplicate, waiting for attendance), and the next send. With personId, exactly what that one person gets and when. Its forecast checks every gate (consent, frequency, quiet hours before the event, the tool's connection, live switches) and says what would be held or blocked and why. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `sequenceId` | string | yes | The sequence's id or key, from get_sequence_status. |
| `personId` | string | no | Optional. A lead id or email: that person's own timeline. |

### `get_sequence_status`

**How a sequence is going**

Per step: how many were added to the tool (sent), recorded in shadow (parallel mode), failed, suppressed, skipped, held for a person's confirm (more due at once than the workspace's limit), waiting (paced) and still to come, with the reasons and each failure. Also whether the workspace is in parallel mode or its writes are paused. With no sequenceId, lists the workspace's sequences. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `sequenceId` | string | no | Optional. The sequence's id or key. |

### `pause_sequence`

**Pause a sequence**

Stops PYLO adding anyone to the sequence's steps, as an internal plan made and applied in one call. Nothing already sent is undone. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `sequenceId` | string | yes | The sequence's id or key. |
| `reason` | string | yes | One sentence the team reads on the Sequences page. |

### `resume_sequence`

**Resume a sequence**

Carries a paused sequence on, as an internal plan made and applied in one call. Steps still ahead go at their times; steps missed while it was paused follow each step's catch-up rule. Needs config:apply.

Changes PYLO. Needs a token with the `config:apply` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `sequenceId` | string | yes | The sequence's id or key. |

### `list_pipelines`

**Pipelines and custom fields**

Every pipeline in the workspace with its stages in board order, each open, won or lost, plus the custom fields with their types and merge fields. The two default pipelines are each lead's own record: lead_status (the lead's status) and opportunity (its opportunity stage). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_pipeline_board`

**A pipeline board**

One pipeline as its board: per stage the count, the money total per currency (never added across currencies) and the first cards with name, value, owner and days in the stage. Quick filters: a search, the owner (a team member's id, or none), the lead source, at least so many days in the stage, and custom field filters written key:op:value (ops is, is_not, contains, gt, lt, before, after, exists, not_exists). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `pipeline` | string | no | The pipeline's key, from list_pipelines. Default opportunity. |
| `q` | string | no | Optional. Part of a name or an email. |
| `owner` | string | no | Optional. A team member's id, or none. |
| `source` | string | no | Optional. A lead source. |
| `staleDays` | number | no | Optional. Only cards at least this many days in their stage. |
| `fields` | array | no | Optional. Custom field filters, each key:op:value. |
| `cardsPerStage` | number | no | Optional. Cards per stage, 0 to 100. Default 20. |

### `list_custom_fields`

**Custom fields**

The workspace's custom fields on leads and opportunities: key and merge field ({key}), label, type (text, number, money, date, dropdown, multi-select, team member, link), options, whether it is required, and the screens and forms that show it. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `includeArchived` | boolean | no | Optional. Include archived fields. |

### `get_stage_history`

**Stage moves**

Moves between pipeline stages made in PYLO, newest first: the lead, the pipeline, from and to, who moved it and how (board, list, a plan, an import or a CRM sync), and when. An automatic move carries its cause: the workflow and step, or the no-answer ladder and rung. By lead, by pipeline, or both, within dates. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | no | Optional. One lead's moves. |
| `pipeline` | string | no | Optional. One pipeline's key. |
| `since` | string | no | Optional. ISO date or time, inclusive. |
| `until` | string | no | Optional. ISO date or time, exclusive. |
| `limit` | number | no | Optional. Up to 2000. Default 100. |

### `plan_pipeline`

**Plan pipeline changes**

Plans custom fields, pipelines and their stages, Close and GoHighLevel mappings, and lead moves, as one plan that apply_plan carries out. Nothing is deleted: a stage or field left out stays, and a field's type never changes. A default pipeline's stages are only renamed or reordered. Moves can start a messaging workflow on "A lead moves to a pipeline stage", so a plan with moves is approved by a person. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `fields` | array | no | Optional. Each { key?, label, type, entity?, options?, currency?, required?, showOn?: { screens, forms } }. |
| `pipelines` | array | no | Optional. Each { key?, name, entity?, ownerRole?, valueField?, newLeadsTo?, stages?: [{ key?, name, outcome? }] }. Matched by key, else by name. newLeadsTo is a stage key: every lead new to the workspace lands there, like Close's default status, so no plan is needed to place new sign-ups (null turns it off). |
| `mappings` | array | no | Optional. Each { provider: close or ghl, kind: stage or field, externalId, externalLabel?, pipeline?, stage?, field? }. Close statuses and fields by their label, GoHighLevel stages and fields by their id. |
| `moves` | array | no | Optional. Each { leadId, pipeline, to }, the stage's key. Up to 1,000. |

### `list_views`

**Saved views**

The workspace's saved views (the setter's queues, Close's Smart Views) this caller sees: shared ones, and a member's own. Each with its filter (pipeline and stages, owner, source and UTMs, tags, created, last contacted, next task, call count, last dial outcome, custom fields), columns, sort and lead count. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `counts` | boolean | no | Optional. false skips the counts, which read every view. Default true. |

### `get_view_leads`

**A view's leads**

One saved view's leads, or an unsaved filter's, a page at a time, sorted as the view says: name, contact, and each chosen column (status, owners, source, created, last contacted, next task, call count, last dial, tags, custom fields). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `viewId` | string | no | Optional. A view's id, from list_views. |
| `filter` | object | no | Optional, instead of viewId or over it. { pipeline, stages, owner: { role, is: me\|none\|<member id> }, sources, utmSource, utmMedium, utmCampaign, tagsAny, tagsNone, created, lastContacted, nextTask (each { op: within_days\|more_than_days\|between\|never\|exists\|overdue, days, from, to }), callCount: { min, max }, dialOutcome, fields: [key:op:value], q }. |
| `columns` | array | no | Optional. Column keys, or field:<key>. |
| `sort` | object | no | Optional. { by: created\|last_contacted\|next_task\|call_count\|name, dir: asc\|desc }. |
| `offset` | number | no | Optional. Default 0. |
| `limit` | number | no | Optional. Up to 200. Default 50. |

### `get_lead_timeline`

**A lead's timeline**

Everything that happened to one lead, newest first: calls and bookings, dials and their outcomes, texts and emails sent and replies (status and subject only, never the text), form submissions, payments, notes, stage moves, team chat mentions, workflow enrollments, tasks done, routing and owner changes. Paged; filter by kind. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | The lead's id. |
| `kinds` | array | no | Optional. Any of call, dial, sms, email, form, booking, payment, note, stage, chat, workflow, task, routing, owner, tag. |
| `cursor` | string | no | Optional. The next value from the page before. |
| `limit` | number | no | Optional. Up to 100. Default 50. |

### `list_tasks`

**Rep tasks**

Tasks: a member sees their own; a workspace or agency token, an owner or an admin sees anyone's (assigneeId) or everyone's (all). Each with its due time as an instant and in the rep's own zone, the lead, where it came from (by hand, a workflow, a callback, in bulk, an agent), and counts of open, overdue and due today. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `assigneeId` | string | no | Optional. A team member's id, or all. |
| `leadId` | string | no | Optional. One lead's tasks. |
| `when` | string: overdue, today, upcoming, done, all | no | Optional. Default all. |
| `limit` | number | no | Optional. Up to 1000. Default 200. |

### `get_routing`

**Lead routing**

How new leads get an owner: whether routing is on and for which intakes (website_form, pylo_form, import, ghl, crm_sync), the fallback owner, each rule in the order it runs (its conditions, the role it fills, round robin or weighted, its members with their weights and how many each was given, its working hours), who is away, and the routing log, newest first: which lead went to whom and why, in words. Owners and admins, as in the app. Read only: routing changes through plan_routing. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | no | Optional. Only this lead's routing decisions. |
| `limit` | number | no | Optional. Log entries, up to 500. Default 50. |

### `plan_routing`

**Plan lead routing**

Plans inbound lead routing as one plan that apply_plan carries out after a person approves it: the settings (on or off, which intakes: website_form, pylo_form, import, ghl, crm_sync; the fallback owner) and rules matched by name (conditions on source, utm_source, utm_medium, utm_campaign, form, intake, answer:<question>, field:<key>; round_robin or weighted among team members; the role it fills; working hours in a zone). Nothing is deleted and no existing lead is reassigned. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `settings` | object | no | Optional. { enabled?, intakes?: { website_form?, pylo_form?, import?, ghl?, crm_sync? }, fallbackMemberId? }. |
| `rules` | array | no | Optional. Each { name, enabled?, role?: setter\|closer\|sdr, strategy?: round_robin\|weighted, when?: [{ on, op: is\|is_not\|contains\|in, value }], members: [{ memberId, weight? }], hours?: { zone, days, start, end } }. |

### `plan_saved_views`

**Plan saved views**

Plans lead views shared with the team (the setter's queues), as one plan that apply_plan carries out after a person approves it. Each view is matched by name: a new name is made, an existing shared view with that name is changed. The filter is the one get_view_leads takes, so try it there first. A view changes no lead. Owners, admins and ops, as in the app. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `views` | array | yes | Up to 50. Each { name, filter, columns?, sort? }: filter as get_view_leads takes it, columns as its column keys, sort { by, dir }. |

### `get_booking_links`

**Booking links**

The workspace's Calendly links with what PYLO does with each: whether it files bookings on it as sales calls (tracked), its funnel, whether its bookings count as qualified, and its default closer for a booking whose host is not on the team. With no link ticked PYLO files every link, so a weekly check-in link files as a sales call. Owners and admins, as in Settings, Connections, Calendly. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `plan_booking_links`

**Plan booking links**

Plans which Calendly links PYLO files as sales calls, and each link's funnel, quality and default closer, as one plan that apply_plan carries out after a person approves it. Name each link by uri, or by its exact name from get_booking_links. Only the fields given change. Ticking the first link stops every unticked link filing, and the plan says so. Calls already filed are not changed. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `links` | array | yes | Up to 200. Each { uri or name, tracked?: boolean, funnel?: vsl_funnel\|dm_funnel\|webinar\|free_community\|outbound\|low_ticket\|crm_import\|null, quality?: qualified\|unqualified\|null, defaultCloserId?: a team member's id or null }. |

### `get_low_budget_answers`

**Low budget answers**

Which answers to an application's budget question file the applicant as low budget in this workspace, or PYLO's default when none are listed. The budget question is the one whose title mentions capital, how much or invest. Owners and admins. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `plan_low_budget_answers`

**Plan low budget answers**

Plans the workspace's low budget answers as one plan that apply_plan carries out after a person approves it. The list replaces the one saved; an empty list goes back to PYLO's default. Applications already filed keep their status. Read past application answers first so each answer is spelled as the form shows it. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `answers` | array | yes | Up to 20, each exactly as the form shows it. Empty for PYLO's default. |

### `plan_move_calls`

**Plan moving booked calls to another closer**

Plans moving booked calls to another closer in PYLO, as one people plan that a person always approves before apply_plan carries it out. It changes the closer on each call in PYLO only: Calendly cannot change the host of a booked call, so the booking stays on the old host's Calendly and calendar, and the plan says so. A call that already has an outcome, or is voided, is not moved. Nobody is messaged. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callIds` | array | no | Optional. Calls from list_calls, all to toCloserId. |
| `toCloserId` | string | no | With callIds: the active team member who takes them. |
| `moves` | array | no | Optional, instead of callIds. Each { callId, closerId }. Up to 200. |

### `plan_mark_test`

**Plan marking leads as test**

Plans marking leads as test (the leads a funnel test or a test booking made), or taking the mark off with isTest false, as one plan that apply_plan carries out after a person approves it. Nothing is deleted, and undo_plan on the applied plan puts each lead back as it was. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadIds` | array | yes | Up to 500 leads, by id, from list_leads. |
| `isTest` | boolean | no | Optional. Default true; false takes the mark off. |

### `get_discord_routing`

**Discord routing**

Which channel of the connected Discord server each PYLO event posts to (applications, bookings, cancellations, each call outcome, admin alerts, EODs by role, speed to lead and more), and the server's channels. A pasted webhook shows by its label only, never its address. Owners and admins, as in Settings, Connections, Discord. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `plan_discord_routing`

**Plan Discord routing**

Plans which channel each PYLO event posts to, or none, as one plan that apply_plan carries out after a person approves it. A channel is named by its id or its name and must be in this workspace's own connected server. A webhook address is never planned. Nothing is posted by the plan. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `routes` | array | yes | Each { event, channel: its id or name, label? } or { event, clear: true }. Events as get_discord_routing lists them. |

### `plan_eod_cutoff`

**Plan the EOD cutoff**

Plans when a rep's end of day counts as late, to the minute (23:59 included), read in the workspace's own time zone, as one plan that apply_plan carries out after a person approves it. hour null clears it, and PYLO's default of 19:00 applies. Owners, admins and ops, as in the app. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `hour` | number | yes | 0 to 23. Send null to clear the cutoff. |
| `minute` | number | no | Optional. 0 to 59 past the hour. Default 0. |

### `list_workflows`

**Messaging workflows**

Every messaging workflow in the workspace: its state (draft, shadow, live or paused), its trigger, its published version and how many contacts are active, waiting, done or stopped, with texts and emails sent in the last 7 days. Also the starters plan_workflow can begin from (booked call reminders, webinar registrant, no-show, no-close, payment failed, speed to lead). PYLO sends email and SMS only through a workflow a person published. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_workflow`

**One messaging workflow**

One workflow: its draft document, the problems that stop it being saved, what blocks publishing it live (an account not ready, an SMS link carriers filter), and per-step figures (delivered, opened, clicked, replied, bounced, unsubscribed, complained, failed, opted out), each rate with both of its counts. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `workflowId` | string | yes | The workflow's id or key, from list_workflows. |
| `days` | number | no | Optional. How many days the step figures cover, 1 to 90. Default 30. |

### `get_workflow_run`

**A contact's path through a workflow**

With enrollmentId, one contact's run: every send with its status and reason, every wait, branch and goal, and the replies and email events, in time order. With workflowId, that workflow's runs (status filters active, waiting, done or stopped). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `enrollmentId` | string | no | Optional. One run's id. |
| `workflowId` | string | no | Optional. The workflow's id or key, to list its runs. |
| `status` | string | no | Optional. active, waiting, done or stopped. |
| `limit` | number | no | Optional. Up to 500 runs. Default 100. |

### `list_senders`

**List the senders**

Every way this workspace sends, in one list: email senders (PYLO sending, the client's own SES or SMTP, and any other From address on the same domain), phone numbers (PYLO's or the client's own Twilio) and WhatsApp. Each row has its id (acct:, num: or extra:), channel, address or number, country, display name (what its texts sign as and what {sender_name} fills, never the owner's name), owner, status, today's cap (the account's, shared by its senders) and use, warm-up day, health, and what it may send (one to one, sequences, broadcasts). Then the sender pools: each one's channel, rule (sticky: each lead keeps one sender; country: by the lead's country; owner: by the lead's owner) and members, and what is not set up yet. Reps' own Gmail and Outlook mailboxes are listed too (mbx:, owned by the rep who connected them, with their own daily cap), so a lead's owner's email goes from their own inbox. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `list_suppression`

**List the suppression list**

The workspace's one email suppression list, which every email checks before it goes, from any sender (PYLO sending, the client's SES or SMTP, a rep's own Gmail or Outlook): addresses, whole domains (@domain) and leads, each with why (hard bounce, spam complaint, unsubscribed or replied asking to stop, added by a person) and when. Read only: a person adds to it, or imports opt-outs from Leadey, Close or GoHighLevel, on the Senders page. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `limit` | number | no | Optional. Up to 500 entries, newest first. Default 100. |

### `plan_senders`

**Plan sender and pool changes**

Changes who a lead hears from, AS A PLAN a person approves (apply_plan after request_plan_approval): senders (a sender's display_name, allowed_uses one_to_one, sequences and broadcasts, country, owner as a team member id, health ok, at_risk or paused to rest it), add (another From address on the email account's own sending domain, or another number on the client's own Twilio; a free-mail address is refused because it fails DMARC, and a PYLO number is bought by a person in Messaging, Setup), and pools ({ key, name, channel, rule sticky, country or owner, members: sender ids or { sender, country, owner } }). A sequence step via PYLO names a pool, or the sequence names one per channel. Basic keeps 2 pools of up to 3 senders; Pro has no limit. Never buys, pays, gives OAuth consent or sends. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `senders` | array | no | Changes to senders: [{ sender: "num:...", display_name, allowed_uses, country, owner, health }]. |
| `add` | array | no | Senders to add: [{ account: "acct:...", address }]. |
| `pools` | array | no | Pools to make or change: [{ key, name, channel, rule, members }]. Never deleted by a plan. |

### `get_number_bundles`

**Read the number bundles**

The workspace's regulatory bundles for numbers outside the US (UK mobile numbers first): each one's country and number type, status (draft, submitted, in review, approved, rejected), what the form still needs before a person can submit it, the reviewer's reason on a rejection, and the documents added (a business needs none for a UK mobile). The representative's phone and email show only as given or not. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `plan_numbers`

**Plan a bundle and a number outside the US**

AS A PLAN a person approves: bundles prefills a bundle's form ({ country: "GB", number_type: "mobile", legal_name, registration_authority (the business's own register, such as the Corporate Affairs Commission), registration_number, website, address { street, city, region, postal_code, country } anywhere in the world, authorized { first_name, last_name, email (work), phone (a real mobile) }, classification direct or isv_reseller, end_customers true or false }). PYLO files as an ISV or reseller assigning numbers to end customers by default. It never submits: a person checks the form and presses Submit in Messaging, Setup. numbers buys a number with its APPROVED bundle ({ country, type: mobile, number?, contains? }), paid from credits, so a person approves it; it is blocked without an approved bundle or enough credits. Basic keeps 1 number outside the US; Pro has no limit. A UK lead's texts then go from the UK number. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `bundles` | array | no | Bundle forms to prefill: [{ country, number_type, legal_name, registration_authority, registration_number, website, address, authorized, classification, end_customers }]. |
| `numbers` | array | no | Numbers to buy: [{ country: "GB", type: "mobile", number?, contains? }]. |

### `get_outreach_domains`

**Read the outreach domains**

Each outreach domain of this workspace: bought for outreach or a sending subdomain of the client's own domain, its status (bought, waiting for DNS, authenticated, sending), every DNS record (SPF, DKIM, DMARC, return path) with its own status from the last lookup and what to fix, and each mailbox's warm-up day and today's cap (14 days, 20 to 100 bulk emails a day). ideas are name ideas from the workspace's own domain; check: [names] reads the price and availability of up to 10 from Cloudflare Registrar. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `check` | array | no | Optional. Up to 10 domain names to price and check for availability. |

### `plan_outreach_domain`

**Plan an outreach domain**

Sets up a separate domain to send outreach from, AS A PLAN a person approves (apply_plan after request_plan_approval). buy true buys domain for a year on the workspace's Cloudflare account (a money line: a person approves the price, PYLO checks it again before paying and never pays more; max_price_minor caps it). buy false uses a sending subdomain (subdomain, default mail) of the client's own domain, and PYLO only ever adds records on that subdomain: the apex, the website and the everyday email (MX) are never touched, and nameservers are never moved. Then SPF, DKIM, DMARC and the return path are written one record at a time (add only; without Cloudflare each is shown to add by hand), each is checked by DNS lookup, and once the domain is authenticated its mailboxes ([{ address, display_name }]) switch on with a 14-day warm-up the guard enforces per mailbox. Basic keeps 1 outreach domain; Pro has no limit. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `domain` | string | no | The domain to buy (getyourbrand.com), or the client's own domain (yourbrand.com). |
| `buy` | boolean | no | true to buy it; false (default) for a sending subdomain of the client's own domain. |
| `subdomain` | string | no | Optional, own domain only. The sending subdomain's label. Default mail. |
| `max_price_minor` | number | no | Optional, buy only. The most to pay for a year, in cents. |
| `mailboxes` | array | no | Mailboxes on the domain: [{ address: "jane" or "jane@getyourbrand.com", display_name }]. Up to 5. |

### `get_messaging_health`

**Messaging health**

The workspace's SMS, email and WhatsApp accounts and their checks (Twilio number and A2P registration, SES production access, DKIM, DMARC, the footer address), today's sends against the ramp's daily cap, SMS quality over 7 days (opt-outs and carrier filtering), email domain health, bounces, provider blocks and complaints, every warning, restriction and block, and the WhatsApp sender (whatsapp: connected and ready, its number and display name, Meta's status in words, and the 24-hour window and template rules). Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_wallet`

**Credits (older name)**

The older name for get_credits, kept so existing agents keep working. The workspace's prepaid credits, used by numbers and email PYLO provides (managed mode), AI, calls and recording: the balance in the wallet's own currency (never converted), auto-recharge and the saved card's brand and last four digits, whether managed mode can run here and why not, whether sending is paused for balance, and spend over the last days by kind (texts, carrier fees, emails, number rentals, A2P fees), by workflow and by day. Read only: no tool tops up, buys or releases anything. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `days` | number | no | Optional. How many days the spend covers, 1 to 365. Default 30. |

### `get_credits`

**Credits**

The workspace's credits: its one prepaid balance for everything usage-based (texts, email and numbers PYLO provides, AI generation the workspace pays for, call minutes, recording, transcription and storage), in the wallet's own currency (never converted). Also auto-recharge, each feature and whether it is paid from credits or included (PYLO pays) and why, what uses credits, and spend over the last days by kind, by feature and by day. get_wallet is the older name for the same balance. Read only: no tool tops up or changes which features are paid. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `days` | number | no | Optional. How many days the spend covers, 1 to 365. Default 30. |

### `get_rate_card`

**Messaging rate card**

What PYLO charges for managed messaging in the wallet's currency: each SMS segment, MMS, carrier fees and A2P fees (at cost), numbers a month, email per 1,000, deep verification, number checks and a dedicated IP. Each price is exact (a part of a cent is kept) with the words for it. A currency whose card is not set yet says so. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `list_conversations`

**Messaging conversations**

The two-way inbox: one conversation per contact, newest first, with the last text or email in or out, how many are unread, who on the team it is assigned to, and whether the contact is on do-not-disturb for texts or email. Filter all, unread, unassigned, or waiting: the saved view "Replied, waiting on us, oldest first" (the contact wrote last and nobody answered or marked it done, the longest wait first, each with waitingSince). Or search by name, phone or email. Read only: no tool sends a message. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `filter` | string | no | Optional. all (default), unread, unassigned, or waiting (replied, waiting on us, oldest first). |
| `q` | string | no | Optional. A name, phone or email to search for. |
| `cursor` | string | no | Optional. The next value from the page before. |
| `limit` | number | no | Optional. Up to 100. Default 50. |

### `get_conversation`

**One messaging conversation**

One contact's thread: every text and email in and out, in time order, each with its status and the reason when it did not go, the workflow and step that sent it, its attachments, and which message a reply answered. Read only: a team member replies in the app, and no tool sends a message. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `conversationId` | string | yes | The conversation's id, from list_conversations. |

### `list_chats`

**Team chats**

The team chats you are in, as in the app: the all-team group, and the groups and direct messages you are a member of, each with its members, its last activity and how many messages it holds. Other people's direct messages are never shown; a workspace or agency token reads the all-team group only. Owners and admins only: a rep's agent is refused. Read only: no tool posts in chat. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_chat_thread`

**One team chat**

One team chat's messages, newest page first: who wrote each, when, edits and deletes, reactions, the people mentioned, and each mentioned lead, call, payment or booking as a card with its key data. Only a chat you are in, or the all-team group. Owners and admins only. Read only: no tool posts, edits or reacts in chat. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `chatId` | string | yes | The chat's id, from list_chats. |
| `before` | number | no | Optional. Messages before this seq, for older pages. |
| `limit` | number | no | Optional. Up to 100. Default 50. |

### `list_booking_event_types`

**Booking event types**

Every native booking event type in the workspace: its length, buffers before and after, start-time interval, minimum notice, booking window, daily limit per host, round robin or collective, the hosts with their priority and weight, the location (Google Meet, Zoom, phone or custom), its status (draft, live or off), what stops it going live, and its link and embed snippets. Also each team member's Google Calendar state. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_booking_availability`

**Booking availability**

The start times one event type offers right now, grouped by day in a time zone, with which hosts are free for each, after minimum notice, the booking window, buffers, holidays, daily limits, PYLO's own bookings and each connected host's Google busy times. Also each host's weekly hours. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventTypeKey` | string | yes | The event type's key, from list_booking_event_types. |
| `from` | string | no | Optional. ISO date or time to start from. Default now. |
| `to` | string | no | Optional. ISO date or time to end at. Default two weeks on, at most 62 days. |
| `timezone` | string | no | Optional. An IANA zone like America/New_York to group the days in. |

### `list_bookings`

**Native bookings**

Bookings made on PYLO's own booking pages: who, when, the host, the answers, the UTMs, the lead and call they filed, and whether the Google Calendar write, the intake and the emails went through. Each is also a call in list_calls, like every Calendly or iClosed booking. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `view` | string | no | Optional. upcoming (default), past or all. |
| `status` | string | no | Optional. confirmed, cancelled or disqualified. |
| `hostId` | string | no | Optional. A host's team member id. |
| `eventTypeKey` | string | no | Optional. One event type's key. |
| `limit` | number | no | Optional. Up to 500. Default 50. |

### `plan_booking_event_type`

**Plan a booking event type**

Plans a native booking event type, made or changed, and set to draft, live or off, as one plan that apply_plan carries out. Give key to change an existing one, or name and a starter (funnel: 45 minutes plus 15 after, 3 days ahead, capital confirmed; dm_setting; dialling: no limit ahead, 1 hour's notice; blank) for a new one. changes holds any fields to set: durationMinutes, bufferBeforeMinutes, bufferAfterMinutes, slotIntervalMinutes, minNoticeMinutes, window { kind: rolling, days, businessDays | indefinite | range }, dailyLimitPerHost, assignment (round_robin or collective), hosts [{ memberId, priority 1 to 5, weight 1 to 100 }], sameHostOnReschedule, location, phone, questions (choices can disqualify), disqualify { url, message }, redirect { url, passDetails }, funnel, quality. No tool books, moves or cancels a call. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | no | Optional. An existing event type's key, or the key for a new one. |
| `name` | string | no | Optional. The name, required for a new one. |
| `starter` | string | no | Optional, for a new one. funnel, dm_setting, dialling or blank. |
| `changes` | object | no | Optional. Fields to set on the event type. |
| `status` | string | no | Optional. draft, live or off. Default: unchanged, or draft for a new one. |

### `list_booking_partials`

**Unfinished bookings**

People who started booking on a PYLO booking page and stopped, like iClosed's Potential and Qualified Contacts: they typed an email or phone, did not book, and were quiet ten minutes. Each: the link, how far they got (started, questions_done, time_picked), the time they picked, their answers so far, the source, when last active, and the lead made for them (tagged booking_partial). Also each link's funnel over the last days: views, started, questions done, time picked and booked, each rate as its two counts. Someone who books after leaves the list. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventTypeKey` | string | no | Optional. One link's key. |
| `days` | number | no | Optional. How far back the funnel reads, 1 to 90 days. Default 30. |
| `limit` | number | no | Optional. Up to 500. Default 100. |

### `list_webhooks`

**Outgoing webhooks**

Every outgoing webhook in the workspace: its name, the receiving host and the last four characters of its address (never the address or its secret), its status (active, paused, or paused by PYLO after three deliveries in a row gave up), the recipes that send to it, its last delivery and 7 day counts by status. Also how many recipes still post to a plain URL. A recipe decides when a webhook is used: trigger booking, reschedule, cancellation, booking_partial, outcome, payment, lead_intake, form_submitted or tag_added, with conditions such as event_type_key, and the action { type: "webhook", webhook_id }. Owners and admins. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_webhook_deliveries`

**Webhook deliveries**

Deliveries for one webhook or one event (booking.created, booking.rescheduled, booking.cancelled, booking.partial, booking.partial_recovered, call.outcome, payment.succeeded, payment.failed, lead.created, form.submitted, tag.added): status (pending, delivered, failed and will retry, gave_up, shadow), attempts, the last status code and a sentence for the last error, never the receiver's body. The payload only with includePayload, kept 14 days. Owners and admins. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `webhookId` | string | no | Optional. A webhook's id, from list_webhooks. |
| `name` | string | no | Optional. A webhook's name, instead of its id. |
| `event` | string | no | Optional. One event, like booking.created. |
| `status` | string | no | Optional. pending, delivered, failed, gave_up or shadow. |
| `includePayload` | boolean | no | Optional. True to include each payload. |
| `limit` | number | no | Optional. Up to 200. Default 50. |

### `plan_webhook`

**Plan an outgoing webhook**

Plans an outgoing webhook made (by name, with no address yet), renamed, paused or resumed, or its signing secret rotated (the old one keeps signing for 24 hours), as one plan that apply_plan carries out. Never takes an address: send a drop link with create_webhook_drop. A webhook sends nothing until a live recipe uses it. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `name` | string | yes | The webhook's name, like VSL bookings. Matched exactly. |
| `renameTo` | string | no | Optional. A new name. |
| `status` | string | no | Optional. active or paused. |
| `rotateSecret` | boolean | no | Optional. True for a new signing secret, seen once in the app. |

### `create_webhook_drop`

**Webhook address drop**

A one-time link, for 30 minutes, where the operator pastes the address their automation gave them (a Zapier Catch Hook, a Make custom webhook, an n8n Webhook node) for one webhook, so it never passes through the chat. The webhook must exist first (plan_webhook). Owners and admins. Needs connect:links.

Changes PYLO. Needs a token with the `connect:links` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `webhookId` | string | no | Optional. A webhook's id, from list_webhooks. |
| `name` | string | no | Optional. A webhook's name, instead of its id. |

### `send_test_webhook`

**Send a test webhook**

Posts one sample of an event to one webhook now, marked test: true, with a made-up person (Test Lead, test@example.com, +15555550100) and made-up answers under the workspace's real event type keys and question labels, so a Zapier, Make or n8n step can map every field. Answers with the status code. Tried once more at most. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `webhookId` | string | no | Optional. A webhook's id, from list_webhooks. |
| `name` | string | no | Optional. A webhook's name, instead of its id. |
| `event` | string | no | Optional. Which event's sample. Default booking.created. |

### `retry_webhook_delivery`

**Send a webhook delivery again**

Sends one failed or given-up delivery again now, with its original payload and delivery id, so a receiver that drops repeats still can. A payload older than 14 days cannot be sent again. Owners and admins. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `deliveryId` | string | yes | The delivery's id, from get_webhook_deliveries. |

### `list_dialler_calls`

**Dialler calls**

Calls made and taken in PYLO's own dialer: the rep, the lead, how each ended (answered, no answer, busy, voicemail by answering machine detection), how long, the rep's disposition, notes, a callback's time, and whether it was recorded and why (the lead's state or country decides; the disclosure plays first where the law needs it). A rep's agent sees only their own calls. Read only: no tool places, ends or drops a call. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `days` | number | no | Optional. How far back, 1 to 90 days. Default 7. |
| `leadId` | string | no | Optional. One lead's calls. |
| `teamMemberId` | string | no | Optional, managers only. One rep's calls. |
| `direction` | string | no | Optional. outbound or inbound. |
| `limit` | number | no | Optional. Up to 200. Default 50. |

### `get_dial_queue`

**Power dial queue**

The power dial sessions running now: each rep's queue (from a saved view, filters or a list), how many are dialled and left, the next leads, and every lead skipped with the reason (do not call, do not disturb, outside the lead's calling hours, the law's three-in-24-hours limit, the workspace's cadence rules, no phone). A rep's agent sees only their own. Read only: no tool dials. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_dialler_setup`

**Dialler set-up**

Whether the workspace's dialer is set up (numbers from PYLO paid from credits, or the client's own Twilio), its numbers and which rep has each, and the settings in words: recording and the disclosure message, calling hours, local presence, custom dispositions, voicemail drop consent, the inbound ring group. Read only: setting up, buying numbers and changing settings are an owner's clicks in the app. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `list_dnc`

**Do-not-call list**

The workspace's own do-not-call list for PYLO's dialer: each number, the lead it belongs to, the reason, who put it on and when, newest first. The dialer skips these on every call, power dial and callback. includeLifted adds numbers taken off the list, with who lifted them and when. Read only: anyone adds a number in the app, and an owner or admin lifts one. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `includeLifted` | boolean | no | Optional. true to include lifted numbers. Default false. |
| `limit` | number | no | Optional. Up to 500. Default 500. |

### `get_call_recording`

**Call recording and notes**

PYLO's own recordings of a call: a dialer call (recorded in two channels, rep and lead apart) or a booked Google Meet or Zoom call (PYLO's note taker joined it). Each says where it is (saved, transcribing, ready, waiting for credits, not transcribed and why), who and how long, the summary, key points, objections, next steps and a sentiment line, whether the AI call review has it, how long the audio is kept, and what it cost in credits. Name a recordingId, a callId (a booked call), a diallerCallId or a leadId. A rep's agent reads only the rep's own calls; a closer's the booked calls they closed. Fathom's and other recorders' transcripts are read with get_call_analysis. Read only: no tool records, plays, downloads or deletes a recording. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `recordingId` | string | no | Optional. One recording. |
| `callId` | string | no | Optional. A booked call's recordings. |
| `diallerCallId` | string | no | Optional. A dialer call's recording. |
| `leadId` | string | no | Optional. Every recording of one lead's calls you may read. |
| `days` | number | no | Optional, with leadId. How far back, up to 365 days. Default 365. |
| `limit` | number | no | Optional. Up to 200. Default 20. |

### `get_call_transcript`

**Call transcript**

One PYLO recording's transcript, each line with its time, Rep or Lead, and the speaker's name, or only the lines matching a search (query). Role checked as get_call_recording. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `recordingId` | string | no | The recording (get_call_recording lists them). |
| `query` | string | no | Optional. Words to find; only the matching lines come back. |
| `limit` | number | no | Optional. Lines to return, up to 2000. Default 800. |

### `list_call_recordings`

**Call recordings**

PYLO's own recordings across calls, newest first, each as get_call_recording shows it (status, rep, lead, length, the summary and notes, the AI review hand-off, retention and credits) without the transcript. Filter by status, kind (dialler or meeting), since, lead and rep. Who sees what is checked as in the app: owners, admins and ops see dialer calls, owners and admins booked calls, and anyone else only their own. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `status` | array | no | Optional. Any of scheduled, in_call, queued, waiting_credits, stored, transcribing, transcribed, ready, skipped, failed, cancelled, expired, deleted. |
| `kind` | string: dialler, meeting | no | Optional. Dialer calls or booked video calls. |
| `since` | string | no | Optional. An ISO date or time, up to a year back. Default: the last days. |
| `days` | number | no | Optional, without since. How far back, up to 365 days. Default 30. |
| `leadId` | string | no | Optional. One lead's recordings. |
| `teamMemberId` | string | no | Optional, managers only. One rep's recordings. |
| `limit` | number | no | Optional. Up to 200. Default 50. |

### `get_recorder_settings`

**Recorder settings**

How the workspace records calls: for each call type (dialer calls, calls booked on PYLO, calls booked through Calendly) whether PYLO, Fathom, another recorder or nobody records it, how long recordings are kept, whether the provider's own copy is kept after PYLO's is verified, the note taker's name and the disclosure line in the booking email, what this server can do (transcription, the meeting bot), and a warning where a call would be recorded twice. Owners and admins. Read only: changed in the app. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `list_pages`

**Landing pages**

The workspace's landing pages built in PYLO: name, address (the PYLO address, the workspace subdomain when set up, and each connected custom domain), status (draft or published, and whether the draft has unpublished changes), the template it started from, its goal (a form submission, a booking, or none), whether a split test runs, and the last 30 days: views, unique visitors and conversions to the goal with the rate. Also the templates a page can start from. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_page_stats`

**Landing page figures**

One page's views, unique visitors, conversions to its goal and the conversion rate with both counts (null when no one visited), by source (UTM source, then click id, then the referring site, else direct), by campaign, by split test variant and by day, and the split test's verdict: too early (each version needs 100 unique visitors), no clear winner, or a winner at 95% confidence. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `pageId` | string | no | The page's id, from list_pages. |
| `slug` | string | no | Optional, instead of pageId: the page's address. |
| `days` | number | no | Optional. 7, 30 or 90. Default 30. |
| `timezone` | string | no | Optional. An IANA zone for the days. Default UTC. |

### `get_page_setup`

**Landing page setup**

What every landing page is built on: the brand kit (logo, colours, fonts, button style and any contrast warning), which offer details PYLO's AI writes from are filled, the tracking (the Meta pixel id, whether the Conversions API is on), the home page, and each custom domain with its status (active or pending, and why). No DNS verification value or other secret is shown. Owners and admins, as in the app. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_funnel_tracking`

**Ads funnel tracker**

The workspace's ads funnel from its own pages, counted per visitor by PYLO's capture snippet and Tally's webhook: landing page visitors, how many clicked the opt-in, how many left at the opt-in without submitting, how many submitted, reached the confirmation page, stayed on it at least staySeconds (default 30) and left it sooner, with drop-off between steps, median time on page per step, and the same split by utm_source, utm_campaign, utm_content and Meta ad (the ad_id parameter, or utm_content matching one ad's id or name), with spend, cost per landing visitor and cost per opt-in where ad spend is stored. A step the funnel has never sent is null with the reason and what to set up, never zero. Also the script line for each step and the Tally webhook address. Owners, admins and ops. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `funnel` | string | no | Optional. The funnel's name from data-pylo-funnel. Default "default". |
| `staySeconds` | number | no | Optional. Seconds on the confirmation page that count as stayed, 5 to 600. Default 30. |

### `plan_page`

**Plan a landing page**

Plans a landing page made, or its draft changed, as one plan that apply_plan carries out. Give slug of an existing page, or name (and optionally template: opt_in, application, booking, confirmation, thank_you, webinar_registration, webinar_replay) for a new one. sections replaces the draft's sections: a list of { type, variant, content } where type is hero, vsl, proof, features, about, faq, breakouts, steps, form, booking, countdown, pricing, guarantee or footer (custom HTML is never planned); text is plain, links https, videos YouTube, Vimeo, Wistia, Loom or Vidalytics. goal is { kind: form | booking | none, key }. Applying saves a draft: it never publishes, and a published page keeps serving until a person publishes the draft in the app. Never invent results, prices or guarantees; leave a [bracketed prompt]. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `slug` | string | no | Optional. An existing page's address, or the address for a new one (made from the name otherwise). |
| `name` | string | no | Optional. The page's name, required for a new one. |
| `template` | string | no | Optional, for a new page. One of the templates list_pages names. |
| `sections` | array | no | Optional. The draft's sections, in order. |
| `goal` | object | no | Optional. { kind: form \| booking \| none, key: a form or event type key, or null for any }. |

### `plan_form_from_link`

**Plan a form from a link**

Reads a public form link (Typeform, Tally, Jotform, Google Forms or Fillout) on PYLO's server, with no sign in, maps every question to PYLO's types (short and long text, email, phone, single and multi choice, dropdown, number, money, date, yes or no, rating, consent, link; statements become help text), with choices, required flags, descriptions, the welcome and thank-you text and the jumps that map cleanly, and makes a plan that saves it as a DRAFT form. The answer lists what could not be carried, each with why: show it to the operator. Nothing takes applications until a person publishes it in the app. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `url` | string | yes | The form's public link, as a lead would open it. |
| `title` | string | no | Optional. The PYLO form's name; the form's own title otherwise. |

### `plan_booking_event_from_link`

**Plan an event type from a booking link**

Reads a public scheduling link (Calendly, Cal.com, or a GoHighLevel booking widget) on PYLO's server the way the provider's own page does, and plans a DRAFT PYLO event type with its name, length, description, location, time zone and invitee questions (types, required flags and choices). Hosts and availability are not on a public page: the operator sets them in the app before making it live. The answer lists what could not be carried. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `url` | string | yes | The booking page's public link. |
| `name` | string | no | Optional. The event type's name; the provider's otherwise. |

### `plan_page_from_link`

**Plan a landing page from a reference link**

Reads a reference landing page on PYLO's server and plans a DRAFT PYLO page from it. rights is required: true ONLY when the operator says the page is theirs or they have the rights to use its content; then its words are kept and its images copied into PYLO. Otherwise only the structure and section order are used, every word is written from the workspace's own brand kit and offer, and images, logos and testimonials are placeholders; never another company's logos, testimonials or trademarks. Writing uses PYLO's AI from the workspace's credits: without spend: true it answers only with the page's outline, using no credits. Applied, the page is a draft a person publishes in the app. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `url` | string | yes | The reference page's link. |
| `rights` | boolean | yes | True only when the operator confirms the page is theirs or they have the rights to its content. Ask them. |
| `name` | string | no | Optional. The new page's name. |
| `spend` | boolean | no | True to write the page with PYLO's AI from the workspace's credits, once the operator agrees. |

### `plan_workflow`

**Plan a messaging workflow**

Makes a plan that saves a workflow and, if asked, publishes it in shadow (enrolls contacts and records what it would send, sending nothing) or live. Start from a starter (template: booked_call, webinar_registrant, no_show, no_close, payment_failed, speed_to_lead), an existing workflow (workflowId, to publish its draft), or a whole document (workflow: { key, name, trigger, settings, steps }). Nothing changes until apply_plan runs it. A live workflow messages people, so a person approves the plan by code first, and it is blocked while the accounts it needs are not ready. PYLO sends only through a published workflow a person approved; no tool sends a single message. Its forecast lists every send with its sender, time in the contact's zone and cost, and each one held or blocked by a gate (consent, frequency, sender cap, window, balance, sender health, reach, live switches) with the reason; anything its own settings would hold back is refused before anyone approves. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `template` | string | no | Optional. A starter's key. |
| `workflowId` | string | no | Optional. An existing workflow's id or key: its draft is what is planned. |
| `workflow` | object | no | Optional. A whole workflow document instead of a starter. |
| `key` | string | no | Optional, with a template. The new workflow's key. |
| `name` | string | no | Optional, with a template. Its name. |
| `publish` | string | no | draft (default), shadow or live. |

### `list_broadcasts`

**Messaging broadcasts**

Every broadcast in the workspace (a one-off text, email or WhatsApp template to an audience): its status (draft, scheduled, sending, testing, paused, done, cancelled or stopped), when it went or goes, how many it was for and how many it went to, and the A/B winner. Read only: no tool sends a broadcast. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_broadcast`

**One messaging broadcast**

One broadcast: its audience, message, A/B test and window, the estimate (days, per day, finish), who was left out and why, the credits it holds, and its stats: recipients by status, delivered, opened, clicked, replied, bounced, complained, unsubscribed and opted out, each rate with both counts, per variant. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `broadcastId` | string | yes | The broadcast's id, from list_broadcasts. |

### `list_message_templates`

**Message templates**

The workspace's template library for texts, email and WhatsApp (with Meta's approval status), the starters PYLO offers in the niche's voice, and the merge fields a template may use. Workflows, broadcasts and the inbox copy a template's words when one is chosen. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `channel` | string | no | Optional. sms, email or whatsapp. |
| `archived` | boolean | no | Optional. true to include archived templates. |

### `get_message_template`

**One message template**

One template: its words, the merge fields it uses, how often it was sent in 30 days, and for WhatsApp its name, category, language, Meta's status and any rejection reason. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `templateId` | string | yes | The template's id or key, from list_message_templates. |

### `list_contact_lists`

**Contact lists**

The uploaded contact lists a broadcast can go to: each list's name, how many people are on it, who uploaded it and when, and the consent attested on upload (the channels, the wording people agreed to, who attested it and when). Counts only: no one's name, email or phone. Owners and admins, as in the app. Read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `plan_broadcast`

**Plan a messaging broadcast**

Makes a plan that sends one message to an audience, now or at a set time: leads with a tag, in a pipeline stage, matching custom field filters, or an uploaded list. Text (body), email (1 subject, or 2 to 3 for an A/B test picked by opens or clicks after a set time) or an approved WhatsApp template. The plan shows the count, who is left out and why (no consent, do-not-disturb, no address), the days it takes under the daily limits, and the credits it costs a managed account. Nothing is sent until a person approves and apply_plan runs it; above the workspace's send guard limit the approval is in the app, and a changed audience is refused. No tool sends a message. The preview's forecast lists every send with its sender, time in each contact's zone and cost, and each one held or blocked by a gate (consent, frequency, sender cap, window, balance, sender health, reach, live switches) with the reason; a broadcast its own settings would hold back is refused before anyone approves. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `broadcast` | object | no | Optional. { name, channel: sms\|email\|whatsapp, audience: { kind: tag\|stage\|fields\|list, tags?, tagMode?, pipeline?, stage?, fields?: [{ key, op, value }], listId?, excludeTags? }, content: { channel, body? \| subjects?, html?, preheader? \| templateId? }, ab?: { metric: opens\|clicks, testPercent, decideAfterMinutes }, window?: { start, end, days }, timeZone?: contact\|workspace, sendAt? }. |
| `broadcastId` | string | no | Optional. A draft broadcast's id instead of a whole document. |

### `list_procedures`

**SOP procedures**

Every SOP procedure the agency runs, by folder (onboarding, backend, webinar, sales): PYLO's generic starters and the agency's own, which replace a starter of the same key. Each is an SOP's runnable companion: its SOP numbers, its steps and how each runs (by API, snapshot, browser, drafted or by a person), and the PYLO tool it runs as, if any. The SOPs' own text stays the agency's and is read only. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `folder` | string: onboarding, backend, webinar, sales, traffic | no | Optional. One folder. |

### `get_procedure`

**An SOP procedure**

One procedure, whole: its inputs, its steps each linked to a PYLO tool, a register capability, a content template or a person, its checks from the SOP's QA list, its failure checks, and the SOP conflicts it depends on. With a workspaceId, also that workspace's value for each conflict (its own setting or PYLO's default, with both SOPs cited) and the procedure's recent runs there. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | The procedure's key, from list_procedures. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_sop_coverage`

**How much of the SOPs PYLO runs**

Per SOP and per procedure, how many steps run by API, snapshot or browser, as drafts, or as person steps, and how many are not covered yet; the uncovered steps are the backlog. Also the SOP conflicts PYLO turns into workspace settings, with both sources and the proposed default. Needs read.

Changes PYLO. Needs a token with the `read` scope.

No arguments.

### `ask_sops`

**Ask the SOPs**

"How do we do X", answered from the procedures and, with a workspaceId, the workspace's own SOP documents that the asker may see, each passage cited by procedure, step and SOP number, or by document. Quote the passages; never reword them into a rule they do not say. For operators and reps alike. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `question` | string | yes | The question, in the person's words. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `run_procedure`

**Run an SOP procedure**

Turns a procedure into a plan through the same tools and register as doing it by hand. A procedure that IS one of PYLO's planners runs as it ("run the relaunch SOP for Thursday" makes the same plan as plan_event_relaunch). Otherwise its capability steps become one plan_tool_task plan, the register picking each line's method, all its steps a dated launch plan with owners, and its PYLO tool steps and drafts come back as the calls to make next, in order. A missing input comes back as a question and nothing is planned. Nothing applies until a person approves each plan. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `key` | string | yes | The procedure's key, from list_procedures. |
| `params` | object | no | The procedure's inputs by key (get_procedure lists them), e.g. { eventId, startsAt, timezone, joinUrl }. Never a key or password. |

### `save_procedure`

**Save the agency's own procedure**

Saves an agency's own procedure as a new version (nothing when it did not change): its key, title, folder, SOP numbers, inputs, steps (each with a method and what does it: tool, capability, content { purpose, kind } or person), checks, failure checks and settings. Saved under a starter's key it replaces that starter for this agency. It holds references to the SOPs, never their text: a document carrying SOP text is refused, and PYLO never edits the SOPs themselves. Needs config:plan and an agency token.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `procedure` | object | yes | The whole procedure, as get_procedure returns it. |

### `get_contact_checks`

**A lead's checks before sending**

A lead's checks before sending, for its current number and email: the line type (mobile, landline, VoIP, toll-free), whether a UK number is on the TPS or CTPS register, and whether the email can take mail (syntax, throwaway and role addresses, the domain's mail server). Each has its answer, what it leaves the lead out of (a landline gets no texts, a TPS number gets no marketing texts and is skipped by the power dialer, a dead address gets no email), when it was checked and when it expires, and the credits a lookup cost. A check PYLO could not run, such as no credits for the lookup, says not checked and why, never clear. Read only: no tool runs a paid lookup. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | The lead's id. |

### `get_affiliate_funnel`

**Affiliate funnel**

One affiliate funnel for a period: opt-ins and opt-in people, sales logged, signups pending, retained and reversed, the yearly share, retention and opt-in to signup with both sides, the program's commission per currency, ad spend, cost per opt-in and per signup from ads and blended, return on spend where the currencies match, opt-ins by source, every ad's figures, signups reported in EODs but not logged, and how fresh each source is. EOD counts are reports, never signups. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `member` | string | no | Optional. One rep's team member id. |

### `get_affiliate_overview`

**Every affiliate funnel**

Every affiliate workspace this token can see, each with its figures and its sales portal link, plus totals: counts add, rates are worked out from the summed sides, money stays per currency. An agency token sees every one in the agency. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |

### `list_affiliate_sales`

**Affiliate sales**

Sale records, newest first, each with its rep, how it happened, the plan, its status (reported, confirmed, retained, reversed, checked by a person, void), how it matched an opt-in and the source the rep reported. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `rep` | string | no | Optional. One rep. |
| `status` | string: reported, confirmed, retained, reversed, checked, void | no | Optional. |

### `list_unmatched_signups`

**Signups to link**

What a manager links by hand: signups from the program with no sale record, sales with no signup from the program, EOD signup counts with no records behind them, and signups where the Shared ID names a different rep. Needs read.

Changes PYLO. Needs a token with the `read` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |

### `log_affiliate_sale`

**Log an affiliate sale**

Logs one signup on an affiliate funnel: the buyer, the sale date, how it happened (booked_call, dial, after_call, dm or alone), monthly or yearly, the source the rep reported and a screenshot link. A rep logs their own with forms:self; an owner, admin or ops member logs one for anyone. An agency token proposes it with propose_form_draft (kind affiliate_sale) for the rep to file. The same buyer logged twice is one record. Needs forms:self.

Changes PYLO. Needs a token with the `forms:self` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `buyerName` | string | no | The buyer's name. |
| `buyerEmail` | string | no | The buyer's email. |
| `buyerPhone` | string | no | The buyer's phone. |
| `programEmail` | string | no | Optional. The email used on the program, when it differs. |
| `saleDate` | string | no | YYYY-MM-DD, when the buyer signed up. Defaults to today. |
| `how` | string: booked_call, dial, after_call, dm, alone | no | How it happened. |
| `cadence` | string: monthly, yearly | no | The plan. |
| `tier` | string | no | Optional. The plan's tier. |
| `reportedSource` | string: ads, instagram, youtube, tiktok, dm, referral, other | no | Where the rep says it came from. |
| `proofUrl` | string | no | Optional. An https link to the screenshot. |
| `callId` | string | no | Only for a sale on a booked call. |
| `repId` | string | no | Elevated callers only: the rep. |

### `match_affiliate_sale`

**Link a signup**

Ties one signup from the program (from list_unmatched_signups) to a sale record, a rep, or both. Recorded as a manual match; the sale then follows the program's state. Needs team:manage.

Changes PYLO. Needs a token with the `team:manage` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `actionId` | string | yes | The signup's id, from list_unmatched_signups. |
| `saleId` | string | no | Optional. The sale. |
| `repId` | string | no | Optional. The rep. |

### `plan_affiliate_import`

**Import the program's report**

Reads the affiliate program's Advanced Action Listing (CSV text) and says what it would do: rows, matches by sub ID and Shared ID, states and problems. Nothing is written unless apply is true, which needs config:apply. The report is downloaded by the operator; PYLO never logs into the program. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `csv` | string | yes | The CSV text. |
| `apply` | boolean | no | Write it. Needs config:apply. |

### `set_portal_link`

**Set the sales portal link**

Stores the client's own sales portal address (https) so the affiliate funnels view links to it. PYLO shows it and never fetches it. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace or member token may leave it out. |
| `url` | string | yes | The portal's https address, or empty to clear it. |

### `plan_webinar_event`

**Find or create a webinar session**

Finds the PYLO event for one webinar session, or plans creating it. With webinarId it looks for the WebinarJam key for that session, webinarjam:<webinarId>:<date>, the one the registration flow files under; otherwise it looks for an event of the same host starting within a minute of startsAt. A session is never created twice: when the same host already has an event that day, the answer names it instead (allowSameDay creates a second session on purpose). Nothing is written unless apply is true, which needs config:apply. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `startsAt` | string | yes | The session's start, ISO 8601 with its offset, for example 2026-09-02T18:00:00Z (7pm UK in summer time). |
| `timezone` | string | no | The zone the session is advertised in, for example Europe/London. It decides the session's date. Defaults to Europe/London. |
| `name` | string | no | Optional. Defaults to Webinar and the session's date. |
| `host` | string: webinarjam, everwebinar, zoom, aevent, manual | no | Where the session runs. Defaults to webinarjam. |
| `webinarId` | string | no | Optional. WebinarJam's webinar id. Stored as the event's host event id webinarjam:<id>:<date>. |
| `schedule` | string | no | Optional. WebinarJam's schedule id for the session, stored as the host session id. |
| `endsAt` | string | no | Optional. The session's end, ISO 8601 with its offset. |
| `pitchOffsetMinutes` | number | no | Optional. Whole minutes from the start to the pitch. |
| `mode` | string: live, evergreen, replay | no | Defaults to live. |
| `allowSameDay` | boolean | no | Create a second session on a day that already has one for this host. |
| `apply` | boolean | no | Write it. Needs config:apply. |

### `plan_attendance_import`

**Import a webinar attendee file**

Reads a webinar host's attendee export (CSV text, header row first) for one PYLO event and says what importing it would do: rows read and refused with the reason, registrations matched and to create, leads matched and new, attendees with a join time, no-shows, join times that would change, and the event's registrants and attendees before and after. It uses the app's own import, so a file the app accepts is read the same way. A header row it cannot read is refused, naming the columns it accepts. Nothing is written unless apply is true, which needs config:apply; a second run writes nothing. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `eventId` | string | yes | The PYLO event (session) the file belongs to, from plan_webinar_event, list_events or get_webinar. |
| `csv` | string | yes | The export's text, header row first. |
| `fillGaps` | boolean | no | Also write the Name column into a matched lead's empty name. Off by default, so a second run changes nothing. |
| `apply` | boolean | no | Write it. Needs config:apply. |

### `plan_webinarjam_import`

**Import a WebinarJam session**

Reads one past WebinarJam session's registrants and live attendance straight from WebinarJam, with the workspace's saved WebinarJam key (never shown, never passed), and says what importing them into that session's PYLO event would do, with the same counts as plan_attendance_import. Join and signup times are read in the webinar's own time zone. Pass webinarId, and schedule when the webinar has more than one. The event is found by its WebinarJam key or its start time, or named with eventId; when there is none, the answer gives the plan_webinar_event call that makes it. Nothing is written unless apply is true, which needs config:apply; a second run writes nothing. Needs config:plan.

Changes PYLO. Needs a token with the `config:plan` scope.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `webinarId` | string | yes | WebinarJam's webinar id. |
| `schedule` | string | no | Optional. WebinarJam's schedule id. Needed only when the webinar has more than one. |
| `eventId` | string | no | Optional. The PYLO event to file into. Found by the WebinarJam key or the start time when left out. |
| `timezone` | string | no | Optional. Overrides the webinar's own time zone, for example Europe/London. |
| `fillGaps` | boolean | no | Also write WebinarJam's name, phone and UTMs into a matched lead's empty fields. Off by default, so a second run changes nothing. |
| `apply` | boolean | no | Write it. Needs config:apply. |

## A member's own tools

### `pylo_my_board`

**My board**

Your own board: your figures for this month, the same ones PYLO shows you on My Board. Use it for questions about your own calls, closes and cash. It refuses anything about other members or the workspace as a whole.

No arguments.

### `get_metric_definitions`

**Metric definitions**

What PYLO's metrics mean, from the metric registry: the definition, the numerator and the denominator by name, the exclusions and the period rule. Use it before quoting a figure, to say exactly what it counts. Pass metric for one, prefix for a family (rate., cash., calls.), or neither for every declared metric. Never returns a value: get_metric does. Refuses an id the registry has not declared.

| Argument | Type | Required | Description |
|---|---|---|---|
| `metric` | string | no | One registry id, for example rate.show. |
| `prefix` | string | no | Every declared id starting with this, for example rate. |

### `search_docs`

**Search the help pages**

Searches PYLO's help pages at docs.pylosystem.com and returns the best matching pages, each with its title, url and summary. Use it for how-do-I questions, then read_doc the best one, and link the page in the answer.

| Argument | Type | Required | Description |
|---|---|---|---|
| `query` | string | yes | What the person is trying to do, in their words. |

### `read_doc`

**Read a help page**

Reads one of PYLO's help pages as markdown, by the url or path search_docs returned. Only pages on the help site can be read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `url` | string | yes | The page's url or path, from search_docs. |

### `whats_new`

**What is new in PYLO**

Every change to what an agent can do with PYLO, newest first, each with the tools to use. Tell the operator what they can now do. Optional since, YYYY-MM-DD, for changes after a day.

| Argument | Type | Required | Description |
|---|---|---|---|
| `since` | string | no | Optional. Only changes after this day, YYYY-MM-DD. |

### `explain_figure`

**Explain a figure**

What a figure means and where it is shown, from PYLO's metric registry: its definition, what it divides by, the benchmarks the knowledge base states beside it (and whether they are comparable), its caveats, why it can show as a dash, every screen and section it sits under, the help page that explains it, and whether its card on that screen has a Show explanation toggle. Use it for "what does this number mean", "why is this a dash" and "is this good". Name the metric by id, or the screen's route and section, or pass the member's words as query. Reads no workspace data.

| Argument | Type | Required | Description |
|---|---|---|---|
| `metric` | string | no | A metric id, e.g. rate.show. get_metric_definitions lists them. |
| `page` | string | no | The app route the member is on, e.g. /dashboard or /funnel. |
| `section` | string | no | The section heading on that screen, as it shows it, e.g. Sales activity. |
| `query` | string | no | The member's own words for the figure, when there is no id. |

### `propose_form_draft`

**Draft a form**

Proposes a post-call, DM close, past call or end of day form, filled in, for a member to review and file themselves. It never files the form, and it refuses any money figure: cash is for the member to enter. A post-call draft names its call. A closer, setter or SDR drafts only for themselves. Needs data:write.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: post_call, dm_close, past_call, eod, affiliate_sale | yes | Which form. affiliate_sale is one signup on an affiliate funnel (pack 14). |
| `fields` | object | yes | The form's fields, by the names the form uses. No cash, revenue or price. |
| `callId` | string | no | The call, from list_calls. Required for a post-call draft. |
| `memberId` | string | no | Whose draft. Defaults to the call's closer, or to you. |
| `idempotencyKey` | string | no | Optional. The same key never drafts twice. |

### `get_my_day`

**My day**

"What's on today?" Your own day: today's calls with their confirmation colour, forms you owe (oldest first), your end of day and its cutoff, callbacks you promised, deposits with no remainder scheduled (closers), what PYLO has counted for you so far today, and cash you reported that is still waiting for a payment to match it. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_call_brief`

**Brief for one of my calls**

"Setter notes and application for my 3pm." One of your own calls: the lead's application, the setter's note, the lead's journey (earlier calls, payments and deposits, UTMs) and where it came from. Refuses a call you are not on. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | One of your calls, from get_my_day. |

### `get_eod_draft`

**My end of day, from my logs**

Your end of day with every figure PYLO can count already filled in (calls, closes, cash, dials, pickups over 40 seconds, conversations over 3 minutes, talk time), where each comes from, and what only you can say. Ask the rep only for that, then file_form or propose_form_draft. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `date` | string | no | YYYY-MM-DD. Defaults to your report's day, in your time zone. |

### `get_call_list`

**Who do I call next**

One of your call lists: today, triage (new leads on the speed-to-lead clock), post_webinar, no_shows, recent_no_buy or deposits. Each lead says why it is listed, its last dial and call, and when the cadence rules next allow a call (now, a time, or dead). Triage also offers new leads nobody holds; claim one with claim_lead. Follow-up dates stay in the CRM. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `list` | string: today, triage, post_webinar, no_shows, recent_no_buy, deposits | no | Which list. Defaults to today. |

### `get_my_numbers`

**My numbers against the team**

Your figures for a period, each with its definition, beside the team's average and your rank among reps in your role. Nobody else's figures or names. Rates are fractions. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to the first of this month. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |

### `get_my_commission`

**What have I earned**

Your own commission lines for a period, as your payout breakdown shows them: earned, paid and pending, in the workspace's currency, and cash you reported from a chat that counts only once a payment matches it. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `from` | string | no | YYYY-MM-DD. Defaults to the first of this month. |
| `to` | string | no | YYYY-MM-DD. Defaults to today. |

### `get_my_standing`

**How far am I from moving up**

Your level and its KPIs, the next level's KPIs beside this month's figures, your step on the ladder and your calendar priority. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `log_disposition`

**Log a dial's result**

"Log that as a voicemail." Sets the result of your latest dial to a lead in the last day. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callOrLeadId` | string | yes | One of your calls, or the lead you dialled. |
| `result` | string: voicemail, no_answer, busy, wrong_number, not_interested, callback, booked, connected, do_not_call, other | yes | What happened. |
| `callbackAt` | string | no | Optional, with callback. When to call back, ISO date and time: PYLO puts a call back task on your list for then. |

### `score_lead`

**Score a lead**

"Score the 2pm no-show a 2." Scores the lead on one of your calls, 1 to 5 in half steps: the lead's quality, not whether it closed. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | One of your calls. |
| `score` | number | yes | 1 to 5, in steps of 0.5. |

### `confirm_call`

**Mark a call confirmed**

"Mark my 4pm confirmed." Sets the traffic light on one of your calls: green confirmed, orange unsure, red not confirmed, or rescheduled. Written to PYLO's calls board only; nothing is written to the calendar tool. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `callId` | string | yes | One of your calls. |
| `colour` | string: green, orange, red, rescheduled | yes | The light. |

### `claim_lead`

**Claim a lead**

"I've got this one." The first claim owns the lead, in place of an emoji on the Slack post. A lead another rep claimed is refused. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | The lead, from get_call_list. |
| `list` | string | no | Which list it came from, for the record. |

### `release_lead`

**Release a lead**

Gives back a lead you claimed, so another rep can take it. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `leadId` | string | yes | A lead you claimed. |

### `amend_form`

**Change my filed form's words**

Changes the words of one of your filed forms: a post-call form's notes, reasons, reason code, recording link and rating, or an end of day's written answers. Never the outcome, money or who was on the call: an owner changes those in the app. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: post_call, eod | yes | Which form. |
| `callId` | string | no | For a post-call form: the call. |
| `date` | string | no | For an end of day: its date, YYYY-MM-DD. |
| `fields` | object | yes | The fields to change, by the names the form uses. |

### `file_form`

**File my form from here**

"PCF for Jane: closed, split pay, objection was her spouse, score 4." Files your own post-call form or end of day, money included, once you confirm it. PYLO checks it with the app's own rules, then sends you a notice: your rep app shows the form and a six digit code. Type the code here (confirm_form) or tap once in the rep app. Money can be typed as 6,800 or 6800.50. Cash filed this way counts once a processor payment matches it. Only the call's closer files its form here; anyone else drafts it with propose_form_draft. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `kind` | string: post_call, eod | yes | Which form. |
| `callId` | string | no | For a post-call form: your call. |
| `date` | string | no | For an end of day: YYYY-MM-DD. Defaults to your report's day. |
| `fields` | object | yes | The form's fields by the names the form uses: outcome, cash_collected, revenue_generated, program_id, payment_plan, payment_method, call_rating, lead_quality_score, reason_code (budget, not_decision_maker, just_browsing, geography, timeline, other), notes and the reasons; for an end of day the role's questions (get_eod_draft lists them). |
| `draftId` | string | no | The draft this came from, if any. |

### `confirm_form`

**Confirm my form with its code**

Files a form file_form prepared, with the six digit code the rep read in their own rep app. A code confirms only that rep's own form, lasts 10 minutes and works once. Do not guess a code. Needs forms:self.

| Argument | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |
| `formId` | string | yes | From file_form. |
| `code` | string | yes | The six digits the rep typed. |

### `ask_sops`

**Ask the SOPs**

"How do we do X", answered from the procedures and, with a workspaceId, the workspace's own SOP documents that the asker may see, each passage cited by procedure, step and SOP number, or by document. Quote the passages; never reword them into a rule they do not say. For operators and reps alike. Needs read.

| Argument | Type | Required | Description |
|---|---|---|---|
| `question` | string | yes | The question, in the person's words. |
| `workspaceId` | string | no | Which workspace. A workspace or member token may leave it out: it acts on its own only. |

### `get_commission`

**Commission**

What each team member is owed for a period, in the workspace's currency, with every line behind it: the call, the slot held, the cash, the rate and the rule that set the rate. Read only: PYLO never pays anybody. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_rep_activity`

**Rep activity**

Per rep per day: dials, connects (by call length, not the dialler's answered flag), pick-up rate, conversations over 3 minutes and talk time, with the EOD's reported dials beside the system's and the activity alerts, callbacks kept (the next call within the workspace's window of the promised time) and the leads that went dead with no connect. Give a teamMemberId for one rep. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `teamMemberId` | string | no | One rep's team member id. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_eod_compliance`

**End of day compliance**

End-of-day reports filed against those expected, per team member and role, for a period. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `list_calls`

**Calls**

Calls scheduled in a period, newest first, with outcome, the closer, setter and SDR slots, the booking link each was booked on (bookingLink, from 21 October 2026, so a check-in can be told from a sales call), and whether each was voided or filed as an internal booking. Voided calls are left out unless includeVoided is true. For figures rather than rows use get_call_kpis. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | Start of the period, YYYY-MM-DD. Defaults to 30 days ago. |
| `to` | string | no | End of the period, YYYY-MM-DD. Defaults to today. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `includeVoided` | boolean | no | Include voided calls, each marked with its reason. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `get_buyers`

**Buyers**

Every client the sales team closed, one row per person: what they were sold, cash collected before and after refunds, what is still owed and overdue, refunds, the next payment date, the closer and program, and flags for anything that does not add up (sold against collected plus owed plus refunded, a sale logged twice, two leads for one person, a possible duplicate). Also lists payments with no buyer, and how the totals line up with the dashboard's Revenue booked, Cash collected and Cash outstanding. Use it for "who bought, what did they pay, who still owes". Amounts are in the workspace's currency only. A closer or setter sees only their own buyers. Read only. Another workspace is refused (refused.cross_workspace).

| Argument | Type | Required | Description |
|---|---|---|---|
| `period` | string: this_month, last_month, last_90_days, all_time | no | Which buyers, by the date of their first close. Defaults to all_time. |
| `sort` | string: closed, sold, collectedGross, collected, owed, overdue, refunded, name | no | Order of the rows, largest first for money. Defaults to closed (newest first). |
| `query` | string | no | Only buyers whose name, email or phone contains this. |
| `limit` | number | no | How many to return. Defaults to 100, capped at 500. |
| `workspaceId` | string | no | Which workspace, from list_workspaces. A workspace token may leave it out: it reads its own only. |

### `request_feature`

**Send a feature request to the PYLO team**

When the operator asks for something PYLO's tools cannot do, first tell them PYLO cannot do it yet, then offer to send it to the PYLO team as a feature request. Call this only after they agree. request is what they wanted, in one or two sentences in their words; tried is which tools you tried, if any. Leave out lead names, emails, phone numbers and money figures. Tell them it was sent and that PYLO will let them know here when it is built.

| Argument | Type | Required | Description |
|---|---|---|---|
| `request` | string | yes | What the operator wanted PYLO to do, in one or two sentences. |
| `tried` | string | no | Optional. The PYLO tools you tried, and why they did not do it. |
