{"openapi":"3.1.0","info":{"title":"FORTVISION Platform API","version":"3.1.0","description":"Read access to one FORTVISION workspace: leads, contacts, eCommerce customers, CRM tasks,\nad campaigns, conversations, automations and reports.\n\n**Authentication** — a bearer token created in the app under Integrations → Programmatic access.\nSend it as `Authorization: Bearer fvmcp_…`. Tokens carry scopes, expire, and can be revoked or\nrotated at any time. The token acts as the user who created it: it can never see more than they can.\n\n**Tenancy** — a token is bound to one workspace. Ids from another workspace return 404, never data.\nThe workspace is resolved from the token; it can never be supplied by the client.\n\n**Pagination** — every list takes `page` and `pageSize` (max 100) and returns a `pagination` object.\nThere is no way to request an unbounded result set.\n\n**Rate limits** — per token and per workspace, per minute. Exceeding either returns 429.\n\n**Errors** — `{ \"ok\": false, \"error\": { \"code\": \"...\", \"message\": \"...\" } }` with an HTTP status to match.\nCodes: invalid_input, unauthorized, forbidden, not_found, rate_limited, unavailable, timeout, internal.\n\n**Idempotency** — every operation here is a read and therefore idempotent. Write operations, when they\nship, will require an `Idempotency-Key` header and an explicit confirmation step.\n\nThe same capabilities are available to LLM clients over the Model Context Protocol at `/mcp`."},"servers":[{"url":"https://app.fortvision.com/api/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"fvmcp token","description":"Workspace access token created in FORTVISION → Integrations."}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_input","unauthorized","forbidden","not_found","conflict","rate_limited","unavailable","timeout","internal"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}},"requestId":{"type":"string"}}},"example":{"ok":false,"error":{"code":"not_found","message":"No lead with that id is visible to this token."},"requestId":"req_2f1c9a4b7d0e5a86"}}}}}},"x-scopes":[{"name":"leads.read","risk":"read","stage":1,"description":"Read leads, their statuses, owners and sources.","grantable":true},{"name":"contacts.read","risk":"read","stage":1,"description":"Read contacts, their lists (My Lists), records, Due Date, notes, tasks and activity timeline; CRM companies and custom-field definitions.","grantable":true},{"name":"quotes.read","risk":"read","stage":1,"description":"Read CRM price quotes (items, totals, status, view / accept / sign events, customer link) and the workspace's quote branding and defaults.","grantable":true},{"name":"customers.read","risk":"read","stage":1,"description":"Read eCommerce customers, orders and store list.","grantable":true},{"name":"tasks.read","risk":"read","stage":1,"description":"Read CRM tasks.","grantable":true},{"name":"deals.read","risk":"read","stage":1,"description":"Read sales-pipeline deals, stage history and the pipeline forecast.","grantable":true},{"name":"campaigns.read","risk":"read","stage":1,"description":"Read ad campaigns and their performance metrics.","grantable":true},{"name":"conversations.read","risk":"read","stage":1,"description":"Read WhatsApp / SMS / social conversations.","grantable":true},{"name":"agents.read","risk":"read","stage":1,"description":"Read automations (journeys) and their run stats.","grantable":true},{"name":"reports.read","risk":"read","stage":1,"description":"Read aggregate reports (lead sources, conversions, customer summary).","grantable":true},{"name":"linkedin.read","risk":"read","stage":1,"description":"Read LinkedIn outreach: senders, prospect lists, sequences and their stats, inbox conversations.","grantable":true},{"name":"wallet.read","risk":"read","stage":1,"description":"Read the Wallet loyalty module: cards, member counts and funnel, member search, recent club activity.","grantable":true},{"name":"projects.read","risk":"read","stage":1,"description":"Read Projects boards: groups, columns, items and their status, owners and column values.","grantable":true},{"name":"pages.read","risk":"read","stage":1,"description":"Read landing pages and their performance (views, leads, conversion rate).","grantable":true},{"name":"social.read","risk":"read","stage":1,"description":"Read the social content calendar: posts, statuses, schedule and performance.","grantable":true},{"name":"coupons.read","risk":"read","stage":1,"description":"Read coupons and their issue/redemption/revenue stats.","grantable":true},{"name":"meetings.read","risk":"read","stage":1,"description":"Read booking pages and booked meetings.","grantable":true},{"name":"leads.write","risk":"write","stage":2,"description":"Create and update leads, statuses and owners.","grantable":true},{"name":"contacts.write","risk":"write","stage":2,"description":"Update existing contact records by id: Due Date, status, owner, rating, notes (singly or in batches); create and edit CRM companies. Never creates or deletes contacts.","grantable":true},{"name":"quotes.write","risk":"write","stage":2,"description":"Create price quotes as drafts on a contact / company / deal, edit, duplicate and set their status, and edit the quote branding. Never sends (send_quote needs messages.send) and never deletes (records.delete).","grantable":true},{"name":"customers.write","risk":"write","stage":2,"description":"Update customer records.","grantable":true},{"name":"tasks.write","risk":"write","stage":2,"description":"Create, update and complete tasks.","grantable":true},{"name":"deals.write","risk":"write","stage":2,"description":"Create deals, move them between pipeline stages (incl. Closed Won / Lost) and link contacts and companies.","grantable":true},{"name":"notes.write","risk":"write","stage":2,"description":"Add notes to leads, contacts, companies and deals.","grantable":true},{"name":"messages.draft","risk":"write","stage":2,"description":"Create email / SMS / WhatsApp drafts (never sends).","grantable":true},{"name":"linkedin.write","risk":"write","stage":2,"description":"Create and edit LinkedIn sequences (as drafts), import prospects into lists, pause sequences. Never launches or sends.","grantable":true},{"name":"projects.write","risk":"write","stage":2,"description":"Create Projects boards and items; update item status, owners, dates, column values and comments.","grantable":true},{"name":"agents.write","risk":"write","stage":2,"description":"Enable or pause automations (journeys). Reversible; never edits the flow.","grantable":true},{"name":"pages.write","risk":"write","stage":2,"description":"Create landing pages (AI-generated), edit their content and settings, manage landing-page lists.","grantable":true},{"name":"social.write","risk":"write","stage":2,"description":"Create and edit social posts as drafts, generate post ideas. Never schedules or publishes.","grantable":true},{"name":"coupons.write","risk":"write","stage":2,"description":"Create coupons, pause/resume them, issue a code to a contact.","grantable":true},{"name":"meetings.write","risk":"write","stage":2,"description":"Create and edit booking pages.","grantable":true},{"name":"messages.send","risk":"high","stage":3,"description":"Send email / SMS / WhatsApp. Requires explicit confirmation per send.","grantable":true},{"name":"linkedin.send","risk":"high","stage":3,"description":"Launch or resume LinkedIn sequences and send LinkedIn messages. Requires explicit confirmation per action.","grantable":true},{"name":"campaigns.write","risk":"high","stage":3,"description":"Activate, pause or modify ad campaigns.","grantable":true},{"name":"budgets.write","risk":"high","stage":3,"description":"Change campaign budgets and bids.","grantable":true},{"name":"social.publish","risk":"high","stage":3,"description":"Schedule or publish social posts to connected pages. Requires explicit confirmation per action.","grantable":true},{"name":"records.delete","risk":"high","stage":3,"description":"Delete records. Irreversible.","grantable":true},{"name":"orders.write","risk":"high","stage":3,"description":"Cancel orders, change shipping addresses and refund payments in connected stores (WooCommerce, Shopify, Wix, the WordPress plugin). Refunds need explicit confirmation per action.","grantable":true},{"name":"admin.integrations","risk":"high","stage":3,"description":"Manage integrations and access tokens.","grantable":true}],"paths":{"/workspace":{"get":{"operationId":"get_workspace_info","summary":"Identify the workspace this token acts in, the scopes it holds, the lead statuses this account uses, and which data sources (Facebook, Google Ads, DV360, email, WhatsApp, stores) are actually connected","description":"Identify the workspace this token acts in, the scopes it holds, the lead statuses this account uses, and which data sources (Facebook, Google Ads, DV360, email, WhatsApp, stores) are actually connected. Call this FIRST in a session: it tells you which of the other tools can return anything, so you do not guess.\n\nRequired scope: `leads.read`. Risk level: `read`.","tags":["leads"],"security":[{"bearerAuth":["leads.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"workspace":{"type":"object","properties":{"id":{"type":"string","description":"Workspace / account id."},"isRestrictedUser":{"type":"boolean","description":"True when the token owner is a restricted (grant-scoped) user."},"role":{"type":"string","description":"Role of the token owner (\"\" when none)."}},"additionalProperties":true,"required":["id","isRestrictedUser","role"],"description":"The workspace this token is scoped to."},"user":{"type":"object","properties":{"email":{"type":"string","description":"User email."},"name":{"type":"string","description":"User display name (\"\" when unset)."}},"additionalProperties":true,"required":["email","name"],"description":"The user the token acts as."},"token":{"type":"object","properties":{"id":{"type":"string","description":"Token id."},"name":{"type":"string","description":"Token label."},"scopes":{"type":"array","items":{"type":"string"},"description":"Granted scopes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry (\"\" when it does not expire)."}},"additionalProperties":true,"required":["id","name","scopes","expiresAt"],"description":"The API token in use."},"leadStatuses":{"type":"array","items":{"type":"string"},"description":"The lead pipeline statuses this workspace uses, in order."},"connections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Integration key, e.g. meta-ads, google-ads, gmail."},"name":{"type":"string","description":"Integration display name."},"category":{"type":"string","description":"Group, e.g. Ads, Social, Email."},"status":{"type":"string","description":"connected | expiring | expired | missing."}},"additionalProperties":true},"description":"Connected integrations and their health; absent when the integrations endpoint is unavailable."}},"additionalProperties":true,"required":["ok","requestId","workspace","user","token","leadStatuses"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads":{"get":{"operationId":"search_leads","summary":"Search leads across every source in this workspace (Facebook lead forms, manual/CSV imports, landing pages)","description":"Search leads across every source in this workspace (Facebook lead forms, manual/CSV imports, landing pages). Matches `query` against name, email, phone and campaign name. Use it to answer \"who came in\", \"find the lead called X\", \"leads from campaign Y last week\". Returns a page of summary records — call get_lead for the full form answers.\n\nRequired scope: `leads.read`. Risk level: `read`.","tags":["leads"],"security":[{"bearerAuth":["leads.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Free text: name, email, phone (4+ digits), lead id, or campaign name.","schema":{"type":"string","maxLength":120}},{"name":"status","in":"query","required":false,"description":"Exact pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"source","in":"query","required":false,"description":"Which system the lead came from.","schema":{"type":"string","enum":["facebook","manual","landing_page"]}},{"name":"owner","in":"query","required":false,"description":"Assigned owner (email or name), exact match.","schema":{"type":"string","maxLength":120}},{"name":"band","in":"query","required":false,"description":"Lead-score band: hot, warm, cold, won or lost (hot = at or above the workspace hot threshold).","schema":{"type":"string","enum":["hot","warm","cold","won","lost"]}},{"name":"campaignId","in":"query","required":false,"description":"Restrict to one ad campaign id.","schema":{"type":"string","maxLength":60}},{"name":"sort","in":"query","required":false,"description":"Result order. Default newest first.","schema":{"type":"string","enum":["created_desc","created_asc","name_asc","rating_desc","score_desc"],"default":"created_desc"}},{"name":"dateFrom","in":"query","required":false,"description":"Only records at or after this ISO 8601 date/datetime (e.g. 2026-07-01).","schema":{"type":"string","maxLength":40}},{"name":"dateTo","in":"query","required":false,"description":"Only records at or before this ISO 8601 date/datetime.","schema":{"type":"string","maxLength":40}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"leads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Lead id; source-specific (Facebook lead id, manual _id or landing-page submission id)."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Which store the lead came from."},"name":{"type":"string","description":"Full name (\"\" when unknown)."},"email":{"type":"string","description":"Email, lower-cased (\"\" when unknown)."},"phone":{"type":"string","description":"Phone as entered (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status; normally one of get_workspace_info.leadStatuses (default \"New\")."},"rating":{"type":"number","description":"Human-set rating (0 when unrated)."},"owner":{"type":"string","description":"Assigned owner (email or name, \"\" when unassigned)."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"score":{"type":"number","description":"Lead score 0-100 from the hourly scoring sweep; absent when not scored yet."},"scoreBand":{"type":"string","enum":["hot","warm","cold","won","lost"],"description":"Score band; absent when not scored yet."},"createdAt":{"type":"string","description":"ISO 8601 creation time (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 time of the last human edit/note, else createdAt."},"campaignName":{"type":"string","description":"Ad campaign / UTM campaign name (\"\" when none)."},"formName":{"type":"string","description":"Lead form name (\"Landing page\" for LP leads, \"\" when none)."},"pageName":{"type":"string","description":"Facebook page or landing-page name (\"\" when none)."},"platform":{"type":"string","description":"Origin platform, e.g. facebook, instagram, manual, landing_page."},"isOrganic":{"type":"boolean","description":"True when the lead did not come from a paid click."},"hasNote":{"type":"boolean","description":"True when the lead carries at least one note (edit layer or CRM)."}},"additionalProperties":true,"required":["id","source","name","email","phone","status","rating","owner","dueDate","createdAt","updatedAt","campaignName","formName","pageName","platform","isOrganic","hasNote"]},"description":"Matching leads for this page."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"sources":{"type":"object","properties":{"facebook":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"stale":{"type":"boolean","description":"True when the cached form leads are stale; only present when the store loaded."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Facebook lead-form store: rows contributed, or why it was unavailable."},"manual":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Manual / CSV-import store: rows contributed, or why it was unavailable."},"landing_page":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Landing-page submission store: rows contributed, or why it was unavailable."}},"additionalProperties":true,"required":["facebook","manual","landing_page"],"description":"Which lead stores contributed to the working set; a failed store reports `unavailable` rather than under-counting."},"workingSetTruncated":{"type":"boolean","description":"True when the merged lead set exceeded the working-set cap (200k) and was cut."},"workingSet":{"type":"object","properties":{"hit":{"type":"boolean","description":"true = served from the workspace cache (invalidated by every lead write, max 2 min old)."},"ageMs":{"type":"integer","description":"Age of the cached set in ms (0 on a fresh load)."},"leads":{"type":"integer","description":"Rows in the merged set."}},"additionalProperties":true,"description":"How the merged lead set was obtained."}},"additionalProperties":true,"required":["ok","requestId","leads","pagination","sources","workingSetTruncated"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_lead","summary":"Add a contact to the Leads board","description":"Add a contact to the Leads board. Needs at least an email or a phone number. If someone with that email or phone already exists, nothing is created and the existing lead is returned — so calling this twice is safe. Ad-platform leads arrive on their own; this is for contacts you are adding by hand.\n\nRequired scope: `leads.write`. Risk level: `write`.","tags":["leads"],"security":[{"bearerAuth":["leads.write"]}],"parameters":[{"name":"name","in":"query","required":false,"description":"Full name.","schema":{"type":"string","maxLength":160}},{"name":"email","in":"query","required":false,"description":"Email address.","schema":{"type":"string","maxLength":160}},{"name":"phone","in":"query","required":false,"description":"Phone number, ideally in +country format.","schema":{"type":"string","maxLength":60}},{"name":"company","in":"query","required":false,"description":"Company name (the contact's Company field).","schema":{"type":"string","maxLength":160}},{"name":"status","in":"query","required":false,"description":"Starting pipeline status. Defaults to New.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"owner","in":"query","required":false,"description":"Assign to this user (their email).","schema":{"type":"string","maxLength":120}},{"name":"campaign","in":"query","required":false,"description":"Campaign or source name to record against the lead.","schema":{"type":"string","maxLength":160}},{"name":"sourceLabel","in":"query","required":false,"description":"Where this contact came from, shown in the Form/Page column. Defaults to \"API\".","schema":{"type":"string","maxLength":120}},{"name":"utmSource","in":"query","required":false,"description":"utm_source to record.","schema":{"type":"string","maxLength":80}},{"name":"utmMedium","in":"query","required":false,"description":"utm_medium to record.","schema":{"type":"string","maxLength":80}},{"name":"utmCampaign","in":"query","required":false,"description":"utm_campaign to record.","schema":{"type":"string","maxLength":120}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["lead"],"description":"Always \"lead\"."},"targetId":{"type":"string","description":"Id of the created lead, or of the existing duplicate when created=false."},"created":{"type":"boolean","description":"False when a contact with the same email/phone already existed (nothing written)."},"duplicateOf":{"type":"string","description":"Only when created=false: id of the existing contact."},"lead":{"type":"object","properties":{"id":{"type":"string","description":"Lead id (manual_…)."},"source":{"type":"string","enum":["manual"],"description":"Only when created=true: always \"manual\"."},"name":{"type":"string","description":"Contact name, \"\" when none."},"email":{"type":"string","description":"Lowercased email, \"\" when none."},"phone":{"type":"string","description":"Phone as supplied, \"\" when none."},"status":{"type":"string","description":"Only when created=true: initial pipeline status (default \"New\")."},"owner":{"type":"string","description":"Only when created=true: assigned owner, \"\" when unassigned."}},"additionalProperties":true,"required":["id","name","email","phone"],"description":"The created contact (or the existing duplicate)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","lead"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/{id}":{"get":{"operationId":"get_lead","summary":"Full detail for one lead: every form answer, custom board fields, the note a human left, the campaign/ad set/ad it came from, and any CRM tasks attached to it","description":"Full detail for one lead: every form answer, custom board fields, the note a human left, the campaign/ad set/ad it came from, and any CRM tasks attached to it. Use the id returned by search_leads.\n\nRequired scope: `leads.read`. Risk level: `read`.","tags":["leads"],"security":[{"bearerAuth":["leads.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Lead id from search_leads.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"lead":{"type":"object","properties":{"id":{"type":"string","description":"Lead id; source-specific (Facebook lead id, manual _id or landing-page submission id)."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Which store the lead came from."},"name":{"type":"string","description":"Full name (\"\" when unknown)."},"email":{"type":"string","description":"Email, lower-cased (\"\" when unknown)."},"phone":{"type":"string","description":"Phone as entered (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status; normally one of get_workspace_info.leadStatuses (default \"New\")."},"rating":{"type":"number","description":"Human-set rating (0 when unrated)."},"owner":{"type":"string","description":"Assigned owner (email or name, \"\" when unassigned)."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"score":{"type":"number","description":"Lead score 0-100 from the hourly scoring sweep; absent when not scored yet."},"scoreBand":{"type":"string","enum":["hot","warm","cold","won","lost"],"description":"Score band; absent when not scored yet."},"createdAt":{"type":"string","description":"ISO 8601 creation time (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 time of the last human edit/note, else createdAt."},"campaignName":{"type":"string","description":"Ad campaign / UTM campaign name (\"\" when none)."},"formName":{"type":"string","description":"Lead form name (\"Landing page\" for LP leads, \"\" when none)."},"pageName":{"type":"string","description":"Facebook page or landing-page name (\"\" when none)."},"platform":{"type":"string","description":"Origin platform, e.g. facebook, instagram, manual, landing_page."},"isOrganic":{"type":"boolean","description":"True when the lead did not come from a paid click."},"hasNote":{"type":"boolean","description":"True when the lead carries at least one note (edit layer or CRM)."},"campaign":{"type":"object","properties":{"id":{"type":"string","description":"Platform id (\"\" when unknown)."},"name":{"type":"string","description":"Display name (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name"],"description":"Ad campaign the lead came from."},"adSet":{"type":"object","properties":{"id":{"type":"string","description":"Platform id (\"\" when unknown)."},"name":{"type":"string","description":"Display name (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name"],"description":"Ad set (Meta) the lead came from."},"ad":{"type":"object","properties":{"id":{"type":"string","description":"Platform id (\"\" when unknown)."},"name":{"type":"string","description":"Display name (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name"],"description":"Ad the lead came from."},"form":{"type":"object","properties":{"id":{"type":"string","description":"Platform id (\"\" when unknown)."},"name":{"type":"string","description":"Display name (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name"],"description":"Lead form / landing page the lead was submitted through."},"page":{"type":"object","properties":{"id":{"type":"string","description":"Platform id (\"\" when unknown)."},"name":{"type":"string","description":"Display name (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name"],"description":"Facebook page or landing page."},"formAnswers":{"type":"object","additionalProperties":true,"description":"Raw form answers keyed by lower-cased field name (values ≤500 chars)."},"customFields":{"type":"object","additionalProperties":true,"description":"Workspace custom board columns keyed by column id (string/number values)."},"note":{"type":"string","description":"Legacy edit-layer note text (≤2000 chars, \"\" when none)."},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title (≤200 chars)."},"done":{"type":"boolean","description":"True when completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when none."},"priorityLabel":{"type":"string","description":"Priority label as stored on the board (e.g. Medium)."},"owner":{"type":"string","description":"Assignee (\"\" when unassigned)."},"dueAt":{"type":"string","description":"ISO 8601 due datetime (end of day when no time), \"\" when no due date."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type, e.g. contact, deal, company."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, or null."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo","createdAt","updatedAt"]},"description":"Up to 20 CRM tasks attached to this lead (empty when the CRM is unreadable)."},"notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Note id."},"text":{"type":"string","description":"Note body (≤2000 chars)."},"kind":{"type":"string","description":"Note kind, e.g. note, call, meeting (\"\" when unset)."},"author":{"type":"string","description":"Author email (\"\" when unknown)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","text","kind","author","createdAt"]},"description":"Up to 20 CRM notes, as written by add_lead_note (empty when unreadable)."}},"additionalProperties":true,"required":["id","source","name","email","phone","status","rating","owner","dueDate","createdAt","updatedAt","campaignName","formName","pageName","platform","isOrganic","hasNote","campaign","adSet","ad","form","page","formAnswers","customFields","note","tasks","notes"],"description":"Full lead detail."}},"additionalProperties":true,"required":["ok","requestId","lead"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/stale":{"get":{"operationId":"list_stale_leads","summary":"Open leads nobody has touched in `days` (default 14), oldest first, with how long each has been idle","description":"Open leads nobody has touched in `days` (default 14), oldest first, with how long each has been idle. \"Touched\" means created, edited or noted in the app. Won/Lost/Unresponsive leads are excluded. Use it for pipeline hygiene questions (\"what is going cold?\").\n\nRequired scope: `leads.read`. Risk level: `read`.","tags":["leads"],"security":[{"bearerAuth":["leads.read"]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Idle threshold in days.","schema":{"type":"integer","minimum":1,"maximum":365,"default":14}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"staleAfterDays":{"type":"integer","description":"The idle threshold applied (1-365, default 14)."},"leads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Lead id; source-specific (Facebook lead id, manual _id or landing-page submission id)."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Which store the lead came from."},"name":{"type":"string","description":"Full name (\"\" when unknown)."},"email":{"type":"string","description":"Email, lower-cased (\"\" when unknown)."},"phone":{"type":"string","description":"Phone as entered (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status; normally one of get_workspace_info.leadStatuses (default \"New\")."},"rating":{"type":"number","description":"Human-set rating (0 when unrated)."},"owner":{"type":"string","description":"Assigned owner (email or name, \"\" when unassigned)."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"score":{"type":"number","description":"Lead score 0-100 from the hourly scoring sweep; absent when not scored yet."},"scoreBand":{"type":"string","enum":["hot","warm","cold","won","lost"],"description":"Score band; absent when not scored yet."},"createdAt":{"type":"string","description":"ISO 8601 creation time (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 time of the last human edit/note, else createdAt."},"campaignName":{"type":"string","description":"Ad campaign / UTM campaign name (\"\" when none)."},"formName":{"type":"string","description":"Lead form name (\"Landing page\" for LP leads, \"\" when none)."},"pageName":{"type":"string","description":"Facebook page or landing-page name (\"\" when none)."},"platform":{"type":"string","description":"Origin platform, e.g. facebook, instagram, manual, landing_page."},"isOrganic":{"type":"boolean","description":"True when the lead did not come from a paid click."},"hasNote":{"type":"boolean","description":"True when the lead carries at least one note (edit layer or CRM)."},"idleDays":{"type":"integer","description":"Whole days since the last touch (created / edited / noted)."}},"additionalProperties":true,"required":["id","source","name","email","phone","status","rating","owner","dueDate","createdAt","updatedAt","campaignName","formName","pageName","platform","isOrganic","hasNote","idleDays"]},"description":"Open leads untouched for at least staleAfterDays, oldest touch first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"sources":{"type":"object","properties":{"facebook":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"stale":{"type":"boolean","description":"True when the cached form leads are stale; only present when the store loaded."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Facebook lead-form store: rows contributed, or why it was unavailable."},"manual":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Manual / CSV-import store: rows contributed, or why it was unavailable."},"landing_page":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Landing-page submission store: rows contributed, or why it was unavailable."}},"additionalProperties":true,"required":["facebook","manual","landing_page"],"description":"Which lead stores contributed to the working set; a failed store reports `unavailable` rather than under-counting."}},"additionalProperties":true,"required":["ok","requestId","staleAfterDays","leads","pagination","sources"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/followup":{"get":{"operationId":"list_leads_requiring_followup","summary":"Open leads with a concrete reason to act right now: an overdue CRM task, or a New lead that has sat uncontacted longer than `newLeadHours` (default 24)","description":"Open leads with a concrete reason to act right now: an overdue CRM task, or a New lead that has sat uncontacted longer than `newLeadHours` (default 24). Each row says which reason applies. This reflects what humans recorded — it does not invent a scoring model.\n\nRequired scope: `leads.read`. Risk level: `read`.","tags":["leads"],"security":[{"bearerAuth":["leads.read"]}],"parameters":[{"name":"newLeadHours","in":"query","required":false,"description":"How long a New lead may sit before it counts as needing contact.","schema":{"type":"integer","minimum":1,"maximum":720,"default":24}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"leads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Lead id; source-specific (Facebook lead id, manual _id or landing-page submission id)."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Which store the lead came from."},"name":{"type":"string","description":"Full name (\"\" when unknown)."},"email":{"type":"string","description":"Email, lower-cased (\"\" when unknown)."},"phone":{"type":"string","description":"Phone as entered (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status; normally one of get_workspace_info.leadStatuses (default \"New\")."},"rating":{"type":"number","description":"Human-set rating (0 when unrated)."},"owner":{"type":"string","description":"Assigned owner (email or name, \"\" when unassigned)."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"score":{"type":"number","description":"Lead score 0-100 from the hourly scoring sweep; absent when not scored yet."},"scoreBand":{"type":"string","enum":["hot","warm","cold","won","lost"],"description":"Score band; absent when not scored yet."},"createdAt":{"type":"string","description":"ISO 8601 creation time (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 time of the last human edit/note, else createdAt."},"campaignName":{"type":"string","description":"Ad campaign / UTM campaign name (\"\" when none)."},"formName":{"type":"string","description":"Lead form name (\"Landing page\" for LP leads, \"\" when none)."},"pageName":{"type":"string","description":"Facebook page or landing-page name (\"\" when none)."},"platform":{"type":"string","description":"Origin platform, e.g. facebook, instagram, manual, landing_page."},"isOrganic":{"type":"boolean","description":"True when the lead did not come from a paid click."},"hasNote":{"type":"boolean","description":"True when the lead carries at least one note (edit layer or CRM)."},"reason":{"type":"string","enum":["overdue_task","never_contacted"],"description":"Why the lead needs follow-up."},"overdueTask":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title."},"dueDate":{"type":"string","description":"Due date YYYY-MM-DD."}},"additionalProperties":true,"required":["title","dueDate"],"description":"The overdue task when reason is overdue_task, else null."}},"additionalProperties":true,"required":["id","source","name","email","phone","status","rating","owner","dueDate","createdAt","updatedAt","campaignName","formName","pageName","platform","isOrganic","hasNote","reason","overdueTask"]},"description":"Open leads with a concrete reason to act; overdue tasks first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"sources":{"type":"object","properties":{"facebook":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"stale":{"type":"boolean","description":"True when the cached form leads are stale; only present when the store loaded."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Facebook lead-form store: rows contributed, or why it was unavailable."},"manual":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Manual / CSV-import store: rows contributed, or why it was unavailable."},"landing_page":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Landing-page submission store: rows contributed, or why it was unavailable."}},"additionalProperties":true,"required":["facebook","manual","landing_page"],"description":"Which lead stores contributed to the working set; a failed store reports `unavailable` rather than under-counting."},"newLeadHours":{"type":"integer","description":"Hours after which an uncontacted \"New\" lead counts (1-720, default 24)."}},"additionalProperties":true,"required":["ok","requestId","leads","pagination","sources","newLeadHours"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts":{"get":{"operationId":"search_contacts","summary":"Search PEOPLE rather than submissions: lead records are merged by email (then phone), so someone who filled in three forms is one contact with three leads","description":"Search PEOPLE rather than submissions: lead records are merged by email (then phone), so someone who filled in three forms is one contact with three leads. Each contact carries company, status, owner, rating, the board's Due Date (dueDate, \"\" when none), the lists they are on and their records. Use search_leads for individual submissions, list_contacts_in_list to page through one list.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Free text: name, email or phone.","schema":{"type":"string","maxLength":120}},{"name":"status","in":"query","required":false,"description":"Status of their most recent lead.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"owner","in":"query","required":false,"description":"Assigned owner, exact match.","schema":{"type":"string","maxLength":120}},{"name":"dateFrom","in":"query","required":false,"description":"Only records at or after this ISO 8601 date/datetime (e.g. 2026-07-01).","schema":{"type":"string","maxLength":40}},{"name":"dateTo","in":"query","required":false,"description":"Only records at or before this ISO 8601 date/datetime.","schema":{"type":"string","maxLength":40}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Contact key: \"e:<email>\", \"p:<digits>\" or \"l:<leadId>\"."},"name":{"type":"string","description":"Name (\"\" when unknown)."},"email":{"type":"string","description":"Lower-cased email (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"company":{"type":"string","description":"Company (\"\" when unknown)."},"status":{"type":"string","description":"Status of the most recent record."},"owner":{"type":"string","description":"Owner of the newest record (\"\" when unassigned)."},"rating":{"type":"number","description":"Rating of the newest record."},"dueDate":{"type":"string","description":"The contact's Due Date (newest record's, else the first set), \"\" when none."},"primaryLeadId":{"type":"string","description":"Id of the newest record — what update_contact changes when given the contact id."},"firstSeen":{"type":"string","description":"ISO 8601 of the oldest record."},"lastSeen":{"type":"string","description":"ISO 8601 of the newest record."},"updatedAt":{"type":"string","description":"ISO 8601 of the most recent update across records."},"leadIds":{"type":"array","items":{"type":"string"},"description":"Up to 25 record ids behind this contact."},"sources":{"type":"array","items":{"type":"string","enum":["facebook","manual","landing_page"]},"description":"Distinct sources behind this contact."},"leadCount":{"type":"integer","description":"Total records merged into this contact."},"lists":{"type":"array","items":{"type":"string"},"description":"Union of My Lists across the records."},"records":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Record id — the stable contactId used by the Contacts table, My Lists and update_contact."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Store the record lives in."},"name":{"type":"string","description":"Name (\"\" when unknown)."},"email":{"type":"string","description":"Lower-cased email (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"company":{"type":"string","description":"Company (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email (\"\" when unassigned)."},"rating":{"type":"number","description":"Rating 0-5."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"updatedAt":{"type":"string","description":"ISO 8601 last update."},"lists":{"type":"array","items":{"type":"string"},"description":"Names of the My Lists this record is on."},"hasNote":{"type":"boolean","description":"True when the record carries a note."}},"additionalProperties":true,"required":["id","source","name","email","phone","company","status","owner","rating","dueDate","createdAt","updatedAt","lists"],"description":"One underlying record of the contact."},"description":"Up to 25 underlying records, newest first."}},"additionalProperties":true,"required":["id","name","email","phone","company","status","owner","rating","dueDate","primaryLeadId","firstSeen","lastSeen","updatedAt","leadIds","sources","leadCount","lists","records"]},"description":"Matching contacts, most recently seen first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"sources":{"type":"object","properties":{"facebook":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"stale":{"type":"boolean","description":"True when the cached form leads are stale; only present when the store loaded."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Facebook lead-form store: rows contributed, or why it was unavailable."},"manual":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Manual / CSV-import store: rows contributed, or why it was unavailable."},"landing_page":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Landing-page submission store: rows contributed, or why it was unavailable."}},"additionalProperties":true,"required":["facebook","manual","landing_page"],"description":"Which lead stores contributed to the working set; a failed store reports `unavailable` rather than under-counting."}},"additionalProperties":true,"required":["ok","requestId","contacts","pagination","sources"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/lookup":{"get":{"operationId":"get_contact","summary":"One contact with everything the CRM holds: identity, company, status, owner, rating, the board's Due Date (dueDate, \"\" when none is set), the lists they are on, every underlying record (each with its own dueDate/status/owner/lists — records[0] is the newest and is what update_contact changes), CRM notes and tasks, and a WhatsApp summary (connected? outreach sent? reply received?)","description":"One contact with everything the CRM holds: identity, company, status, owner, rating, the board's Due Date (dueDate, \"\" when none is set), the lists they are on, every underlying record (each with its own dueDate/status/owner/lists — records[0] is the newest and is what update_contact changes), CRM notes and tasks, and a WhatsApp summary (connected? outreach sent? reply received?). Address by contactId / record id, a contact id from search_contacts, email or phone.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"id","in":"query","required":false,"description":"contactId / record id (from list_contacts_in_list or search_leads) or a contact id from search_contacts.","schema":{"type":"string","maxLength":200}},{"name":"email","in":"query","required":false,"description":"Email address.","schema":{"type":"string","maxLength":160}},{"name":"phone","in":"query","required":false,"description":"Phone number in any format.","schema":{"type":"string","maxLength":60}},{"name":"includeWhatsapp","in":"query","required":false,"description":"false to skip the WhatsApp summary (faster).","schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"contact":{"type":"object","properties":{"id":{"type":"string","description":"Contact key: \"e:<email>\", \"p:<digits>\" or \"l:<leadId>\"."},"name":{"type":"string","description":"Name (\"\" when unknown)."},"email":{"type":"string","description":"Lower-cased email (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"company":{"type":"string","description":"Company (\"\" when unknown)."},"status":{"type":"string","description":"Status of the most recent record."},"owner":{"type":"string","description":"Owner of the newest record (\"\" when unassigned)."},"rating":{"type":"number","description":"Rating of the newest record."},"dueDate":{"type":"string","description":"The contact's Due Date (newest record's, else the first set), \"\" when none."},"primaryLeadId":{"type":"string","description":"Id of the newest record — what update_contact changes when given the contact id."},"firstSeen":{"type":"string","description":"ISO 8601 of the oldest record."},"lastSeen":{"type":"string","description":"ISO 8601 of the newest record."},"updatedAt":{"type":"string","description":"ISO 8601 of the most recent update across records."},"leadIds":{"type":"array","items":{"type":"string"},"description":"Up to 25 record ids behind this contact."},"sources":{"type":"array","items":{"type":"string","enum":["facebook","manual","landing_page"]},"description":"Distinct sources behind this contact."},"leadCount":{"type":"integer","description":"Total records merged into this contact."},"lists":{"type":"array","items":{"type":"string"},"description":"Union of My Lists across the records."},"records":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Record id — the stable contactId used by the Contacts table, My Lists and update_contact."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Store the record lives in."},"name":{"type":"string","description":"Name (\"\" when unknown)."},"email":{"type":"string","description":"Lower-cased email (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"company":{"type":"string","description":"Company (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email (\"\" when unassigned)."},"rating":{"type":"number","description":"Rating 0-5."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"updatedAt":{"type":"string","description":"ISO 8601 last update."},"lists":{"type":"array","items":{"type":"string"},"description":"Names of the My Lists this record is on."},"hasNote":{"type":"boolean","description":"True when the record carries a note."}},"additionalProperties":true,"required":["id","source","name","email","phone","company","status","owner","rating","dueDate","createdAt","updatedAt","lists"],"description":"One underlying record of the contact."},"description":"Up to 25 underlying records, newest first."},"notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Note id."},"text":{"type":"string","description":"Note body (≤2000 chars)."},"kind":{"type":"string","description":"Note kind, e.g. note, call, meeting (\"\" when unset)."},"author":{"type":"string","description":"Author email (\"\" when unknown)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"leadId":{"type":"string","description":"Record the note hangs off."}},"additionalProperties":true,"required":["id","text","kind","author","createdAt"]},"description":"Up to 50 CRM notes across the records, newest first (each with leadId)."},"tasks":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"Task (see get_task) plus leadId."},"description":"Up to 20 CRM tasks attached to the records."},"hasNote":{"type":"boolean","description":"True when any note exists."},"whatsapp":{"type":"object","properties":{"channelConnected":{"type":["boolean","null"],"description":"true/false; null when it could not be determined or the contact has no phone."},"inbound":{"type":"integer","description":"Messages received from the contact (visible window)."},"outbound":{"type":"integer","description":"Messages sent to the contact (visible window)."},"lastInboundAt":{"type":"string","description":"ISO 8601 of the last reply, \"\" when none."},"lastOutboundAt":{"type":"string","description":"ISO 8601 of the last outreach, \"\" when none."},"hasOutreach":{"type":"boolean","description":"At least one outbound message exists."},"hasReply":{"type":"boolean","description":"At least one inbound message exists."},"partial":{"type":"boolean","description":"History window is capped; older messages may exist."},"note":{"type":"string","description":"Explicit caveats (not connected, partial, no phone…)."}},"additionalProperties":true,"description":"WhatsApp summary for the contact."}},"additionalProperties":true,"required":["id","name","email","phone","company","status","owner","rating","dueDate","primaryLeadId","firstSeen","lastSeen","updatedAt","leadIds","sources","leadCount","lists","records","notes","tasks","whatsapp"],"description":"The contact with CRM detail."}},"additionalProperties":true,"required":["ok","requestId","contact"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/activity":{"get":{"operationId":"get_contact_activity","summary":"Behavioural timeline for one person: site page views, cart events and purchases, plus channel touches (email opens/clicks, SMS clicks, landing-page and on-site interactions), with the engagement score and order totals the platform already computes","description":"Behavioural timeline for one person: site page views, cart events and purchases, plus channel touches (email opens/clicks, SMS clicks, landing-page and on-site interactions), with the engagement score and order totals the platform already computes. Identify them by email or phone. Use it to answer \"what has this person actually done?\".\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"email","in":"query","required":false,"description":"Email address.","schema":{"type":"string","maxLength":160}},{"name":"phone","in":"query","required":false,"description":"Phone number in any format.","schema":{"type":"string","maxLength":60}},{"name":"limit","in":"query","required":false,"description":"Maximum events to return.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"contact":{"type":"object","properties":{"email":{"type":"string","description":"Lower-cased email (\"\" when addressed by phone)."},"phone":{"type":"string","description":"Phone digits (\"\" when addressed by email)."}},"additionalProperties":true,"required":["email","phone"],"description":"The identifier the timeline was resolved for."},"notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Note id."},"text":{"type":"string","description":"Note body (≤2000 chars)."},"kind":{"type":"string","description":"Note kind, e.g. note, call, meeting (\"\" when unset)."},"author":{"type":"string","description":"Author email (\"\" when unknown)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","text","kind","author","createdAt"]},"description":"Up to 50 CRM notes on the matching lead (empty when none / no lead match)."},"summary":{"type":["object","null"],"properties":{"orders":{"type":"integer","description":"Orders attributed to this contact."},"totalSpend":{"type":"number","description":"Total order value in `currency`."},"currency":{"type":"string","description":"Currency code (\"\" when unknown)."},"engagementScore":{"type":"number","description":"Engagement score as shown in the app."},"lastOrderAt":{"type":"string","description":"ISO 8601 of the last order (\"\" when none)."}},"additionalProperties":true,"required":["orders","totalSpend","currency","engagementScore","lastOrderAt"],"description":"Engagement summary from site + channel events; null when none."},"events":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Event type, e.g. pageview, cart, purchase, email_open."},"at":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"channel":{"type":"string","description":"Channel / source (\"\" when unknown)."},"url":{"type":"string","description":"Page URL when the event has one (\"\" otherwise)."},"value":{"type":["number","null"],"description":"Order total or event value; null when none."}},"additionalProperties":true,"required":["type","at","channel","url","value"]},"description":"Individual events, newest first, up to `limit` (max 100)."}},"additionalProperties":true,"required":["ok","requestId","contact","notes","summary","events"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/lists":{"get":{"operationId":"list_contact_lists","summary":"The Leads board's named contact lists (\"My Lists\", e","description":"The Leads board's named contact lists (\"My Lists\", e.g. \"FORTVISION Sales CRM\") with their ids, names and sizes. memberCount = ids stored on the list; visibleCount = members that resolve to a record this token can see (the number the app shows). Pass the id (or the exact name) to list_contacts_in_list. Landing-page lists are a different thing: list_landing_page_lists.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Filter by name (substring).","schema":{"type":"string","maxLength":120}},{"name":"group","in":"query","required":false,"description":"Only lists of this kind.","schema":{"type":"string","enum":["my_list","linkedin","linkedin_ads","wallet","tiktok","calls"]}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"List id, \"ml:<name>\" — pass to list_contacts_in_list."},"name":{"type":"string","description":"List name as shown in the app."},"group":{"type":"string","enum":["my_list","linkedin","linkedin_ads","wallet","tiktok","calls"],"description":"Rail section the list belongs to."},"memberCount":{"type":"integer","description":"Ids stored on the list."},"visibleCount":{"type":"integer","description":"Members that resolve to a record this token can see (the app's count)."},"movedToAnotherWorkspace":{"type":"boolean","description":"True when the list was moved to another workspace (the app hides it)."}},"additionalProperties":true,"required":["id","name","group","memberCount","visibleCount","movedToAnotherWorkspace"]},"description":"Lists, largest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"totalLists":{"type":"integer","description":"Lists matching the filters."}},"additionalProperties":true,"required":["ok","requestId","lists","pagination","totalLists"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_contact_list","summary":"Create an empty My List on the Leads board","description":"Create an empty My List on the Leads board. If a list with that name exists it is returned unchanged (created:false). Then add members with add_contacts_to_list.\n\nRequired scope: `contacts.write`. Risk level: `write`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"List name as it should appear in the app.","schema":{"type":"string","maxLength":120}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"true when a new list was created; false when the name already existed."},"list":{"type":"object","properties":{"id":{"type":"string","description":"ml:<name>."},"name":{"type":"string","description":"Name."},"memberCount":{"type":"integer","description":"Members."}},"additionalProperties":true,"required":["id","name","memberCount"],"description":"The list."},"targetType":{"type":"string","enum":["contact_list"],"description":"Always contact_list."},"targetId":{"type":"string","description":"List id."},"verified":{"type":"boolean","description":"Read back after saving."},"message":{"type":"string","description":"Set when the list already existed."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","list","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/lists/{listId}/contacts":{"get":{"operationId":"list_contacts_in_list","summary":"Every contact on ONE list, paginated, in list order (newest members first)","description":"Every contact on ONE list, paginated, in list order (newest members first). Each row carries the stable contactId (the record id the Contacts table and update_contact use), the lists it belongs to, name, email, phone, company, status, owner, rating, dueDate (\"\" when none), createdAt and updatedAt. total (list.memberCount) is the stored membership; members whose record is not visible to this token are counted in notVisible, never mixed in from other lists. Filters narrow the page, never the membership.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"List id from list_contact_lists (\"ml:<name>\") or the exact list name.","schema":{"type":"string","maxLength":140}},{"name":"query","in":"query","required":false,"description":"Free text: name, email, company or phone.","schema":{"type":"string","maxLength":120}},{"name":"status","in":"query","required":false,"description":"Only this pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"owner","in":"query","required":false,"description":"Only this owner (email), exact match.","schema":{"type":"string","maxLength":120}},{"name":"hasDueDate","in":"query","required":false,"description":"true = only contacts with a Due Date set; false = only those without.","schema":{"type":"boolean"}},{"name":"dueBefore","in":"query","required":false,"description":"Only contacts whose Due Date is on or before this day (yyyy-mm-dd).","schema":{"type":"string","maxLength":10}},{"name":"dueAfter","in":"query","required":false,"description":"Only contacts whose Due Date is on or after this day (yyyy-mm-dd).","schema":{"type":"string","maxLength":10}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"list":{"type":"object","properties":{"id":{"type":"string","description":"List id."},"name":{"type":"string","description":"List name."},"memberCount":{"type":"integer","description":"Ids stored on the list (the total)."}},"additionalProperties":true,"required":["id","name","memberCount"],"description":"The list."},"contacts":{"type":"array","items":{"type":"object","properties":{"contactId":{"type":"string","description":"Stable record id — use with get_contact / update_contact."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Store the record lives in."},"name":{"type":"string","description":"Name (\"\" when unknown)."},"email":{"type":"string","description":"Lower-cased email (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"company":{"type":"string","description":"Company (\"\" when unknown)."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email (\"\" when unassigned)."},"rating":{"type":"number","description":"Rating 0-5."},"dueDate":{"type":"string","description":"The board's Due Date (yyyy-mm-dd), \"\" when none is set."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"updatedAt":{"type":"string","description":"ISO 8601 last update."},"lists":{"type":"array","items":{"type":"string"},"description":"Names of the My Lists this record is on."},"hasNote":{"type":"boolean","description":"True when the record carries a note."}},"additionalProperties":true,"required":["contactId","source","name","email","phone","company","status","owner","rating","dueDate","createdAt","updatedAt","lists"]},"description":"This page of members, in list order."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"matched":{"type":"integer","description":"Members visible to this token that pass the filters (what pagination counts)."},"notVisible":{"type":"integer","description":"Member ids with no visible record (deleted or outside the grant)."},"note":{"type":"string","description":"Present when notVisible > 0."}},"additionalProperties":true,"required":["ok","requestId","list","contacts","pagination","matched","notVisible"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/whatsapp":{"get":{"operationId":"get_contact_whatsapp_history","summary":"The WhatsApp thread with one contact — inbound and outbound messages with time, channel and text — from the workspace's business number and any QR-linked personal number","description":"The WhatsApp thread with one contact — inbound and outbound messages with time, channel and text — from the workspace's business number and any QR-linked personal number. Says explicitly whether WhatsApp is connected (channelConnected) and whether the history is partial, and summarises hasOutreach / hasReply so \"was this person already contacted, did they answer?\" has a definite answer. Address the contact by contactId / contact id, or by phone.\n\nRequired scope: `conversations.read`. Risk level: `read`.","tags":["conversations"],"security":[{"bearerAuth":["conversations.read"]}],"parameters":[{"name":"id","in":"query","required":false,"description":"contactId from list_contacts_in_list, a lead id, or a contact id from search_contacts.","schema":{"type":"string","maxLength":200}},{"name":"phone","in":"query","required":false,"description":"Alternatively the phone number, any format.","schema":{"type":"string","maxLength":60}},{"name":"limit","in":"query","required":false,"description":"Newest messages to return (max 200).","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"contactId":{"type":"string","description":"Resolved record id when addressed by id."},"phone":{"type":"string","description":"Phone digits the thread was resolved for (\"\" when the contact has none)."},"channelConnected":{"type":["boolean","null"],"description":"true/false; null when undeterminable."},"senders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"\"business\" or \"qr:<accountId>\"."},"label":{"type":"string","description":"Display label (name · number)."},"kind":{"type":"string","enum":["business","personal"],"description":"Cloud API vs personal QR number."},"connected":{"type":"boolean","description":"false when the number is currently unlinked."},"status":{"type":"string","description":"Provider status when known."},"issue":{"type":"string","description":"Why it is not connected."}},"additionalProperties":true,"required":["id","label","kind","connected"]},"description":"Numbers a one-to-one message can go out from (send_whatsapp_to_contact `via`): the Cloud API business number and personal QR numbers, with live link state."},"serviceWindowOpen":{"type":"boolean","description":"true when the contact wrote in the last 24 hours — the Cloud API accepts free text; otherwise only approved templates (personal numbers are not subject to this)."},"messages":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound = from the contact."},"channel":{"type":"string","enum":["whatsapp"],"description":"Always whatsapp."},"via":{"type":"string","description":"\"business\" (Cloud API number) or the personal number it went through."},"text":{"type":"string","description":"Message text (≤500 chars)."},"id":{"type":"string","description":"Outbound Cloud API messages: Meta message id."},"status":{"type":"string","description":"Outbound Cloud API messages: sent | delivered | read | failed (last webhook status)."},"error":{"type":"string","description":"When failed: Meta's error title."}},"additionalProperties":true,"required":["at","direction","channel","via","text"]},"description":"Oldest → newest, up to limit."},"counts":{"type":"object","properties":{"inbound":{"type":"integer","description":"From the contact."},"outbound":{"type":"integer","description":"To the contact."}},"additionalProperties":true,"required":["inbound","outbound"],"description":"Totals in the visible window."},"lastInboundAt":{"type":"string","description":"ISO 8601 of the last reply, \"\" when none."},"lastOutboundAt":{"type":"string","description":"ISO 8601 of the last outreach, \"\" when none."},"hasOutreach":{"type":"boolean","description":"At least one outbound message."},"hasReply":{"type":"boolean","description":"At least one inbound message."},"partial":{"type":"boolean","description":"True when the window is capped and older messages may exist."},"note":{"type":"string","description":"Explicit caveats: not connected, partial history, no phone, nothing found."}},"additionalProperties":true,"required":["ok","requestId","phone","channelConnected","senders","serviceWindowOpen","messages","counts","lastInboundAt","lastOutboundAt","hasOutreach","hasReply","partial"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/lists/{listId}/add":{"post":{"operationId":"add_contacts_to_list","summary":"Add contact records to a My List by their record ids (contactId / lead id)","description":"Add contact records to a My List by their record ids (contactId / lead id). Every id must be a record this token can see — an unknown id refuses the whole call and nothing is changed. Records already on the list are counted as alreadyMembers. Membership is read back after saving (verified). Up to 1000 ids per call.\n\nRequired scope: `contacts.write`. Risk level: `write`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"List id (\"ml:<name>\") or exact name.","schema":{"type":"string","maxLength":140}},{"name":"contactIds","in":"query","required":true,"description":"Record ids to add.","schema":{"type":"array","maxItems":1000,"items":{"type":"string"}}},{"name":"createIfMissing","in":"query","required":false,"description":"true = create the list when it does not exist (default false).","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["contact_list"],"description":"Always contact_list."},"targetId":{"type":"string","description":"List id."},"list":{"type":"object","properties":{"id":{"type":"string","description":"ml:<name>."},"name":{"type":"string","description":"Name."},"memberCount":{"type":"integer","description":"Members now."}},"additionalProperties":true,"required":["id","name","memberCount"],"description":"The list after the change."},"added":{"type":"integer","description":"Ids newly added."},"alreadyMembers":{"type":"integer","description":"Ids that were already on the list."},"verified":{"type":"boolean","description":"Every id is on the list after read-back."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","list","added","alreadyMembers","verified"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/lists/{listId}/remove":{"post":{"operationId":"remove_contacts_from_list","summary":"Remove contact records from a My List (the records themselves are untouched and stay on the board)","description":"Remove contact records from a My List (the records themselves are untouched and stay on the board). For records that were imported INTO this list, the list tag on the record is cleared too (tagsCleared) so the board does not re-add them. Reversible with add_contacts_to_list.\n\nRequired scope: `contacts.write`. Risk level: `write`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"List id (\"ml:<name>\") or exact name.","schema":{"type":"string","maxLength":140}},{"name":"contactIds","in":"query","required":true,"description":"Record ids to remove.","schema":{"type":"array","maxItems":1000,"items":{"type":"string"}}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["contact_list"],"description":"Always contact_list."},"targetId":{"type":"string","description":"List id."},"list":{"type":"object","properties":{"id":{"type":"string","description":"ml:<name>."},"name":{"type":"string","description":"Name."},"memberCount":{"type":"integer","description":"Members now."}},"additionalProperties":true,"required":["id","name","memberCount"],"description":"The list after the change."},"removed":{"type":"integer","description":"Ids removed."},"notMembers":{"type":"integer","description":"Ids that were not on the list."},"tagsCleared":{"type":"integer","description":"Imported/landing-page records whose list tag was cleared so the board does not re-add them."},"tagErrors":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Records whose tag could not be cleared."},"verified":{"type":"boolean","description":"No id remains on the list after read-back."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","list","removed","notMembers","tagsCleared","verified"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/lists/{listId}/delete":{"post":{"operationId":"delete_contact_list","summary":"Delete a My List (lists of up to 500 members; larger ones only in the app)","description":"Delete a My List (lists of up to 500 members; larger ones only in the app). Member records are NOT deleted. PREVIEW FIRST: without confirm it reports the list, its size and how many imported records carry its tag (cleared on delete so the list does not resurrect).\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"List id (\"ml:<name>\") or exact name.","schema":{"type":"string","maxLength":140}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only."},"list":{"type":"object","properties":{"id":{"type":"string","description":"ml:<name>."},"name":{"type":"string","description":"Name."},"memberCount":{"type":"integer","description":"Members."}},"additionalProperties":true,"description":"Preview: the list and its size."},"taggedRecords":{"type":"integer","description":"Preview: records carrying this list's tag."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview warnings."},"deleted":{"type":"boolean","description":"Run: the list is gone."},"name":{"type":"string","description":"Run: the deleted list name."},"formerMembers":{"type":"integer","description":"Run: how many members it had (records untouched)."},"tagsCleared":{"type":"integer","description":"Run: record tags cleared."},"verified":{"type":"boolean","description":"Run: read back — the list no longer exists."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."},"targetType":{"type":"string","description":"Kind of record the action targets."},"targetId":{"type":"string","description":"Id of the record the action targets."}},"additionalProperties":true,"required":["ok","requestId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/{id}/update":{"post":{"operationId":"update_contact","summary":"Update ONE existing contact record by its stable id: the board's Due Date (dueDate, a calendar day — \"\" clears it; this is the contact's own date, not a task due date), pipeline status, owner, rating, name / email / phone / company (not for Facebook leads), and/or add a note","description":"Update ONE existing contact record by its stable id: the board's Due Date (dueDate, a calendar day — \"\" clears it; this is the contact's own date, not a task due date), pipeline status, owner, rating, name / email / phone / company (not for Facebook leads), and/or add a note. Only the fields you pass change. Fails with not_found for an unknown id and NEVER creates a record (use create_lead / import_contacts for that). Pass dryRun:true to preview before/after without writing. After writing, the record is read back and \"verified\" reports whether the store now shows the new values.\n\nRequired scope: `contacts.write`. Risk level: `write`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"contactId from list_contacts_in_list (= the lead/record id), or a contact id from search_contacts (its newest record is updated).","schema":{"type":"string","maxLength":200}},{"name":"dueDate","in":"query","required":false,"description":"Due Date as yyyy-mm-dd, or \"\" to clear.","schema":{"type":"string","maxLength":40}},{"name":"status","in":"query","required":false,"description":"New pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"owner","in":"query","required":false,"description":"New owner (their email), or \"\" to unassign.","schema":{"type":"string","maxLength":120}},{"name":"rating","in":"query","required":false,"description":"Star rating, 0-5.","schema":{"type":"integer","minimum":0,"maximum":5}},{"name":"name","in":"query","required":false,"description":"New full name (manual and landing-page/imported records only).","schema":{"type":"string","maxLength":160}},{"name":"email","in":"query","required":false,"description":"New email (manual and landing-page/imported records only). Changes the contact's identity key.","schema":{"type":"string","maxLength":160}},{"name":"phone","in":"query","required":false,"description":"New phone (manual and landing-page/imported records only).","schema":{"type":"string","maxLength":60}},{"name":"company","in":"query","required":false,"description":"New company (landing-page/imported records only).","schema":{"type":"string","maxLength":160}},{"name":"note","in":"query","required":false,"description":"A note to add to the contact's timeline.","schema":{"type":"string","maxLength":5000}},{"name":"noteKind","in":"query","required":false,"description":"What the note records (default note).","schema":{"type":"string","enum":["note","call","email","meeting","linkedin","sms","other"]}},{"name":"dryRun","in":"query","required":false,"description":"true = report before/after and change nothing.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["contact"],"description":"Always contact."},"targetId":{"type":"string","description":"The record id that was (or would be) changed."},"contactId":{"type":"string","description":"Same as targetId — the stable record id."},"contact":{"type":"object","properties":{"id":{"type":"string","description":"Contact key."},"name":{"type":"string","description":"Name."},"email":{"type":"string","description":"Email."},"phone":{"type":"string","description":"Phone."},"records":{"type":"integer","description":"Records behind the contact."}},"additionalProperties":true,"required":["id","name","email","phone","records"],"description":"Identity of the merged contact."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Store the record lives in."},"lists":{"type":"array","items":{"type":"string"},"description":"My Lists the record is on."},"before":{"type":"object","properties":{"dueDate":{"type":"string","description":"yyyy-mm-dd, \"\" when none."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email, \"\" when unassigned."},"rating":{"type":"number","description":"Rating 0-5."},"name":{"type":"string","description":"Full name."},"email":{"type":"string","description":"Email."},"phone":{"type":"string","description":"Phone."},"company":{"type":"string","description":"Company."}},"additionalProperties":true,"required":["dueDate","status","owner","rating"],"description":"Contact record fields (Due Date, status, owner, rating)."},"after":{"type":"object","properties":{"dueDate":{"type":"string","description":"yyyy-mm-dd, \"\" when none."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email, \"\" when unassigned."},"rating":{"type":"number","description":"Rating 0-5."},"name":{"type":"string","description":"Full name."},"email":{"type":"string","description":"Email."},"phone":{"type":"string","description":"Phone."},"company":{"type":"string","description":"Company."}},"additionalProperties":true,"required":["dueDate","status","owner","rating"],"description":"Contact record fields (Due Date, status, owner, rating)."},"changed":{"type":"array","items":{"type":"string","enum":["dueDate","status","owner","rating","name","email","phone","company"]},"description":"Fields that differ between before and after."},"preview":{"type":"boolean","description":"true on a dryRun."},"updated":{"type":"boolean","description":"true when a field was written (false on dryRun or when nothing differed)."},"verified":{"type":["boolean","null"],"description":"After writing: the record was read back and shows the new values. null on dryRun."},"readBack":{"type":["object","null"],"properties":{"dueDate":{"type":"string","description":"yyyy-mm-dd, \"\" when none."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email, \"\" when unassigned."},"rating":{"type":"number","description":"Rating 0-5."},"name":{"type":"string","description":"Full name."},"email":{"type":"string","description":"Email."},"phone":{"type":"string","description":"Phone."},"company":{"type":"string","description":"Company."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["dueDate","status","owner","rating"],"description":"The record as re-read after the write (null on dryRun)."},"message":{"type":"string","description":"Dry-run explanation."},"noteWouldBeAdded":{"type":"string","description":"Dry run: the note text that would be added."},"note":{"type":"object","additionalProperties":true,"description":"The note added (id, kind, text, createdAt)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","contactId","contact","source","lists","before","after","changed","updated"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/batch-update":{"post":{"operationId":"update_contacts_batch","summary":"Update up to 200 existing contact records in one call, each with its own fields (dueDate, status, owner, rating, name, email, phone, company, note)","description":"Update up to 200 existing contact records in one call, each with its own fields (dueDate, status, owner, rating, name, email, phone, company, note). PREVIEW FIRST: without confirm it resolves every id and reports before/after per contact and which ids do not exist. On confirm each record is written through the same path as update_contact, failures are reported per item without stopping the rest, nothing is ever created, and one read-back pass verifies every change. Fields not named on an item are left untouched.\n\nRequired scope: `contacts.write`. Risk level: `high`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"updates","in":"query","required":true,"description":"Items: { id, dueDate?, status?, owner?, rating?, name?, email?, phone?, company?, note?, noteKind? }.","schema":{"type":"array","maxItems":200,"items":{"type":"object"}}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: update_contacts_batch."},"total":{"type":"integer","description":"Items in the batch."},"found":{"type":"integer","description":"Preview: ids that resolve to a visible record."},"notFound":{"type":"integer","description":"Preview: ids with no visible record (nothing will be created)."},"invalid":{"type":"integer","description":"Preview: items with invalid values."},"willChange":{"type":"integer","description":"Preview: records that would change."},"unchanged":{"type":"integer","description":"Records whose supplied values already matched."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview warnings."},"updated":{"type":"integer","description":"Run: records written."},"failed":{"type":"integer","description":"Run: items that failed (see results[].error)."},"verified":{"type":"integer","description":"Run: written records whose read-back matched."},"mismatched":{"type":"integer","description":"Run: written records whose read-back did NOT match — investigate."},"message":{"type":"string","description":"Run summary."},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The id as supplied."},"contactId":{"type":"string","description":"Resolved record id."},"found":{"type":"boolean","description":"Preview: resolved?"},"ok":{"type":"boolean","description":"Run: written (or already correct) without error."},"verified":{"type":"boolean","description":"Run: read-back matched."},"source":{"type":"string","description":"Store of the record."},"email":{"type":"string","description":"Record email."},"before":{"type":"object","properties":{"dueDate":{"type":"string","description":"yyyy-mm-dd, \"\" when none."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email, \"\" when unassigned."},"rating":{"type":"number","description":"Rating 0-5."},"name":{"type":"string","description":"Full name."},"email":{"type":"string","description":"Email."},"phone":{"type":"string","description":"Phone."},"company":{"type":"string","description":"Company."}},"additionalProperties":true,"required":["dueDate","status","owner","rating"],"description":"Contact record fields (Due Date, status, owner, rating)."},"after":{"type":"object","properties":{"dueDate":{"type":"string","description":"yyyy-mm-dd, \"\" when none."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner email, \"\" when unassigned."},"rating":{"type":"number","description":"Rating 0-5."},"name":{"type":"string","description":"Full name."},"email":{"type":"string","description":"Email."},"phone":{"type":"string","description":"Phone."},"company":{"type":"string","description":"Company."}},"additionalProperties":true,"required":["dueDate","status","owner","rating"],"description":"Contact record fields (Due Date, status, owner, rating)."},"changed":{"type":"array","items":{"type":"string"},"description":"Fields that change."},"noteWouldBeAdded":{"type":"string","description":"Preview: note text."},"note":{"type":"string","description":"Run: id of the note added."},"error":{"type":"string","description":"Why this item failed (not_found: … / invalid_input: …)."}},"additionalProperties":true,"required":["id"]},"description":"One entry per item, in input order (preview and run)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."},"targetType":{"type":"string","description":"Kind of record the action targets."},"targetId":{"type":"string","description":"Id of the record the action targets."}},"additionalProperties":true,"required":["ok","requestId","results"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores":{"get":{"operationId":"list_stores","summary":"The connected eCommerce stores/websites in this workspace (Shopify, WooCommerce, Wix, or GTM-connected sites)","description":"The connected eCommerce stores/websites in this workspace (Shopify, WooCommerce, Wix, or GTM-connected sites). Every customer tool needs a storeId from here.\n\nRequired scope: `customers.read`. Risk level: `read`.","tags":["customers"],"security":[{"bearerAuth":["customers.read"]}],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"stores":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Store (site) id — pass as storeId to the customer tools."},"name":{"type":"string","description":"Store name (falls back to domain or id)."},"domain":{"type":"string","description":"Store domain (\"\" when unknown)."},"platform":{"type":"string","description":"Store platform, e.g. woocommerce, shopify, wix (\"\" when unknown)."},"productCount":{"type":"integer","description":"Products in the synced catalog."}},"additionalProperties":true,"required":["id","name","domain","platform","productCount"]},"description":"Connected eCommerce stores (sites) visible to this token."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"source":{"type":"string","description":"Backing store the list was read from (e.g. redis)."}},"additionalProperties":true,"required":["ok","requestId","stores","pagination","source"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/customers":{"get":{"operationId":"search_customers","summary":"Customers of one store, aggregated from its orders: order count, lifetime spend, average order value, first and last order","description":"Customers of one store, aggregated from its orders: order count, lifetime spend, average order value, first and last order. Filter by minimum orders or a last-order date range; sort by recency (default) or spend.\n\nRequired scope: `customers.read`. Risk level: `read`.","tags":["customers"],"security":[{"bearerAuth":["customers.read"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"query","in":"query","required":false,"description":"Free text: email, name or phone.","schema":{"type":"string","maxLength":120}},{"name":"minOrders","in":"query","required":false,"description":"Only customers with at least this many orders.","schema":{"type":"integer","minimum":1,"maximum":1000}},{"name":"sort","in":"query","required":false,"description":"Result order.","schema":{"type":"string","enum":["recent_desc","spend_desc"],"default":"recent_desc"}},{"name":"dateFrom","in":"query","required":false,"description":"Only records at or after this ISO 8601 date/datetime (e.g. 2026-07-01).","schema":{"type":"string","maxLength":40}},{"name":"dateTo","in":"query","required":false,"description":"Only records at or before this ISO 8601 date/datetime.","schema":{"type":"string","maxLength":40}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"customers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Customer key: lower-cased email, or \"order:<id>\" for orders without one."},"email":{"type":"string","description":"Lower-cased email (\"\" when the order carried none)."},"name":{"type":"string","description":"Customer name (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"orders":{"type":"integer","description":"Number of orders (within the 1000 most recent store orders)."},"totalSpend":{"type":"number","description":"Sum of order totals in `currency`, 2 decimals."},"currency":{"type":"string","description":"Currency of the first order seen (else store currency, \"\" when unknown)."},"firstOrderAt":{"type":"string","description":"ISO 8601 of the earliest order (\"\" when unknown)."},"lastOrderAt":{"type":"string","description":"ISO 8601 of the latest order (\"\" when unknown)."},"storeId":{"type":"string","description":"Store id the customer belongs to."},"avgOrderValue":{"type":"number","description":"totalSpend / orders, 2 decimals."}},"additionalProperties":true,"required":["id","email","name","phone","orders","totalSpend","currency","firstOrderAt","lastOrderAt","storeId","avgOrderValue"]},"description":"Matching customers (aggregated from orders)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"storeId":{"type":"string","description":"The store searched."},"source":{"type":"string","description":"Backing store the orders were read from (e.g. redis)."},"note":{"type":"string","description":"Caveat from the orders read (e.g. capped), only when present."}},"additionalProperties":true,"required":["ok","requestId","customers","pagination","storeId","source"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/customers/lookup":{"get":{"operationId":"get_customer","summary":"One customer of one store by email (or the id from search_customers), with their order totals and dates","description":"One customer of one store by email (or the id from search_customers), with their order totals and dates.\n\nRequired scope: `customers.read`. Risk level: `read`.","tags":["customers"],"security":[{"bearerAuth":["customers.read"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"email","in":"query","required":false,"description":"Customer email.","schema":{"type":"string","maxLength":160}},{"name":"id","in":"query","required":false,"description":"Customer id from search_customers.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"customer":{"type":"object","properties":{"id":{"type":"string","description":"Customer key: lower-cased email, or \"order:<id>\" for orders without one."},"email":{"type":"string","description":"Lower-cased email (\"\" when the order carried none)."},"name":{"type":"string","description":"Customer name (\"\" when unknown)."},"phone":{"type":"string","description":"Phone (\"\" when unknown)."},"orders":{"type":"integer","description":"Number of orders (within the 1000 most recent store orders)."},"totalSpend":{"type":"number","description":"Sum of order totals in `currency`, 2 decimals."},"currency":{"type":"string","description":"Currency of the first order seen (else store currency, \"\" when unknown)."},"firstOrderAt":{"type":"string","description":"ISO 8601 of the earliest order (\"\" when unknown)."},"lastOrderAt":{"type":"string","description":"ISO 8601 of the latest order (\"\" when unknown)."},"storeId":{"type":"string","description":"Store id the customer belongs to."},"avgOrderValue":{"type":"number","description":"totalSpend / orders, 2 decimals."}},"additionalProperties":true,"required":["id","email","name","phone","orders","totalSpend","currency","firstOrderAt","lastOrderAt","storeId","avgOrderValue"],"description":"The customer, aggregated from the store orders."}},"additionalProperties":true,"required":["ok","requestId","customer"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/orders":{"get":{"operationId":"list_customer_orders","summary":"Recent orders of one customer in one store, newest first: number, status, total, items, coupons and dates","description":"Recent orders of one customer in one store, newest first: number, status, total, items, coupons and dates. Identify the customer by email, phone or an order number (at least one).\n\nRequired scope: `customers.read`. Risk level: `read`.","tags":["customers"],"security":[{"bearerAuth":["customers.read"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"email","in":"query","required":false,"description":"Customer email.","schema":{"type":"string","maxLength":160}},{"name":"phone","in":"query","required":false,"description":"Customer phone, any format.","schema":{"type":"string","maxLength":40}},{"name":"orderNumber","in":"query","required":false,"description":"An order number or id.","schema":{"type":"string","maxLength":60}},{"name":"limit","in":"query","required":false,"description":"How many orders (default 5).","schema":{"type":"integer","minimum":1,"maximum":20,"default":5}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Order id."},"number":{"type":"string","description":"Order number as shown to the customer (falls back to id)."},"status":{"type":"string","description":"Order status when known."},"total":{"type":"number","description":"Order total in `currency` when known."},"currency":{"type":"string","description":"Currency code when known."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Product name."},"qty":{"type":"number","description":"Quantity when known."}},"additionalProperties":true,"required":["name"]},"description":"Up to 20 line items when the order carries them."},"itemCount":{"type":"number","description":"Number of items when known."},"coupons":{"type":"array","items":{},"description":"Up to 5 coupon codes applied, as stored on the order."},"shippingMethod":{"type":"string","description":"Shipping method when known."},"shippingCity":{"type":"string","description":"Shipping city when known."}},"additionalProperties":true,"required":["id","number","createdAt"]},"description":"Matching orders, newest first, up to `limit` (max 20)."},"storeId":{"type":"string","description":"The store searched."},"source":{"type":"string","description":"Backing store the orders were read from (e.g. redis)."}},"additionalProperties":true,"required":["ok","requestId","orders","storeId","source"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/abandoned-carts":{"get":{"operationId":"list_abandoned_carts","summary":"Identified visitors who added to the cart in the last N hours and have not bought since: email and/or phone, when, the last product and the cart value","description":"Identified visitors who added to the cart in the last N hours and have not bought since: email and/or phone, when, the last product and the cart value. For cart-recovery messages — send only to people who already agreed to hear from the shop.\n\nRequired scope: `customers.read`. Risk level: `read`.","tags":["customers"],"security":[{"bearerAuth":["customers.read"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"hours","in":"query","required":false,"description":"How far back to look (1-72, default 24).","schema":{"type":"integer","minimum":1,"maximum":72,"default":24}},{"name":"minAgeMinutes","in":"query","required":false,"description":"Ignore carts younger than this — the visitor may still be checking out (15-720, default 60).","schema":{"type":"integer","minimum":15,"maximum":720,"default":60}},{"name":"limit","in":"query","required":false,"description":"How many carts (default 100).","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"carts":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Email or \"\"."},"phone":{"type":"string","description":"Phone or \"\"."},"site":{"type":"string","description":"Site / publisher id the event came from."},"at":{"type":"string","description":"When the item was added, ISO 8601."},"product":{"type":"object","properties":{"id":{"type":"string","description":"Product id."},"name":{"type":"string","description":"Product name."},"price":{"type":"number","description":"Unit price, store currency."},"url":{"type":"string","description":"Product URL or \"\"."}},"additionalProperties":true,"required":["id","name","url"],"description":"Last product added (absent when the event carried none)."},"cartValue":{"type":"number","description":"Cart value at the time, store currency."}},"additionalProperties":true,"required":["email","phone","site","at"]},"description":"Identified visitors with an add-to-cart and no purchase since, newest first."},"hours":{"type":"integer","description":"Look-back window actually used (1-72)."}},"additionalProperties":true,"required":["ok","requestId","carts","hours"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/orders/{orderId}/cancel":{"post":{"operationId":"cancel_order","summary":"Cancel one order in the connected store (WooCommerce, Shopify, Wix or the WordPress plugin)","description":"Cancel one order in the connected store (WooCommerce, Shopify, Wix or the WordPress plugin). Only orders not yet fulfilled can be cancelled; the store restocks the items and, where it can, emails the customer. Money is NOT returned by this tool — use refund_order for that.\n\nRequired scope: `orders.write`. Risk level: `write`.","tags":["orders"],"security":[{"bearerAuth":["orders.write"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"orderId","in":"path","required":true,"description":"The order number (as the customer sees it) or the store id of the order.","schema":{"type":"string","maxLength":80}},{"name":"reason","in":"query","required":false,"description":"Why, in a few words — kept on the order.","schema":{"type":"string","maxLength":200}},{"name":"notifyCustomer","in":"query","required":false,"description":"Let the store email the customer about the cancellation. Default true.","schema":{"type":"boolean","default":true}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"cancelled":{"type":"boolean","description":"Always true on success."},"platform":{"type":"string","description":"Store platform, e.g. woocommerce, shopify, wix."},"order":{"type":"object","properties":{"id":{"type":"string","description":"Platform order id."},"number":{"type":"string","description":"Order number as shown to the customer."},"status":{"type":"string","description":"Platform order status, e.g. processing, cancelled."},"financialStatus":{"type":"string","description":"Payment status (Shopify/Wix), e.g. paid, refunded."},"total":{"type":"number","description":"Order total in the store currency."},"currency":{"type":"string","description":"ISO 4217 currency code."},"refunded":{"type":"number","description":"Amount already refunded."},"createdAt":{"type":"string","description":"Order creation time (platform format)."},"customer":{"type":"object","properties":{"email":{"type":"string","description":"Email, lower-cased."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["email","phone"],"description":"Customer contact."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Product name."},"qty":{"type":"integer","description":"Quantity."}},"additionalProperties":true,"required":["name","qty"]},"description":"Line items."},"shipping":{"type":"object","properties":{"name":{"type":"string","description":"Recipient name."},"address1":{"type":"string","description":"Address line 1."},"address2":{"type":"string","description":"Address line 2."},"city":{"type":"string","description":"City."},"state":{"type":"string","description":"State / province."},"postcode":{"type":"string","description":"Postal code."},"country":{"type":"string","description":"Country code or name."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["name","address1","address2","city","state","postcode","country","phone"],"description":"Shipping address (absent when the order has none)."},"cancellable":{"type":"boolean","description":"true when the order can still be cancelled."},"pending":{"type":"boolean","description":"true when the platform queued the change asynchronously."}},"additionalProperties":true,"required":["id","number","status","refunded","customer","items","cancellable"],"description":"Normalised store order (WooCommerce / Shopify / Wix / plugin)."},"targetType":{"type":"string","enum":["order"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Order number."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","cancelled","platform","order","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/orders/{orderId}/address":{"post":{"operationId":"update_order_address","summary":"Change the shipping address of one order in the connected store","description":"Change the shipping address of one order in the connected store. Give only the fields that change; the rest are kept. Refused by the store once the order has shipped.\n\nRequired scope: `orders.write`. Risk level: `write`.","tags":["orders"],"security":[{"bearerAuth":["orders.write"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"orderId","in":"path","required":true,"description":"The order number or the store id of the order.","schema":{"type":"string","maxLength":80}},{"name":"address","in":"query","required":true,"description":"Fields to change: name, address1, address2, city, state, postcode, country (ISO-2), phone.","schema":{"type":"string"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"updated":{"type":"boolean","description":"Always true on success."},"platform":{"type":"string","description":"Store platform, e.g. woocommerce, shopify, wix."},"order":{"type":"object","properties":{"id":{"type":"string","description":"Platform order id."},"number":{"type":"string","description":"Order number as shown to the customer."},"status":{"type":"string","description":"Platform order status, e.g. processing, cancelled."},"financialStatus":{"type":"string","description":"Payment status (Shopify/Wix), e.g. paid, refunded."},"total":{"type":"number","description":"Order total in the store currency."},"currency":{"type":"string","description":"ISO 4217 currency code."},"refunded":{"type":"number","description":"Amount already refunded."},"createdAt":{"type":"string","description":"Order creation time (platform format)."},"customer":{"type":"object","properties":{"email":{"type":"string","description":"Email, lower-cased."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["email","phone"],"description":"Customer contact."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Product name."},"qty":{"type":"integer","description":"Quantity."}},"additionalProperties":true,"required":["name","qty"]},"description":"Line items."},"shipping":{"type":"object","properties":{"name":{"type":"string","description":"Recipient name."},"address1":{"type":"string","description":"Address line 1."},"address2":{"type":"string","description":"Address line 2."},"city":{"type":"string","description":"City."},"state":{"type":"string","description":"State / province."},"postcode":{"type":"string","description":"Postal code."},"country":{"type":"string","description":"Country code or name."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["name","address1","address2","city","state","postcode","country","phone"],"description":"Shipping address (absent when the order has none)."},"cancellable":{"type":"boolean","description":"true when the order can still be cancelled."},"pending":{"type":"boolean","description":"true when the platform queued the change asynchronously."}},"additionalProperties":true,"required":["id","number","status","refunded","customer","items","cancellable"],"description":"Normalised store order (WooCommerce / Shopify / Wix / plugin)."},"targetType":{"type":"string","enum":["order"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Order number."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","updated","platform","order","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/orders/{orderId}/refund":{"post":{"operationId":"refund_order","summary":"Refund money on one order through the store's own payment gateway — the whole amount still refundable, or a partial amount","description":"Refund money on one order through the store's own payment gateway — the whole amount still refundable, or a partial amount. Two calls: a preview showing the order, what was paid and what would go back, then confirm:true with the token.\n\nRequired scope: `orders.write`. Risk level: `high`.","tags":["orders"],"security":[{"bearerAuth":["orders.write"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"orderId","in":"path","required":true,"description":"The order number or the store id of the order.","schema":{"type":"string","maxLength":80}},{"name":"amount","in":"query","required":false,"description":"Amount to refund in the order currency. Omit for everything still refundable.","schema":{"type":"number"}},{"name":"reason","in":"query","required":false,"description":"Why, in a few words — kept on the refund.","schema":{"type":"string","maxLength":200}},{"name":"notifyCustomer","in":"query","required":false,"description":"Let the store email the customer about the refund. Default true.","schema":{"type":"boolean","default":true}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willRefund":{"type":"object","properties":{"amount":{"type":"number","description":"Amount to refund, 2 decimals, capped at the unrefunded balance."},"currency":{"type":"string","description":"ISO 4217 currency code."},"order":{"type":"object","properties":{"id":{"type":"string","description":"Platform order id."},"number":{"type":"string","description":"Order number as shown to the customer."},"status":{"type":"string","description":"Platform order status, e.g. processing, cancelled."},"financialStatus":{"type":"string","description":"Payment status (Shopify/Wix), e.g. paid, refunded."},"total":{"type":"number","description":"Order total in the store currency."},"currency":{"type":"string","description":"ISO 4217 currency code."},"refunded":{"type":"number","description":"Amount already refunded."},"createdAt":{"type":"string","description":"Order creation time (platform format)."},"customer":{"type":"object","properties":{"email":{"type":"string","description":"Email, lower-cased."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["email","phone"],"description":"Customer contact."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Product name."},"qty":{"type":"integer","description":"Quantity."}},"additionalProperties":true,"required":["name","qty"]},"description":"Line items."},"shipping":{"type":"object","properties":{"name":{"type":"string","description":"Recipient name."},"address1":{"type":"string","description":"Address line 1."},"address2":{"type":"string","description":"Address line 2."},"city":{"type":"string","description":"City."},"state":{"type":"string","description":"State / province."},"postcode":{"type":"string","description":"Postal code."},"country":{"type":"string","description":"Country code or name."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["name","address1","address2","city","state","postcode","country","phone"],"description":"Shipping address (absent when the order has none)."},"cancellable":{"type":"boolean","description":"true when the order can still be cancelled."},"pending":{"type":"boolean","description":"true when the platform queued the change asynchronously."}},"additionalProperties":true,"required":["id","number","status","refunded","customer","items","cancellable"],"description":"Normalised store order (WooCommerce / Shopify / Wix / plugin)."}},"additionalProperties":true,"required":["amount","order"],"description":"Preview only: what the refund would do."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"refunded":{"type":"boolean","description":"Run only: true on success."},"platform":{"type":"string","description":"Run only: store platform."},"refund":{"type":"object","properties":{"id":{"type":"string","description":"Platform refund id (\"\" if none)."},"amount":{"type":"number","description":"Refunded amount."},"currency":{"type":"string","description":"ISO 4217 currency code."},"external":{"description":"Wix only: set when the refund must be completed offline."}},"additionalProperties":true,"required":["id"],"description":"Run only: the refund the platform created."},"order":{"type":"object","properties":{"id":{"type":"string","description":"Platform order id."},"number":{"type":"string","description":"Order number as shown to the customer."},"status":{"type":"string","description":"Platform order status, e.g. processing, cancelled."},"financialStatus":{"type":"string","description":"Payment status (Shopify/Wix), e.g. paid, refunded."},"total":{"type":"number","description":"Order total in the store currency."},"currency":{"type":"string","description":"ISO 4217 currency code."},"refunded":{"type":"number","description":"Amount already refunded."},"createdAt":{"type":"string","description":"Order creation time (platform format)."},"customer":{"type":"object","properties":{"email":{"type":"string","description":"Email, lower-cased."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["email","phone"],"description":"Customer contact."},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Product name."},"qty":{"type":"integer","description":"Quantity."}},"additionalProperties":true,"required":["name","qty"]},"description":"Line items."},"shipping":{"type":"object","properties":{"name":{"type":"string","description":"Recipient name."},"address1":{"type":"string","description":"Address line 1."},"address2":{"type":"string","description":"Address line 2."},"city":{"type":"string","description":"City."},"state":{"type":"string","description":"State / province."},"postcode":{"type":"string","description":"Postal code."},"country":{"type":"string","description":"Country code or name."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["name","address1","address2","city","state","postcode","country","phone"],"description":"Shipping address (absent when the order has none)."},"cancellable":{"type":"boolean","description":"true when the order can still be cancelled."},"pending":{"type":"boolean","description":"true when the platform queued the change asynchronously."}},"additionalProperties":true,"required":["id","number","status","refunded","customer","items","cancellable"],"description":"Run only: the order after the refund."},"targetType":{"type":"string","enum":["order"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Order number."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/stores/{storeId}/summary":{"get":{"operationId":"get_customer_summary","summary":"Store-level customer economics: customer count, orders, revenue, average order value, repeat-purchase rate and the ten highest-spending customers","description":"Store-level customer economics: customer count, orders, revenue, average order value, repeat-purchase rate and the ten highest-spending customers. Use it for \"how is this store doing?\" before drilling into individuals.\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[{"name":"storeId","in":"path","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"storeId":{"type":"string","description":"The store summarized."},"source":{"type":"string","description":"Backing store the orders were read from (e.g. redis)."},"customers":{"type":"integer","description":"Distinct customers (within the 1000 most recent orders)."},"orders":{"type":"integer","description":"Total orders in the store."},"revenue":{"type":"number","description":"Sum of customer spend in `currency`, 2 decimals."},"currency":{"type":"string","description":"Currency code (\"\" when unknown)."},"avgOrderValue":{"type":"number","description":"revenue / orders, 2 decimals."},"repeatCustomers":{"type":"integer","description":"Customers with more than one order."},"repeatRate":{"type":"number","description":"repeatCustomers / customers in percent (0-100, 1 decimal)."},"topCustomers":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Lower-cased email (\"\" when none)."},"name":{"type":"string","description":"Name (\"\" when unknown)."},"orders":{"type":"integer","description":"Order count."},"totalSpend":{"type":"number","description":"Spend in `currency`."}},"additionalProperties":true,"required":["email","name","orders","totalSpend"]},"description":"Top 10 customers by spend."}},"additionalProperties":true,"required":["ok","requestId","storeId","source","customers","orders","revenue","currency","avgOrderValue","repeatCustomers","repeatRate","topCustomers"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/tasks":{"get":{"operationId":"list_tasks","summary":"CRM tasks in this workspace, soonest due first","description":"CRM tasks in this workspace, soonest due first. Open tasks only unless includeDone is true. Filter by owner, by due-date window, or by the record a task hangs off (relatedType contact/company/deal + relatedId).\n\nRequired scope: `tasks.read`. Risk level: `read`.","tags":["tasks"],"security":[{"bearerAuth":["tasks.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Substring of the task title.","schema":{"type":"string","maxLength":120}},{"name":"owner","in":"query","required":false,"description":"Assignee, exact match.","schema":{"type":"string","maxLength":120}},{"name":"includeDone","in":"query","required":false,"description":"Include completed tasks.","schema":{"type":"boolean","default":false}},{"name":"relatedType","in":"query","required":false,"description":"Only tasks attached to this record type.","schema":{"type":"string","enum":["contact","company","deal"]}},{"name":"relatedId","in":"query","required":false,"description":"Only tasks attached to this record id.","schema":{"type":"string","maxLength":80}},{"name":"dueFrom","in":"query","required":false,"description":"Only tasks due at or after this ISO 8601 date.","schema":{"type":"string","maxLength":40}},{"name":"dueTo","in":"query","required":false,"description":"Only tasks due at or before this ISO 8601 date.","schema":{"type":"string","maxLength":40}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title (≤200 chars)."},"done":{"type":"boolean","description":"True when completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when none."},"priorityLabel":{"type":"string","description":"Priority label as stored on the board (e.g. Medium)."},"owner":{"type":"string","description":"Assignee (\"\" when unassigned)."},"dueAt":{"type":"string","description":"ISO 8601 due datetime (end of day when no time), \"\" when no due date."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type, e.g. contact, deal, company."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, or null."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo","createdAt","updatedAt"]},"description":"Matching tasks, soonest due first (no due date last)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."}},"additionalProperties":true,"required":["ok","requestId","tasks","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_task","summary":"Create a CRM task","description":"Create a CRM task. Attach it to a lead by passing relatedType \"contact\" and the lead id, and it will show on that lead and in list_leads_requiring_followup once overdue.\n\nRequired scope: `tasks.write`. Risk level: `write`.","tags":["tasks"],"security":[{"bearerAuth":["tasks.write"]}],"parameters":[{"name":"title","in":"query","required":true,"description":"What needs doing.","schema":{"type":"string","maxLength":200}},{"name":"dueDate","in":"query","required":false,"description":"ISO 8601 date, or date-time to set a time of day.","schema":{"type":"string","maxLength":40}},{"name":"owner","in":"query","required":false,"description":"Assign to this user (their email).","schema":{"type":"string","maxLength":120}},{"name":"priority","in":"query","required":false,"description":"Task priority.","schema":{"type":"string","enum":["low","normal","high","urgent"]}},{"name":"relatedType","in":"query","required":false,"description":"Attach the task to this record type.","schema":{"type":"string","enum":["contact","company","deal"]}},{"name":"relatedId","in":"query","required":false,"description":"Id of the record to attach to. Required with relatedType.","schema":{"type":"string","maxLength":80}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["task"],"description":"Always \"task\"."},"targetId":{"type":"string","description":"Id of the created task."},"created":{"type":"boolean","description":"Always true on success."},"task":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title."},"done":{"type":"boolean","description":"True when the task is completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when unset."},"priorityLabel":{"type":"string","description":"Priority as stored on the board (e.g. Medium), \"\" when unset."},"owner":{"type":"string","description":"Assignee (email or name), \"\" when unassigned."},"dueAt":{"type":"string","description":"Due date/time as ISO 8601 (end of day when no time), \"\" when none."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type (e.g. contact, deal, company)."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, null when the task is not linked."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo"],"description":"The task as list_tasks would return it."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","task"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/tasks/{id}":{"get":{"operationId":"get_task","summary":"One CRM task by id: title, due date, assignee, priority, whether it is done, and the contact/company/deal it hangs off","description":"One CRM task by id: title, due date, assignee, priority, whether it is done, and the contact/company/deal it hangs off.\n\nRequired scope: `tasks.read`. Risk level: `read`.","tags":["tasks"],"security":[{"bearerAuth":["tasks.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Task id from list_tasks.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"task":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title (≤200 chars)."},"done":{"type":"boolean","description":"True when completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when none."},"priorityLabel":{"type":"string","description":"Priority label as stored on the board (e.g. Medium)."},"owner":{"type":"string","description":"Assignee (\"\" when unassigned)."},"dueAt":{"type":"string","description":"ISO 8601 due datetime (end of day when no time), \"\" when no due date."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type, e.g. contact, deal, company."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, or null."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo","createdAt","updatedAt"],"description":"The task."}},"additionalProperties":true,"required":["ok","requestId","task"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/deals":{"get":{"operationId":"list_deals","summary":"Sales-pipeline deals in this workspace, soonest expected close first","description":"Sales-pipeline deals in this workspace, soonest expected close first. Open deals by default; each row carries stage, amount, currency, win probability, weighted amount, forecast category, owner, days in stage, linked contact/company ids and line items. The response also lists the pipeline stages this workspace uses.\n\nRequired scope: `deals.read`. Risk level: `read`.","tags":["deals"],"security":[{"bearerAuth":["deals.read"]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Which deals: 'open' (default), 'won', 'lost' or 'all'.","schema":{"type":"string","enum":["open","won","lost","all"]}},{"name":"stage","in":"query","required":false,"description":"Only deals in this pipeline stage (exact name, see the stages list in any list_deals response).","schema":{"type":"string","maxLength":40}},{"name":"pipeline","in":"query","required":false,"description":"Only deals in this pipeline (id or name; the response lists the pipelines this workspace has).","schema":{"type":"string","maxLength":60}},{"name":"owner","in":"query","required":false,"description":"Only deals owned by this person (exact owner text).","schema":{"type":"string","maxLength":120}},{"name":"query","in":"query","required":false,"description":"Substring of the deal name, company name or next step.","schema":{"type":"string","maxLength":120}},{"name":"contactId","in":"query","required":false,"description":"Only deals linked to this contact / lead id.","schema":{"type":"string","maxLength":80}},{"name":"companyId","in":"query","required":false,"description":"Only deals linked to this company id.","schema":{"type":"string","maxLength":80}},{"name":"minAmount","in":"query","required":false,"description":"Only deals with at least this amount.","schema":{"type":"number"}},{"name":"closeFrom","in":"query","required":false,"description":"Only deals whose expected close date is on/after this date (YYYY-MM-DD).","schema":{"type":"string","maxLength":10}},{"name":"closeTo","in":"query","required":false,"description":"Only deals whose expected close date is on/before this date (YYYY-MM-DD).","schema":{"type":"string","maxLength":10}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"deals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Deal id."},"name":{"type":"string","description":"Deal name."},"stage":{"type":"string","description":"Current stage name; \"Closed Won\" / \"Closed Lost\" when closed."},"pipeline":{"type":"string","description":"Pipeline id (\"default\" for the main pipeline)."},"pipelineName":{"type":"string","description":"Pipeline display name."},"open":{"type":"boolean","description":"True unless the stage starts with \"Closed\"."},"amount":{"type":"number","description":"Deal value in `currency` (0 when unset)."},"currency":{"type":"string","description":"ISO 4217 code; falls back to the workspace CRM currency."},"probability":{"type":"number","description":"Win probability 0-100 (deal-specific, else stage default)."},"weightedAmount":{"type":"number","description":"amount × probability / 100."},"forecastCategory":{"type":"string","description":"Commit | Best case | Pipeline | Omit (or custom); \"\" for closed deals."},"closeDate":{"type":"string","description":"Expected close date YYYY-MM-DD (\"\" when unset)."},"closedAt":{"type":"string","description":"ISO 8601 actual close time (\"\" when open)."},"owner":{"type":"string","description":"Owner email/name (\"\" when unassigned)."},"dealType":{"type":"string","description":"Free-form deal type (\"\" when unset)."},"priority":{"type":"string","description":"Free-form priority (\"\" when unset)."},"nextStep":{"type":"string","description":"Next step text (≤300 chars)."},"lostReason":{"type":"string","description":"Lost reason (\"\" unless lost)."},"daysInStage":{"type":"integer","description":"Whole days since the deal entered its current stage (0 when closed)."},"stageEnteredAt":{"type":"string","description":"ISO 8601 time the current stage was entered (\"\" when unknown)."},"stageHistory":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","description":"Previous stage."},"to":{"type":"string","description":"New stage."},"at":{"type":"string","description":"ISO 8601."},"by":{"type":"string","description":"Who moved it."}},"additionalProperties":true,"required":["from","to","at","by"]},"description":"Last 20 stage transitions, oldest first."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact (lead) ids."},"companyIds":{"type":"array","items":{"type":"string"},"description":"Linked company ids."},"companies":{"type":"array","items":{"type":"string"},"description":"Names of the linked companies that resolved."},"lineItems":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Item name."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (0 when unset)."},"unitPrice":{"type":"number","description":"Unit price in the deal currency."}},"additionalProperties":true,"required":["name","sku","quantity","unitPrice"]},"description":"Up to 50 line items."},"description":{"type":"string","description":"Description (≤2000 chars)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name","stage","pipeline","pipelineName","open","amount","currency","probability","weightedAmount","forecastCategory","closeDate","closedAt","owner","dealType","priority","nextStep","lostReason","daysInStage","stageEnteredAt","stageHistory","contactIds","companyIds","companies","lineItems","description","createdAt","updatedAt"]},"description":"Matching deals, earliest close date first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"stages":{"type":"array","items":{"type":"string"},"description":"Default pipeline stage names, open stages then Closed Won / Closed Lost."},"currency":{"type":"string","description":"Workspace CRM currency (ISO 4217, default USD)."},"pipelines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pipeline id (\"default\" for the main one)."},"name":{"type":"string","description":"Pipeline name."},"stages":{"type":"array","items":{"type":"string"},"description":"Stage names, open stages then Closed Won / Closed Lost."}},"additionalProperties":true,"required":["id","name","stages"]},"description":"All pipelines and their stage lists."}},"additionalProperties":true,"required":["ok","requestId","deals","pagination","stages","currency","pipelines"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_deal","summary":"Create a sales deal in the pipeline, optionally linked to contacts and companies","description":"Create a sales deal in the pipeline, optionally linked to contacts and companies. Defaults to the first open stage; stage names must match this workspace's pipeline (see list_deals). Stage history starts with the creation.\n\nRequired scope: `deals.write`. Risk level: `write`.","tags":["deals"],"security":[{"bearerAuth":["deals.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Deal name.","schema":{"type":"string","maxLength":200}},{"name":"amount","in":"query","required":false,"description":"Deal amount in the deal currency.","schema":{"type":"number"}},{"name":"currency","in":"query","required":false,"description":"3-letter ISO currency; defaults to the workspace pipeline currency.","schema":{"type":"string","maxLength":3}},{"name":"pipeline","in":"query","required":false,"description":"Pipeline id or name; defaults to the workspace default pipeline.","schema":{"type":"string","maxLength":60}},{"name":"stage","in":"query","required":false,"description":"Pipeline stage name (of that pipeline); defaults to its first open stage.","schema":{"type":"string","maxLength":40}},{"name":"closeDate","in":"query","required":false,"description":"Expected close date, YYYY-MM-DD.","schema":{"type":"string","maxLength":10}},{"name":"owner","in":"query","required":false,"description":"Owner name or email.","schema":{"type":"string","maxLength":120}},{"name":"probability","in":"query","required":false,"description":"Win probability 0-100; omit to use the stage default.","schema":{"type":"number"}},{"name":"forecastCategory","in":"query","required":false,"description":"Forecast category override.","schema":{"type":"string","enum":["Pipeline","Best case","Commit","Omit"]}},{"name":"dealType","in":"query","required":false,"description":"e.g. New business, Existing business, Renewal, Upsell.","schema":{"type":"string","maxLength":40}},{"name":"priority","in":"query","required":false,"description":"Low, Medium or High.","schema":{"type":"string","enum":["Low","Medium","High"]}},{"name":"nextStep","in":"query","required":false,"description":"What happens next on this deal.","schema":{"type":"string","maxLength":300}},{"name":"description","in":"query","required":false,"description":"Free-text description.","schema":{"type":"string","maxLength":2000}},{"name":"contactIds","in":"query","required":false,"description":"Contact / lead ids to link to the deal.","schema":{"type":"array","items":{"type":"string"}}},{"name":"companyIds","in":"query","required":false,"description":"Company ids to link to the deal.","schema":{"type":"array","items":{"type":"string"}}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["deal"],"description":"Always \"deal\"."},"targetId":{"type":"string","description":"Id of the created deal."},"created":{"type":"boolean","description":"Always true on success."},"deal":{"type":"object","properties":{"id":{"type":"string","description":"Deal id."},"name":{"type":"string","description":"Deal name."},"stage":{"type":"string","description":"Current pipeline stage name."},"pipeline":{"type":"string","description":"Pipeline id (\"default\" for the main pipeline)."},"pipelineName":{"type":"string","description":"Pipeline display name."},"open":{"type":"boolean","description":"False once the stage starts with \"Closed\"."},"amount":{"type":"number","description":"Deal value in `currency`; 0 when unset."},"currency":{"type":"string","description":"3-letter ISO currency code (workspace default when unset)."},"probability":{"type":"number","description":"Win probability 0-100 (own value or derived from the stage)."},"weightedAmount":{"type":"number","description":"amount × probability / 100."},"forecastCategory":{"type":"string","description":"Pipeline | Best case | Commit | Omit (derived when unset); \"\" for closed deals."},"closeDate":{"type":"string","description":"Expected close date YYYY-MM-DD, \"\" when unset."},"closedAt":{"type":"string","description":"ISO 8601 time the deal was closed, \"\" when open."},"owner":{"type":"string","description":"Deal owner, \"\" when unassigned."},"dealType":{"type":"string","description":"Free-text deal type, \"\" when unset."},"priority":{"type":"string","description":"Free-text priority, \"\" when unset."},"nextStep":{"type":"string","description":"Next step text, \"\" when unset."},"lostReason":{"type":"string","description":"Reason when Closed Lost, \"\" otherwise."},"daysInStage":{"type":"integer","description":"Whole days since entering the current stage; 0 for closed deals."},"stageEnteredAt":{"type":"string","description":"ISO 8601 time the current stage was entered, \"\" when unknown."},"stageHistory":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","description":"Previous stage, \"\" for the first entry."},"to":{"type":"string","description":"New stage."},"at":{"type":"string","description":"ISO 8601 time of the transition, \"\" when unknown."},"by":{"type":"string","description":"Who moved it, \"\" when unknown."}},"additionalProperties":true,"required":["from","to","at","by"],"description":"One stage transition."},"description":"Last 20 stage transitions, oldest first."},"contactIds":{"type":"array","items":{"type":"string","description":"Contact id."},"description":"Linked contact (lead) ids."},"companyIds":{"type":"array","items":{"type":"string","description":"Company id."},"description":"Linked company ids."},"companies":{"type":"array","items":{"type":"string","description":"Company name."},"description":"Names of the linked companies that resolved."},"lineItems":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Item name."},"sku":{"type":"string","description":"SKU, \"\" when none."},"quantity":{"type":"number","description":"Quantity; 0 when unset."},"unitPrice":{"type":"number","description":"Unit price in the deal currency; 0 when unset."}},"additionalProperties":true,"required":["name","sku","quantity","unitPrice"],"description":"One product line item."},"description":"Up to 50 product line items."},"description":{"type":"string","description":"Description, \"\" when none."},"createdAt":{"type":"string","description":"ISO 8601 creation time, \"\" when unknown."},"updatedAt":{"type":"string","description":"ISO 8601 last update time, \"\" when unknown."}},"additionalProperties":true,"required":["id","name","stage","pipeline","pipelineName","open","amount","currency","probability","weightedAmount","forecastCategory","closeDate","closedAt","owner","dealType","priority","nextStep","lostReason","daysInStage","stageEnteredAt","stageHistory","contactIds","companyIds","companies","lineItems","description","createdAt","updatedAt"],"description":"The deal as get_deal would return it, rebuilt from the saved record."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","deal"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/deals/{id}":{"get":{"operationId":"get_deal","summary":"One deal by id with its full stage history (who moved it, when), line items, linked contacts and companies, lost reason and closed date","description":"One deal by id with its full stage history (who moved it, when), line items, linked contacts and companies, lost reason and closed date.\n\nRequired scope: `deals.read`. Risk level: `read`.","tags":["deals"],"security":[{"bearerAuth":["deals.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Deal id from list_deals.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"deal":{"type":"object","properties":{"id":{"type":"string","description":"Deal id."},"name":{"type":"string","description":"Deal name."},"stage":{"type":"string","description":"Current stage name; \"Closed Won\" / \"Closed Lost\" when closed."},"pipeline":{"type":"string","description":"Pipeline id (\"default\" for the main pipeline)."},"pipelineName":{"type":"string","description":"Pipeline display name."},"open":{"type":"boolean","description":"True unless the stage starts with \"Closed\"."},"amount":{"type":"number","description":"Deal value in `currency` (0 when unset)."},"currency":{"type":"string","description":"ISO 4217 code; falls back to the workspace CRM currency."},"probability":{"type":"number","description":"Win probability 0-100 (deal-specific, else stage default)."},"weightedAmount":{"type":"number","description":"amount × probability / 100."},"forecastCategory":{"type":"string","description":"Commit | Best case | Pipeline | Omit (or custom); \"\" for closed deals."},"closeDate":{"type":"string","description":"Expected close date YYYY-MM-DD (\"\" when unset)."},"closedAt":{"type":"string","description":"ISO 8601 actual close time (\"\" when open)."},"owner":{"type":"string","description":"Owner email/name (\"\" when unassigned)."},"dealType":{"type":"string","description":"Free-form deal type (\"\" when unset)."},"priority":{"type":"string","description":"Free-form priority (\"\" when unset)."},"nextStep":{"type":"string","description":"Next step text (≤300 chars)."},"lostReason":{"type":"string","description":"Lost reason (\"\" unless lost)."},"daysInStage":{"type":"integer","description":"Whole days since the deal entered its current stage (0 when closed)."},"stageEnteredAt":{"type":"string","description":"ISO 8601 time the current stage was entered (\"\" when unknown)."},"stageHistory":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","description":"Previous stage."},"to":{"type":"string","description":"New stage."},"at":{"type":"string","description":"ISO 8601."},"by":{"type":"string","description":"Who moved it."}},"additionalProperties":true,"required":["from","to","at","by"]},"description":"Last 20 stage transitions, oldest first."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact (lead) ids."},"companyIds":{"type":"array","items":{"type":"string"},"description":"Linked company ids."},"companies":{"type":"array","items":{"type":"string"},"description":"Names of the linked companies that resolved."},"lineItems":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Item name."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (0 when unset)."},"unitPrice":{"type":"number","description":"Unit price in the deal currency."}},"additionalProperties":true,"required":["name","sku","quantity","unitPrice"]},"description":"Up to 50 line items."},"description":{"type":"string","description":"Description (≤2000 chars)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name","stage","pipeline","pipelineName","open","amount","currency","probability","weightedAmount","forecastCategory","closeDate","closedAt","owner","dealType","priority","nextStep","lostReason","daysInStage","stageEnteredAt","stageHistory","contactIds","companyIds","companies","lineItems","description","createdAt","updatedAt"],"description":"The deal."}},"additionalProperties":true,"required":["ok","requestId","deal"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"update_deal","summary":"Update a deal: move it to another stage (including Closed Won / Closed Lost with a lost reason), change amount, close date, owner, probability, forecast category, next step, or link more contacts and companies","description":"Update a deal: move it to another stage (including Closed Won / Closed Lost with a lost reason), change amount, close date, owner, probability, forecast category, next step, or link more contacts and companies. Stage moves are recorded in the deal's stage history.\n\nRequired scope: `deals.write`. Risk level: `write`.","tags":["deals"],"security":[{"bearerAuth":["deals.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Deal id from list_deals.","schema":{"type":"string","maxLength":80}},{"name":"name","in":"query","required":false,"description":"New deal name.","schema":{"type":"string","maxLength":200}},{"name":"pipeline","in":"query","required":false,"description":"Move the deal to another pipeline (id or name); its stage is kept when that pipeline has it, else reset to the first stage.","schema":{"type":"string","maxLength":60}},{"name":"stage","in":"query","required":false,"description":"Pipeline stage to move the deal to (exact name; Closed Won / Closed Lost close it).","schema":{"type":"string","maxLength":40}},{"name":"lostReason","in":"query","required":false,"description":"Why the deal was lost (used with stage Closed Lost).","schema":{"type":"string","maxLength":120}},{"name":"amount","in":"query","required":false,"description":"Deal amount in the deal currency.","schema":{"type":"number"}},{"name":"currency","in":"query","required":false,"description":"3-letter ISO currency.","schema":{"type":"string","maxLength":3}},{"name":"closeDate","in":"query","required":false,"description":"Expected close date, YYYY-MM-DD.","schema":{"type":"string","maxLength":10}},{"name":"owner","in":"query","required":false,"description":"Owner name or email.","schema":{"type":"string","maxLength":120}},{"name":"probability","in":"query","required":false,"description":"Win probability 0-100.","schema":{"type":"number"}},{"name":"forecastCategory","in":"query","required":false,"description":"Forecast category override.","schema":{"type":"string","enum":["Pipeline","Best case","Commit","Omit"]}},{"name":"dealType","in":"query","required":false,"description":"e.g. New business, Existing business, Renewal, Upsell.","schema":{"type":"string","maxLength":40}},{"name":"priority","in":"query","required":false,"description":"Low, Medium or High.","schema":{"type":"string","enum":["Low","Medium","High"]}},{"name":"nextStep","in":"query","required":false,"description":"What happens next on this deal.","schema":{"type":"string","maxLength":300}},{"name":"description","in":"query","required":false,"description":"Free-text description.","schema":{"type":"string","maxLength":2000}},{"name":"contactIds","in":"query","required":false,"description":"Additional contact / lead ids to link.","schema":{"type":"array","items":{"type":"string"}}},{"name":"companyIds","in":"query","required":false,"description":"Additional company ids to link.","schema":{"type":"array","items":{"type":"string"}}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["deal"],"description":"Always \"deal\"."},"targetId":{"type":"string","description":"Id of the updated deal."},"updated":{"type":"boolean","description":"Always true on success."},"deal":{"type":"object","properties":{"id":{"type":"string","description":"Deal id."},"name":{"type":"string","description":"Deal name."},"stage":{"type":"string","description":"Current pipeline stage name."},"pipeline":{"type":"string","description":"Pipeline id (\"default\" for the main pipeline)."},"pipelineName":{"type":"string","description":"Pipeline display name."},"open":{"type":"boolean","description":"False once the stage starts with \"Closed\"."},"amount":{"type":"number","description":"Deal value in `currency`; 0 when unset."},"currency":{"type":"string","description":"3-letter ISO currency code (workspace default when unset)."},"probability":{"type":"number","description":"Win probability 0-100 (own value or derived from the stage)."},"weightedAmount":{"type":"number","description":"amount × probability / 100."},"forecastCategory":{"type":"string","description":"Pipeline | Best case | Commit | Omit (derived when unset); \"\" for closed deals."},"closeDate":{"type":"string","description":"Expected close date YYYY-MM-DD, \"\" when unset."},"closedAt":{"type":"string","description":"ISO 8601 time the deal was closed, \"\" when open."},"owner":{"type":"string","description":"Deal owner, \"\" when unassigned."},"dealType":{"type":"string","description":"Free-text deal type, \"\" when unset."},"priority":{"type":"string","description":"Free-text priority, \"\" when unset."},"nextStep":{"type":"string","description":"Next step text, \"\" when unset."},"lostReason":{"type":"string","description":"Reason when Closed Lost, \"\" otherwise."},"daysInStage":{"type":"integer","description":"Whole days since entering the current stage; 0 for closed deals."},"stageEnteredAt":{"type":"string","description":"ISO 8601 time the current stage was entered, \"\" when unknown."},"stageHistory":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","description":"Previous stage, \"\" for the first entry."},"to":{"type":"string","description":"New stage."},"at":{"type":"string","description":"ISO 8601 time of the transition, \"\" when unknown."},"by":{"type":"string","description":"Who moved it, \"\" when unknown."}},"additionalProperties":true,"required":["from","to","at","by"],"description":"One stage transition."},"description":"Last 20 stage transitions, oldest first."},"contactIds":{"type":"array","items":{"type":"string","description":"Contact id."},"description":"Linked contact (lead) ids."},"companyIds":{"type":"array","items":{"type":"string","description":"Company id."},"description":"Linked company ids."},"companies":{"type":"array","items":{"type":"string","description":"Company name."},"description":"Names of the linked companies that resolved."},"lineItems":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Item name."},"sku":{"type":"string","description":"SKU, \"\" when none."},"quantity":{"type":"number","description":"Quantity; 0 when unset."},"unitPrice":{"type":"number","description":"Unit price in the deal currency; 0 when unset."}},"additionalProperties":true,"required":["name","sku","quantity","unitPrice"],"description":"One product line item."},"description":"Up to 50 product line items."},"description":{"type":"string","description":"Description, \"\" when none."},"createdAt":{"type":"string","description":"ISO 8601 creation time, \"\" when unknown."},"updatedAt":{"type":"string","description":"ISO 8601 last update time, \"\" when unknown."}},"additionalProperties":true,"required":["id","name","stage","pipeline","pipelineName","open","amount","currency","probability","weightedAmount","forecastCategory","closeDate","closedAt","owner","dealType","priority","nextStep","lostReason","daysInStage","stageEnteredAt","stageHistory","contactIds","companyIds","companies","lineItems","description","createdAt","updatedAt"],"description":"The deal as get_deal would return it, rebuilt from the saved record."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","deal"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/deals/forecast":{"get":{"operationId":"get_pipeline_forecast","summary":"Pipeline forecast for this workspace: open amount and weighted amount, totals by stage, by forecast category (Commit / Best case / Pipeline), by expected close month and by owner, won this month and quarter versus the configured targets, win rate, average deal size and sales cycle, plus hygiene counts (stale, past close date, no close date)","description":"Pipeline forecast for this workspace: open amount and weighted amount, totals by stage, by forecast category (Commit / Best case / Pipeline), by expected close month and by owner, won this month and quarter versus the configured targets, win rate, average deal size and sales cycle, plus hygiene counts (stale, past close date, no close date).\n\nRequired scope: `deals.read`. Risk level: `read`.","tags":["deals"],"security":[{"bearerAuth":["deals.read"]}],"parameters":[{"name":"months","in":"query","required":false,"description":"How many close months ahead to break down (1-12, default 6).","schema":{"type":"integer"}},{"name":"pipeline","in":"query","required":false,"description":"Restrict the forecast to one pipeline (id or name); omit for every pipeline together.","schema":{"type":"string","maxLength":60}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"currency":{"type":"string","description":"Workspace CRM currency for every amount below."},"asOf":{"type":"string","description":"Report date YYYY-MM-DD (UTC)."},"pipeline":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Pipeline id."},"name":{"type":"string","description":"Pipeline name."}},"additionalProperties":true,"required":["id","name"],"description":"The pipeline the forecast is limited to; null = all pipelines."},"pipelines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pipeline id."},"name":{"type":"string","description":"Pipeline name."},"openCount":{"type":"integer","description":"Open deals in this pipeline."}},"additionalProperties":true,"required":["id","name","openCount"]},"description":"Every pipeline with its open-deal count."},"open":{"type":"object","properties":{"count":{"type":"integer","description":"Open deals."},"amount":{"type":"number","description":"Sum of open deal amounts."},"weightedAmount":{"type":"number","description":"Sum of open weighted amounts (amount × probability)."}},"additionalProperties":true,"required":["count","amount","weightedAmount"],"description":"All open deals."},"byForecastCategory":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","enum":["Commit","Best case","Pipeline","Omit"],"description":"Forecast category."},"count":{"type":"integer","description":"Open deals in the category."},"amount":{"type":"number","description":"Sum of their amounts."}},"additionalProperties":true,"required":["category","count","amount"]},"description":"Open deals split by forecast category."},"wonThisMonth":{"type":"object","properties":{"count":{"type":"integer","description":"Deals won."},"amount":{"type":"number","description":"Sum won."}},"additionalProperties":true,"required":["count","amount"],"description":"Deals closed won this calendar month."},"wonThisQuarter":{"type":"object","properties":{"quarter":{"type":"string","description":"Quarter label, e.g. 2026-Q3."},"count":{"type":"integer","description":"Deals won."},"amount":{"type":"number","description":"Sum won."}},"additionalProperties":true,"required":["quarter","count","amount"],"description":"Deals closed won this calendar quarter."},"target":{"type":"object","properties":{"monthly":{"type":"number","description":"Monthly target."},"quarterly":{"type":"number","description":"Quarterly target."}},"additionalProperties":true,"required":["monthly","quarterly"],"description":"Revenue targets configured in CRM settings (0 when unset)."},"winRate":{"type":["integer","null"],"description":"Won / closed in percent (0-100); null when nothing has closed."},"winRateBasis":{"type":"string","enum":["last 90 days","all time"],"description":"Window the win rate was computed over."},"avgDealSize":{"type":["number","null"],"description":"Average won amount (rounded); null when nothing was won."},"avgSalesCycleDays":{"type":["integer","null"],"description":"Average days from creation to close for won deals; null when unknown."},"staleDeals":{"type":"integer","description":"Open deals sitting in their stage for at least staleAfterDays."},"staleAfterDays":{"type":"integer","description":"Stale threshold in days (CRM setting, default 14)."},"overdueDeals":{"type":"integer","description":"Open deals whose close date is in the past."},"noCloseDate":{"type":"integer","description":"Open deals without a close date."},"byStage":{"type":"array","items":{"type":"object","properties":{"stage":{"type":"string","description":"Stage name."},"probability":{"type":"number","description":"Default win probability for the stage (0-100)."},"count":{"type":"integer","description":"Deals in the stage."},"amount":{"type":"number","description":"Sum of amounts."},"weightedAmount":{"type":"number","description":"Sum of weighted amounts."}},"additionalProperties":true,"required":["stage","probability","count","amount","weightedAmount"]},"description":"Every stage (open and closed) with totals."},"byCloseMonth":{"type":"array","items":{"type":"object","properties":{"month":{"type":"string","description":"Month YYYY-MM."},"openCount":{"type":"integer","description":"Open deals expected to close that month."},"openAmount":{"type":"number","description":"Their amount."},"weightedAmount":{"type":"number","description":"Their weighted amount."},"wonCount":{"type":"integer","description":"Deals already won with a close date in that month."},"wonAmount":{"type":"number","description":"Their amount."}},"additionalProperties":true,"required":["month","openCount","openAmount","weightedAmount","wonCount","wonAmount"]},"description":"One row per month from this month forward (`months`, default 6)."},"byOwner":{"type":"array","items":{"type":"object","properties":{"owner":{"type":"string","description":"Owner, or \"(unassigned)\"."},"openCount":{"type":"integer","description":"Open deals."},"openAmount":{"type":"number","description":"Open amount."},"weightedAmount":{"type":"number","description":"Open weighted amount."},"wonCount":{"type":"integer","description":"Deals won (all time)."},"wonAmount":{"type":"number","description":"Amount won (all time)."},"wonThisMonth":{"type":"number","description":"Amount won this calendar month."},"monthlyTarget":{"type":["number","null"],"description":"Owner monthly target; null when none set."},"targetProgress":{"type":["integer","null"],"description":"wonThisMonth / monthlyTarget in percent; null without a target."},"winRate":{"type":["integer","null"],"description":"Won / closed in percent; null when nothing closed."}},"additionalProperties":true,"required":["owner","openCount","openAmount","weightedAmount","wonCount","wonAmount","wonThisMonth","monthlyTarget","targetProgress","winRate"]},"description":"Per-owner pipeline and attainment, sorted by owner."}},"additionalProperties":true,"required":["ok","requestId","currency","asOf","pipeline","pipelines","open","byForecastCategory","wonThisMonth","wonThisQuarter","target","winRate","winRateBasis","avgDealSize","avgSalesCycleDays","staleDeals","staleAfterDays","overdueDeals","noCloseDate","byStage","byCloseMonth","byOwner"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/tasks/overdue":{"get":{"operationId":"list_overdue_tasks","summary":"Open tasks past their due date, most overdue first, each with how many days late it is","description":"Open tasks past their due date, most overdue first, each with how many days late it is. Optionally scoped to one owner.\n\nRequired scope: `tasks.read`. Risk level: `read`.","tags":["tasks"],"security":[{"bearerAuth":["tasks.read"]}],"parameters":[{"name":"owner","in":"query","required":false,"description":"Assignee, exact match.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title (≤200 chars)."},"done":{"type":"boolean","description":"True when completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when none."},"priorityLabel":{"type":"string","description":"Priority label as stored on the board (e.g. Medium)."},"owner":{"type":"string","description":"Assignee (\"\" when unassigned)."},"dueAt":{"type":"string","description":"ISO 8601 due datetime (end of day when no time), \"\" when no due date."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type, e.g. contact, deal, company."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, or null."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"overdueDays":{"type":"integer","description":"Whole days past due."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo","createdAt","updatedAt","overdueDays"]},"description":"Open tasks past their due time, most overdue first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."}},"additionalProperties":true,"required":["ok","requestId","tasks","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/ad-accounts":{"get":{"operationId":"list_ad_accounts","summary":"Ad accounts this token may see, across Meta, Google Ads and DV360, with currency","description":"Ad accounts this token may see, across Meta, Google Ads and DV360, with currency. Campaign ids are only unique within a platform, so start here and pass accountId + platform downstream.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"platform","in":"query","required":false,"description":"Restrict to one platform.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"adAccounts":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"id":{"type":"string","description":"Account id without act_ prefix or dashes; pass as accountId to list_campaigns."},"name":{"type":"string","description":"Account name."},"currency":{"type":"string","description":"Account currency code (\"\" when unknown)."},"status":{"type":"string","description":"Meta only: ACTIVE, INACTIVE or \"\"."},"managerId":{"type":"string","description":"Google only: manager (MCC) customer id, \"\" when none."}},"additionalProperties":true,"required":["platform","id","name","currency"]},"description":"Ad accounts across Meta, Google Ads and DV360 that this token may read."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."}},"additionalProperties":true,"required":["ok","requestId","adAccounts","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns":{"get":{"operationId":"list_campaigns","summary":"Ad campaigns with their performance for a date preset (default last_30d): spend, impressions, clicks, results, CTR, CPC and cost per result, highest spend first","description":"Ad campaigns with their performance for a date preset (default last_30d): spend, impressions, clicks, results, CTR, CPC and cost per result, highest spend first. Reads the platform's synced cache, so figures are as fresh as the last sync, not live. Without accountId it reads the first few accounts and says so in `notes` — pass accountId for a complete, cheap answer.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"platform","in":"query","required":false,"description":"Restrict to one platform.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"accountId","in":"query","required":false,"description":"Ad account id from list_ad_accounts.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":false,"description":"Campaign status, e.g. ACTIVE or PAUSED.","schema":{"type":"string","maxLength":30}},{"name":"query","in":"query","required":false,"description":"Substring of the campaign name, or an exact campaign id.","schema":{"type":"string","maxLength":120}},{"name":"datePreset","in":"query","required":false,"description":"Reporting window.","schema":{"type":"string","enum":["today","yesterday","last_7d","last_14d","last_30d","this_month","last_month","maximum"],"default":"last_30d"}},{"name":"sort","in":"query","required":false,"description":"Result order.","schema":{"type":"string","enum":["spend_desc","name_asc"],"default":"spend_desc"}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"campaigns":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"accountId":{"type":"string","description":"Ad account id without the act_ prefix (\"\" when unknown)."},"id":{"type":"string","description":"Campaign id, platform-specific (Google gads_ prefix stripped)."},"name":{"type":"string","description":"Campaign name."},"status":{"type":"string","description":"Platform status, e.g. ACTIVE, PAUSED, ENABLED (\"\" when unknown)."},"objective":{"type":"string","description":"Campaign objective (\"\" when unknown)."},"dailyBudget":{"type":["number","null"],"description":"Daily budget in account currency (major units), null when not set."},"spend":{"type":"number","description":"Spend in account currency for the date preset."},"impressions":{"type":"integer","description":"Impressions for the date preset."},"clicks":{"type":"integer","description":"Clicks for the date preset."},"results":{"type":"number","description":"Conversions the campaign optimizes for (leads/purchases), else platform conversions."},"ctr":{"type":"number","description":"Click-through rate in percent (0-100)."},"cpc":{"type":"number","description":"Cost per click in account currency."},"costPerResult":{"type":"number","description":"Spend / results in account currency (0 when no results)."},"currency":{"type":"string","description":"Account currency code (\"\" when unknown)."}},"additionalProperties":true,"required":["platform","accountId","id","name","status","objective","dailyBudget","spend","impressions","clicks","results","ctr","cpc","costPerResult","currency"]},"description":"Campaigns with metrics for the date preset, highest spend first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"datePreset":{"type":"string","description":"Date preset the metrics cover, e.g. last_30d."},"accountsScanned":{"type":"integer","description":"Ad accounts actually read (max 8; Google max 3)."},"accountsAvailable":{"type":"integer","description":"Ad accounts that matched the filter."},"notes":{"type":"array","items":{"type":"string"},"description":"Caveats (accounts skipped, platform read errors); absent when none."}},"additionalProperties":true,"required":["ok","requestId","campaigns","pagination","datePreset","accountsScanned","accountsAvailable"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns/{id}":{"get":{"operationId":"get_campaign","summary":"One campaign with its settings and headline metrics","description":"One campaign with its settings and headline metrics. Ids are platform-scoped — pass the platform and accountId you got from list_campaigns.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign id from list_campaigns.","schema":{"type":"string","maxLength":60}},{"name":"platform","in":"query","required":false,"description":"Platform the id belongs to.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"accountId","in":"query","required":false,"description":"Ad account id, to avoid scanning every account.","schema":{"type":"string","maxLength":60}},{"name":"datePreset","in":"query","required":false,"description":"Reporting window.","schema":{"type":"string","enum":["today","yesterday","last_7d","last_14d","last_30d","this_month","last_month","maximum"],"default":"last_30d"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"campaign":{"type":"object","properties":{"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"accountId":{"type":"string","description":"Ad account id without the act_ prefix (\"\" when unknown)."},"id":{"type":"string","description":"Campaign id, platform-specific (Google gads_ prefix stripped)."},"name":{"type":"string","description":"Campaign name."},"status":{"type":"string","description":"Platform status, e.g. ACTIVE, PAUSED, ENABLED (\"\" when unknown)."},"objective":{"type":"string","description":"Campaign objective (\"\" when unknown)."},"dailyBudget":{"type":["number","null"],"description":"Daily budget in account currency (major units), null when not set."},"spend":{"type":"number","description":"Spend in account currency for the date preset."},"impressions":{"type":"integer","description":"Impressions for the date preset."},"clicks":{"type":"integer","description":"Clicks for the date preset."},"results":{"type":"number","description":"Conversions the campaign optimizes for (leads/purchases), else platform conversions."},"ctr":{"type":"number","description":"Click-through rate in percent (0-100)."},"cpc":{"type":"number","description":"Cost per click in account currency."},"costPerResult":{"type":"number","description":"Spend / results in account currency (0 when no results)."},"currency":{"type":"string","description":"Account currency code (\"\" when unknown)."}},"additionalProperties":true,"required":["platform","accountId","id","name","status","objective","dailyBudget","spend","impressions","clicks","results","ctr","cpc","costPerResult","currency"],"description":"The campaign with its metrics."},"datePreset":{"type":"string","description":"Date preset the metrics cover, e.g. last_30d."}},"additionalProperties":true,"required":["ok","requestId","campaign","datePreset"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns/{id}/performance":{"get":{"operationId":"get_campaign_performance","summary":"Just the metrics for one campaign over a date preset — spend, impressions, clicks, results, CTR, CPC, cost per result","description":"Just the metrics for one campaign over a date preset — spend, impressions, clicks, results, CTR, CPC, cost per result. Use it when you only need the numbers.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign id from list_campaigns.","schema":{"type":"string","maxLength":60}},{"name":"platform","in":"query","required":false,"description":"Platform the id belongs to.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"accountId","in":"query","required":false,"description":"Ad account id.","schema":{"type":"string","maxLength":60}},{"name":"datePreset","in":"query","required":false,"description":"Reporting window.","schema":{"type":"string","enum":["today","yesterday","last_7d","last_14d","last_30d","this_month","last_month","maximum"],"default":"last_30d"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"campaign":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id."},"name":{"type":"string","description":"Campaign name."},"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"status":{"type":"string","description":"Platform status."},"currency":{"type":"string","description":"Account currency code."}},"additionalProperties":true,"required":["id","name","platform","status","currency"],"description":"Campaign identity."},"datePreset":{"type":"string","description":"Date preset the metrics cover, e.g. last_30d."},"metrics":{"type":"object","properties":{"spend":{"type":"number","description":"Spend."},"impressions":{"type":"integer","description":"Impressions."},"clicks":{"type":"integer","description":"Clicks."},"results":{"type":"number","description":"Optimized conversions (leads/purchases)."},"ctr":{"type":"number","description":"Click-through rate in percent."},"cpc":{"type":"number","description":"Cost per click."},"costPerResult":{"type":"number","description":"Spend / results (0 when no results)."}},"additionalProperties":true,"required":["spend","impressions","clicks","results","ctr","cpc","costPerResult"],"description":"Performance for the date preset, in account currency."}},"additionalProperties":true,"required":["ok","requestId","campaign","datePreset","metrics"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/reports/lead-sources":{"get":{"operationId":"get_lead_source_report","summary":"Lead volume and outcome grouped by source, campaign, form, page or status, over an optional date range: leads, won, lost, still open and win rate per group","description":"Lead volume and outcome grouped by source, campaign, form, page or status, over an optional date range: leads, won, lost, still open and win rate per group. Use it for \"where are our leads coming from and which convert?\".\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[{"name":"groupBy","in":"query","required":false,"description":"Grouping dimension.","schema":{"type":"string","enum":["source","campaign","form","page","status"],"default":"source"}},{"name":"status","in":"query","required":false,"description":"Restrict to one status before grouping.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"dateFrom","in":"query","required":false,"description":"Only records at or after this ISO 8601 date/datetime (e.g. 2026-07-01).","schema":{"type":"string","maxLength":40}},{"name":"dateTo","in":"query","required":false,"description":"Only records at or before this ISO 8601 date/datetime.","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"groupBy":{"type":"string","enum":["source","campaign","form","page","status"],"description":"Grouping applied."},"totalLeads":{"type":"integer","description":"Leads matching the filters."},"groups":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Group value (\"(none)\" when empty)."},"leads":{"type":"integer","description":"Leads in the group."},"won":{"type":"integer","description":"Leads with status Won."},"lost":{"type":"integer","description":"Leads with status Lost or Unresponsive."},"open":{"type":"integer","description":"Leads in an open status."},"winRate":{"type":"number","description":"won / leads in percent (0-100, 1 decimal)."}},"additionalProperties":true,"required":["key","leads","won","lost","open","winRate"]},"description":"Up to 100 groups, most leads first."},"sources":{"type":"object","properties":{"facebook":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"stale":{"type":"boolean","description":"True when the cached form leads are stale; only present when the store loaded."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Facebook lead-form store: rows contributed, or why it was unavailable."},"manual":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Manual / CSV-import store: rows contributed, or why it was unavailable."},"landing_page":{"type":"object","properties":{"count":{"type":"integer","description":"Rows read from this store (0 when unavailable)."},"unavailable":{"type":"string","description":"Set only when the store failed to load: short reason (≤140 chars)."}},"additionalProperties":true,"required":["count"],"description":"Landing-page submission store: rows contributed, or why it was unavailable."}},"additionalProperties":true,"required":["facebook","manual","landing_page"],"description":"Which lead stores contributed to the working set; a failed store reports `unavailable` rather than under-counting."},"dateFrom":{"type":"string","description":"The dateFrom filter echoed back (\"\" when none)."},"dateTo":{"type":"string","description":"The dateTo filter echoed back (\"\" when none)."}},"additionalProperties":true,"required":["ok","requestId","groupBy","totalLeads","groups","sources","dateFrom","dateTo"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/reports/conversions":{"get":{"operationId":"get_conversion_report","summary":"Revenue attribution over the last N days: orders and revenue credited back to the ad, email or SMS touch that produced them, using the platform's own attribution model","description":"Revenue attribution over the last N days: orders and revenue credited back to the ad, email or SMS touch that produced them, using the platform's own attribution model. Not recomputed here, so it agrees with what the app shows.\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Look-back window in days.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"days":{"type":"integer","description":"Attribution window in days (1-365, default 30)."},"rows":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","description":"Network / channel, e.g. facebook, google, email, sms."},"campaign":{"type":"string","description":"Campaign name."},"conversions":{"type":"integer","description":"Orders attributed to the campaign."},"revenue":{"type":"number","description":"Attributed revenue, 2 decimals."},"currency":{"type":"string","description":"Currency code (\"\" when unknown)."},"spend":{"type":["number","null"],"description":"Ad spend when known, else null."}},"additionalProperties":true,"required":["channel","campaign","conversions","revenue","currency","spend"]},"description":"Up to 100 attributed campaigns."},"byChannel":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","description":"Network / channel."},"conversions":{"type":"integer","description":"Attributed orders."},"revenue":{"type":"number","description":"Attributed revenue, 2 decimals."}},"additionalProperties":true,"required":["channel","conversions","revenue"]},"description":"Attributed totals per channel, highest revenue first."},"totals":{"type":"object","properties":{"conversions":{"type":"integer","description":"Orders credited to a touch."},"revenue":{"type":"number","description":"Revenue credited to a touch."},"allConversions":{"type":"integer","description":"Every order in the window."},"allRevenue":{"type":"number","description":"Revenue of every order in the window."}},"additionalProperties":true,"required":["conversions","revenue","allConversions","allRevenue"],"description":"Attributed vs. all orders in the window."}},"additionalProperties":true,"required":["ok","requestId","days","rows","byChannel","totals"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/conversations":{"get":{"operationId":"list_conversations","summary":"Open message threads across WhatsApp, SMS, Facebook Messenger and Instagram DMs, newest first, with the last message, its time and the unread count","description":"Open message threads across WhatsApp, SMS, Facebook Messenger and Instagram DMs, newest first, with the last message, its time and the unread count. Reading never marks anything read. Channels that are not connected are skipped and listed in `notes`.\n\nRequired scope: `conversations.read`. Risk level: `read`.","tags":["conversations"],"security":[{"bearerAuth":["conversations.read"]}],"parameters":[{"name":"channel","in":"query","required":false,"description":"Restrict to one channel.","schema":{"type":"string","enum":["whatsapp","sms","facebook","instagram"]}},{"name":"unreadOnly","in":"query","required":false,"description":"Only threads with unread inbound messages.","schema":{"type":"boolean","default":false}},{"name":"query","in":"query","required":false,"description":"Substring of the contact name, or a phone number.","schema":{"type":"string","maxLength":120}},{"name":"dateFrom","in":"query","required":false,"description":"Only records at or after this ISO 8601 date/datetime (e.g. 2026-07-01).","schema":{"type":"string","maxLength":40}},{"name":"dateTo","in":"query","required":false,"description":"Only records at or before this ISO 8601 date/datetime.","schema":{"type":"string","maxLength":40}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"conversations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Channel-prefixed id (whatsapp:<phone>, sms:<phone>, facebook|instagram:<pageId>:<convId>); pass to get_conversation."},"channel":{"type":"string","enum":["whatsapp","sms","facebook","instagram"],"description":"Channel."},"contact":{"type":"object","properties":{"name":{"type":"string","description":"Display name (falls back to phone)."},"phone":{"type":"string","description":"Phone (whatsapp, sms)."},"externalId":{"type":"string","description":"Platform user id (facebook, instagram)."}},"additionalProperties":true,"required":["name"],"description":"The other party."},"lastMessage":{"type":"string","description":"Snippet of the latest message (≤200 chars)."},"lastMessageAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"unread":{"type":"integer","description":"Unread message count."},"messageCount":{"type":"integer","description":"WhatsApp only: messages in the thread."},"pageId":{"type":"string","description":"Facebook/Instagram only: the page the thread belongs to."}},"additionalProperties":true,"required":["id","channel","contact","lastMessage","lastMessageAt","unread"]},"description":"Inbox threads across channels, newest message first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"notes":{"type":"array","items":{"type":"string"},"description":"Per-channel read errors; absent when none."}},"additionalProperties":true,"required":["ok","requestId","conversations","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/calls":{"get":{"operationId":"list_calls","summary":"Phone calls, newest first: the dialer log (browser calls and \"call from phone\", with outcome, duration, notes and the number used) and inbound calls on the workspace's virtual / tracking numbers (caller, tracking number, campaign / landing page when the caller came from an ad)","description":"Phone calls, newest first: the dialer log (browser calls and \"call from phone\", with outcome, duration, notes and the number used) and inbound calls on the workspace's virtual / tracking numbers (caller, tracking number, campaign / landing page when the caller came from an ad). A recorded call carries recordingUrl, a play link valid for one hour. Filter by date window, direction, phone or recorded calls only.\n\nRequired scope: `conversations.read`. Risk level: `read`.","tags":["conversations"],"security":[{"bearerAuth":["conversations.read"]}],"parameters":[{"name":"dateFrom","in":"query","required":false,"description":"Only calls at or after this ISO 8601 date.","schema":{"type":"string","maxLength":40}},{"name":"dateTo","in":"query","required":false,"description":"Only calls at or before this ISO 8601 date.","schema":{"type":"string","maxLength":40}},{"name":"direction","in":"query","required":false,"description":"outbound = dialer calls, inbound = tracking-number calls; omit for both.","schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"phone","in":"query","required":false,"description":"Only calls with this phone (matched on the last 9 digits).","schema":{"type":"string","maxLength":30}},{"name":"recordedOnly","in":"query","required":false,"description":"Only calls that have a recording.","schema":{"type":"boolean","default":false}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Twilio CallSid when known, else a time+phone key."},"at":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound = tracking-number call, outbound = dialer call."},"source":{"type":"string","description":"\"browser dialer\", \"call from phone\" or \"tracking number · <site>\"."},"phone":{"type":"string","description":"The other party, E.164 (\"\" when unknown)."},"contactName":{"type":"string","description":"Lead name (dialer calls; \"\" for tracking-number calls)."},"leadId":{"type":"string","description":"Lead id when the dialer was opened from a lead, else \"\"."},"outcome":{"type":"string","description":"Connected, No answer, Busy… (\"\" when not set)."},"durationSec":{"type":"integer","description":"Talk time in seconds."},"duration":{"type":"string","description":"m:ss."},"ourNumber":{"type":"string","description":"Caller ID used (outbound) or the tracking number dialled (inbound), E.164."},"notes":{"type":"string","description":"Notes saved from the dialer (\"\" otherwise)."},"error":{"type":"string","description":"Dialer fault, when the call failed for a technical reason (\"\" otherwise)."},"campaign":{"type":"string","description":"Inbound only: utm_campaign of the visitor who held the tracking number."},"landingPage":{"type":"string","description":"Inbound only: page the visitor was on."},"gclid":{"type":"string","description":"Inbound only: Google click id when the caller came from an ad."},"qualified":{"type":"boolean","description":"Inbound only: marked qualified."},"recorded":{"type":"boolean","description":"A recording exists."},"recordingUrl":{"type":"string","description":"Play / download link, valid ~1 hour (\"\" when not recorded)."},"recordingSec":{"type":"integer","description":"Recording length in seconds (0 when not recorded)."}},"additionalProperties":true,"required":["id","at","direction","source","phone","contactName","leadId","outcome","durationSec","duration","ourNumber","notes","error","recorded","recordingUrl","recordingSec"]},"description":"Phone calls, newest first: dialer calls (outbound) and inbound calls on the tracking numbers of this workspace."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"notes":{"type":"array","items":{"type":"string"},"description":"Present when one of the two sources could not be read."}},"additionalProperties":true,"required":["ok","requestId","calls","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/conversations/{id}":{"get":{"operationId":"get_conversation","summary":"The messages of one thread, oldest to newest, each marked inbound or outbound","description":"The messages of one thread, oldest to newest, each marked inbound or outbound. Use the composite id from list_conversations (for example \"whatsapp:+972…\"). Reading does not mark the thread read and does not send anything.\n\nRequired scope: `conversations.read`. Risk level: `read`.","tags":["conversations"],"security":[{"bearerAuth":["conversations.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Composite conversation id from list_conversations.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"description":"Maximum messages to return (most recent).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"conversation":{"type":"object","properties":{"id":{"type":"string","description":"The id requested."},"channel":{"type":"string","enum":["whatsapp","sms","facebook","instagram"],"description":"Channel."},"contact":{"type":"object","properties":{"name":{"type":"string","description":"Display name (whatsapp)."},"phone":{"type":"string","description":"Phone."}},"additionalProperties":true,"required":["phone"],"description":"The other party (whatsapp, sms)."},"pageId":{"type":"string","description":"Facebook/Instagram only: the page id."}},"additionalProperties":true,"required":["id","channel"],"description":"Thread identity."},"messages":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound = from the contact, outbound = sent by the workspace."},"text":{"type":"string","description":"Message text (≤2000 chars)."},"type":{"type":"string","description":"WhatsApp only: message type, e.g. text, image."},"from":{"type":"string","description":"Facebook/Instagram only: sender label."}},"additionalProperties":true,"required":["at","direction","text"]},"description":"The last `limit` messages (max 100), oldest first."},"optedOut":{"type":"boolean","description":"SMS only: true when the number opted out."}},"additionalProperties":true,"required":["ok","requestId","conversation","messages"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/automations":{"get":{"operationId":"list_automations","summary":"Marketing automations (journeys) in this workspace: name, whether enabled, what triggers entry and which step types it runs (email, SMS, WhatsApp, wait, filter, ad audience)","description":"Marketing automations (journeys) in this workspace: name, whether enabled, what triggers entry and which step types it runs (email, SMS, WhatsApp, wait, filter, ad audience). These are this platform's automated agents — it has no separate \"AI agent\" object.\n\nRequired scope: `agents.read`. Risk level: `read`.","tags":["agents"],"security":[{"bearerAuth":["agents.read"]}],"parameters":[{"name":"enabledOnly","in":"query","required":false,"description":"Only automations currently enabled.","schema":{"type":"boolean","default":false}},{"name":"query","in":"query","required":false,"description":"Substring of the automation name.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"automations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Automation (journey) id."},"name":{"type":"string","description":"Automation name."},"enabled":{"type":"boolean","description":"True when the journey is switched on."},"entryType":{"type":"string","description":"Entry trigger type (\"\" when unknown)."},"stepTypes":{"type":"array","items":{"type":"string"},"description":"Distinct step types used (email, sms, whatsapp, wait, audience, …)."},"stepCount":{"type":"integer","description":"Number of steps walked (branches included, capped)."},"owner":{"type":"string","description":"Owner email (\"\" when unknown)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."}},"additionalProperties":true,"required":["id","name","enabled","entryType","stepTypes","stepCount","owner","createdAt","updatedAt"]},"description":"Automations (journeys), most recently updated first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."}},"additionalProperties":true,"required":["ok","requestId","automations","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/automations/{id}":{"get":{"operationId":"get_automation","summary":"One automation with its run statistics: contacts entered and completed, emails and SMS sent, conversions, orders, opens and unsubscribes","description":"One automation with its run statistics: contacts entered and completed, emails and SMS sent, conversions, orders, opens and unsubscribes.\n\nRequired scope: `agents.read`. Risk level: `read`.","tags":["agents"],"security":[{"bearerAuth":["agents.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Automation id from list_automations.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"automation":{"type":"object","properties":{"id":{"type":"string","description":"Automation (journey) id."},"name":{"type":"string","description":"Automation name."},"enabled":{"type":"boolean","description":"True when the journey is switched on."},"entryType":{"type":"string","description":"Entry trigger type (\"\" when unknown)."},"stepTypes":{"type":"array","items":{"type":"string"},"description":"Distinct step types used (email, sms, whatsapp, wait, audience, …)."},"stepCount":{"type":"integer","description":"Number of steps walked (branches included, capped)."},"owner":{"type":"string","description":"Owner email (\"\" when unknown)."},"createdAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"updatedAt":{"type":"string","description":"ISO 8601 (\"\" when unknown)."},"stats":{"type":["object","null"],"properties":{"started":{"type":"integer","description":"Contacts that entered the journey."},"completed":{"type":"integer","description":"Contacts that finished it."},"emailsSent":{"type":"integer","description":"Emails sent."},"smsSent":{"type":"integer","description":"SMS sent."},"conversions":{"type":"integer","description":"Conversions attributed."},"orders":{"type":"integer","description":"Orders attributed."},"opens":{"type":"integer","description":"Email opens."},"unsubscribes":{"type":"integer","description":"Unsubscribes."}},"additionalProperties":true,"required":["started","completed","emailsSent","smsSent","conversions","orders","opens","unsubscribes"],"description":"Lifetime counters; null when the stats read failed."}},"additionalProperties":true,"required":["id","name","enabled","entryType","stepTypes","stepCount","owner","createdAt","updatedAt","stats"],"description":"The automation with its lifetime stats."}},"additionalProperties":true,"required":["ok","requestId","automation"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/{id}/update":{"post":{"operationId":"update_lead","summary":"Change a lead's pipeline status, owner, rating or the board's Due Date","description":"Change a lead's pipeline status, owner, rating or the board's Due Date. Supply only the fields you want to change; the rest are left alone. Returns before and after so the change is auditable. Works for leads from any source — the update is routed to the store that source uses, so it shows up in the app. Never creates a lead.\n\nRequired scope: `leads.write`. Risk level: `write`.","tags":["leads"],"security":[{"bearerAuth":["leads.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Lead id from search_leads.","schema":{"type":"string","maxLength":80}},{"name":"status","in":"query","required":false,"description":"New pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"owner","in":"query","required":false,"description":"New owner (their email). Pass an empty string to unassign.","schema":{"type":"string","maxLength":120}},{"name":"rating","in":"query","required":false,"description":"Star rating, 0-5.","schema":{"type":"integer","minimum":0,"maximum":5}},{"name":"dueDate","in":"query","required":false,"description":"The board's Due Date, yyyy-mm-dd, or \"\" to clear.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["lead"],"description":"Always \"lead\"."},"targetId":{"type":"string","description":"Id of the updated lead."},"updated":{"type":"boolean","description":"Always true on success."},"lead":{"type":"object","properties":{"id":{"type":"string","description":"Lead id."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Where the lead came from: facebook | manual | landing_page."},"name":{"type":"string","description":"Lead name."},"email":{"type":"string","description":"Lead email, \"\" when none."}},"additionalProperties":true,"required":["id","source","name","email"],"description":"Identity of the updated lead."},"before":{"type":"object","properties":{"status":{"type":"string","description":"Pipeline status, e.g. New, Contacted, Qualified, Won, Lost."},"owner":{"type":"string","description":"Assigned owner, \"\" when unassigned."},"rating":{"type":"number","description":"Star rating 0-5."},"dueDate":{"type":"string","description":"The board Due Date (yyyy-mm-dd), \"\" when none."}},"additionalProperties":true,"required":["status","owner","rating","dueDate"],"description":"status / owner / rating / dueDate before the change."},"after":{"type":"object","properties":{"status":{"type":"string","description":"Pipeline status, e.g. New, Contacted, Qualified, Won, Lost."},"owner":{"type":"string","description":"Assigned owner, \"\" when unassigned."},"rating":{"type":"number","description":"Star rating 0-5."},"dueDate":{"type":"string","description":"The board Due Date (yyyy-mm-dd), \"\" when none."}},"additionalProperties":true,"required":["status","owner","rating","dueDate"],"description":"status / owner / rating / dueDate after the change."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","lead","before","after"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/{id}/status":{"post":{"operationId":"update_lead_status","summary":"Move one lead to a different pipeline status","description":"Move one lead to a different pipeline status. A focused alias for update_lead when status is all you are changing.\n\nRequired scope: `leads.write`. Risk level: `write`.","tags":["leads"],"security":[{"bearerAuth":["leads.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Lead id from search_leads.","schema":{"type":"string","maxLength":80}},{"name":"status","in":"query","required":true,"description":"New pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["lead"],"description":"Always \"lead\"."},"targetId":{"type":"string","description":"Id of the updated lead."},"updated":{"type":"boolean","description":"Always true on success."},"lead":{"type":"object","properties":{"id":{"type":"string","description":"Lead id."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Where the lead came from: facebook | manual | landing_page."},"name":{"type":"string","description":"Lead name."},"email":{"type":"string","description":"Lead email, \"\" when none."}},"additionalProperties":true,"required":["id","source","name","email"],"description":"Identity of the updated lead."},"before":{"type":"object","properties":{"status":{"type":"string","description":"Pipeline status, e.g. New, Contacted, Qualified, Won, Lost."},"owner":{"type":"string","description":"Assigned owner, \"\" when unassigned."},"rating":{"type":"number","description":"Star rating 0-5."},"dueDate":{"type":"string","description":"The board Due Date (yyyy-mm-dd), \"\" when none."}},"additionalProperties":true,"required":["status","owner","rating","dueDate"],"description":"status / owner / rating / dueDate before the change."},"after":{"type":"object","properties":{"status":{"type":"string","description":"Pipeline status, e.g. New, Contacted, Qualified, Won, Lost."},"owner":{"type":"string","description":"Assigned owner, \"\" when unassigned."},"rating":{"type":"number","description":"Star rating 0-5."},"dueDate":{"type":"string","description":"The board Due Date (yyyy-mm-dd), \"\" when none."}},"additionalProperties":true,"required":["status","owner","rating","dueDate"],"description":"status / owner / rating / dueDate after the change."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","lead","before","after"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/{id}/owner":{"post":{"operationId":"assign_lead_owner","summary":"Assign a lead to a team member by their email address, or unassign it with an empty string","description":"Assign a lead to a team member by their email address, or unassign it with an empty string.\n\nRequired scope: `leads.write`. Risk level: `write`.","tags":["leads"],"security":[{"bearerAuth":["leads.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Lead id from search_leads.","schema":{"type":"string","maxLength":80}},{"name":"owner","in":"query","required":true,"description":"Owner email, or \"\" to unassign.","schema":{"type":"string","maxLength":120}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["lead"],"description":"Always \"lead\"."},"targetId":{"type":"string","description":"Id of the updated lead."},"updated":{"type":"boolean","description":"Always true on success."},"lead":{"type":"object","properties":{"id":{"type":"string","description":"Lead id."},"source":{"type":"string","enum":["facebook","manual","landing_page"],"description":"Where the lead came from: facebook | manual | landing_page."},"name":{"type":"string","description":"Lead name."},"email":{"type":"string","description":"Lead email, \"\" when none."}},"additionalProperties":true,"required":["id","source","name","email"],"description":"Identity of the updated lead."},"before":{"type":"object","properties":{"status":{"type":"string","description":"Pipeline status, e.g. New, Contacted, Qualified, Won, Lost."},"owner":{"type":"string","description":"Assigned owner, \"\" when unassigned."},"rating":{"type":"number","description":"Star rating 0-5."},"dueDate":{"type":"string","description":"The board Due Date (yyyy-mm-dd), \"\" when none."}},"additionalProperties":true,"required":["status","owner","rating","dueDate"],"description":"status / owner / rating / dueDate before the change."},"after":{"type":"object","properties":{"status":{"type":"string","description":"Pipeline status, e.g. New, Contacted, Qualified, Won, Lost."},"owner":{"type":"string","description":"Assigned owner, \"\" when unassigned."},"rating":{"type":"number","description":"Star rating 0-5."},"dueDate":{"type":"string","description":"The board Due Date (yyyy-mm-dd), \"\" when none."}},"additionalProperties":true,"required":["status","owner","rating","dueDate"],"description":"status / owner / rating / dueDate after the change."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","lead","before","after"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/{id}/notes":{"post":{"operationId":"add_lead_note","summary":"Add a note to a lead's timeline","description":"Add a note to a lead's timeline. Set kind to log something that happened — a call, an email, a meeting — so it appears as that activity rather than a plain note, and set occurredAt to back-date it.\n\nRequired scope: `notes.write`. Risk level: `write`.","tags":["notes"],"security":[{"bearerAuth":["notes.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Lead id from search_leads.","schema":{"type":"string","maxLength":80}},{"name":"text","in":"query","required":true,"description":"The note body.","schema":{"type":"string","maxLength":5000}},{"name":"kind","in":"query","required":false,"description":"What this records. Defaults to note.","schema":{"type":"string","enum":["note","call","email","meeting","linkedin","sms","other"]}},{"name":"occurredAt","in":"query","required":false,"description":"ISO 8601 time it actually happened, if not now.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["lead"],"description":"Always \"lead\"."},"targetId":{"type":"string","description":"Id of the lead the note was attached to."},"created":{"type":"boolean","description":"Always true on success."},"note":{"type":"object","properties":{"id":{"type":"string","description":"Note id, \"\" if the store did not return one."},"kind":{"type":"string","enum":["note","call","email","meeting","linkedin","sms","other"],"description":"Timeline chip kind."},"text":{"type":"string","description":"First 200 characters of the note text."},"createdAt":{"type":"string","description":"ISO 8601 creation time."}},"additionalProperties":true,"required":["id","kind","text","createdAt"],"description":"The saved timeline entry."},"lead":{"type":"object","properties":{"id":{"type":"string","description":"Lead id."},"name":{"type":"string","description":"Lead name."},"email":{"type":"string","description":"Lead email, \"\" when none."}},"additionalProperties":true,"required":["id","name","email"],"description":"Identity of the lead."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","note","lead"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/tasks/{id}/update":{"post":{"operationId":"update_task","summary":"Change a task's title, due date, owner, priority or done state","description":"Change a task's title, due date, owner, priority or done state. Only the fields you supply change.\n\nRequired scope: `tasks.write`. Risk level: `write`.","tags":["tasks"],"security":[{"bearerAuth":["tasks.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Task id from list_tasks.","schema":{"type":"string","maxLength":80}},{"name":"title","in":"query","required":false,"description":"New title.","schema":{"type":"string","maxLength":200}},{"name":"dueDate","in":"query","required":false,"description":"New ISO 8601 due date, or \"\" to clear it.","schema":{"type":"string","maxLength":40}},{"name":"owner","in":"query","required":false,"description":"New owner email, or \"\" to unassign.","schema":{"type":"string","maxLength":120}},{"name":"priority","in":"query","required":false,"description":"New priority.","schema":{"type":"string","enum":["low","normal","high","urgent"]}},{"name":"done","in":"query","required":false,"description":"Mark done or not done.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["task"],"description":"Always \"task\"."},"targetId":{"type":"string","description":"Id of the updated task."},"updated":{"type":"boolean","description":"Always true on success."},"task":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title."},"done":{"type":"boolean","description":"True when the task is completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when unset."},"priorityLabel":{"type":"string","description":"Priority as stored on the board (e.g. Medium), \"\" when unset."},"owner":{"type":"string","description":"Assignee (email or name), \"\" when unassigned."},"dueAt":{"type":"string","description":"Due date/time as ISO 8601 (end of day when no time), \"\" when none."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type (e.g. contact, deal, company)."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, null when the task is not linked."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo"],"description":"The task as list_tasks would return it."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","task"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/tasks/{id}/complete":{"post":{"operationId":"complete_task","summary":"Mark a task done","description":"Mark a task done. Calling it on an already-completed task changes nothing and says so.\n\nRequired scope: `tasks.write`. Risk level: `write`.","tags":["tasks"],"security":[{"bearerAuth":["tasks.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Task id from list_tasks.","schema":{"type":"string","maxLength":80}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["task"],"description":"Always \"task\"."},"targetId":{"type":"string","description":"Task id."},"updated":{"type":"boolean","description":"False when the task was already done (nothing written)."},"alreadyDone":{"type":"boolean","description":"Present (true) only when the task was already completed."},"task":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title."},"done":{"type":"boolean","description":"True when the task is completed."},"priority":{"type":"string","description":"API priority: low | normal | high | urgent, or \"\" when unset."},"priorityLabel":{"type":"string","description":"Priority as stored on the board (e.g. Medium), \"\" when unset."},"owner":{"type":"string","description":"Assignee (email or name), \"\" when unassigned."},"dueAt":{"type":"string","description":"Due date/time as ISO 8601 (end of day when no time), \"\" when none."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type (e.g. contact, deal, company)."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked CRM entity, null when the task is not linked."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo"],"description":"The task as list_tasks would return it."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","task"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/drafts/email":{"post":{"operationId":"create_email_draft","summary":"Write an email DRAFT into FORTVISION","description":"Write an email DRAFT into FORTVISION. It appears under Email → Drafts for a human to review, style and send — this tool never sends anything and never picks recipients. Give it plain content (subject, headline, body paragraphs separated by blank lines, an optional button) and it builds a valid email in the editor's format. Use direction \"rtl\" for Hebrew or Arabic.\n\nRequired scope: `messages.draft`. Risk level: `write`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"subject","in":"query","required":true,"description":"Subject line.","schema":{"type":"string","maxLength":200}},{"name":"name","in":"query","required":false,"description":"Internal name for the draft. Defaults to the subject.","schema":{"type":"string","maxLength":120}},{"name":"preheader","in":"query","required":false,"description":"Preview text shown after the subject in most inboxes.","schema":{"type":"string","maxLength":200}},{"name":"headline","in":"query","required":false,"description":"Large headline at the top of the email.","schema":{"type":"string","maxLength":200}},{"name":"body","in":"query","required":false,"description":"Body copy. Separate paragraphs with a blank line; each becomes its own block.","schema":{"type":"string","maxLength":20000}},{"name":"buttonLabel","in":"query","required":false,"description":"Call-to-action button text.","schema":{"type":"string","maxLength":60}},{"name":"buttonUrl","in":"query","required":false,"description":"Where the button links (http/https).","schema":{"type":"string","maxLength":600}},{"name":"direction","in":"query","required":false,"description":"Text direction. Use rtl for Hebrew/Arabic.","schema":{"type":"string","enum":["ltr","rtl"],"default":"ltr"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["email_draft"],"description":"Always \"email_draft\"."},"targetId":{"type":"string","description":"Draft id."},"created":{"type":"boolean","description":"Always true on success."},"draft":{"type":"object","properties":{"id":{"type":"string","description":"Draft id (t_…)."},"channel":{"type":"string","enum":["email"],"description":"Always \"email\"."},"name":{"type":"string","description":"Draft name (falls back to the subject)."},"subject":{"type":"string","description":"Email subject."},"blocks":{"type":"integer","description":"Number of editor blocks generated (heading, paragraphs, button)."},"updatedAt":{"type":"string","description":"ISO 8601 save time."}},"additionalProperties":true,"required":["id","channel","name","subject","blocks","updatedAt"],"description":"The saved draft (nothing is sent)."},"whereToFind":{"type":"string","description":"Where a human finds the draft in the app."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","draft","whereToFind"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/drafts/sms":{"post":{"operationId":"create_sms_draft","summary":"Save an SMS DRAFT the SMS composer can pick up","description":"Save an SMS DRAFT the SMS composer can pick up. Never sends and never selects recipients. The response reports the character count and how many 160-character segments the message will cost.\n\nRequired scope: `messages.draft`. Risk level: `write`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"message","in":"query","required":true,"description":"The SMS body.","schema":{"type":"string","maxLength":1600}},{"name":"name","in":"query","required":false,"description":"Internal name for the draft.","schema":{"type":"string","maxLength":120}},{"name":"senderProfileId","in":"query","required":false,"description":"Sender profile to use, from the SMS senders list.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["sms_draft"],"description":"Always \"sms_draft\"."},"targetId":{"type":"string","description":"Draft id."},"created":{"type":"boolean","description":"Always true on success."},"draft":{"type":"object","properties":{"id":{"type":"string","description":"Draft id (d_…)."},"channel":{"type":"string","enum":["sms"],"description":"Always \"sms\"."},"name":{"type":"string","description":"Draft name (first 40 chars of the message when not supplied)."},"message":{"type":"string","description":"Full message text (≤ 1600 chars)."},"characters":{"type":"integer","description":"Message length in characters."},"segments":{"type":"integer","description":"SMS segments at 160 chars each."},"updatedAt":{"type":"string","description":"ISO 8601 save time."}},"additionalProperties":true,"required":["id","channel","name","message","characters","segments","updatedAt"],"description":"The saved draft (nothing is sent)."},"whereToFind":{"type":"string","description":"Where a human finds the draft in the app."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","draft","whereToFind"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/drafts/whatsapp":{"post":{"operationId":"create_whatsapp_draft","summary":"Save a WhatsApp DRAFT into the WhatsApp composer, where it appears under Drafts for a human to finish and send","description":"Save a WhatsApp DRAFT into the WhatsApp composer, where it appears under Drafts for a human to finish and send. Never sends. WhatsApp delivers only approved templates outside a 24-hour service window, so a draft names a template rather than free text — call list_whatsapp_templates first — and templateVariables fill its placeholders in order.\n\nRequired scope: `messages.draft`. Risk level: `write`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"templateName","in":"query","required":true,"description":"Approved template name (or id) from list_whatsapp_templates.","schema":{"type":"string","maxLength":120}},{"name":"templateVariables","in":"query","required":false,"description":"Values for the template placeholders, in order.","schema":{"type":"array","maxItems":10,"items":{"type":"string"}}},{"name":"name","in":"query","required":false,"description":"Ignored — the draft is named after its template, matching the composer.","schema":{"type":"string","maxLength":120}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["whatsapp_draft"],"description":"Always \"whatsapp_draft\"."},"targetId":{"type":"string","description":"Draft id."},"created":{"type":"boolean","description":"Always true on success."},"draft":{"type":"object","properties":{"id":{"type":"string","description":"Draft id (wd_…)."},"channel":{"type":"string","enum":["whatsapp"],"description":"Always \"whatsapp\"."},"name":{"type":"string","description":"Draft name (= the template name)."},"templateName":{"type":"string","description":"Approved template name."},"templateId":{"type":"string","description":"Template id the composer selects by."},"body":{"type":"string","description":"Template body text (≤ 1000 chars), \"\" when the template has none."},"variables":{"type":"integer","description":"Number of template variables supplied."},"updatedAt":{"type":"string","description":"ISO 8601 save time."}},"additionalProperties":true,"required":["id","channel","name","templateName","templateId","body","variables","updatedAt"],"description":"The saved draft (nothing is sent)."},"note":{"type":"string","description":"Only when fewer variables were supplied than the template takes."},"whereToFind":{"type":"string","description":"Where a human finds the draft in the app."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","draft","whereToFind"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/drafts":{"get":{"operationId":"list_message_drafts","summary":"List saved email, SMS and WhatsApp drafts, newest first, marking which were created through this API","description":"List saved email, SMS and WhatsApp drafts, newest first, marking which were created through this API. Use it to find a draft id before reading it or sending it.\n\nRequired scope: `messages.draft`. Risk level: `read`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"channel","in":"query","required":false,"description":"Restrict to one channel.","schema":{"type":"string","enum":["email","sms","whatsapp"]}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"drafts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Draft id."},"channel":{"type":"string","enum":["email","sms","whatsapp"],"description":"Draft channel."},"name":{"type":"string","description":"Draft name."},"subject":{"type":"string","description":"Email drafts only: subject line."},"preview":{"type":"string","description":"SMS drafts only: first 200 chars of the message."},"templateId":{"type":"string","description":"WhatsApp drafts only: template id."},"createdVia":{"type":"string","description":"\"api\" when created through this API, otherwise \"app\"."},"updatedAt":{"type":"string","description":"ISO 8601 last save time, \"\" when unknown."}},"additionalProperties":true,"required":["id","channel","name","createdVia","updatedAt"],"description":"One draft summary row."},"description":"Drafts across the requested channel(s), newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number returned."},"pageSize":{"type":"integer","description":"Rows per page."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page cursor for the list."}},"additionalProperties":true,"required":["ok","requestId","drafts","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/drafts/{id}":{"get":{"operationId":"get_message_draft","summary":"Read one draft in full — for email, its subject and every content block; for SMS and WhatsApp, the message body","description":"Read one draft in full — for email, its subject and every content block; for SMS and WhatsApp, the message body.\n\nRequired scope: `messages.draft`. Risk level: `read`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Draft id from list_message_drafts.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"draft":{"type":"object","properties":{"id":{"type":"string","description":"Draft id."},"channel":{"type":"string","enum":["email","sms","whatsapp"],"description":"Draft channel."},"name":{"type":"string","description":"Draft name."},"updatedAt":{"type":"string","description":"ISO 8601 last save time, \"\" when unknown."},"subject":{"type":"string","description":"email only: subject line."},"preheader":{"type":"string","description":"email only: preheader text, \"\" when none."},"content":{"type":"array","items":{"type":"object","properties":{"type":{"description":"Block type, e.g. heading, text, button."},"text":{"type":"string","description":"Block text (≤ 2000 chars), \"\" when none."},"href":{"type":"string","description":"Button link, \"\" for non-button blocks."}},"additionalProperties":true,"required":["text","href"],"description":"One editor block."},"description":"email only: the editor blocks in order."},"templateId":{"type":"string","description":"whatsapp only: template id."},"variables":{"type":"array","items":{"type":"string","description":"Variable value."},"description":"whatsapp only: template variable values in order."},"requireApproval":{"type":"boolean","description":"whatsapp only: whether sending requires client approval."},"message":{"type":"string","description":"sms only: message text (≤ 2000 chars)."}},"additionalProperties":true,"required":["id","channel","name","updatedAt"],"description":"The draft; which keys appear depends on `channel`."}},"additionalProperties":true,"required":["ok","requestId","draft"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/mailboxes":{"get":{"operationId":"list_connected_email_accounts","summary":"The personal Gmail / Outlook mailboxes connected to this workspace (Sequences → Email accounts), with provider, connection status and whether each can hold drafts (canCreateDrafts) and send (canSend)","description":"The personal Gmail / Outlook mailboxes connected to this workspace (Sequences → Email accounts), with provider, connection status and whether each can hold drafts (canCreateDrafts) and send (canSend). Call it before create_mailbox_draft / bulk_create_mailbox_drafts to pick the `from` mailbox, e.g. elad@fortvision.com. Never returns tokens or credentials. A mailbox whose status is needs_reconnect was connected before the draft permission existed — the owner reconnects it in the app.\n\nRequired scope: `messages.draft`. Risk level: `read`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"accounts":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"The mailbox address — what to pass as `from` / `mailbox`."},"provider":{"type":"string","enum":["gmail","outlook"],"description":"Mail provider."},"status":{"type":"string","enum":["connected","needs_reconnect"],"description":"needs_reconnect: the stored grant lacks the draft permission; the owner reconnects in Sequences → Email accounts."},"canCreateDrafts":{"type":"boolean","description":"Whether drafts can be created in this mailbox right now."},"canSend":{"type":"boolean","description":"Whether the grant allows sending (used by send_outreach_email, a separate tool)."},"permissionsVerified":{"type":"boolean","description":"false when the grant predates permission recording: the flags are optimistic and a provider refusal is reported as needs_reconnect."},"isDefault":{"type":"boolean","description":"The token owner's default mailbox."},"connectedBy":{"type":"string","description":"Workspace member who connected it."},"connectedAt":{"type":"string","description":"ISO 8601 connection time."}},"additionalProperties":true,"required":["email","provider","status","canCreateDrafts","canSend","permissionsVerified","isDefault"]},"description":"Connected personal mailboxes in this workspace. Never includes tokens."},"note":{"type":"string"}},"additionalProperties":true,"required":["ok","requestId","accounts","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/mailboxes/drafts":{"post":{"operationId":"create_mailbox_draft","summary":"Save ONE real email draft into a connected Gmail / Outlook mailbox's Drafts folder (not the Email Marketing editor — that is create_email_draft)","description":"Save ONE real email draft into a connected Gmail / Outlook mailbox's Drafts folder (not the Email Marketing editor — that is create_email_draft). The owner opens, edits and sends it from their mailbox; this tool NEVER sends and creating a draft grants no permission to send. `from` must be a mailbox from list_connected_email_accounts. Recipients must be real, verified addresses — invalid ones are rejected, never guessed. Hebrew / Arabic is detected and the body is wrapped dir=\"rtl\" (or pass direction). Give bodyHtml (kept as-is, scripts stripped) and/or bodyText (plain text is turned into simple HTML; a text twin is always included). The owner's saved FORTVISION signature is appended unless appendSignature:false. The recipient is matched to a CRM contact by email and the draft is recorded on that contact's timeline — the contact is NOT marked contacted. Returns the provider draft id plus a link that opens the draft in Gmail / Outlook on the web. Pass an idempotencyKey so a retry cannot create the draft twice.\n\nRequired scope: `messages.draft`. Risk level: `write`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"from","in":"query","required":true,"description":"Connected mailbox that will hold the draft (its email address).","schema":{"type":"string","maxLength":160}},{"name":"to","in":"query","required":true,"description":"Recipient addresses (\"Name <addr>\" accepted). At least one; max 20.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"cc","in":"query","required":false,"description":"CC addresses.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"bcc","in":"query","required":false,"description":"BCC addresses.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"subject","in":"query","required":true,"description":"Subject line (UTF-8; Hebrew is fine).","schema":{"type":"string","maxLength":300}},{"name":"bodyHtml","in":"query","required":false,"description":"HTML body. Keep it simple email HTML; use <div dir=\"rtl\"> for Hebrew or let direction handle it.","schema":{"type":"string","maxLength":200000}},{"name":"bodyText","in":"query","required":false,"description":"Plain-text body (required if bodyHtml is absent; otherwise used as the text alternative).","schema":{"type":"string","maxLength":100000}},{"name":"direction","in":"query","required":false,"description":"Text direction. Auto-detected from the content when omitted.","schema":{"type":"string","enum":["ltr","rtl"]}},{"name":"fromName","in":"query","required":false,"description":"Display name for the From header (Gmail drafts only; Outlook uses the mailbox name).","schema":{"type":"string","maxLength":120}},{"name":"appendSignature","in":"query","required":false,"description":"Append the mailbox owner's saved FORTVISION signature (default true).","schema":{"type":"boolean","default":true}},{"name":"dealId","in":"query","required":false,"description":"Also log the draft as an email-kind note on this deal (list_deals).","schema":{"type":"string","maxLength":40}},{"name":"createContactIfMissing","in":"query","required":false,"description":"If the first To recipient matches no CRM contact, create one (email + contactName + contactCompany, source \"Mailbox draft\"). Default false.","schema":{"type":"boolean","default":false}},{"name":"contactName","in":"query","required":false,"description":"Name for the contact created by createContactIfMissing.","schema":{"type":"string","maxLength":160}},{"name":"contactCompany","in":"query","required":false,"description":"Company for the contact created by createContactIfMissing.","schema":{"type":"string","maxLength":160}},{"name":"contactSource","in":"query","required":false,"description":"Source label for a created contact (default \"Mailbox draft\").","schema":{"type":"string","maxLength":120}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["mailbox_draft"]},"targetId":{"type":"string","description":"The provider draft id."},"created":{"type":"boolean"},"sent":{"type":"boolean","enum":[false],"description":"Always false: this tool cannot send."},"mailbox":{"type":"string"},"provider":{"type":"string","enum":["gmail","outlook"]},"direction":{"type":"string","description":"Text direction applied to the body (ltr / rtl)."},"draft":{"type":"object","properties":{"draftId":{"type":"string","description":"Provider draft id: Gmail drafts.* id (changes on update) or the Outlook message id."},"messageId":{"type":"string","description":"Gmail: the underlying message id (what the web link uses). Outlook: same as draftId."},"threadId":{"type":"string","description":"Gmail thread id / Outlook conversation id."},"mailbox":{"type":"string","description":"Mailbox address the draft lives in."},"provider":{"type":"string","enum":["gmail","outlook"]},"kind":{"type":"string","enum":["personal_mailbox_draft"],"description":"Always personal_mailbox_draft — distinguishes it from Email Marketing drafts."},"to":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"cc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"bcc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"subject":{"type":"string"},"snippet":{"type":"string","description":"Provider preview text."},"bodyHtml":{"type":"string","description":"Full HTML body (get_mailbox_draft only)."},"bodyText":{"type":"string","description":"Plain-text body (get_mailbox_draft only)."},"createdAt":{"type":"string","description":"ISO 8601 (Gmail reports one timestamp for created and updated)."},"updatedAt":{"type":"string","description":"ISO 8601 last modification."},"status":{"type":"string","enum":["draft","sent"],"description":"Always draft for a draft; sent only appears if the mailbox owner has sent it since."},"webUrl":{"type":"string","description":"Link that opens the draft in Gmail / Outlook on the web (empty if the provider gave no id)."},"webUrlKind":{"type":"string","enum":["provider","constructed"],"description":"provider = returned by Outlook (verified); constructed = built from the Gmail message id."}},"additionalProperties":true,"required":["draftId","mailbox","provider","kind","to","subject","status","webUrl","webUrlKind"],"description":"One personal mailbox draft (never an Email Marketing draft)."},"crm":{"type":"object","properties":{"linkedContacts":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"contactId":{"type":"string"},"name":{"type":"string"},"company":{"type":"string"}},"additionalProperties":true,"required":["email","contactId"]}},"unmatchedRecipients":{"type":"array","items":{"type":"string"},"description":"Recipients with no CRM contact (drafts are created regardless)."},"createdContacts":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"contactId":{"type":"string"},"name":{"type":"string"},"duplicate":{"type":"boolean"},"error":{"type":"string"}},"additionalProperties":true,"required":["email"]},"description":"Contacts created by createContactIfMissing (empty otherwise)."},"deal":{"type":["object","null"],"properties":{"dealId":{"type":"string"},"name":{"type":"string"},"error":{"type":"string"}},"additionalProperties":true,"description":"The deal the draft was logged on, when dealId was passed."}},"additionalProperties":true,"required":["linkedContacts","unmatchedRecipients","createdContacts"],"description":"CRM association made for the recipients. Nothing here marks a contact as contacted."},"message":{"type":"string"},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","sent","mailbox","provider","draft","crm","message"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"get":{"operationId":"list_mailbox_drafts","summary":"List the drafts currently in a connected mailbox's Drafts folder (all of them, not only API-created), newest first: draft id, recipients, subject, created / updated time and a link to open each in Gmail / Outlook","description":"List the drafts currently in a connected mailbox's Drafts folder (all of them, not only API-created), newest first: draft id, recipients, subject, created / updated time and a link to open each in Gmail / Outlook. Cursor-paged: pass nextCursor back as cursor. These are personal mailbox drafts — Email Marketing drafts are list_message_drafts.\n\nRequired scope: `messages.draft`. Risk level: `read`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"mailbox","in":"query","required":true,"description":"Connected mailbox address from list_connected_email_accounts.","schema":{"type":"string","maxLength":160}},{"name":"limit","in":"query","required":false,"description":"Drafts per page (1-100, default 50).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"nextCursor from the previous page.","schema":{"type":"string","maxLength":400}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"mailbox":{"type":"string"},"provider":{"type":"string","enum":["gmail","outlook"]},"kind":{"type":"string","enum":["personal_mailbox_drafts"]},"drafts":{"type":"array","items":{"type":"object","properties":{"draftId":{"type":"string","description":"Provider draft id: Gmail drafts.* id (changes on update) or the Outlook message id."},"messageId":{"type":"string","description":"Gmail: the underlying message id (what the web link uses). Outlook: same as draftId."},"threadId":{"type":"string","description":"Gmail thread id / Outlook conversation id."},"mailbox":{"type":"string","description":"Mailbox address the draft lives in."},"provider":{"type":"string","enum":["gmail","outlook"]},"kind":{"type":"string","enum":["personal_mailbox_draft"],"description":"Always personal_mailbox_draft — distinguishes it from Email Marketing drafts."},"to":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"cc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"bcc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"subject":{"type":"string"},"snippet":{"type":"string","description":"Provider preview text."},"bodyHtml":{"type":"string","description":"Full HTML body (get_mailbox_draft only)."},"bodyText":{"type":"string","description":"Plain-text body (get_mailbox_draft only)."},"createdAt":{"type":"string","description":"ISO 8601 (Gmail reports one timestamp for created and updated)."},"updatedAt":{"type":"string","description":"ISO 8601 last modification."},"status":{"type":"string","enum":["draft","sent"],"description":"Always draft for a draft; sent only appears if the mailbox owner has sent it since."},"webUrl":{"type":"string","description":"Link that opens the draft in Gmail / Outlook on the web (empty if the provider gave no id)."},"webUrlKind":{"type":"string","enum":["provider","constructed"],"description":"provider = returned by Outlook (verified); constructed = built from the Gmail message id."}},"additionalProperties":true,"required":["draftId","mailbox","provider","kind","to","subject","status","webUrl","webUrlKind"],"description":"One personal mailbox draft (never an Email Marketing draft)."}},"nextCursor":{"type":"string","description":"Pass back as cursor for the next page; empty when there is none."},"hasMore":{"type":"boolean"},"total":{"type":["integer","null"],"description":"Provider estimate of the Drafts folder size, when it gives one."},"note":{"type":"string"}},"additionalProperties":true,"required":["ok","requestId","mailbox","provider","kind","drafts","nextCursor","hasMore","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/mailboxes/drafts/{draftId}":{"get":{"operationId":"get_mailbox_draft","summary":"Read one draft from a connected mailbox in full: recipients (to / cc / bcc), subject, HTML and plain-text body, timestamps, provider ids and the open-in-provider link","description":"Read one draft from a connected mailbox in full: recipients (to / cc / bcc), subject, HTML and plain-text body, timestamps, provider ids and the open-in-provider link. The draft id must come from list_mailbox_drafts or create_mailbox_draft for THAT mailbox.\n\nRequired scope: `messages.draft`. Risk level: `read`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"mailbox","in":"query","required":true,"description":"Connected mailbox address.","schema":{"type":"string","maxLength":160}},{"name":"draftId","in":"path","required":true,"description":"Provider draft id.","schema":{"type":"string","maxLength":300}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"mailbox":{"type":"string"},"provider":{"type":"string","enum":["gmail","outlook"]},"draft":{"type":"object","properties":{"draftId":{"type":"string","description":"Provider draft id: Gmail drafts.* id (changes on update) or the Outlook message id."},"messageId":{"type":"string","description":"Gmail: the underlying message id (what the web link uses). Outlook: same as draftId."},"threadId":{"type":"string","description":"Gmail thread id / Outlook conversation id."},"mailbox":{"type":"string","description":"Mailbox address the draft lives in."},"provider":{"type":"string","enum":["gmail","outlook"]},"kind":{"type":"string","enum":["personal_mailbox_draft"],"description":"Always personal_mailbox_draft — distinguishes it from Email Marketing drafts."},"to":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"cc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"bcc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"subject":{"type":"string"},"snippet":{"type":"string","description":"Provider preview text."},"bodyHtml":{"type":"string","description":"Full HTML body (get_mailbox_draft only)."},"bodyText":{"type":"string","description":"Plain-text body (get_mailbox_draft only)."},"createdAt":{"type":"string","description":"ISO 8601 (Gmail reports one timestamp for created and updated)."},"updatedAt":{"type":"string","description":"ISO 8601 last modification."},"status":{"type":"string","enum":["draft","sent"],"description":"Always draft for a draft; sent only appears if the mailbox owner has sent it since."},"webUrl":{"type":"string","description":"Link that opens the draft in Gmail / Outlook on the web (empty if the provider gave no id)."},"webUrlKind":{"type":"string","enum":["provider","constructed"],"description":"provider = returned by Outlook (verified); constructed = built from the Gmail message id."}},"additionalProperties":true,"required":["draftId","mailbox","provider","kind","to","subject","status","webUrl","webUrlKind"],"description":"One personal mailbox draft (never an Email Marketing draft)."}},"additionalProperties":true,"required":["ok","requestId","mailbox","provider","draft"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"update_mailbox_draft","summary":"Change an existing draft in a connected mailbox: to / cc / bcc, subject, bodyHtml / bodyText","description":"Change an existing draft in a connected mailbox: to / cc / bcc, subject, bodyHtml / bodyText. Only the fields passed change; the rest of the draft is kept. Never sends. Gmail re-issues the draft id on update — use the draftId in the response from then on.\n\nRequired scope: `messages.draft`. Risk level: `write`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"mailbox","in":"query","required":true,"description":"Connected mailbox address.","schema":{"type":"string","maxLength":160}},{"name":"draftId","in":"path","required":true,"description":"Provider draft id from list_mailbox_drafts / create_mailbox_draft.","schema":{"type":"string","maxLength":300}},{"name":"to","in":"query","required":false,"description":"New To list (replaces the current one).","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"cc","in":"query","required":false,"description":"New CC list (replaces; pass [] to clear).","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"bcc","in":"query","required":false,"description":"New BCC list (replaces; pass [] to clear).","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"subject","in":"query","required":false,"description":"New subject.","schema":{"type":"string","maxLength":300}},{"name":"bodyHtml","in":"query","required":false,"description":"New HTML body (replaces the body).","schema":{"type":"string","maxLength":200000}},{"name":"bodyText","in":"query","required":false,"description":"New plain-text body (replaces the body when bodyHtml is absent).","schema":{"type":"string","maxLength":100000}},{"name":"direction","in":"query","required":false,"description":"Text direction for a new body.","schema":{"type":"string","enum":["ltr","rtl"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["mailbox_draft"]},"targetId":{"type":"string","description":"The draft id AFTER the update (Gmail re-issues ids)."},"updated":{"type":"boolean"},"sent":{"type":"boolean","enum":[false]},"mailbox":{"type":"string"},"provider":{"type":"string","enum":["gmail","outlook"]},"draft":{"type":"object","properties":{"draftId":{"type":"string","description":"Provider draft id: Gmail drafts.* id (changes on update) or the Outlook message id."},"messageId":{"type":"string","description":"Gmail: the underlying message id (what the web link uses). Outlook: same as draftId."},"threadId":{"type":"string","description":"Gmail thread id / Outlook conversation id."},"mailbox":{"type":"string","description":"Mailbox address the draft lives in."},"provider":{"type":"string","enum":["gmail","outlook"]},"kind":{"type":"string","enum":["personal_mailbox_draft"],"description":"Always personal_mailbox_draft — distinguishes it from Email Marketing drafts."},"to":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"cc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"bcc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"subject":{"type":"string"},"snippet":{"type":"string","description":"Provider preview text."},"bodyHtml":{"type":"string","description":"Full HTML body (get_mailbox_draft only)."},"bodyText":{"type":"string","description":"Plain-text body (get_mailbox_draft only)."},"createdAt":{"type":"string","description":"ISO 8601 (Gmail reports one timestamp for created and updated)."},"updatedAt":{"type":"string","description":"ISO 8601 last modification."},"status":{"type":"string","enum":["draft","sent"],"description":"Always draft for a draft; sent only appears if the mailbox owner has sent it since."},"webUrl":{"type":"string","description":"Link that opens the draft in Gmail / Outlook on the web (empty if the provider gave no id)."},"webUrlKind":{"type":"string","enum":["provider","constructed"],"description":"provider = returned by Outlook (verified); constructed = built from the Gmail message id."}},"additionalProperties":true,"required":["draftId","mailbox","provider","kind","to","subject","status","webUrl","webUrlKind"],"description":"One personal mailbox draft (never an Email Marketing draft)."},"changed":{"type":"array","items":{"type":"string"},"description":"Which fields were changed."},"message":{"type":"string"},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","sent","mailbox","provider","draft","changed","message"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/mailboxes/drafts/{draftId}/delete":{"post":{"operationId":"delete_mailbox_draft","summary":"Delete one draft from a connected mailbox's Drafts folder","description":"Delete one draft from a connected mailbox's Drafts folder. PREVIEW FIRST: without confirm it reads the draft back and reports exactly which draft (subject, recipients, mailbox) would be removed. Only call it on an explicit request to delete that draft — never on an ambiguous instruction; a sent message is never deleted by this tool.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"mailbox","in":"query","required":true,"description":"Connected mailbox address.","schema":{"type":"string","maxLength":160}},{"name":"draftId","in":"path","required":true,"description":"Provider draft id.","schema":{"type":"string","maxLength":300}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["mailbox_draft"]},"targetId":{"type":"string"},"mailbox":{"type":"string"},"provider":{"type":"string","enum":["gmail","outlook"]},"draft":{"type":"object","properties":{"draftId":{"type":"string","description":"Provider draft id: Gmail drafts.* id (changes on update) or the Outlook message id."},"messageId":{"type":"string","description":"Gmail: the underlying message id (what the web link uses). Outlook: same as draftId."},"threadId":{"type":"string","description":"Gmail thread id / Outlook conversation id."},"mailbox":{"type":"string","description":"Mailbox address the draft lives in."},"provider":{"type":"string","enum":["gmail","outlook"]},"kind":{"type":"string","enum":["personal_mailbox_draft"],"description":"Always personal_mailbox_draft — distinguishes it from Email Marketing drafts."},"to":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"cc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"bcc":{"type":"array","items":{"type":"string"},"description":"Addresses as \"Name <addr>\" or \"addr\"."},"subject":{"type":"string"},"snippet":{"type":"string","description":"Provider preview text."},"bodyHtml":{"type":"string","description":"Full HTML body (get_mailbox_draft only)."},"bodyText":{"type":"string","description":"Plain-text body (get_mailbox_draft only)."},"createdAt":{"type":"string","description":"ISO 8601 (Gmail reports one timestamp for created and updated)."},"updatedAt":{"type":"string","description":"ISO 8601 last modification."},"status":{"type":"string","enum":["draft","sent"],"description":"Always draft for a draft; sent only appears if the mailbox owner has sent it since."},"webUrl":{"type":"string","description":"Link that opens the draft in Gmail / Outlook on the web (empty if the provider gave no id)."},"webUrlKind":{"type":"string","enum":["provider","constructed"],"description":"provider = returned by Outlook (verified); constructed = built from the Gmail message id."}},"additionalProperties":true,"required":["draftId","mailbox","provider","kind","to","subject","status","webUrl","webUrlKind"],"description":"Preview only: the draft that would be deleted."},"summary":{"type":"string","description":"Preview only: what will be deleted."},"warnings":{"type":"array","items":{"type":"string"}},"deleted":{"type":"boolean","description":"Run only: true when the provider removed it."},"message":{"type":"string"},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","mailbox","provider"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/mailboxes/drafts/bulk":{"post":{"operationId":"bulk_create_mailbox_drafts","summary":"Save up to 100 personalised email drafts into ONE connected mailbox's Drafts folder in a single operation — the outbound-sales case (\"26 drafts from elad@fortvision","description":"Save up to 100 personalised email drafts into ONE connected mailbox's Drafts folder in a single operation — the outbound-sales case (\"26 drafts from elad@fortvision.com to these advertisers\"). Each entry keeps its own recipients, subject and body. PREVIEW FIRST (the dry run): without confirm nothing is created and the response lists, per entry, whether it is valid, already created by an earlier run with this idempotencyKey, and which CRM contact it matches; invalid or missing recipients are rejected, never guessed. With confirm it creates the drafts (a few at a time, retrying provider rate limits) and returns one row per entry with status created / exists / failed / invalid, the provider draft id and the open-in-mailbox link — partial success is reported, not hidden. Retrying with the SAME idempotencyKey creates only what is still missing. NEVER sends anything; the owner sends each draft from the mailbox.\n\nRequired scope: `messages.draft`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"mailbox","in":"query","required":true,"description":"Connected mailbox that will hold the drafts (from list_connected_email_accounts).","schema":{"type":"string","maxLength":160}},{"name":"drafts","in":"query","required":true,"description":"One entry per draft: { to: [\"addr\" | \"Name <addr>\"] (required), subject (required), bodyHtml and/or bodyText (one required), cc, bcc, company, name, direction, dealId }. company/name are echoed back in the result row to map drafts to prospects.","schema":{"type":"array","maxItems":100,"items":{"type":"object"}}},{"name":"direction","in":"query","required":false,"description":"Default text direction for entries that do not set their own (auto-detected otherwise).","schema":{"type":"string","enum":["ltr","rtl"]}},{"name":"fromName","in":"query","required":false,"description":"Display name for the From header (Gmail only).","schema":{"type":"string","maxLength":120}},{"name":"appendSignature","in":"query","required":false,"description":"Append the owner's saved signature to every draft (default true).","schema":{"type":"boolean","default":true}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["mailbox"]},"targetId":{"type":"string","description":"The mailbox address."},"mailbox":{"type":"string"},"provider":{"type":"string","enum":["gmail","outlook"]},"requested":{"type":"integer","description":"Entries in drafts[]."},"willCreate":{"type":"integer","description":"Preview only: entries that would be created."},"alreadyCreated":{"type":"integer","description":"Preview only: entries an earlier run with this idempotencyKey already created."},"created":{"type":"integer","description":"Run only."},"existing":{"type":"integer","description":"Run only: skipped because already created under this idempotencyKey."},"failed":{"type":"integer","description":"Run only: provider failures (retry with the same idempotencyKey)."},"invalid":{"type":"integer","description":"Entries rejected before any provider call (bad / missing recipients, empty subject or body, duplicates)."},"sent":{"type":"integer","description":"Run only: always 0."},"drafts":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the drafts[] input."},"company":{"type":"string","description":"Echoed from the input."},"name":{"type":"string","description":"Echoed from the input."},"to":{"type":"array","items":{"type":"string"}},"subject":{"type":"string"},"status":{"type":"string","enum":["pending","created","exists","failed","invalid"],"description":"Preview: pending (will create) / exists / invalid. Run: created / exists / failed / invalid."},"error":{"type":"string","description":"Why it is invalid or failed; empty otherwise."},"draftId":{"type":"string","description":"Provider draft id once created (or from the earlier run)."},"messageId":{"type":"string"},"webUrl":{"type":"string","description":"Open-in-mailbox link once created."},"contactId":{"type":"string","description":"Linked CRM contact, when the recipient matched one."},"contactName":{"type":"string"}},"additionalProperties":true,"required":["index","to","subject","status","error","draftId","webUrl","contactId"]},"description":"One row per input entry — trust these over the counters."},"crm":{"type":"object","properties":{"matchedContacts":{"type":"integer"},"unmatchedRecipients":{"type":"integer"}},"additionalProperties":true,"required":["matchedContacts","unmatchedRecipients"]},"summary":{"type":"string","description":"Preview only."},"warnings":{"type":"array","items":{"type":"string"}},"message":{"type":"string","description":"Run only."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","mailbox","provider","requested","invalid","drafts","crm"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns/email/send":{"post":{"operationId":"send_email_campaign","summary":"Send an existing email draft to an audience","description":"Send an existing email draft to an audience. PREVIEW FIRST: called without confirm it changes nothing and reports exactly who would receive it, how many were removed as unsubscribed or bounced, and the sending address. Unsubscribed, bounced and complained addresses are always excluded and an unsubscribe link is always added. Create the draft with create_email_draft first; this tool never writes content.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"draftId","in":"query","required":true,"description":"Email draft id from list_message_drafts.","schema":{"type":"string","maxLength":80}},{"name":"leadIds","in":"query","required":false,"description":"Exact leads to send to. Most precise option.","schema":{"type":"array","maxItems":500,"items":{"type":"string"}}},{"name":"status","in":"query","required":false,"description":"Send to every lead currently in this pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"audience","in":"query","required":false,"description":"Set to \"all_leads\" to reach every lead with a usable email address. Still capped and still previewed.","schema":{"type":"string","enum":["all_leads"]}},{"name":"fromEmail","in":"query","required":false,"description":"Verified sending address. Defaults to the workspace's first verified identity.","schema":{"type":"string","maxLength":160}},{"name":"fromName","in":"query","required":false,"description":"Display name shown as the sender.","schema":{"type":"string","maxLength":80}},{"name":"replyTo","in":"query","required":false,"description":"Reply-to address.","schema":{"type":"string","maxLength":160}},{"name":"sendAt","in":"query","required":false,"description":"ISO 8601 time to send. Defaults to about a minute from now.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["send_email_campaign"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["email_draft","email_campaign"],"description":"email_draft on preview, email_campaign once queued."},"targetId":{"type":"string","description":"Draft id on preview; campaign id once queued."},"draft":{"type":"object","properties":{"id":{"type":"string","description":"Draft id."},"name":{"type":"string","description":"Draft name."},"subject":{"type":"string","description":"Subject line."}},"additionalProperties":true,"required":["id","name","subject"],"description":"Preview only: the draft that would be sent."},"from":{"type":"object","properties":{"email":{"type":"string","description":"From address."},"name":{"type":"string","description":"From display name (\"\" when none)."}},"additionalProperties":true,"required":["email","name"],"description":"Verified sending identity."},"audience":{"type":"object","properties":{"matched":{"type":"integer","description":"Leads matched by leadIds / status / audience."},"missingAddress":{"type":"integer","description":"Matched leads with no address on this channel."},"invalidAddress":{"type":"integer","description":"Addresses that failed format validation and were dropped."},"duplicatesRemoved":{"type":"integer","description":"Duplicate addresses collapsed to one."},"suppressed":{"type":"integer","description":"Removed as unsubscribed, bounced, complained or STOP."},"willReceive":{"type":"integer","description":"Final recipient count."}},"additionalProperties":true,"required":["matched","missingAddress","invalidAddress","duplicatesRemoved","suppressed","willReceive"],"description":"Audience accounting after suppression: how many matched and how many will actually receive."},"sampleRecipients":{"type":"array","items":{"type":"string"},"description":"Preview only: up to 5 recipient emails."},"sendAt":{"type":"string","description":"Preview only: ISO 8601 send time, or \"immediately\"."},"htmlBytes":{"type":"integer","description":"Preview only: rendered HTML size in bytes."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"sent":{"type":"boolean","description":"True once the campaign is queued."},"campaignId":{"type":"string","description":"Queued campaign id (camp_api_…)."},"scheduledFor":{"type":"string","description":"ISO 8601 time the send is scheduled for."},"recipients":{"type":"integer","description":"Recipients queued."},"subject":{"type":"string","description":"Subject line as queued."},"jobs":{"description":"Number of send jobs the queue split this into (from the scheduler)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","from","audience"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences":{"get":{"operationId":"list_email_sequences","summary":"List the outreach email sequences (multi-step cadences sent from the connected Gmail/Outlook mailboxes by the platform's sequence engine): id, name, status (running/paused), step subjects and day offsets, recipient/pending/replied counts, sending mailbox and daily cap","description":"List the outreach email sequences (multi-step cadences sent from the connected Gmail/Outlook mailboxes by the platform's sequence engine): id, name, status (running/paused), step subjects and day offsets, recipient/pending/replied counts, sending mailbox and daily cap.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"sequences":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","description":"Sequence state, e.g. \"running\" or \"paused\"."},"steps":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer","description":"1-based step number."},"type":{"type":"string","description":"Step channel: email, sms, whatsapp or task."},"subject":{"type":"string","description":"Email subject (\"\" for non-email steps)."},"delayDays":{"type":"number","description":"Days after the previous step."}},"additionalProperties":true,"required":["n","type","subject","delayDays"]},"description":"Cadence steps in order."},"recipients":{"type":"integer","description":"Enrolled recipients."},"pending":{"type":"integer","description":"Recipients not done and not replied."},"replied":{"type":"integer","description":"Recipients who replied."},"fromAddr":{"type":"string","description":"Sending mailbox, \"__rotate__\", or \"(default mailbox)\"."},"dailyCap":{"type":"number","description":"Max sequence emails per day."},"stopOnReply":{"type":"boolean","description":"Cadence stops for a recipient who replies."},"stats":{"type":"object","additionalProperties":true,"description":"Cumulative counters, e.g. { sent, replies, opens }."},"createdAt":{"type":"number","description":"Creation time, epoch milliseconds."}},"additionalProperties":true,"required":["id","name","status","steps","recipients","pending","replied","fromAddr","stopOnReply","stats"]},"description":"Every outreach sequence in the workspace."}},"additionalProperties":true,"required":["ok","requestId","sequences"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences/create":{"post":{"operationId":"create_email_sequence","summary":"Create an outreach email SEQUENCE — a multi-step cadence sent from a connected mailbox over days","description":"Create an outreach email SEQUENCE — a multi-step cadence sent from a connected mailbox over days. It is created PAUSED: nothing sends until start_email_sequence is confirmed (or Start in the Sequences tab), so creating it is reversible. steps: up to 8 of {subject, body (plain text ok), delayDays — days AFTER the previous step, first step usually 0}. recipients: up to 500 of {email, name?}. from: a connected mailbox address or \"__rotate__\" (default) to rotate across all connected mailboxes by remaining warm-up budget. Replies and bounces automatically stop the cadence for that recipient (stopOnReply defaults true).\n\nRequired scope: `messages.draft`. Risk level: `write`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Sequence name.","schema":{"type":"string","maxLength":120}},{"name":"steps","in":"query","required":true,"description":"Cadence steps in order. Each: { subject (required on first step), body (plain text or simple HTML), delayDays (0-60, days after the PREVIOUS step) }.","schema":{"type":"array","maxItems":8,"items":{"type":"object"}}},{"name":"recipients","in":"query","required":true,"description":"Who to enroll. Each: { email (required), name }.","schema":{"type":"array","maxItems":500,"items":{"type":"object"}}},{"name":"from","in":"query","required":false,"description":"Sending mailbox address, or \"__rotate__\" (default) to rotate across connected mailboxes.","schema":{"type":"string","maxLength":160}},{"name":"dailyCap","in":"query","required":false,"description":"Max sequence emails per day (1-100, default 20). Per-mailbox warm-up caps still apply on top.","schema":{"type":"number"}},{"name":"stopOnReply","in":"query","required":false,"description":"Stop the cadence for a recipient when they reply. Default true.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","description":"Sequence state, e.g. \"running\" or \"paused\"."},"steps":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer","description":"1-based step number."},"type":{"type":"string","description":"Step channel: email, sms, whatsapp or task."},"subject":{"type":"string","description":"Email subject (\"\" for non-email steps)."},"delayDays":{"type":"number","description":"Days after the previous step."}},"additionalProperties":true,"required":["n","type","subject","delayDays"]},"description":"Cadence steps in order."},"recipients":{"type":"integer","description":"Enrolled recipients."},"pending":{"type":"integer","description":"Recipients not done and not replied."},"replied":{"type":"integer","description":"Recipients who replied."},"fromAddr":{"type":"string","description":"Sending mailbox, \"__rotate__\", or \"(default mailbox)\"."},"dailyCap":{"type":"number","description":"Max sequence emails per day."},"stopOnReply":{"type":"boolean","description":"Cadence stops for a recipient who replies."},"stats":{"type":"object","additionalProperties":true,"description":"Cumulative counters, e.g. { sent, replies, opens }."},"createdAt":{"type":"number","description":"Creation time, epoch milliseconds."},"targetType":{"type":"string","enum":["email_sequence"],"description":"Record type."},"targetId":{"type":"string","description":"New sequence id."},"created":{"type":"boolean","description":"Always true; the sequence is created PAUSED."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","id","name","status","steps","recipients","pending","replied","fromAddr","stopOnReply","stats","targetType","targetId","created"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences/start":{"post":{"operationId":"start_email_sequence","summary":"Start (activate) a paused outreach sequence so the platform cron begins sending it","description":"Start (activate) a paused outreach sequence so the platform cron begins sending it. PREVIEW FIRST: called without confirm it changes nothing and reports the pending recipient count, the step cadence, the sending mailbox and every mailbox's warm-up budget. Only after confirm does the sequence switch to running — first sends go out within ~10 minutes, throttled by the sequence daily cap and per-mailbox warm-up caps.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"id","in":"query","required":true,"description":"Sequence id from list_email_sequences or create_email_sequence.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["email_sequence"],"description":"Record type."},"targetId":{"type":"string","description":"Sequence id."},"summary":{"type":"string","description":"Preview only: what starting will do (pending count, cadence, mailbox, caps)."},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","description":"Sequence state, e.g. \"running\" or \"paused\"."},"steps":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer","description":"1-based step number."},"type":{"type":"string","description":"Step channel: email, sms, whatsapp or task."},"subject":{"type":"string","description":"Email subject (\"\" for non-email steps)."},"delayDays":{"type":"number","description":"Days after the previous step."}},"additionalProperties":true,"required":["n","type","subject","delayDays"]},"description":"Cadence steps in order."},"recipients":{"type":"integer","description":"Enrolled recipients."},"pending":{"type":"integer","description":"Recipients not done and not replied."},"replied":{"type":"integer","description":"Recipients who replied."},"fromAddr":{"type":"string","description":"Sending mailbox, \"__rotate__\", or \"(default mailbox)\"."},"dailyCap":{"type":"number","description":"Max sequence emails per day."},"stopOnReply":{"type":"boolean","description":"Cadence stops for a recipient who replies."},"stats":{"type":"object","additionalProperties":true,"description":"Cumulative counters, e.g. { sent, replies, opens }."},"createdAt":{"type":"number","description":"Creation time, epoch milliseconds."}},"additionalProperties":true,"required":["id","name","status","steps","recipients","pending","replied","fromAddr","stopOnReply","stats"],"description":"Sequence summary (same shape as list_email_sequences rows)."},"mailboxes":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","description":"Mailbox address."},"sentToday":{"type":"integer","description":"Sends counted against the mailbox today."},"dailyCap":{"type":["number","null"],"description":"Warm-up cap for today; null = no cap."}},"additionalProperties":true,"required":["address","sentToday","dailyCap"]},"description":"Every connected mailbox with its warm-up usage today."},"started":{"type":"boolean","description":"True when the sequence switched to running; false if it already was."},"status":{"type":"string","description":"Sequence status after the call, e.g. \"running\"."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences/{id}":{"get":{"operationId":"get_email_sequence","summary":"Full detail of ONE outreach email sequence: settings, steps, the exclusive recipient breakdown (notStarted / due / awaiting / delayed / completed / replied / stopped / bounced / unsubscribed — with definitions of every counter), per-recipient state (stage, next send time, thread, reply / auto-reply / bounce / delay evidence, stop reason, review flags) and the scheduler view (last run, why it sent or did not, per-mailbox daily quota used vs cap)","description":"Full detail of ONE outreach email sequence: settings, steps, the exclusive recipient breakdown (notStarted / due / awaiting / delayed / completed / replied / stopped / bounced / unsubscribed — with definitions of every counter), per-recipient state (stage, next send time, thread, reply / auto-reply / bounce / delay evidence, stop reason, review flags) and the scheduler view (last run, why it sent or did not, per-mailbox daily quota used vs cap). Filter recipients with bucket and query; paginated.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id from list_email_sequences.","schema":{"type":"string","maxLength":60}},{"name":"bucket","in":"query","required":false,"description":"Only recipients in this bucket.","schema":{"type":"string","enum":["notStarted","due","awaiting","delayed","completed","replied","stopped","bounced","unsubscribed","review","autoreplied"]}},{"name":"query","in":"query","required":false,"description":"Substring of email / name / phone.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","description":"running / paused."},"steps":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer","description":"1-based step number."},"type":{"type":"string","description":"email, sms, whatsapp or task."},"subject":{"type":"string","description":"Email subject."},"delayDays":{"type":"number","description":"Days after the previous step."},"delayHours":{"type":"number","description":"Extra hours after the previous step."},"skipIf":{"type":"string","description":"none, replied or opened."}},"additionalProperties":true,"required":["n","type","delayDays","delayHours","skipIf"]},"description":"Cadence steps."},"fromAddr":{"type":"string","description":"Sending mailbox, \"__rotate__\", or \"\" for the default."},"dailyCap":{"type":"number","description":"Max sequence emails per day."},"stopOnReply":{"type":"boolean","description":"Cadence stops for a recipient who replies."},"stats":{"type":"object","additionalProperties":true,"description":"Cumulative counters { sent, replies, opens, … }."},"createdAt":{"type":"number","description":"Epoch milliseconds."},"updatedAt":{"type":"number","description":"Epoch milliseconds."}},"additionalProperties":true,"required":["id","name","status","steps"],"description":"The sequence record (without its recipient list)."},"breakdown":{"type":"object","properties":{"recipients":{"type":"integer","description":"Enrolled people."},"notStarted":{"type":"integer","description":"Nothing sent yet."},"due":{"type":"integer","description":"Next step due now, waiting for a slot."},"awaiting":{"type":"integer","description":"Next step scheduled for a future time."},"delayed":{"type":"integer","description":"Provider reported a temporary delay (4.x.x)."},"completed":{"type":"integer","description":"Every step sent, no reply."},"replied":{"type":"integer","description":"A human answered."},"stopped":{"type":"integer","description":"Cadence ended without a reply."},"bounced":{"type":"integer","description":"Permanent delivery failure."},"unsubscribed":{"type":"integer","description":"Opted out."},"autoReplied":{"type":"integer","description":"Overlay: mailbox answered automatically."},"opened":{"type":"integer","description":"Overlay: tracking pixel fired."},"review":{"type":"integer","description":"Overlay: flagged for a human decision."},"byStage":{"type":"object","additionalProperties":true,"description":"Recipient count per step reached, keyed by stage number."}},"additionalProperties":true,"required":["recipients","notStarted","due","awaiting","delayed","completed","replied","stopped","bounced","unsubscribed","autoReplied","opened","review","byStage"],"description":"Exclusive recipient buckets (they add up to recipients) plus overlay counters."},"definitions":{"type":"object","additionalProperties":true,"description":"Plain-language definition of every counter and bucket name, keyed by name."},"scheduler":{"type":"object","properties":{"mailboxes":{"type":"object","additionalProperties":true,"description":"Keyed by mailbox address: { usedToday, warmupCap (null = none), warmupEnabled, noRotate, day }."},"lastRun":{"description":"Record of the engine's last run for this user, or null."},"lastTickAnywhere":{"type":["string","null"],"description":"ISO 8601 time of the last cron tick for any workspace, or null."},"userActive":{"type":"boolean","description":"This user is in the engine's active set."},"userLocked":{"type":"boolean","description":"A run for this user is in progress."},"cadence":{"type":"string","description":"How the engine schedules sends (interval, caps, day boundary)."}},"additionalProperties":true,"required":["mailboxes","lastRun","lastTickAnywhere","userActive","userLocked","cadence"],"description":"Engine state and per-mailbox quota for this sequence's mailboxes."},"recipients":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"phone":{"type":"string","description":"Phone, or \"\"."},"leadId":{"type":"string","description":"Linked lead id, or \"\"."},"stage":{"type":"integer","description":"Steps sent so far."},"bucket":{"type":"string","enum":["notStarted","due","awaiting","delayed","completed","replied","stopped","bounced","unsubscribed"],"description":"Exclusive state bucket."},"nextAt":{"type":"number","description":"Next step time, epoch ms (0 = none)."},"firstSentAt":{"type":"number","description":"Epoch ms, 0 = never."},"lastSentAt":{"type":"number","description":"Epoch ms, 0 = never."},"sentFrom":{"type":"string","description":"Mailbox that sent to this recipient."},"threadId":{"type":"string","description":"Provider thread id."},"done":{"type":"boolean","description":"Cadence finished."},"doneAt":{"type":"number","description":"Epoch ms, 0 = not done."},"replied":{"type":"boolean","description":"A human replied."},"repliedAt":{"type":"number","description":"Epoch ms, 0 = none."},"replyFrom":{"type":"string","description":"Address the reply came from."},"replyMatch":{"type":"string","description":"How the reply was matched (thread, sender, domain, manual)."},"sentiment":{"type":["string","null"],"description":"AI-classified reply sentiment, or null."},"autoReplyAt":{"type":"number","description":"Epoch ms of an auto-reply, 0 = none."},"autoReplyFrom":{"type":"string","description":"Auto-reply sender."},"autoReplySubject":{"type":"string","description":"Auto-reply subject."},"bounced":{"type":"boolean","description":"Permanent delivery failure."},"bounceStatus":{"type":"string","description":"DSN status code, e.g. 5.1.1."},"bounceDiag":{"type":"string","description":"Provider diagnostic text."},"dsnDelayedAt":{"type":"number","description":"Epoch ms of a temporary delay, 0 = none."},"dsnStatus":{"type":"string","description":"Delay DSN status code."},"dsnResolved":{"type":"string","description":"How the delay resolved, or \"\"."},"unsub":{"type":"boolean","description":"Unsubscribed."},"opened":{"type":"boolean","description":"Tracking pixel fired."},"stopReason":{"type":"string","description":"Why the cadence stopped, or \"\"."},"stoppedAt":{"type":"number","description":"Epoch ms, 0 = none."},"stoppedBy":{"type":"string","description":"Who/what stopped it."},"review":{"type":"string","description":"Note for a human to act on, or \"\"."},"holdReason":{"type":"string","description":"Why the engine is holding this recipient, or \"\"."}},"additionalProperties":true,"required":["email","name","phone","leadId","stage","bucket","nextAt","firstSentAt","lastSentAt","sentFrom","threadId","done","doneAt","replied","repliedAt","replyFrom","replyMatch","sentiment","autoReplyAt","autoReplyFrom","autoReplySubject","bounced","bounceStatus","bounceDiag","dsnDelayedAt","dsnStatus","dsnResolved","unsub","opened","stopReason","stoppedAt","stoppedBy","review","holdReason"]},"description":"Per-recipient state (one page, after bucket/query filters)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number."},"pageSize":{"type":"integer","description":"Items per page."},"total":{"type":"integer","description":"Total items across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list."}},"additionalProperties":true,"required":["ok","requestId","sequence","breakdown","definitions","scheduler","recipients","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences/{id}/delivery":{"get":{"operationId":"get_email_sequence_delivery","summary":"Delivery outcomes of ONE sequence, separated the way the engine separates them: permanent failures (5","description":"Delivery outcomes of ONE sequence, separated the way the engine separates them: permanent failures (5.x.x bounces — suppressed), temporary delays (4.x.x — provider still retrying, NOT bounces), auto-replies (out-of-office / mailbox closing — never counted as replies), human replies (with how each was matched: same thread, sender address, or company domain + quoted subject), manual stops, unsubscribes, and everything flagged for human review.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id from list_email_sequences.","schema":{"type":"string","maxLength":60}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","description":"running / paused."},"fromAddr":{"type":"string","description":"Sending mailbox, \"__rotate__\", or \"\"."},"stats":{"type":"object","additionalProperties":true,"description":"Cumulative counters { sent, replies, opens, … }."}},"additionalProperties":true,"required":["id","name","status","fromAddr","stats"],"description":"Sequence header."},"breakdown":{"type":"object","properties":{"recipients":{"type":"integer","description":"Enrolled people."},"notStarted":{"type":"integer","description":"Nothing sent yet."},"due":{"type":"integer","description":"Next step due now, waiting for a slot."},"awaiting":{"type":"integer","description":"Next step scheduled for a future time."},"delayed":{"type":"integer","description":"Provider reported a temporary delay (4.x.x)."},"completed":{"type":"integer","description":"Every step sent, no reply."},"replied":{"type":"integer","description":"A human answered."},"stopped":{"type":"integer","description":"Cadence ended without a reply."},"bounced":{"type":"integer","description":"Permanent delivery failure."},"unsubscribed":{"type":"integer","description":"Opted out."},"autoReplied":{"type":"integer","description":"Overlay: mailbox answered automatically."},"opened":{"type":"integer","description":"Overlay: tracking pixel fired."},"review":{"type":"integer","description":"Overlay: flagged for a human decision."},"byStage":{"type":"object","additionalProperties":true,"description":"Recipient count per step reached, keyed by stage number."}},"additionalProperties":true,"required":["recipients","notStarted","due","awaiting","delayed","completed","replied","stopped","bounced","unsubscribed","autoReplied","opened","review","byStage"],"description":"Exclusive recipient buckets (they add up to recipients) plus overlay counters."},"definitions":{"type":"object","additionalProperties":true,"description":"Plain-language definition of every counter and bucket name, keyed by name."},"permanentFailures":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"status":{"type":"string","description":"DSN status code."},"diagnostic":{"type":"string","description":"Provider diagnostic text."},"at":{"type":["string","null"],"description":"ISO 8601, or null."},"suppressed":{"type":"boolean","description":"Always true."}},"additionalProperties":true,"required":["email","name","status","diagnostic","at","suppressed"]},"description":"5.x.x bounces — suppressed workspace-wide."},"temporaryDelays":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"status":{"type":"string","description":"DSN status code."},"at":{"type":["string","null"],"description":"ISO 8601, or null."},"resolved":{"type":"string","description":"Resolution, or \"pending — provider still retrying\"."},"note":{"type":"string","description":"Explanation that nothing is re-sent meanwhile."}},"additionalProperties":true,"required":["email","name","status","at","resolved","note"]},"description":"4.x.x delays the provider is still retrying — NOT bounces."},"autoReplies":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"from":{"type":"string","description":"Auto-reply sender."},"subject":{"type":"string","description":"Auto-reply subject."},"at":{"type":["string","null"],"description":"ISO 8601, or null."},"cadence":{"type":"string","description":"What happened to the cadence: stop reason, \"ended\" or \"held\"."},"review":{"type":"string","description":"Note for a human, or \"\"."}},"additionalProperties":true,"required":["email","name","from","subject","at","cadence","review"]},"description":"Out-of-office / mailbox-closing auto-replies (never counted as replies)."},"humanReplies":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"from":{"type":"string","description":"Address the reply came from."},"at":{"type":["string","null"],"description":"ISO 8601, or null."},"matchedBy":{"type":"string","description":"How the reply was matched (thread, sender, domain, manual)."},"sentiment":{"type":["string","null"],"description":"AI-classified sentiment, or null."},"cadence":{"type":"string","enum":["stopped"],"description":"Always \"stopped\"."}},"additionalProperties":true,"required":["email","name","from","at","matchedBy","sentiment","cadence"]},"description":"Verified human replies."},"stopped":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"reason":{"type":"string","description":"Stop reason."},"at":{"type":["string","null"],"description":"ISO 8601, or null."},"by":{"type":"string","description":"Who stopped it (\"system\" when unknown)."},"review":{"type":"string","description":"Note for a human, or \"\"."}},"additionalProperties":true,"required":["email","name","reason","at","by","review"]},"description":"Cadences ended by a person/tool without a reply or bounce."},"needsReview":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"bucket":{"type":"string","description":"Current state bucket."},"review":{"type":"string","description":"What to review."}},"additionalProperties":true,"required":["email","name","bucket","review"]},"description":"Recipients flagged for a human decision."},"unsubscribed":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."}},"additionalProperties":true,"required":["email","name"]},"description":"Recipients who opted out."}},"additionalProperties":true,"required":["ok","requestId","sequence","breakdown","definitions","permanentFailures","temporaryDelays","autoReplies","humanReplies","stopped","needsReview","unsubscribed"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/scheduler":{"get":{"operationId":"get_outreach_scheduler","summary":"The sequence engine's activity for this workspace: when it last ran, what each sequence did in that run and why (cap reached, outside sending window, idle until a date, paused mid-run), every connected mailbox's sends today vs its cap (the cap is per MAILBOX and shared by all sequences sending from it — two sequences at 20/day on one mailbox send 20 together, not 40), and whether a run is in progress","description":"The sequence engine's activity for this workspace: when it last ran, what each sequence did in that run and why (cap reached, outside sending window, idle until a date, paused mid-run), every connected mailbox's sends today vs its cap (the cap is per MAILBOX and shared by all sequences sending from it — two sequences at 20/day on one mailbox send 20 together, not 40), and whether a run is in progress. Use it before concluding the scheduler is stuck.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"mailboxes":{"type":"object","additionalProperties":true,"description":"Keyed by mailbox address: { usedToday, warmupCap (null = none), warmupEnabled, noRotate, day }."},"lastRun":{"description":"Record of the engine's last run for this user, or null."},"lastTickAnywhere":{"type":["string","null"],"description":"ISO 8601 time of the last cron tick for any workspace, or null."},"userActive":{"type":"boolean","description":"This user is in the engine's active set."},"userLocked":{"type":"boolean","description":"A run for this user is in progress."},"cadence":{"type":"string","description":"How the engine schedules sends (interval, caps, day boundary)."}},"additionalProperties":true,"required":["ok","requestId","mailboxes","lastRun","lastTickAnywhere","userActive","userLocked","cadence"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences/{id}/pause":{"post":{"operationId":"pause_email_sequence","summary":"Pause a running outreach email sequence","description":"Pause a running outreach email sequence. Safe, instant and idempotent: the engine checks a live status flag before every send, so even a run already in progress stops before its next email; recipients keep their place. Resuming is a separate, confirmed action (start_email_sequence). Never deletes anything.\n\nRequired scope: `campaigns.write`. Risk level: `write`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id from list_email_sequences.","schema":{"type":"string","maxLength":60}},{"name":"reason","in":"query","required":false,"description":"Why (shown on the sequence).","schema":{"type":"string","maxLength":200}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["email_sequence"],"description":"Record type."},"targetId":{"type":"string","description":"Sequence id."},"status":{"type":"string","description":"Status after the call (always \"paused\" on success)."},"was":{"type":"string","description":"Status before the call."},"changed":{"type":"boolean","description":"False when it was already paused."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","status","was","changed"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/sequences/{id}/recipients/stop":{"post":{"operationId":"stop_email_sequence_recipient","summary":"Stop ONE recipient's cadence in an email sequence for good (they answered from another address, asked to be left alone, their mailbox is closing…)","description":"Stop ONE recipient's cadence in an email sequence for good (they answered from another address, asked to be left alone, their mailbox is closing…). Atomic against a run in progress (the engine re-checks a per-recipient stop set before each send) and idempotent. markReplied:true also records a human reply for the funnel — counted once, never twice. Nothing is deleted; the recipient stays visible as \"stopped\".\n\nRequired scope: `campaigns.write`. Risk level: `write`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"email","in":"query","required":true,"description":"Enrolled recipient email.","schema":{"type":"string","maxLength":160}},{"name":"reason","in":"query","required":false,"description":"Short reason, e.g. \"replied from personal address\", \"mailbox retiring\".","schema":{"type":"string","maxLength":120}},{"name":"markReplied","in":"query","required":false,"description":"Also count this as a human reply (only if one was verified).","schema":{"type":"boolean","default":false}},{"name":"repliedAt","in":"query","required":false,"description":"ISO time of the verified reply (default now).","schema":{"type":"string","maxLength":40}},{"name":"replyFrom","in":"query","required":false,"description":"Address the reply came from, if different from the recipient.","schema":{"type":"string","maxLength":160}},{"name":"review","in":"query","required":false,"description":"Note for a human to act on (e.g. replacement address to consider).","schema":{"type":"string","maxLength":300}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["email_sequence"],"description":"Record type."},"targetId":{"type":"string","description":"Sequence id."},"recipient":{"type":"object","properties":{"email":{"type":"string","description":"Recipient email."},"name":{"type":"string","description":"Recipient name."},"stage":{"type":"integer","description":"Steps sent so far."},"done":{"type":"boolean","description":"Always true after a stop."},"replied":{"type":"boolean","description":"Counted as a human reply."},"repliedAt":{"type":"number","description":"Epoch ms of the reply, when replied."},"stopReason":{"type":"string","description":"Why the cadence stopped."},"stoppedAt":{"type":"number","description":"Epoch ms."},"review":{"type":"string","description":"Note for a human, or \"\"."}},"additionalProperties":true,"required":["email","name","done","stopReason","stoppedAt","review"],"description":"The recipient after the stop."},"before":{"type":"object","properties":{"done":{"type":"boolean","description":"Was already done."},"replied":{"type":"boolean","description":"Was already counted as replied."},"stopReason":{"type":"string","description":"Previous stop reason, or \"\"."}},"additionalProperties":true,"required":["done","replied","stopReason"],"description":"State before the call (for idempotency checks)."},"changed":{"type":"boolean","description":"False when the recipient was already stopped (and not newly marked replied)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","recipient","before","changed"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/email/send":{"post":{"operationId":"send_outreach_email","summary":"Send ONE email from a mailbox connected to this workspace (the Gmail/Outlook inboxes under Sequences → Email accounts), e","description":"Send ONE email from a mailbox connected to this workspace (the Gmail/Outlook inboxes under Sequences → Email accounts), e.g. for cold outreach from warmed-up addresses. NOT the campaign engine: use this — not send_email_campaign — whenever the mail should leave a real connected inbox. Content is either subject+body inline, or draftId of an email draft (rendered as a personal email: text only, no campaign wrapper, no unsubscribe footer). PREVIEW FIRST: called without confirm it changes nothing and reports which mailbox will send, its warm-up budget used today, and every connected mailbox's remaining budget. Sends count against the SAME per-mailbox daily warm-up cap the sequence engine uses, and a mailbox at its cap is refused — one recipient per call, so sending N emails is N previewed calls.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"to","in":"query","required":true,"description":"Recipient email address.","schema":{"type":"string","maxLength":160}},{"name":"subject","in":"query","required":false,"description":"Subject line. Required unless draftId is given (then defaults to the draft's subject).","schema":{"type":"string","maxLength":300}},{"name":"body","in":"query","required":false,"description":"Email body — plain text is fine (line breaks preserved); simple HTML accepted. Required unless draftId is given.","schema":{"type":"string","maxLength":20000}},{"name":"draftId","in":"query","required":false,"description":"Alternatively: an email draft id from list_message_drafts; its text content is sent as a personal email.","schema":{"type":"string","maxLength":80}},{"name":"from","in":"query","required":false,"description":"Sending mailbox address from the connected list, or \"__rotate__\" (default) to auto-pick the mailbox with the most warm-up budget left today.","schema":{"type":"string","maxLength":160}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["outreach_email"],"description":"Record type."},"targetId":{"type":"string","description":"Recipient email address."},"summary":{"type":"string","description":"Preview only: what would be sent, from which mailbox, and its budget; starts with BLOCKED when the mailbox has no budget left."},"fromAddress":{"type":"string","description":"Sending mailbox (auto-picked when from was omitted or \"__rotate__\")."},"sentToday":{"type":"integer","description":"Preview only: sends counted against that mailbox today."},"dailyCap":{"type":["number","null"],"description":"Preview only: warm-up cap for today; null = no cap."},"mailboxes":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","description":"Mailbox address."},"sentToday":{"type":"integer","description":"Sends counted against the mailbox today."},"dailyCap":{"type":["number","null"],"description":"Warm-up cap for today; null = no cap."}},"additionalProperties":true,"required":["address","sentToday","dailyCap"]},"description":"Every connected mailbox with its warm-up usage today."},"sent":{"type":"boolean","description":"True once the email was handed to the mailbox provider."},"messageId":{"type":"string","description":"Provider message id, or \"\"."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","fromAddress"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns/sms/send":{"post":{"operationId":"send_sms_campaign","summary":"Send an existing SMS draft to an audience","description":"Send an existing SMS draft to an audience. PREVIEW FIRST: without confirm it reports the recipient count, the total SMS segments it will cost, and who was excluded for opting out. Numbers that replied STOP are always excluded. Create the draft with create_sms_draft first.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"draftId","in":"query","required":true,"description":"SMS draft id from list_message_drafts.","schema":{"type":"string","maxLength":80}},{"name":"leadIds","in":"query","required":false,"description":"Exact leads to send to.","schema":{"type":"array","maxItems":500,"items":{"type":"string"}}},{"name":"status","in":"query","required":false,"description":"Send to every lead currently in this pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"audience","in":"query","required":false,"description":"Set to \"all_leads\" to reach every lead with a usable phone number.","schema":{"type":"string","enum":["all_leads"]}},{"name":"senderProfileId","in":"query","required":false,"description":"Verified sender profile id. Defaults to the draft's, then the first verified profile.","schema":{"type":"string","maxLength":60}},{"name":"sendAt","in":"query","required":false,"description":"ISO 8601 time to send. Defaults to about a minute from now.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["send_sms_campaign"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["sms_draft","sms_campaign"],"description":"sms_draft on preview, sms_campaign once queued."},"targetId":{"type":"string","description":"Draft id on preview; campaign id once queued."},"draft":{"type":"object","properties":{"id":{"type":"string","description":"Draft id."},"name":{"type":"string","description":"Draft name."},"message":{"type":"string","description":"Message body."},"characters":{"type":"integer","description":"Body length in characters."},"segments":{"type":"integer","description":"SMS segments per message (160 chars each)."}},"additionalProperties":true,"required":["id","name","message","characters","segments"],"description":"Preview only: the draft that would be sent."},"sender":{"description":"Preview: { id, name } of the verified sender profile; after send: the sender name string."},"audience":{"type":"object","properties":{"matched":{"type":"integer","description":"Leads matched by leadIds / status / audience."},"missingAddress":{"type":"integer","description":"Matched leads with no address on this channel."},"invalidAddress":{"type":"integer","description":"Addresses that failed format validation and were dropped."},"duplicatesRemoved":{"type":"integer","description":"Duplicate addresses collapsed to one."},"suppressed":{"type":"integer","description":"Removed as unsubscribed, bounced, complained or STOP."},"willReceive":{"type":"integer","description":"Final recipient count."}},"additionalProperties":true,"required":["matched","missingAddress","invalidAddress","duplicatesRemoved","suppressed","willReceive"],"description":"Audience accounting after suppression: how many matched and how many will actually receive."},"sampleRecipients":{"type":"array","items":{"type":"string"},"description":"Preview only: up to 5 recipient phones (E.164)."},"estimatedSegmentsTotal":{"type":"integer","description":"Preview only: segments × recipients (cost basis)."},"sendAt":{"type":"string","description":"Preview only: ISO 8601 send time, or \"immediately\"."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"sent":{"type":"boolean","description":"True once the campaign is queued."},"campaignId":{"type":"string","description":"Queued campaign id."},"scheduledFor":{"type":"string","description":"ISO 8601 time the send is scheduled for."},"recipients":{"type":"integer","description":"Recipients queued."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","sender","audience"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/leads/bulk-update":{"post":{"operationId":"bulk_update_leads","summary":"Change the status and/or owner of many leads at once","description":"Change the status and/or owner of many leads at once. PREVIEW FIRST: without confirm it reports how many records match, how many would actually change, and a sample. Capped per call — a larger reassignment belongs in the app where the selection is visible.\n\nRequired scope: `leads.write`. Risk level: `high`.","tags":["leads"],"security":[{"bearerAuth":["leads.write"]}],"parameters":[{"name":"leadIds","in":"query","required":false,"description":"Exact leads to update.","schema":{"type":"array","maxItems":500,"items":{"type":"string"}}},{"name":"fromStatus","in":"query","required":false,"description":"Alternatively, update every lead currently in this status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"status","in":"query","required":false,"description":"New status to set.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"owner","in":"query","required":false,"description":"New owner email, or \"\" to unassign.","schema":{"type":"string","maxLength":120}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["bulk_update_leads"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["lead"],"description":"Record type."},"matched":{"type":"integer","description":"Leads selected by leadIds / fromStatus."},"willChange":{"type":"integer","description":"Preview only: leads whose status/owner would actually change."},"alreadyCorrect":{"type":"integer","description":"Preview only: leads already in the target state."},"bySource":{"type":"object","additionalProperties":true,"description":"Preview only: matched count per lead source, keyed by source."},"change":{"type":"object","properties":{"status":{"type":"string","description":"New status, when given."},"owner":{"type":"string","description":"New owner email (\"\" = unassign), when given."}},"additionalProperties":true,"description":"Preview only: the patch to apply."},"sample":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Lead id."},"name":{"description":"Lead name."},"email":{"description":"Lead email."},"status":{"description":"Current status."},"owner":{"description":"Current owner."}},"additionalProperties":true,"required":["id","name","email","status","owner"]},"description":"Preview only: up to 5 matched leads."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"updated":{"type":"integer","description":"Leads written."},"unchanged":{"type":"integer","description":"Leads skipped as already correct."},"failed":{"type":"integer","description":"Leads whose write failed."},"errors":{"type":"array","items":{"type":"object","properties":{"leadId":{"type":"string","description":"Lead id."},"error":{"type":"string","description":"Error message."}},"additionalProperties":true,"required":["leadId","error"]},"description":"First 5 failures."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."},"targetId":{"type":"string","description":"Id of the record the action targets."}},"additionalProperties":true,"required":["ok","requestId","targetType","matched"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/contacts/import":{"post":{"operationId":"import_contacts","summary":"Bulk-import or migrate contacts into a Leads list (e","description":"Bulk-import or migrate contacts into a Leads list (e.g. from HubSpot) with upsert semantics: an existing contact — matched by externalId, else by email within the list, else by normalised phone when the record has no email — is UPDATED, never duplicated. Each record needs an email OR a phone. A record may carry several linked tasks (`tasks[]`, or a single `task`), each keyed by its source task id (task.hubspotTaskId / task.externalId) so re-imports update the same task; due date AND time are kept exactly as written (no timezone shift); status COMPLETED marks the task done; priority low/normal/high/urgent (HubSpot LOW/MEDIUM/HIGH accepted); owner is kept even if that user is no longer active. Notes land on the contact timeline. Re-running the same import changes nothing. The result carries one row PER RECORD (externalId, HubSpot ids, lead id, task ids, created/updated/failed + the error) and a read-back verification flag — trust the rows, not the counters. PREVIEW FIRST: without confirm it reports, per record, whether it would create or update and which are invalid, writing nothing.\n\nRequired scope: `leads.write`. Risk level: `high`.","tags":["leads"],"security":[{"bearerAuth":["leads.write"]}],"parameters":[{"name":"listId","in":"query","required":true,"description":"Target Leads list name, e.g. \"FORTVISION Sales CRM\".","schema":{"type":"string","maxLength":120}},{"name":"source","in":"query","required":false,"description":"Migration source label recorded on each contact, e.g. \"HubSpot\".","schema":{"type":"string","maxLength":80}},{"name":"records","in":"query","required":true,"description":"Contact records. Each: { email or phone (one required), name, firstName, lastName, company, website, status, owner, tags, externalId, hubspotContactId, hubspotTaskId, lastContactedAt, dueDate, consent, task:{title,description,status,dueDate,assignedTo,priority,hubspotTaskId,completedAt,createdAt}, tasks:[same shape], notes:[{body,createdAt,author,source}] }. A task-only row for an EXISTING contact: { externalId (the task id), contactExternalId | contactEmail | contactPhone, task:{…} }.","schema":{"type":"array","maxItems":500,"items":{"type":"object"}}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["import_contacts"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["contact"],"description":"Preview only: record type."},"records":{"type":"integer","description":"Preview only: records submitted."},"wouldCreate":{"type":"integer","description":"Preview only: records that would create a contact."},"wouldUpdate":{"type":"integer","description":"Preview only: records that would update an existing contact."},"invalid":{"type":"integer","description":"Preview only: records that cannot be imported."},"sample":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","description":"Normalised email, when present."},"phone":{"type":"string","description":"Phone, when present."},"exists":{"type":"boolean","description":"A matching contact already exists."},"matchedBy":{"type":"string","description":"Match key: externalId, email, phone…"},"task":{"type":"boolean","description":"Record carries at least one task."},"tasks":{"type":"integer","description":"Tasks on the record."},"notes":{"type":"integer","description":"Notes on the record."}},"additionalProperties":true,"required":["exists","task","tasks","notes"]},"description":"Preview only: up to 5 resolved records."},"errors":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the submitted records array."},"externalId":{"type":"string","description":"Record externalId, or \"\"."},"email":{"type":"string","description":"Record email, or \"\"."},"phone":{"type":"string","description":"Record phone (import only)."},"error":{"type":"string","description":"Why it failed."}},"additionalProperties":true,"required":["index","externalId","email","error"]},"description":"Records rejected or failed (first 50 on preview, 100 on import)."},"results":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the submitted records array."},"externalId":{"type":"string","description":"Record externalId, or \"\"."},"email":{"type":"string","description":"Record email, or \"\"."},"phone":{"type":"string","description":"Record phone, or \"\"."},"hubspotContactId":{"type":"string","description":"HubSpot contact id, or \"\"."},"hubspotTaskIds":{"type":"array","items":{"type":"string"},"description":"Task keys derived from the record."},"contactRef":{"type":"string","description":"Contact reference used to attach tasks/notes, when given."},"action":{"type":"string","enum":["create","update","invalid","created","updated","skipped","failed"],"description":"Preview: create/update/invalid. Import: created/updated/skipped/failed."},"leadId":{"type":"string","description":"Matched or written lead id."},"matchedBy":{"type":"string","description":"Match key: externalId, email, phone, phone_conflict…"},"phoneConflict":{"type":"object","additionalProperties":true,"description":"Phone matches a DIFFERENT name: { leadId, name } — created separately, not merged."},"tasks":{"description":"Preview: task count. Import: [{ externalId, id, action, done }]."},"notes":{"type":"integer","description":"Preview only: notes on the record."},"notesAdded":{"type":"integer","description":"Import only: notes written."},"attached":{"type":"boolean","description":"Import only: tasks/notes attached to an existing contact."},"verified":{"type":"boolean","description":"Import only: contact found on read-back."},"error":{"type":"string","description":"Why the record was rejected or failed."}},"additionalProperties":true,"required":["index","externalId","email","phone","hubspotContactId","hubspotTaskIds"]},"description":"One row per submitted record."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"dryRun":{"type":"boolean","description":"Present (true) on the underlying preview payload."},"created":{"type":"integer","description":"Import only: contacts created."},"updated":{"type":"integer","description":"Import only: contacts updated."},"skipped":{"type":"integer","description":"Import only: records skipped (not an object)."},"failed":{"type":"integer","description":"Import only: records that failed."},"tasksCreated":{"type":"integer","description":"Import only: tasks created on the board."},"tasksUpdated":{"type":"integer","description":"Import only: tasks updated on the board."},"adoptedLegacyTasks":{"type":"integer","description":"Import only: orphaned legacy tasks brought onto the board first."},"listId":{"type":"string","description":"Import only: the list written to (\"ml:\" prefixed)."},"runId":{"type":"string","description":"Import only: idempotency run id, when one was given."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."},"targetId":{"type":"string","description":"Id of the record the action targets."}},"additionalProperties":true,"required":["ok","requestId","errors","results"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns/{id}/status":{"post":{"operationId":"update_campaign_status","summary":"Pause or activate an ad campaign on Meta, Google Ads or DV360","description":"Pause or activate an ad campaign on Meta, Google Ads or DV360. PREVIEW FIRST: without confirm it reports the current state, the intended state and recent spend. The change is applied through the platform's own change pipeline, read back from the ad platform to verify, and recorded so it can be rolled back from the AI Assistant's change history.\n\nRequired scope: `campaigns.write`. Risk level: `high`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign id from list_campaigns.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":true,"description":"Target state.","schema":{"type":"string","enum":["ACTIVE","PAUSED"]}},{"name":"platform","in":"query","required":false,"description":"Platform the id belongs to.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"accountId","in":"query","required":false,"description":"Ad account id, so the campaign is found without scanning every account.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["update_campaign_status"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["campaign"],"description":"Record type."},"targetId":{"type":"string","description":"Campaign id."},"campaign":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id (platform prefix stripped)."},"name":{"type":"string","description":"Campaign name."},"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"accountId":{"type":"string","description":"Ad account id (preview only)."},"currency":{"type":"string","description":"Account currency code (budget tool only)."}},"additionalProperties":true,"required":["id","name","platform"],"description":"The campaign being changed."},"from":{"description":"Status before: current status on preview; as recorded by the change pipeline after apply."},"to":{"description":"Status after: the intended status on preview; the read-back status after apply."},"noop":{"type":"boolean","description":"Preview only: the campaign is already in that state."},"spendLast30d":{"type":"number","description":"Preview only: spend over the campaign list's date preset, account currency."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"updated":{"type":"boolean","description":"True once the change was applied."},"verified":{"type":"boolean","description":"Read-back from the ad platform matched the intended status."},"changeId":{"description":"Id of the rollbackable change record."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","campaign","from","to"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaigns/{id}/budget":{"post":{"operationId":"update_campaign_budget","summary":"Change an ad campaign's daily budget, in the ACCOUNT CURRENCY (not cents or micros)","description":"Change an ad campaign's daily budget, in the ACCOUNT CURRENCY (not cents or micros). PREVIEW FIRST: without confirm it reports the current budget, the new one, the percentage change and recent spend, and warns if the change looks like a unit mistake. Applied, verified against the ad platform and rollbackable.\n\nRequired scope: `budgets.write`. Risk level: `high`.","tags":["budgets"],"security":[{"bearerAuth":["budgets.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign id from list_campaigns.","schema":{"type":"string","maxLength":60}},{"name":"dailyBudget","in":"query","required":true,"description":"New daily budget in the account currency, e.g. 250 for ₪250/day.","schema":{"type":"number","minimum":0.01}},{"name":"platform","in":"query","required":false,"description":"Platform the id belongs to.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"accountId","in":"query","required":false,"description":"Ad account id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["update_campaign_budget"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["campaign"],"description":"Record type."},"targetId":{"type":"string","description":"Campaign id."},"campaign":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id (platform prefix stripped)."},"name":{"type":"string","description":"Campaign name."},"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"accountId":{"type":"string","description":"Ad account id (preview only)."},"currency":{"type":"string","description":"Account currency code (budget tool only)."}},"additionalProperties":true,"required":["id","name","platform"],"description":"The campaign being changed."},"from":{"description":"Daily budget before, account currency (null when unknown on preview)."},"to":{"description":"Daily budget after: requested on preview; read back from the platform after apply."},"changePct":{"type":["number","null"],"description":"Preview only: percentage change vs the current budget; null when unknown."},"spendLast30d":{"type":"number","description":"Preview only: spend over the campaign list's date preset, account currency."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"updated":{"type":"boolean","description":"True once the change was applied."},"verified":{"type":"boolean","description":"Read-back from the ad platform matched the new budget."},"changeId":{"description":"Id of the rollbackable change record."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","campaign","from","to"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/tasks/{id}/delete":{"post":{"operationId":"delete_task","summary":"Permanently delete a CRM task","description":"Permanently delete a CRM task. PREVIEW FIRST: without confirm it shows the task that would be destroyed. There is no undo and no trash — prefer complete_task unless the task should never have existed.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Task id from list_tasks.","schema":{"type":"string","maxLength":80}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["delete_task"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["task"],"description":"Record type."},"targetId":{"type":"string","description":"Task id."},"task":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title."},"done":{"type":"boolean","description":"Completed."},"priority":{"type":"string","description":"Normalised priority (\"\" when none)."},"priorityLabel":{"type":"string","description":"Priority as stored."},"owner":{"type":"string","description":"Assignee email."},"dueAt":{"type":"string","description":"Due time, ISO 8601, or \"\"."},"relatedTo":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Entity type, e.g. lead."},"id":{"type":"string","description":"Entity id."}},"additionalProperties":true,"required":["type","id"],"description":"Linked record, or null."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["id","title","done","priority","priorityLabel","owner","dueAt","relatedTo","createdAt","updatedAt"],"description":"The task record."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"deleted":{"type":"boolean","description":"True once the task is gone."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","task"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaign-drafts":{"get":{"operationId":"list_campaign_drafts","summary":"Campaign drafts saved in the Meta, Google Ads and DV360 publish wizards but not yet published: name, type, ad account, and how many ad groups / ad sets / creatives each has","description":"Campaign drafts saved in the Meta, Google Ads and DV360 publish wizards but not yet published: name, type, ad account, and how many ad groups / ad sets / creatives each has. These are what publish_campaign_draft can put live.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"platform","in":"query","required":false,"description":"Restrict to one platform.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"drafts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Draft id."},"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Wizard the draft belongs to."},"name":{"type":"string","description":"Draft name."},"type":{"type":"string","description":"Campaign type."},"adAccountId":{"type":"string","description":"Ad account / customer / advertiser id (\"act_\" stripped)."},"adGroups":{"type":"integer","description":"Ad group count, when known."},"adSets":{"type":"integer","description":"Ad set count, when known."},"creatives":{"type":"integer","description":"Creative count, when known."},"updatedAt":{"type":"string","description":"ISO 8601, or \"\"."}},"additionalProperties":true,"required":["id","platform","name","type","adAccountId","updatedAt"]},"description":"Unpublished wizard drafts, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number."},"pageSize":{"type":"integer","description":"Items per page."},"total":{"type":"integer","description":"Total items across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list."},"notes":{"type":"array","items":{"type":"string"},"description":"Platforms whose draft list could not be read, with the reason."}},"additionalProperties":true,"required":["ok","requestId","drafts","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaign-drafts/{draftId}/publish":{"post":{"operationId":"publish_campaign_draft","summary":"Publish a saved campaign draft to the ad platform, creating a real campaign","description":"Publish a saved campaign draft to the ad platform, creating a real campaign. PREVIEW FIRST: without confirm it summarises the campaign in plain language — name, type, budget, countries, how many ad sets and creatives — and warns about anything missing. Meta campaigns are created PAUSED so they can be reviewed before spending. This tool cannot invent a campaign: build or edit the draft in the publish wizard first, then publish it here.\n\nRequired scope: `campaigns.write`. Risk level: `high`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.write"]}],"parameters":[{"name":"platform","in":"query","required":true,"description":"Which wizard the draft belongs to.","schema":{"type":"string","enum":["meta","google","dv360"]}},{"name":"draftId","in":"path","required":true,"description":"Draft id from list_campaign_drafts.","schema":{"type":"string","maxLength":80}},{"name":"accountId","in":"query","required":false,"description":"Ad account / customer / advertiser id, if the draft does not carry one.","schema":{"type":"string","maxLength":60}},{"name":"pageId","in":"query","required":false,"description":"Meta only: the Facebook Page ads run from, if the draft does not carry one.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["publish_campaign_draft"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["campaign_draft","campaign"],"description":"campaign_draft on preview, campaign once published."},"targetId":{"type":"string","description":"Draft id on preview; new campaign id once published (\"\" if the platform returned none)."},"platform":{"type":"string","enum":["meta","google","dv360"],"description":"Ad platform."},"adAccountId":{"type":"string","description":"Preview only: ad account the campaign will be created in."},"campaign":{"type":"object","properties":{"name":{"type":"string","description":"Campaign name."},"type":{"type":"string","description":"Campaign type / objective."},"dailyBudget":{"type":["number","null"],"description":"Daily budget in account currency, or null."},"lifetimeBudget":{"type":["number","null"],"description":"Lifetime budget in account currency, or null."},"countries":{"type":"array","items":{"type":"string"},"description":"Targeted countries (first 20), when set."},"adGroups":{"type":"integer","description":"Ad group count (Google)."},"adSets":{"type":"integer","description":"Ad set count (Meta)."},"creatives":{"type":"integer","description":"Creative count."},"lineItems":{"type":"integer","description":"Line item count (DV360)."},"adGroupNames":{"type":"array","items":{"type":"string"},"description":"First 5 ad group names (Google only)."},"adSetNames":{"type":"array","items":{"type":"string"},"description":"First 5 ad set names (Meta only)."}},"additionalProperties":true,"required":["name","type","dailyBudget","lifetimeBudget"],"description":"Plain-language summary of the draft's campaign plan."},"warnings":{"description":"Preview: string cautions. After publish: the platform's own warnings (e.g. image warnings), if any."},"published":{"type":"boolean","description":"True once the campaign was created."},"campaignId":{"type":"string","description":"New campaign id on the platform (\"\" if not returned)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","platform","campaign"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/whatsapp/templates":{"get":{"operationId":"list_whatsapp_templates","summary":"WhatsApp message templates on this workspace's Business account, with their approval status, language, category, body text and how many variables each takes — plus the sender numbers available","description":"WhatsApp message templates on this workspace's Business account, with their approval status, language, category, body text and how many variables each takes — plus the sender numbers available. Outside a 24-hour service window Meta only delivers approved templates, so start here before sending.\n\nRequired scope: `conversations.read`. Risk level: `read`.","tags":["conversations"],"security":[{"bearerAuth":["conversations.read"]}],"parameters":[{"name":"approvedOnly","in":"query","required":false,"description":"Only templates Meta has approved. Default true.","schema":{"type":"boolean","default":true}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Template id."},"name":{"type":"string","description":"Template name."},"status":{"type":"string","description":"Meta review status, e.g. APPROVED."},"language":{"type":"string","description":"Language code, e.g. he, en_US."},"category":{"type":"string","description":"MARKETING / UTILITY / AUTHENTICATION."},"variables":{"type":"integer","description":"Number of {{n}} placeholders."},"body":{"type":"string","description":"Template body text."}},"additionalProperties":true,"required":["id","name","status","language","category","variables","body"]},"description":"WhatsApp message templates (approved only unless approvedOnly:false)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number."},"pageSize":{"type":"integer","description":"Items per page."},"total":{"type":"integer","description":"Total items across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list."},"senders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Phone number id."},"phone":{"type":"string","description":"Display phone number."},"name":{"type":"string","description":"Business name."}},"additionalProperties":true,"required":["id","phone","name"]},"description":"Connected WhatsApp Business phone numbers."}},"additionalProperties":true,"required":["ok","requestId","templates","pagination","senders"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/whatsapp/send":{"post":{"operationId":"send_whatsapp_message","summary":"Send an approved WhatsApp template to an audience","description":"Send an approved WhatsApp template to an audience. PREVIEW FIRST: without confirm it shows the template body that will actually arrive, the recipient count, and who was excluded for opting out. Numbers that opted out are always removed. Capped at 500 recipients per call. Unapproved templates are refused — Meta would not deliver them.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"templateName","in":"query","required":true,"description":"Template name or id from list_whatsapp_templates.","schema":{"type":"string","maxLength":120}},{"name":"templateVariables","in":"query","required":false,"description":"Values for the template placeholders, in order.","schema":{"type":"array","maxItems":10,"items":{"type":"string"}}},{"name":"leadIds","in":"query","required":false,"description":"Exact leads to message.","schema":{"type":"array","maxItems":500,"items":{"type":"string"}}},{"name":"status","in":"query","required":false,"description":"Message every lead currently in this pipeline status.","schema":{"type":"string","enum":["New","Contacted","Qualified","Scheduled a Meeting","Proposal","Negotiation","Won","Lost","Unresponsive"]}},{"name":"audience","in":"query","required":false,"description":"Set to \"all_leads\" to reach every lead with a usable phone number.","schema":{"type":"string","enum":["all_leads"]}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["send_whatsapp_message"],"description":"Preview only: the action being previewed."},"targetType":{"type":"string","enum":["whatsapp_template","whatsapp_send"],"description":"whatsapp_template on preview, whatsapp_send once queued."},"targetId":{"type":"string","description":"Template id on preview; send campaign id (or template id) once queued."},"template":{"description":"Preview: { id, name, language, category, body, variables }; after send: the template name string."},"audience":{"type":"object","properties":{"matched":{"type":"integer","description":"Leads matched by leadIds / status / audience."},"missingAddress":{"type":"integer","description":"Matched leads with no address on this channel."},"invalidAddress":{"type":"integer","description":"Addresses that failed format validation and were dropped."},"duplicatesRemoved":{"type":"integer","description":"Duplicate addresses collapsed to one."},"suppressed":{"type":"integer","description":"Removed as unsubscribed, bounced, complained or STOP."},"willReceive":{"type":"integer","description":"Final recipient count."}},"additionalProperties":true,"required":["matched","missingAddress","invalidAddress","duplicatesRemoved","suppressed","willReceive"],"description":"Audience accounting after suppression: how many matched and how many will actually receive."},"sampleRecipients":{"type":"array","items":{"type":"string"},"description":"Preview only: up to 5 recipient phones (E.164)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Plain-language cautions to show before confirming."},"sent":{"type":"boolean","description":"True once the send is queued."},"recipients":{"type":"integer","description":"Recipients queued."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","template","audience"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/events":{"get":{"operationId":"list_webhook_events","summary":"The event types a webhook subscription can listen for, with what each one means","description":"The event types a webhook subscription can listen for, with what each one means. Call this before creating a subscription so you use real event names.\n\nRequired scope: `admin.integrations`. Risk level: `read`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"events":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","enum":["lead.created","lead.updated","lead.status_changed","task.created","task.completed","task.overdue","deal.created","deal.updated","deal.stage_changed","deal.won","campaign.status_changed","campaign.budget_changed","message.sent","customer.updated","conversation.created","conversation.assigned","conversation.closed","csat.received"],"description":"Event type name to pass in create_webhook.events."},"description":{"type":"string","description":"What triggers the event."}},"additionalProperties":true,"required":["name","description"],"description":"One event type."},"description":"Every event type a subscription can listen for."},"signatureHeader":{"type":"string","description":"How the X-Fortvision-Signature header is built (HMAC-SHA256 over `${t}.${rawBody}`)."},"idempotencyHeader":{"type":"string","description":"Note that X-Fortvision-Event-Id is stable across retries."}},"additionalProperties":true,"required":["ok","requestId","events","signatureHeader","idempotencyHeader"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks":{"get":{"operationId":"list_webhooks","summary":"The webhook endpoints registered for this workspace, with their events, whether they are active, their last delivery result and how many consecutive failures they have","description":"The webhook endpoints registered for this workspace, with their events, whether they are active, their last delivery result and how many consecutive failures they have. Secrets are never returned — only a hint of the first and last characters.\n\nRequired scope: `admin.integrations`. Risk level: `read`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"webhooks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Subscription id (wh_…)."},"url":{"type":"string","description":"https endpoint that receives deliveries."},"events":{"type":"array","items":{"type":"string","description":"Event type, e.g. lead.created."},"description":"Subscribed event type names."},"description":{"type":"string","description":"Caller-supplied description, \"\" when none."},"active":{"type":"boolean","description":"False when disabled by the caller or auto-disabled after repeated failures."},"createdAt":{"type":"number","description":"Creation time, Unix epoch milliseconds."},"createdBy":{"type":"string","description":"Email of the user whose token created it (lowercase), \"\" when unknown."},"lastDeliveryAt":{"type":"number","description":"Last delivery attempt, Unix epoch ms; 0 when never delivered."},"lastStatus":{"description":"HTTP status of the last attempt, or an error string on failure; null when never delivered."},"consecutiveFailures":{"type":"integer","description":"Failed attempts in a row; 20 auto-disables the endpoint."},"disabledAt":{"type":"number","description":"Auto-disable time, Unix epoch ms; 0 when not disabled."},"disabledReason":{"type":"string","description":"Why it was auto-disabled, \"\" when not."},"secretRotatedAt":{"type":"number","description":"Last secret rotation, Unix epoch ms; 0 when never rotated."},"secretHint":{"type":"string","description":"First 11 and last 4 characters of the signing secret, never the secret itself."}},"additionalProperties":true,"required":["id","url","events","description","active","createdAt","createdBy","lastDeliveryAt","lastStatus","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","secretHint"],"description":"One subscription, secret stripped."},"description":"Subscriptions in this workspace, newest first, secrets stripped."}},"additionalProperties":true,"required":["ok","requestId","webhooks"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_webhook","summary":"Register an https endpoint to receive signed event deliveries","description":"Register an https endpoint to receive signed event deliveries. The signing secret is returned ONCE — store it, because it is the only thing that proves a delivery came from FORTVISION. Verify each request by recomputing HMAC-SHA256 over `${timestamp}.${rawBody}` using the RAW body, and reject deliveries whose timestamp is more than a few minutes old.\n\nRequired scope: `admin.integrations`. Risk level: `write`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[{"name":"url","in":"query","required":true,"description":"https endpoint to POST to. Must be a public host.","schema":{"type":"string","maxLength":500}},{"name":"events","in":"query","required":true,"description":"Event types to subscribe to — see list_webhook_events.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"description","in":"query","required":false,"description":"What this endpoint is for.","schema":{"type":"string","maxLength":200}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"subscription":{"type":"object","properties":{"id":{"type":"string","description":"Subscription id (wh_…)."},"url":{"type":"string","description":"https endpoint that receives deliveries."},"events":{"type":"array","items":{"type":"string","description":"Event type, e.g. lead.created."},"description":"Subscribed event type names."},"description":{"type":"string","description":"Caller-supplied description, \"\" when none."},"active":{"type":"boolean","description":"False when disabled by the caller or auto-disabled after repeated failures."},"createdAt":{"type":"number","description":"Creation time, Unix epoch milliseconds."},"createdBy":{"type":"string","description":"Email of the user whose token created it (lowercase), \"\" when unknown."},"lastDeliveryAt":{"type":"number","description":"Last delivery attempt, Unix epoch ms; 0 when never delivered."},"lastStatus":{"description":"HTTP status of the last attempt, or an error string on failure; null when never delivered."},"consecutiveFailures":{"type":"integer","description":"Failed attempts in a row; 20 auto-disables the endpoint."},"disabledAt":{"type":"number","description":"Auto-disable time, Unix epoch ms; 0 when not disabled."},"disabledReason":{"type":"string","description":"Why it was auto-disabled, \"\" when not."},"secretRotatedAt":{"type":"number","description":"Last secret rotation, Unix epoch ms; 0 when never rotated."},"secretHint":{"type":"string","description":"First 11 and last 4 characters of the signing secret, never the secret itself."}},"additionalProperties":true,"required":["id","url","events","description","active","createdAt","createdBy","lastDeliveryAt","lastStatus","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","secretHint"],"description":"The subscription without its secret."},"secret":{"type":"string","description":"Signing secret (whsec_…), returned ONCE — store it."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","subscription","secret"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}/update":{"post":{"operationId":"update_webhook","summary":"Change a webhook endpoint's URL, event list or description, or re-enable one that was auto-disabled after repeated failures","description":"Change a webhook endpoint's URL, event list or description, or re-enable one that was auto-disabled after repeated failures.\n\nRequired scope: `admin.integrations`. Risk level: `write`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Subscription id from list_webhooks.","schema":{"type":"string","maxLength":60}},{"name":"url","in":"query","required":false,"description":"New https endpoint.","schema":{"type":"string","maxLength":500}},{"name":"events","in":"query","required":false,"description":"Replacement event list.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"description","in":"query","required":false,"description":"New description.","schema":{"type":"string","maxLength":200}},{"name":"active","in":"query","required":false,"description":"Enable or disable deliveries. Enabling also clears the failure counter.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"subscription":{"type":"object","properties":{"id":{"type":"string","description":"Subscription id (wh_…)."},"url":{"type":"string","description":"https endpoint that receives deliveries."},"events":{"type":"array","items":{"type":"string","description":"Event type, e.g. lead.created."},"description":"Subscribed event type names."},"description":{"type":"string","description":"Caller-supplied description, \"\" when none."},"active":{"type":"boolean","description":"False when disabled by the caller or auto-disabled after repeated failures."},"createdAt":{"type":"number","description":"Creation time, Unix epoch milliseconds."},"createdBy":{"type":"string","description":"Email of the user whose token created it (lowercase), \"\" when unknown."},"lastDeliveryAt":{"type":"number","description":"Last delivery attempt, Unix epoch ms; 0 when never delivered."},"lastStatus":{"description":"HTTP status of the last attempt, or an error string on failure; null when never delivered."},"consecutiveFailures":{"type":"integer","description":"Failed attempts in a row; 20 auto-disables the endpoint."},"disabledAt":{"type":"number","description":"Auto-disable time, Unix epoch ms; 0 when not disabled."},"disabledReason":{"type":"string","description":"Why it was auto-disabled, \"\" when not."},"secretRotatedAt":{"type":"number","description":"Last secret rotation, Unix epoch ms; 0 when never rotated."},"secretHint":{"type":"string","description":"First 11 and last 4 characters of the signing secret, never the secret itself."}},"additionalProperties":true,"required":["id","url","events","description","active","createdAt","createdBy","lastDeliveryAt","lastStatus","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","secretHint"],"description":"The subscription without its secret."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","subscription"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}/rotate":{"post":{"operationId":"rotate_webhook_secret","summary":"Issue a new signing secret for an endpoint","description":"Issue a new signing secret for an endpoint. The old secret keeps signing alongside the new one for 24 hours, so you can deploy the new value without dropping deliveries in between. The new secret is returned once.\n\nRequired scope: `admin.integrations`. Risk level: `write`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Subscription id from list_webhooks.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"subscription":{"type":"object","properties":{"id":{"type":"string","description":"Subscription id (wh_…)."},"url":{"type":"string","description":"https endpoint that receives deliveries."},"events":{"type":"array","items":{"type":"string","description":"Event type, e.g. lead.created."},"description":"Subscribed event type names."},"description":{"type":"string","description":"Caller-supplied description, \"\" when none."},"active":{"type":"boolean","description":"False when disabled by the caller or auto-disabled after repeated failures."},"createdAt":{"type":"number","description":"Creation time, Unix epoch milliseconds."},"createdBy":{"type":"string","description":"Email of the user whose token created it (lowercase), \"\" when unknown."},"lastDeliveryAt":{"type":"number","description":"Last delivery attempt, Unix epoch ms; 0 when never delivered."},"lastStatus":{"description":"HTTP status of the last attempt, or an error string on failure; null when never delivered."},"consecutiveFailures":{"type":"integer","description":"Failed attempts in a row; 20 auto-disables the endpoint."},"disabledAt":{"type":"number","description":"Auto-disable time, Unix epoch ms; 0 when not disabled."},"disabledReason":{"type":"string","description":"Why it was auto-disabled, \"\" when not."},"secretRotatedAt":{"type":"number","description":"Last secret rotation, Unix epoch ms; 0 when never rotated."},"secretHint":{"type":"string","description":"First 11 and last 4 characters of the signing secret, never the secret itself."}},"additionalProperties":true,"required":["id","url","events","description","active","createdAt","createdBy","lastDeliveryAt","lastStatus","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","secretHint"],"description":"The subscription without its secret."},"secret":{"type":"string","description":"New signing secret (whsec_…), returned ONCE."},"note":{"type":"string","description":"States until when (ISO 8601) the previous secret keeps signing (24 h overlap)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","subscription","secret","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}/test":{"post":{"operationId":"test_webhook","summary":"Send a synthetic webhook","description":"Send a synthetic webhook.test delivery to one endpoint right now and report the HTTP status it returned. Use it to prove signature verification works before relying on real events.\n\nRequired scope: `admin.integrations`. Risk level: `write`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Subscription id from list_webhooks.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"delivered":{"type":"boolean","description":"True when the endpoint returned 2xx."},"httpStatus":{"type":"integer","description":"HTTP status returned; 0 on a network error or timeout."},"error":{"type":"string","description":"Network error (\"timeout\" or message), \"\" when an HTTP response arrived."},"durationMs":{"type":"number","description":"Round-trip time in milliseconds."},"hint":{"type":"string","description":"What to check when the endpoint did not accept the delivery."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","delivered","httpStatus","error","durationMs","hint"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/deliveries":{"get":{"operationId":"list_webhook_deliveries","summary":"Recent delivery attempts for this workspace: which event, which endpoint, which attempt number, the HTTP status or error, and how long it took","description":"Recent delivery attempts for this workspace: which event, which endpoint, which attempt number, the HTTP status or error, and how long it took. Use it to debug an endpoint that is not receiving.\n\nRequired scope: `admin.integrations`. Risk level: `read`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many attempts to return.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"deliveries":{"type":"array","items":{"type":"object","properties":{"ts":{"type":"number","description":"Attempt time, Unix epoch milliseconds."},"deliveryId":{"type":"string","description":"Delivery id (whd_…); test deliveries are whd_test_…."},"subscriptionId":{"type":"string","description":"Subscription the attempt went to."},"eventId":{"type":"string","description":"Event id, stable across retries."},"eventType":{"type":"string","description":"Event type name (webhook.test for test deliveries)."},"attempt":{"type":"integer","description":"1-based attempt number."},"ok":{"type":"boolean","description":"True when the endpoint returned 2xx."},"status":{"type":"integer","description":"HTTP status; 0 on a network error or timeout."},"error":{"type":"string","description":"Network error (\"timeout\" or message), \"\" when an HTTP response arrived."},"durationMs":{"type":"number","description":"Round-trip time in milliseconds."}},"additionalProperties":true,"required":["ts","deliveryId","subscriptionId","eventId","eventType","attempt","ok","status","error","durationMs"],"description":"One delivery attempt."},"description":"Most recent delivery attempts first (log capped at 200)."}},"additionalProperties":true,"required":["ok","requestId","deliveries"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}/delete":{"post":{"operationId":"delete_webhook","summary":"Permanently remove a webhook endpoint","description":"Permanently remove a webhook endpoint. PREVIEW FIRST: without confirm it shows which endpoint and events would stop. Any integration relying on those deliveries stops receiving them immediately.\n\nRequired scope: `admin.integrations`. Risk level: `high`.","tags":["admin"],"security":[{"bearerAuth":["admin.integrations"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Subscription id from list_webhooks.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["delete_webhook"],"description":"Preview only: always \"delete_webhook\"."},"targetType":{"type":"string","enum":["webhook"],"description":"Preview only: always \"webhook\"."},"targetId":{"type":"string","description":"Preview only: id of the subscription that would be removed."},"webhook":{"type":"object","properties":{"id":{"type":"string","description":"Subscription id (wh_…)."},"url":{"type":"string","description":"https endpoint that receives deliveries."},"events":{"type":"array","items":{"type":"string","description":"Event type, e.g. lead.created."},"description":"Subscribed event type names."},"description":{"type":"string","description":"Caller-supplied description, \"\" when none."},"active":{"type":"boolean","description":"False when disabled by the caller or auto-disabled after repeated failures."},"createdAt":{"type":"number","description":"Creation time, Unix epoch milliseconds."},"createdBy":{"type":"string","description":"Email of the user whose token created it (lowercase), \"\" when unknown."},"lastDeliveryAt":{"type":"number","description":"Last delivery attempt, Unix epoch ms; 0 when never delivered."},"lastStatus":{"description":"HTTP status of the last attempt, or an error string on failure; null when never delivered."},"consecutiveFailures":{"type":"integer","description":"Failed attempts in a row; 20 auto-disables the endpoint."},"disabledAt":{"type":"number","description":"Auto-disable time, Unix epoch ms; 0 when not disabled."},"disabledReason":{"type":"string","description":"Why it was auto-disabled, \"\" when not."},"secretRotatedAt":{"type":"number","description":"Last secret rotation, Unix epoch ms; 0 when never rotated."},"secretHint":{"type":"string","description":"First 11 and last 4 characters of the signing secret, never the secret itself."}},"additionalProperties":true,"required":["id","url","events","description","active","createdAt","createdBy","lastDeliveryAt","lastStatus","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","secretHint"],"description":"Preview only: the subscription that would be removed, secret stripped."},"warnings":{"type":"array","items":{"type":"string","description":"Warning text."},"description":"Preview only: what stops when it is deleted."},"deleted":{"type":"boolean","description":"Confirmed run only: always true."},"id":{"type":"string","description":"Confirmed run only: id of the removed subscription."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/senders":{"get":{"operationId":"list_linkedin_senders","summary":"The LinkedIn accounts (senders) connected to this workspace: status (available / cooling-down / disconnected), daily action limits and how much of each was used today","description":"The LinkedIn accounts (senders) connected to this workspace: status (available / cooling-down / disconnected), daily action limits and how much of each was used today. Call this before creating a sequence — senderIds come from here. Senders are connected in the app only; this API never handles LinkedIn credentials.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"live":{"type":"boolean","description":"True when the LinkedIn provider is configured (real accounts, not demo)."},"senders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sender id (use in senderIds)."},"name":{"type":"string","description":"Display name (real LinkedIn name when resolved)."},"headline":{"type":"string","description":"LinkedIn headline."},"status":{"type":"string","description":"available | disconnected | checkpoint | restricted …"},"paused":{"type":"boolean","description":"Manually paused in the app."},"coolingUntil":{"type":"string","description":"ISO 8601 end of a rate-limit cooldown, only while cooling."},"dailyLimits":{"type":"object","properties":{"follows":{"type":"integer","description":"Max follows per day."},"messages":{"type":"integer","description":"Max messages per day."},"inmails":{"type":"integer","description":"Max InMails per day."},"invites":{"type":"integer","description":"Max connection invites per day."},"views":{"type":"integer","description":"Max profile views per day."},"likes":{"type":"integer","description":"Max post likes per day."}},"additionalProperties":true,"description":"Per-day action caps, only when configured."},"sentToday":{"type":"object","additionalProperties":true,"description":"Today's usage, metric → count (invites, messages, views, likes, inmails …)."}},"additionalProperties":true,"required":["id","name","headline","status","paused","sentToday"],"description":"One connected LinkedIn account."},"description":"Connected senders; [] for restricted users."}},"additionalProperties":true,"required":["ok","requestId","live","senders"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/lists":{"get":{"operationId":"list_linkedin_lists","summary":"Prospect lists for LinkedIn outreach: how each was built (search / post engagers / URLs / CSV), its import status and prospect count","description":"Prospect lists for LinkedIn outreach: how each was built (search / post engagers / URLs / CSV), its import status and prospect count. A sequence targets one of these lists.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Substring of the list name.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"List id."},"name":{"type":"string","description":"List name."},"source":{"type":"string","description":"How it was built: search | post | urls | csv."},"status":{"type":"string","description":"Import state: importing | ready."},"count":{"type":"integer","description":"Prospects in the list (grows while importing)."},"createdAt":{"type":"string","description":"ISO 8601 creation time."}},"additionalProperties":true,"required":["id","name","source","status","count","createdAt"],"description":"Prospect list."},"description":"Prospect lists, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."}},"additionalProperties":true,"required":["ok","requestId","lists","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_linkedin_list","summary":"Create a prospect list from a LinkedIn SEARCH (people search / event attendees / Sales Navigator URL) or from a POST's engagers (everyone who reacted to or commented on it — preview first with preview_linkedin_post_engagers)","description":"Create a prospect list from a LinkedIn SEARCH (people search / event attendees / Sales Navigator URL) or from a POST's engagers (everyone who reacted to or commented on it — preview first with preview_linkedin_post_engagers). The import runs in the background over minutes; poll get_linkedin_list until status \"ready\". Creating a list sends nothing.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"name","in":"query","required":false,"description":"List name (required for searchUrl; defaults for postUrl).","schema":{"type":"string","maxLength":140}},{"name":"searchUrl","in":"query","required":false,"description":"A linkedin.com search URL to import from. Pass this OR postUrl.","schema":{"type":"string","maxLength":1500}},{"name":"postUrl","in":"query","required":false,"description":"A LinkedIn post URL whose engagers to import. Pass this OR searchUrl.","schema":{"type":"string","maxLength":500}},{"name":"includeReactions","in":"query","required":false,"description":"postUrl only: import people who reacted. Default true.","schema":{"type":"boolean"}},{"name":"includeComments","in":"query","required":false,"description":"postUrl only: import people who commented. Default true.","schema":{"type":"boolean"}},{"name":"senderId","in":"query","required":false,"description":"Sender whose LinkedIn session performs the import. Defaults to the first available sender.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true."},"list":{"type":"object","properties":{"id":{"type":"string","description":"List id."},"name":{"type":"string","description":"List name."},"source":{"type":"string","description":"How it was built: search | post | urls | csv."},"status":{"type":"string","description":"Import state: importing | ready."},"count":{"type":"integer","description":"Prospects in the list (grows while importing)."},"createdAt":{"type":"string","description":"ISO 8601 creation time."}},"additionalProperties":true,"required":["id","name","source","status","count","createdAt"],"description":"The new list; status \"importing\", count 0 until the background import fills it."},"note":{"type":"string","description":"Polling hint."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","list","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/lists/{listId}":{"get":{"operationId":"get_linkedin_list","summary":"One prospect list with its prospects (name, title, company, profile URL)","description":"One prospect list with its prospects (name, title, company, profile URL). While an import is running the list's status is \"importing\" and the count grows — poll until \"ready\".\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"List id from list_linkedin_lists.","schema":{"type":"string","maxLength":60}},{"name":"query","in":"query","required":false,"description":"Filter prospects by name, company or email.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"list":{"type":"object","properties":{"id":{"type":"string","description":"List id."},"name":{"type":"string","description":"List name."},"source":{"type":"string","description":"How it was built: search | post | urls | csv."},"status":{"type":"string","description":"Import state: importing | ready."},"count":{"type":"integer","description":"Prospects in the list (grows while importing)."},"createdAt":{"type":"string","description":"ISO 8601 creation time."}},"additionalProperties":true,"required":["id","name","source","status","count","createdAt"],"description":"Prospect list."},"leads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Prospect id (leadId for set_linkedin_lead_state)."},"fullName":{"type":"string","description":"Full name."},"jobTitle":{"type":"string","description":"Job title."},"headline":{"type":"string","description":"LinkedIn headline."},"company":{"type":"string","description":"Company."},"location":{"type":"string","description":"Location."},"email":{"type":"string","description":"Email when known, else \"\"."},"linkedinUrl":{"type":"string","description":"Profile URL."}},"additionalProperties":true,"required":["id","fullName","jobTitle","headline","company","location","email","linkedinUrl"],"description":"One prospect."},"description":"Prospects on this page, sorted by name."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."}},"additionalProperties":true,"required":["ok","requestId","list","leads","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences":{"get":{"operationId":"list_linkedin_sequences","summary":"LinkedIn outreach sequences (campaigns): status (draft/running/paused/finished), target list, senders, step count, enrollment counts and headline stats (invites, accepted, messages, replies)","description":"LinkedIn outreach sequences (campaigns): status (draft/running/paused/finished), target list, senders, step count, enrollment counts and headline stats (invites, accepted, messages, replies).\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Only sequences in this state.","schema":{"type":"string","enum":["draft","running","paused","finished"]}},{"name":"query","in":"query","required":false,"description":"Substring of the sequence name.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"sequences":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"listId":{"type":["string","null"],"description":"Target prospect list id, null when none attached."},"senderIds":{"type":"array","items":{"type":"string","description":"Sender id."},"description":"Sender account ids the sequence rotates across."},"stepCount":{"type":"integer","description":"Total steps including nested branch steps."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Lifetime counters for this sequence (metric → count); {} when none yet."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Sending window."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"launchedAt":{"type":"string","description":"ISO 8601 first-launch time; \"\" when never launched."}},"additionalProperties":true,"required":["id","name","status","listId","senderIds","stepCount","counts","stats","schedule","createdAt","launchedAt"],"description":"Sequence summary."},"description":"Sequences, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."}},"additionalProperties":true,"required":["ok","requestId","sequences","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_linkedin_sequence","summary":"Create a LinkedIn outreach sequence as a DRAFT — nothing sends until launch_linkedin_sequence is confirmed, so creating is reversible","description":"Create a LinkedIn outreach sequence as a DRAFT — nothing sends until launch_linkedin_sequence is confirmed, so creating is reversible. steps: ordered actions, each {type, delayDays, delayHours, message, messageB (A/B variant), subject (inmail/email), withdrawAfterDays (connect)}. Types: view_profile, like_post, endorse, connect, message, inmail, send_email, call_task (opens a call-the-lead task on the Tasks board; taskTitle, taskNote, taskDueDays), and branch nodes if_connected/{connected,notConnected}, if_replied/{replied,notReplied}, if_open/{open,notOpen}, if_opened/{opened,notOpened} and if_clicked/{clicked,notClicked} (the e-mail of the preceding send_email step; waitDays = how long to keep checking) whose branch keys hold sub-step arrays. Personalization tokens like {firstName} {company} work in messages. Attach a prospect list (listId from list_linkedin_lists) and senders (senderIds from list_linkedin_senders) here or later with update_linkedin_sequence.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Sequence name.","schema":{"type":"string","maxLength":140}},{"name":"steps","in":"query","required":true,"description":"Ordered steps — see the tool description for the shape.","schema":{"type":"array","maxItems":40,"items":{"type":"object"}}},{"name":"listId","in":"query","required":false,"description":"Prospect list to target (from list_linkedin_lists).","schema":{"type":"string","maxLength":60}},{"name":"excludeListId","in":"query","required":false,"description":"List whose members are excluded.","schema":{"type":"string","maxLength":60}},{"name":"senderIds","in":"query","required":false,"description":"Sender account ids to rotate across.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"scheduleDays","in":"query","required":false,"description":"Sending days, 0=Sunday … 6=Saturday. Default Mon-Fri.","schema":{"type":"array","maxItems":7,"items":{"type":"string"}}},{"name":"scheduleFrom","in":"query","required":false,"description":"Daily window start, HH:MM (default 09:00).","schema":{"type":"string","maxLength":5}},{"name":"scheduleTo","in":"query","required":false,"description":"Daily window end, HH:MM (default 19:00).","schema":{"type":"string","maxLength":5}},{"name":"tzOffset","in":"query","required":false,"description":"Timezone offset in hours for the window, e.g. 3 for Israel summer.","schema":{"type":"integer","minimum":-12,"maximum":14}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true."},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"listId":{"type":["string","null"],"description":"Target prospect list id, null when none attached."},"senderIds":{"type":"array","items":{"type":"string","description":"Sender id."},"description":"Sender account ids the sequence rotates across."},"stepCount":{"type":"integer","description":"Total steps including nested branch steps."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Lifetime counters for this sequence (metric → count); {} when none yet."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Sending window."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"launchedAt":{"type":"string","description":"ISO 8601 first-launch time; \"\" when never launched."},"steps":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["view_profile","like_post","comment_post","endorse","connect","if_connected","if_open","if_replied","message","voice_note","inmail","send_email","if_opened","if_clicked","call_task","if_booked","send_whatsapp","send_sms","withdraw_invite","find_email","if_interested","if_visited","if_has_email","if_has_phone","if_active","wait","split","end","add_to_list","add_tag","create_contact","notify","webhook","never_contact"],"description":"Step / branch-node type."},"delayDays":{"type":"integer","description":"Days to wait before this step."},"delayHours":{"type":"integer","description":"Extra hours to wait before this step."},"message":{"type":"string","description":"Message / invite note text (≤2000 chars), only when set."},"messageB":{"type":"string","description":"A/B variant B text, only when set."},"subject":{"type":"string","description":"InMail / email subject, only when set."},"fallback":{"type":"string","description":"Fallback text, only when set."},"withdrawAfterDays":{"type":"number","description":"connect: withdraw the invite after N days, only when > 0."},"connected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notConnected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"replied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notReplied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"open":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpen":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"opened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"clicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notClicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"booked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notBooked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"interested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notInterested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"visited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notVisited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"active":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"inactive":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"a":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"b":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."}},"additionalProperties":true,"required":["type","delayDays","delayHours"],"description":"One sequence step."},"description":"Ordered steps with message text and branch sub-flows."},"excludeListId":{"type":"string","description":"Exclusion list id, only when set."}},"additionalProperties":true,"required":["id","name","status","listId","senderIds","stepCount","counts","stats","schedule","createdAt","launchedAt","steps"],"description":"Sequence with its steps."},"stepsDropped":{"type":"integer","description":"Steps trimmed by the server (depth/count limits); 0 = all kept."},"note":{"type":"string","description":"Draft reminder and what is still missing before launch."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","sequence","stepsDropped","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}":{"get":{"operationId":"get_linkedin_sequence","summary":"One sequence in full: every step with its message text (including A/B variant B and branch sub-flows), schedule window, live per-prospect breakdown (pending / in progress / replied / failed), per-sender stats, A/B variant results and a 30-day daily series","description":"One sequence in full: every step with its message text (including A/B variant B and branch sub-flows), schedule window, live per-prospect breakdown (pending / in progress / replied / failed), per-sender stats, A/B variant results and a 30-day daily series.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id from list_linkedin_sequences.","schema":{"type":"string","maxLength":60}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"listId":{"type":["string","null"],"description":"Target prospect list id, null when none attached."},"senderIds":{"type":"array","items":{"type":"string","description":"Sender id."},"description":"Sender account ids the sequence rotates across."},"stepCount":{"type":"integer","description":"Total steps including nested branch steps."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Lifetime counters for this sequence (metric → count); {} when none yet."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Sending window."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"launchedAt":{"type":"string","description":"ISO 8601 first-launch time; \"\" when never launched."},"steps":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["view_profile","like_post","comment_post","endorse","connect","if_connected","if_open","if_replied","message","voice_note","inmail","send_email","if_opened","if_clicked","call_task","if_booked","send_whatsapp","send_sms","withdraw_invite","find_email","if_interested","if_visited","if_has_email","if_has_phone","if_active","wait","split","end","add_to_list","add_tag","create_contact","notify","webhook","never_contact"],"description":"Step / branch-node type."},"delayDays":{"type":"integer","description":"Days to wait before this step."},"delayHours":{"type":"integer","description":"Extra hours to wait before this step."},"message":{"type":"string","description":"Message / invite note text (≤2000 chars), only when set."},"messageB":{"type":"string","description":"A/B variant B text, only when set."},"subject":{"type":"string","description":"InMail / email subject, only when set."},"fallback":{"type":"string","description":"Fallback text, only when set."},"withdrawAfterDays":{"type":"number","description":"connect: withdraw the invite after N days, only when > 0."},"connected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notConnected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"replied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notReplied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"open":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpen":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"opened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"clicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notClicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"booked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notBooked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"interested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notInterested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"visited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notVisited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"active":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"inactive":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"a":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"b":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."}},"additionalProperties":true,"required":["type","delayDays","delayHours"],"description":"One sequence step."},"description":"Ordered steps with message text and branch sub-flows."},"excludeListId":{"type":"string","description":"Exclusion list id, only when set."},"breakdown":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects with a progress record."},"pending":{"type":"integer","description":"Active, not started."},"inprogress":{"type":"integer","description":"Active, mid-cadence."},"finished":{"type":"integer","description":"Done (replied / finished / not accepted / not connected)."},"failed":{"type":"integer","description":"Failed."},"excluded":{"type":"integer","description":"Excluded at launch."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Has replied at any point."},"accepted":{"type":"integer","description":"Accepted the connection invite."}},"additionalProperties":true,"description":"Live per-prospect breakdown computed from progress records."},"abVariants":{"type":"object","additionalProperties":true,"description":"A/B results: stepId → { A: {sent, won}, B: {sent, won} }; won = accepted (connect) or replied."},"daily":{"type":"object","additionalProperties":true,"description":"Newest 30 days: \"YYYY-MM-DD\" → { metric → count }."},"senderStats":{"type":"object","additionalProperties":true,"description":"senderId → { metric → count } for this sequence."}},"additionalProperties":true,"required":["id","name","status","listId","senderIds","stepCount","counts","stats","schedule","createdAt","launchedAt","steps","breakdown","abVariants","daily","senderStats"],"description":"Sequence with steps, live breakdown and analytics."}},"additionalProperties":true,"required":["ok","requestId","sequence"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/post-engagers":{"get":{"operationId":"preview_linkedin_post_engagers","summary":"Who engaged with a LinkedIn post (reactions and comments) — counts and a sample of names, WITHOUT creating anything","description":"Who engaged with a LinkedIn post (reactions and comments) — counts and a sample of names, WITHOUT creating anything. Use before create_linkedin_list with postUrl to see who you would import.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"postUrl","in":"query","required":true,"description":"LinkedIn post URL (feed/update/… or /posts/…-activity-…).","schema":{"type":"string","maxLength":500}},{"name":"senderId","in":"query","required":false,"description":"Sender whose LinkedIn session reads the post. Defaults to the first available sender.","schema":{"type":"string","maxLength":60}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"postId":{"type":"string","description":"Resolved post URN, e.g. urn:li:activity:7…"},"engagers":{"type":"object","properties":{"reactions":{"type":"object","properties":{"count":{"type":"integer","description":"Engagers on the first page (≤25)."},"more":{"type":"boolean","description":"True when more pages exist."},"sample":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Full name."},"headline":{"type":"string","description":"Headline (≤80 chars)."}},"additionalProperties":true,"description":"Engager."},"description":"Up to 6 names."},"error":{"type":"string","description":"Provider error, only on failure."}},"additionalProperties":true,"description":"People who reacted (or {error} if the lookup failed)."},"comments":{"type":"object","properties":{"count":{"type":"integer","description":"Engagers on the first page (≤25)."},"more":{"type":"boolean","description":"True when more pages exist."},"sample":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Full name."},"headline":{"type":"string","description":"Headline (≤80 chars)."}},"additionalProperties":true,"description":"Engager."},"description":"Up to 6 names."},"error":{"type":"string","description":"Provider error, only on failure."}},"additionalProperties":true,"description":"People who commented (or {error} if the lookup failed)."}},"additionalProperties":true,"required":["reactions","comments"],"description":"Per engagement kind: count of the first page, whether more exist, a sample of names."}},"additionalProperties":true,"required":["ok","requestId","postId","engagers"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/inbox":{"get":{"operationId":"list_linkedin_inbox","summary":"The unified LinkedIn inbox across every connected sender: conversation threads with the counterpart's name/company, last-message time, unread state, tags and assignee","description":"The unified LinkedIn inbox across every connected sender: conversation threads with the counterpart's name/company, last-message time, unread state, tags and assignee. Reading the LIST marks nothing read.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"unreadOnly","in":"query","required":false,"description":"Only unread threads.","schema":{"type":"boolean","default":false}},{"name":"query","in":"query","required":false,"description":"Filter by counterpart name, company or snippet.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"threads":{"type":"array","items":{"type":"object","properties":{"chatId":{"type":"string","description":"Thread id (pass to get_linkedin_conversation / send_linkedin_message)."},"senderId":{"type":"string","description":"Connected sender the thread belongs to."},"senderName":{"type":"string","description":"That sender's display name."},"name":{"type":"string","description":"Counterpart name."},"headline":{"type":"string","description":"Counterpart headline."},"company":{"type":"string","description":"Counterpart company."},"providerId":{"type":"string","description":"Counterpart provider id (for profile resolution), only when known."},"lastAt":{"type":"string","description":"ISO 8601 time of the last message; \"\" if unknown."},"snippet":{"type":"string","description":"Last message text (≤240 chars), only when available."},"unread":{"type":"boolean","description":"Thread has unread messages."},"favorite":{"type":"boolean","description":"Starred locally."},"tags":{"type":"array","items":{"type":"string","description":"Tag."},"description":"Local tags."},"assignee":{"type":"string","description":"Assigned team member, only when set."}},"additionalProperties":true,"required":["chatId","senderId","senderName","name","headline","company","lastAt","unread","favorite","tags"],"description":"One inbox conversation."},"description":"Conversations, newest first (≤200 across all senders)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."},"live":{"type":"boolean","description":"True when the LinkedIn provider is configured."}},"additionalProperties":true,"required":["ok","requestId","threads","pagination","live"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/inbox/messages":{"get":{"operationId":"get_linkedin_conversation","summary":"The messages of one LinkedIn conversation (newest 100), plus the counterpart's profile when resolvable","description":"The messages of one LinkedIn conversation (newest 100), plus the counterpart's profile when resolvable. NOTE: opening a conversation marks it READ on LinkedIn itself, exactly as in the app.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"senderId","in":"query","required":true,"description":"The sender the thread belongs to (from list_linkedin_inbox).","schema":{"type":"string","maxLength":60}},{"name":"chatId","in":"query","required":true,"description":"Thread id from list_linkedin_inbox.","schema":{"type":"string","maxLength":120}},{"name":"providerId","in":"query","required":false,"description":"Counterpart provider id from the thread, to resolve their profile.","schema":{"type":"string","maxLength":120}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"messages":{"type":"array","items":{"type":"object","properties":{"fromMe":{"type":"boolean","description":"Sent by the sender (us)."},"text":{"type":"string","description":"Message text (≤4000 chars)."},"at":{"type":"string","description":"ISO 8601 time; \"\" if unknown."}},"additionalProperties":true,"required":["fromMe","text","at"],"description":"One message."},"description":"Newest 100 messages, oldest first."},"profile":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Full name."},"headline":{"type":"string","description":"Headline."},"company":{"type":"string","description":"Company."},"linkedinUrl":{"type":"string","description":"Profile URL."}},"additionalProperties":true,"required":["name","headline","company","linkedinUrl"],"description":"Counterpart profile when providerId was given and resolvable, else null."},"markedRead":{"type":"boolean","description":"Always true — opening marks the thread read on LinkedIn."}},"additionalProperties":true,"required":["ok","requestId","messages","profile","markedRead"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/overview":{"get":{"operationId":"get_linkedin_overview","summary":"The LinkedIn dashboard in one call: total invites / accepted / messages / replies, a 30-day daily series, every sequence's headline numbers and per-sender totals","description":"The LinkedIn dashboard in one call: total invites / accepted / messages / replies, a 30-day daily series, every sequence's headline numbers and per-sender totals.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"totals":{"type":"object","properties":{"views":{"type":"integer","description":"Profile views."},"likes":{"type":"integer","description":"Post likes."},"invites":{"type":"integer","description":"Connection invites sent."},"accepted":{"type":"integer","description":"Invites accepted."},"messages":{"type":"integer","description":"Messages sent."},"inmails":{"type":"integer","description":"InMails sent."},"replies":{"type":"integer","description":"Message replies received."},"inmail_replies":{"type":"integer","description":"InMail replies received."}},"additionalProperties":true,"description":"Lifetime totals across all sequences (metric → count)."},"daily":{"type":"object","additionalProperties":true,"description":"Newest 30 days merged across sequences: \"YYYY-MM-DD\" → { metric → count }."},"sequences":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Metric name → count (views, likes, invites, accepted, messages, inmails, replies, inmail_replies …)."},"launchedAt":{"type":"string","description":"ISO 8601 launch time; \"\" when never launched."}},"additionalProperties":true,"required":["id","name","status","counts","stats","launchedAt"],"description":"Sequence headline numbers."},"description":"Up to 30 sequences, most recently launched first."},"senderTotals":{"type":"object","additionalProperties":true,"description":"senderId → { metric → count } across all sequences."}},"additionalProperties":true,"required":["ok","requestId","totals","daily","sequences","senderTotals"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/send-health":{"get":{"operationId":"get_linkedin_send_health","summary":"Detects stalled outreach: running sequences whose every sender is cooling down or disconnected (with how many actions are due), and which senders are free","description":"Detects stalled outreach: running sequences whose every sender is cooling down or disconnected (with how many actions are due), and which senders are free. If canFix is true, fix_linkedin_send_health adds the free senders to the blocked sequences.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"blocked":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"active":{"type":"integer","description":"Active prospects waiting."},"due":{"type":"integer","description":"Prospects whose next action is already due."},"reason":{"type":"string","enum":["disconnected","paused","cooling"],"description":"Why nothing sends."},"senders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sender id."},"name":{"type":"string","description":"Sender name."},"status":{"type":"string","description":"available | disconnected | checkpoint | restricted …"},"paused":{"type":"boolean","description":"Manually paused."},"coolingUntil":{"type":["string","null"],"description":"ISO 8601 cooldown end, null when not cooling."},"reason":{"type":"string","description":"Throttle / restriction reason text, \"\" if none."}},"additionalProperties":true,"required":["id","name","status","paused","coolingUntil","reason"],"description":"Sender state."},"description":"The sequence's senders and their state."}},"additionalProperties":true,"required":["id","name","active","due","reason","senders"],"description":"A stalled sequence."},"description":"Running sequences with active prospects and no usable sender."},"freeSenders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sender id."},"name":{"type":"string","description":"Sender name."}},"additionalProperties":true,"required":["id","name"],"description":"Sender."},"description":"Senders usable right now (available, not paused, not cooling)."},"totalDue":{"type":"integer","description":"Sum of due prospects across blocked sequences."},"canFix":{"type":"boolean","description":"True when something is blocked AND a free sender exists."}},"additionalProperties":true,"required":["ok","requestId","blocked","freeSenders","totalDue","canFix"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/agents":{"get":{"operationId":"list_linkedin_agents","summary":"LinkedIn Source Agents: each watches intent signals (people engaging with keyword posts, competitor / creator / own-profile posts, event attendees, a recurring Sales Navigator search), scores every person against the agent's ICP with AI and feeds the matches into its list — into the Copilot review queue (reviewMode) or straight into the running campaign on that list","description":"LinkedIn Source Agents: each watches intent signals (people engaging with keyword posts, competitor / creator / own-profile posts, event attendees, a recurring Sales Navigator search), scores every person against the agent's ICP with AI and feeds the matches into its list — into the Copilot review queue (reviewMode) or straight into the running campaign on that list. Returns ICP, signals with per-signal results, counters and how many leads wait in Copilot.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Substring of the agent name.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"queueCount":{"type":"integer","description":"Leads waiting in the Copilot queue across all agents."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Agent id."},"name":{"type":"string","description":"Agent name."},"paused":{"type":"boolean","description":"True = the scheduler skips it."},"reviewMode":{"type":"boolean","description":"True = new leads wait in Copilot; false = autopilot into the running campaign."},"senderId":{"type":"string","description":"LinkedIn sender it scans with."},"listId":{"type":"string","description":"The list it fills."},"campaignId":{"type":"string","description":"Campaign created with the agent, if any."},"icp":{"type":"object","properties":{"titles":{"type":"array","items":{"type":"string","description":"Title."},"description":"Target titles."},"industries":{"type":"array","items":{"type":"string","description":"Industry."},"description":"Target industries."},"sizes":{"type":"array","items":{"type":"string","description":"Employee bracket."},"description":"Company sizes."},"locations":{"type":"array","items":{"type":"string","description":"Location."},"description":"Locations."},"mode":{"type":"string","description":"precision | broad | skip."},"minScore":{"type":"number","description":"Fit threshold 0–1."}},"additionalProperties":true,"description":"Ideal customer profile summary."},"signals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Signal id."},"type":{"type":"string","description":"keyword | keyword_post | competitor | influencer | own_profile | own_company | event | search."},"value":{"type":"string","description":"Keyword / URL."},"enabled":{"type":"boolean","description":"Runs when true."},"runs":{"type":"integer","description":"Runs so far."},"imported":{"type":"integer","description":"People that passed the ICP."},"approved":{"type":"integer","description":"Approved in Copilot."},"rejected":{"type":"integer","description":"Rejected in Copilot."},"lastError":{"type":"string","description":"Last run error, or empty."}},"additionalProperties":true,"required":["id","type","value","enabled","runs","imported","approved","rejected","lastError"],"description":"One signal."},"description":"Configured signals with results."},"counters":{"type":"object","properties":{"found":{"type":"integer","description":"New people found."},"scored":{"type":"integer","description":"People scored by AI."},"imported":{"type":"integer","description":"Passed the ICP."},"queued":{"type":"integer","description":"Sent to Copilot."},"approved":{"type":"integer","description":"Approved."},"rejected":{"type":"integer","description":"Rejected."}},"additionalProperties":true,"required":["found","scored","imported","queued","approved","rejected"],"description":"Lifetime counters."},"queueCount":{"type":"integer","description":"Waiting in Copilot for this agent."},"lastRunAt":{"type":"string","description":"ISO time of the last run, or empty."},"createdAt":{"type":"string","description":"ISO creation time."}},"additionalProperties":true,"required":["id","name","paused","reviewMode","senderId","listId","icp","signals","counters","queueCount","lastRunAt","createdAt"],"description":"One Source Agent."},"description":"Agents (paged)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."}},"additionalProperties":true,"required":["ok","requestId","queueCount","items","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/copilot":{"get":{"operationId":"list_linkedin_copilot_queue","summary":"The Copilot review queue: people the Source Agents found, with fit / intent scores (1–3 flames), the analyst reason and the exact activity that surfaced them, waiting for approve / reject","description":"The Copilot review queue: people the Source Agents found, with fit / intent scores (1–3 flames), the analyst reason and the exact activity that surfaced them, waiting for approve / reject. Highest score first. Use decide_linkedin_copilot_lead to act on one.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"agentId","in":"query","required":false,"description":"Only this agent's leads.","schema":{"type":"string","maxLength":60}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"agents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Agent id."},"name":{"type":"string","description":"Name."},"queueCount":{"type":"integer","description":"Waiting leads."}},"additionalProperties":true,"required":["id","name","queueCount"],"description":"Agent."},"description":"Agents with their queue sizes."},"items":{"type":"array","items":{"type":"object","properties":{"listId":{"type":"string","description":"List id (needed to decide)."},"leadId":{"type":"string","description":"Lead id (needed to decide)."},"fullName":{"type":"string","description":"Name."},"headline":{"type":"string","description":"LinkedIn headline."},"jobTitle":{"type":"string","description":"Title (may be inferred)."},"company":{"type":"string","description":"Company (may be inferred)."},"location":{"type":"string","description":"Location."},"linkedinUrl":{"type":"string","description":"Profile URL."},"score":{"type":"object","properties":{"fit":{"type":"number","description":"ICP fit 0–1."},"intent":{"type":"integer","description":"Intent 0–3."},"total":{"type":"number","description":"Combined 0–3."},"flames":{"type":"integer","description":"1–3 flames."},"reason":{"type":"string","description":"One-sentence analyst reason."},"intentType":{"type":"string","description":"Intent slug."}},"additionalProperties":true,"required":["fit","intent","total","flames","reason","intentType"],"description":"AI scoring."},"signal":{"type":"object","properties":{"type":{"type":"string","description":"Signal type."},"value":{"type":"string","description":"Keyword / URL."},"engagement":{"type":"string","description":"The activity that surfaced them."}},"additionalProperties":true,"required":["type","value","engagement"],"description":"What surfaced them."},"agentId":{"type":"string","description":"Agent that found them."},"queuedAt":{"type":"string","description":"ISO time queued."}},"additionalProperties":true,"required":["listId","leadId","fullName","headline","jobTitle","company","location","linkedinUrl","score","signal","agentId","queuedAt"],"description":"One queued lead."},"description":"Queued leads, highest score first (paged)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."}},"additionalProperties":true,"required":["ok","requestId","agents","items","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/copilot/{listId}/{leadId}":{"post":{"operationId":"decide_linkedin_copilot_lead","summary":"Approve or reject ONE lead in the Copilot queue","description":"Approve or reject ONE lead in the Copilot queue. Approve → the person enters the running campaign on the agent's list (if one is running; otherwise they wait as approved). Reject → never shown again; the reason tunes the agent's ICP over time.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"listId from list_linkedin_copilot_queue.","schema":{"type":"string","maxLength":60}},{"name":"leadId","in":"path","required":true,"description":"leadId from list_linkedin_copilot_queue.","schema":{"type":"string","maxLength":80}},{"name":"decision","in":"query","required":true,"description":"approve or reject.","schema":{"type":"string","enum":["approve","reject"]}},{"name":"reason","in":"query","required":false,"description":"Reject reason code.","schema":{"type":"string","enum":["company_competitor","company_wrong_industry_or_type","company_wrong_size","company_wrong_location","contact_wrong_title_or_function","contact_wrong_seniority","contact_known_or_duplicate","data_incorrect_or_outdated","signal_not_relevant","other"]}},{"name":"reasonText","in":"query","required":false,"description":"Free text when reason is other.","schema":{"type":"string","maxLength":500}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true."},"requestId":{"type":"string"},"decision":{"type":"string","description":"approve | reject."},"enrolled":{"type":"integer","description":"Running campaigns the lead was enrolled into (approve only)."},"remaining":{"type":"integer","description":"Leads still waiting in the queue."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","ok","decision","enrolled","remaining"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/agents/{id}/run":{"post":{"operationId":"run_linkedin_agent","summary":"Run ONE signal of a Source Agent now (the scheduler runs one every 3 hours anyway): scans LinkedIn through the agent's sender, scores the people found and adds the matches to the list / Copilot queue","description":"Run ONE signal of a Source Agent now (the scheduler runs one every 3 hours anyway): scans LinkedIn through the agent's sender, scores the people found and adds the matches to the list / Copilot queue. Takes up to ~45 s; counts against the sender's daily scan budget. Nothing is sent to anyone.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Agent id from list_linkedin_agents.","schema":{"type":"string","maxLength":60}},{"name":"signalId","in":"query","required":false,"description":"A specific signal id; default = the next one round-robin.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"False when the run hit an error (see error)."},"requestId":{"type":"string"},"signal":{"type":"object","properties":{"id":{"type":"string","description":"Signal id."},"type":{"type":"string","description":"Type."},"value":{"type":"string","description":"Value."}},"additionalProperties":true,"required":["id","type","value"],"description":"The signal that ran."},"found":{"type":"integer","description":"Raw people found."},"newPeople":{"type":"integer","description":"After dedupe against seen / contacted / blacklist / list."},"scored":{"type":"integer","description":"Scored by AI."},"imported":{"type":"integer","description":"Passed the ICP and were added."},"queued":{"type":"integer","description":"Of those, sent to Copilot."},"enrolled":{"type":"integer","description":"Of those, enrolled into a running campaign (autopilot)."},"error":{"type":"string","description":"Error text, or empty."},"note":{"type":"string","description":"Budget / deadline note, or empty."},"sample":{"type":"array","items":{"type":"object","properties":{"leadId":{"type":"string","description":"Lead id."},"name":{"type":"string","description":"Name."},"flames":{"type":"integer","description":"1–3."},"reason":{"type":"string","description":"Reason."}},"additionalProperties":true,"required":["leadId","name","flames","reason"],"description":"Lead."},"description":"Up to 6 of the added people."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","ok","signal","found","newPeople","scored","imported","queued","enrolled","error","note","sample"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/today":{"get":{"operationId":"get_outreach_today","summary":"The Outreach \"Today\" screen: call tasks due today or overdue (with the CRM contact they are linked to), replies waiting for an answer across LinkedIn and e-mail (with whether an AI draft is ready), and the hottest leads waiting in the Copilot queue","description":"The Outreach \"Today\" screen: call tasks due today or overdue (with the CRM contact they are linked to), replies waiting for an answer across LinkedIn and e-mail (with whether an AI draft is ready), and the hottest leads waiting in the Copilot queue. Read-only; use it to brief the user on what to act on now.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"date":{"type":"string","description":"Today (YYYY-MM-DD, server time)."},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Task title."},"dueDate":{"type":"string","description":"YYYY-MM-DD."},"overdue":{"type":"boolean","description":"Due before today."},"priority":{"type":"string","description":"low | medium | high."},"contactId":{"type":"string","description":"Leads-board contact id the task is linked to; \"\" when none."},"contactName":{"type":"string","description":"Who it is about."},"isCall":{"type":"boolean","description":"Looks like a call task."}},"additionalProperties":true,"required":["id","title","dueDate","overdue","priority","contactId","contactName","isCall"],"description":"One task."},"description":"Open tasks due today or earlier, soonest first (≤50)."},"replies":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","description":"linkedin | email."},"chatId":{"type":"string","description":"Conversation id (list_linkedin_inbox / list_email_threads)."},"senderId":{"type":"string","description":"LinkedIn sender id; \"\" for e-mail."},"name":{"type":"string","description":"Counterpart."},"company":{"type":"string","description":"Company, when known."},"lastMessage":{"type":"string","description":"Last message snippet."},"lastAt":{"type":"string","description":"ISO time; \"\" if unknown."},"sentiment":{"type":"string","description":"AI class for e-mail replies (interested / not_interested / other); \"\" otherwise."},"hasDraft":{"type":"boolean","description":"An AI reply draft is ready."},"leadId":{"type":"string","description":"Outreach lead id; \"\" for pure LinkedIn chats."}},"additionalProperties":true,"required":["channel","chatId","senderId","name","company","lastMessage","lastAt","sentiment","hasDraft","leadId"],"description":"One waiting reply."},"description":"Conversations with an unanswered incoming message (≤50)."},"hot":{"type":"array","items":{"type":"object","properties":{"listId":{"type":"string","description":"List id."},"leadId":{"type":"string","description":"Lead id."},"name":{"type":"string","description":"Full name."},"title":{"type":"string","description":"Job title."},"company":{"type":"string","description":"Company."},"reason":{"type":"string","description":"Why the AI flagged them."},"linkedinUrl":{"type":"string","description":"Profile URL; \"\" if none."}},"additionalProperties":true,"required":["listId","leadId","name","title","company","reason","linkedinUrl"],"description":"One hot lead."},"description":"Copilot queue entries with three flames (≤30)."}},"additionalProperties":true,"required":["ok","requestId","date","calls","replies","hot"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/email-threads":{"get":{"operationId":"list_email_threads","summary":"E-mail conversations started by an Outreach campaign's e-mail step that got a reply: the lead, campaign, subject, the AI sentiment (interested / not_interested / other), a one-line summary, the reply snippet and the AI-drafted answer when one is ready","description":"E-mail conversations started by an Outreach campaign's e-mail step that got a reply: the lead, campaign, subject, the AI sentiment (interested / not_interested / other), a one-line summary, the reply snippet and the AI-drafted answer when one is ready. Read-only; the draft is sent with the app (Outreach → Inbox / Today) or by the user.\n\nRequired scope: `linkedin.read`. Risk level: `read`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.read"]}],"parameters":[{"name":"unreadOnly","in":"query","required":false,"description":"Only threads not yet answered / read.","schema":{"type":"boolean","default":false}},{"name":"withDraftOnly","in":"query","required":false,"description":"Only threads that have an AI-drafted reply waiting.","schema":{"type":"boolean","default":false}},{"name":"query","in":"query","required":false,"description":"Filter by name, company, e-mail, subject or snippet.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"threads":{"type":"array","items":{"type":"object","properties":{"leadId":{"type":"string","description":"Outreach lead id."},"chatId":{"type":"string","description":"Conversation id (\"em:<leadId>\")."},"name":{"type":"string","description":"Counterpart."},"email":{"type":"string","description":"Their address."},"company":{"type":"string","description":"Company."},"campaignId":{"type":"string","description":"Campaign id."},"campaign":{"type":"string","description":"Campaign name."},"subject":{"type":"string","description":"Thread subject."},"sentiment":{"type":"string","description":"interested | not_interested | other | \"\"."},"summary":{"type":"string","description":"One-line AI summary of the reply."},"snippet":{"type":"string","description":"Reply snippet (≤240 chars)."},"hasDraft":{"type":"boolean","description":"An AI reply draft is ready."},"draft":{"type":"string","description":"The draft text; \"\" when none."},"unread":{"type":"boolean","description":"Not yet answered / read."},"lastAt":{"type":"string","description":"ISO time of the last message."},"linkedinChatId":{"type":"string","description":"The same person's LinkedIn chat id when one exists; \"\"."}},"additionalProperties":true,"required":["leadId","chatId","name","email","company","campaignId","campaign","subject","sentiment","summary","snippet","hasDraft","draft","unread","lastAt","linkedinChatId"],"description":"One e-mail conversation."},"description":"E-mail conversations, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (capped server-side)."},"total":{"type":"integer","description":"Total rows after filtering, across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page info from lib/mcp/schema.js paginate()."}},"additionalProperties":true,"required":["ok","requestId","threads","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/outreach/call-tasks":{"post":{"operationId":"create_call_task","summary":"Open a \"call this lead\" task on the Tasks board for an Outreach lead","description":"Open a \"call this lead\" task on the Tasks board for an Outreach lead. The lead becomes (or is matched to) a Leads-board CRM contact first, so the task is linked to the contact and a call placed through the app's dialer is logged on it. Returns the task and the contact id. Reversible (the task can be completed or deleted).\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"listId","in":"query","required":true,"description":"The Outreach list the lead is on.","schema":{"type":"string","maxLength":60}},{"name":"leadId","in":"query","required":true,"description":"The lead id (from get_linkedin_list / list_linkedin_copilot_queue).","schema":{"type":"string","maxLength":80}},{"name":"title","in":"query","required":false,"description":"Task title; default \"Call <name>\".","schema":{"type":"string","maxLength":140}},{"name":"note","in":"query","required":false,"description":"What to say / context for the caller.","schema":{"type":"string","maxLength":1000}},{"name":"dueDays","in":"query","required":false,"description":"Due in N days (0 = today).","schema":{"type":"integer","default":0}},{"name":"priority","in":"query","required":false,"description":"low | medium | high.","schema":{"type":"string","enum":["low","medium","high"],"default":"medium"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true on success."},"task":{"type":"object","properties":{"id":{"type":"string","description":"Task id."},"title":{"type":"string","description":"Title."},"dueDate":{"type":"string","description":"YYYY-MM-DD."},"contactId":{"type":"string","description":"Leads-board contact the task is linked to."},"contactName":{"type":"string","description":"Contact name."},"phone":{"type":"string","description":"Phone on the lead; \"\" when none."}},"additionalProperties":true,"required":["id","title","dueDate","contactId","contactName","phone"],"description":"The task."},"targetType":{"type":"string","description":"\"task\"."},"targetId":{"type":"string","description":"Task id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","task","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/update":{"post":{"operationId":"update_linkedin_sequence","summary":"Edit a sequence: name, steps, target list, senders or schedule","description":"Edit a sequence: name, steps, target list, senders or schedule. Only the fields you pass change; the run status is kept. Editing the steps of a RUNNING sequence affects prospects that have not reached those steps yet.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"name","in":"query","required":false,"description":"New name.","schema":{"type":"string","maxLength":140}},{"name":"steps","in":"query","required":false,"description":"FULL replacement step array (same shape as create_linkedin_sequence).","schema":{"type":"array","maxItems":40,"items":{"type":"object"}}},{"name":"listId","in":"query","required":false,"description":"New target list id.","schema":{"type":"string","maxLength":60}},{"name":"excludeListId","in":"query","required":false,"description":"New exclusion list id, or \"\" to clear.","schema":{"type":"string","maxLength":60}},{"name":"senderIds","in":"query","required":false,"description":"FULL replacement sender id list.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"scheduleDays","in":"query","required":false,"description":"Sending days, 0=Sunday … 6=Saturday.","schema":{"type":"array","maxItems":7,"items":{"type":"string"}}},{"name":"scheduleFrom","in":"query","required":false,"description":"Daily window start HH:MM.","schema":{"type":"string","maxLength":5}},{"name":"scheduleTo","in":"query","required":false,"description":"Daily window end HH:MM.","schema":{"type":"string","maxLength":5}},{"name":"tzOffset","in":"query","required":false,"description":"Timezone offset in hours.","schema":{"type":"integer","minimum":-12,"maximum":14}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"updated":{"type":"boolean","description":"Always true."},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"listId":{"type":["string","null"],"description":"Target prospect list id, null when none attached."},"senderIds":{"type":"array","items":{"type":"string","description":"Sender id."},"description":"Sender account ids the sequence rotates across."},"stepCount":{"type":"integer","description":"Total steps including nested branch steps."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Lifetime counters for this sequence (metric → count); {} when none yet."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Sending window."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"launchedAt":{"type":"string","description":"ISO 8601 first-launch time; \"\" when never launched."},"steps":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["view_profile","like_post","comment_post","endorse","connect","if_connected","if_open","if_replied","message","voice_note","inmail","send_email","if_opened","if_clicked","call_task","if_booked","send_whatsapp","send_sms","withdraw_invite","find_email","if_interested","if_visited","if_has_email","if_has_phone","if_active","wait","split","end","add_to_list","add_tag","create_contact","notify","webhook","never_contact"],"description":"Step / branch-node type."},"delayDays":{"type":"integer","description":"Days to wait before this step."},"delayHours":{"type":"integer","description":"Extra hours to wait before this step."},"message":{"type":"string","description":"Message / invite note text (≤2000 chars), only when set."},"messageB":{"type":"string","description":"A/B variant B text, only when set."},"subject":{"type":"string","description":"InMail / email subject, only when set."},"fallback":{"type":"string","description":"Fallback text, only when set."},"withdrawAfterDays":{"type":"number","description":"connect: withdraw the invite after N days, only when > 0."},"connected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notConnected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"replied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notReplied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"open":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpen":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"opened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"clicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notClicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"booked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notBooked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"interested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notInterested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"visited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notVisited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"active":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"inactive":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"a":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"b":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."}},"additionalProperties":true,"required":["type","delayDays","delayHours"],"description":"One sequence step."},"description":"Ordered steps with message text and branch sub-flows."},"excludeListId":{"type":"string","description":"Exclusion list id, only when set."}},"additionalProperties":true,"required":["id","name","status","listId","senderIds","stepCount","counts","stats","schedule","createdAt","launchedAt","steps"],"description":"Sequence with its steps."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","updated","sequence"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/pause":{"post":{"operationId":"pause_linkedin_sequence","summary":"Pause a running sequence — the cron stops processing its prospects until it is resumed","description":"Pause a running sequence — the cron stops processing its prospects until it is resumed. Safe and instant; resume_linkedin_sequence continues from where it stopped.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"paused":{"type":"boolean","description":"Always true."},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"listId":{"type":["string","null"],"description":"Target prospect list id, null when none attached."},"senderIds":{"type":"array","items":{"type":"string","description":"Sender id."},"description":"Sender account ids the sequence rotates across."},"stepCount":{"type":"integer","description":"Total steps including nested branch steps."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Lifetime counters for this sequence (metric → count); {} when none yet."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Sending window."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"launchedAt":{"type":"string","description":"ISO 8601 first-launch time; \"\" when never launched."}},"additionalProperties":true,"required":["id","name","status","listId","senderIds","stepCount","counts","stats","schedule","createdAt","launchedAt"],"description":"Sequence summary."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","paused","sequence"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/duplicate":{"post":{"operationId":"duplicate_linkedin_sequence","summary":"Copy a sequence into a new DRAFT (same steps, list and senders, no progress)","description":"Copy a sequence into a new DRAFT (same steps, list and senders, no progress). Useful for A/B testing a variation without touching the original.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id to copy.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true."},"sequence":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Run state."},"listId":{"type":["string","null"],"description":"Target prospect list id, null when none attached."},"senderIds":{"type":"array","items":{"type":"string","description":"Sender id."},"description":"Sender account ids the sequence rotates across."},"stepCount":{"type":"integer","description":"Total steps including nested branch steps."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Enrollment breakdown cached on the sequence; {} for a never-launched draft."},"stats":{"type":"object","additionalProperties":true,"description":"Lifetime counters for this sequence (metric → count); {} when none yet."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Sending window."},"createdAt":{"type":"string","description":"ISO 8601 creation time."},"launchedAt":{"type":"string","description":"ISO 8601 first-launch time; \"\" when never launched."},"steps":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["view_profile","like_post","comment_post","endorse","connect","if_connected","if_open","if_replied","message","voice_note","inmail","send_email","if_opened","if_clicked","call_task","if_booked","send_whatsapp","send_sms","withdraw_invite","find_email","if_interested","if_visited","if_has_email","if_has_phone","if_active","wait","split","end","add_to_list","add_tag","create_contact","notify","webhook","never_contact"],"description":"Step / branch-node type."},"delayDays":{"type":"integer","description":"Days to wait before this step."},"delayHours":{"type":"integer","description":"Extra hours to wait before this step."},"message":{"type":"string","description":"Message / invite note text (≤2000 chars), only when set."},"messageB":{"type":"string","description":"A/B variant B text, only when set."},"subject":{"type":"string","description":"InMail / email subject, only when set."},"fallback":{"type":"string","description":"Fallback text, only when set."},"withdrawAfterDays":{"type":"number","description":"connect: withdraw the invite after N days, only when > 0."},"connected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notConnected":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"replied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notReplied":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"open":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpen":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"opened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notOpened":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"clicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notClicked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"booked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notBooked":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"interested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notInterested":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"visited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"notVisited":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noEmail":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"hasPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"noPhone":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"active":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"inactive":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"a":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."},"b":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"A step: {type, delayDays, delayHours, message?, …}."},"description":"Nested sub-steps (same shape as a step), only when non-empty."}},"additionalProperties":true,"required":["type","delayDays","delayHours"],"description":"One sequence step."},"description":"Ordered steps with message text and branch sub-flows."},"excludeListId":{"type":"string","description":"Exclusion list id, only when set."}},"additionalProperties":true,"required":["id","name","status","listId","senderIds","stepCount","counts","stats","schedule","createdAt","launchedAt","steps"],"description":"The new DRAFT copy (name suffixed \" (copy)\")."},"note":{"type":"string","description":"Reminder that the copy is a draft on the same list/senders."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","sequence","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/lead":{"post":{"operationId":"set_linkedin_lead_state","summary":"Manage ONE prospect inside a sequence: pause them, resume them, or stop their cadence for good (op \"stop\" is how you exclude someone who asked to be left alone)","description":"Manage ONE prospect inside a sequence: pause them, resume them, or stop their cadence for good (op \"stop\" is how you exclude someone who asked to be left alone).\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"leadId","in":"query","required":true,"description":"Prospect id from get_linkedin_list.","schema":{"type":"string","maxLength":60}},{"name":"op","in":"query","required":true,"description":"What to do.","schema":{"type":"string","enum":["pause","resume","stop"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true."},"requestId":{"type":"string"},"progress":{"type":"object","properties":{"status":{"type":"string","description":"active (resumed) | paused | finished (stopped)."}},"additionalProperties":true,"required":["status"],"description":"The prospect's new cadence state."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","ok","progress"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/send-health/fix":{"post":{"operationId":"fix_linkedin_send_health","summary":"One-click fix for a stalled queue: adds every currently-usable sender to the running sequences whose own senders are all cooling down, so the cron's rebalance has somewhere to move waiting prospects","description":"One-click fix for a stalled queue: adds every currently-usable sender to the running sequences whose own senders are all cooling down, so the cron's rebalance has somewhere to move waiting prospects. Run get_linkedin_send_health first; only acts on sequences it reported as blocked.\n\nRequired scope: `linkedin.write`. Risk level: `write`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"sequenceIds","in":"query","required":false,"description":"Limit the fix to these sequences. Default: every blocked one.","schema":{"type":"array","maxItems":50,"items":{"type":"string"}}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"fixed":{"type":"boolean","description":"True when at least one sequence was changed."},"changed":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Sequence id."},"name":{"type":"string","description":"Sequence name."},"added":{"type":"integer","description":"Senders added."},"addedNames":{"type":"array","items":{"type":"string","description":"Sender name."},"description":"Names of the added senders."}},"additionalProperties":true,"required":["id","name","added","addedNames"],"description":"One changed sequence."},"description":"Sequences that received extra senders."},"sendersAdded":{"type":"array","items":{"type":"string","description":"Sender name."},"description":"Names of every free sender considered."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","fixed","changed","sendersAdded"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/launch":{"post":{"operationId":"launch_linkedin_sequence","summary":"Launch a sequence: enrolls the target list's prospects and real LinkedIn outreach begins within minutes (staggered, inside the schedule window, under per-sender daily caps)","description":"Launch a sequence: enrolls the target list's prospects and real LinkedIn outreach begins within minutes (staggered, inside the schedule window, under per-sender daily caps). PREVIEW FIRST: called without confirm it changes nothing and reports how many prospects would enroll, the senders, the steps and any blockers (no list / no sender / empty list). People who already replied are never re-enrolled. Relaunching an already-run sequence re-enrolls unfinished prospects from step 0.\n\nRequired scope: `linkedin.send`. Risk level: `high`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.send"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["linkedin_sequence"],"description":"Preview only."},"targetId":{"type":"string","description":"Preview only: sequence id."},"sequence":{"description":"Preview: the sequence NAME (string). Run: the launched sequence summary object (status \"running\")."},"currentStatus":{"type":"string","description":"Preview only: status before launching."},"prospects":{"type":"integer","description":"Preview only: prospects on the target list (0 if none/empty)."},"senders":{"type":"integer","description":"Preview only: number of attached senders."},"steps":{"type":"integer","description":"Preview only: total steps."},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","description":"Weekday 0-6."},"description":"Sending days, 0=Sunday … 6=Saturday."},"from":{"type":"string","description":"Daily window start, HH:MM."},"to":{"type":"string","description":"Daily window end, HH:MM."},"tzOffset":{"type":"number","description":"Timezone offset in hours for the window."}},"additionalProperties":true,"description":"Preview only: sending window."},"alreadyRepliedKept":{"type":"integer","description":"Preview only: prospects who already replied and will not be re-enrolled."},"problems":{"type":"array","items":{"type":"string","description":"Blocker."},"description":"Preview only: blockers; empty = ready."},"summary":{"type":"string","description":"Preview only: human summary."},"launched":{"type":"boolean","description":"Run only: always true."},"enrolled":{"type":"integer","description":"Run only: prospects enrolled."},"excluded":{"type":"integer","description":"Run only: prospects skipped by exclusions / blacklist."},"keptReplied":{"type":"integer","description":"Run only: prospects left untouched because they had replied."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","sequence"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/resume":{"post":{"operationId":"resume_linkedin_sequence","summary":"Resume a paused sequence — the cron continues each unfinished prospect from exactly where they stopped (no re-enrollment, no restart from step 0; that is what launch does)","description":"Resume a paused sequence — the cron continues each unfinished prospect from exactly where they stopped (no re-enrollment, no restart from step 0; that is what launch does). PREVIEW FIRST: without confirm it reports how many prospects are pending / mid-cadence.\n\nRequired scope: `linkedin.send`. Risk level: `high`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.send"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["linkedin_sequence"],"description":"Preview only."},"targetId":{"type":"string","description":"Preview only: sequence id."},"sequence":{"description":"Preview: the sequence NAME (string). Run: the sequence summary object (status \"running\")."},"currentStatus":{"type":"string","description":"Preview only: status before resuming."},"pending":{"type":"integer","description":"Preview only: prospects not started yet."},"inProgress":{"type":"integer","description":"Preview only: prospects mid-cadence."},"summary":{"type":"string","description":"Preview only: human summary."},"resumed":{"type":"boolean","description":"Run only: always true."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","sequence"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/inbox/send":{"post":{"operationId":"send_linkedin_message","summary":"Reply in an existing LinkedIn conversation as one of the connected senders","description":"Reply in an existing LinkedIn conversation as one of the connected senders. PREVIEW FIRST: without confirm it changes nothing and echoes exactly which sender says what in which thread. A sent LinkedIn message cannot be unsent.\n\nRequired scope: `linkedin.send`. Risk level: `high`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.send"]}],"parameters":[{"name":"senderId","in":"query","required":true,"description":"Sender the thread belongs to.","schema":{"type":"string","maxLength":60}},{"name":"chatId","in":"query","required":true,"description":"Thread id from list_linkedin_inbox.","schema":{"type":"string","maxLength":120}},{"name":"text","in":"query","required":true,"description":"The message text.","schema":{"type":"string","maxLength":8000}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["linkedin_chat"],"description":"Preview only."},"targetId":{"type":"string","description":"Preview only: the chat id."},"from":{"type":"string","description":"Preview only: sender display name."},"chatId":{"type":"string","description":"Thread id the message goes to / went to."},"text":{"type":"string","description":"Preview only: the exact text that will be sent."},"summary":{"type":"string","description":"Preview only: human summary."},"sent":{"type":"boolean","description":"Run only: always true."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","chatId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/lists/import-urls":{"post":{"operationId":"import_linkedin_leads","summary":"Add specific LinkedIn profiles (by URL, max 40) to a prospect list — a new one or an existing one","description":"Add specific LinkedIn profiles (by URL, max 40) to a prospect list — a new one or an existing one. HIGH IMPACT because adding to a list a RUNNING sequence targets enrolls the new prospects immediately and outreach to them starts within minutes. PREVIEW FIRST: without confirm it reports the target list, how many URLs are valid, and exactly which running sequences would start contacting them.\n\nRequired scope: `linkedin.write`. Risk level: `high`.","tags":["linkedin"],"security":[{"bearerAuth":["linkedin.write"]}],"parameters":[{"name":"urls","in":"query","required":true,"description":"linkedin.com/in/… profile URLs.","schema":{"type":"array","maxItems":40,"items":{"type":"string"}}},{"name":"listId","in":"query","required":false,"description":"Existing list to add to. Omit to create a new list.","schema":{"type":"string","maxLength":60}},{"name":"name","in":"query","required":false,"description":"Name for the new list when listId is omitted.","schema":{"type":"string","maxLength":140}},{"name":"senderId","in":"query","required":false,"description":"Sender whose session resolves the profiles. Defaults to the first available.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["linkedin_list"],"description":"Preview only."},"targetId":{"type":"string","description":"Preview only: existing list id or \"(new list)\"."},"profiles":{"type":"integer","description":"Preview only: valid linkedin.com/in/ URLs (max 40)."},"invalidDropped":{"type":"integer","description":"Preview only: URLs ignored as invalid."},"list":{"description":"Preview: target list NAME (string). Run: the list object after import (id, name, source, status, count, createdAt)."},"resolvingSender":{"type":"string","description":"Preview only: sender id whose session resolves the profiles."},"enrollsIntoRunning":{"type":"array","items":{"type":"string","description":"Sequence name."},"description":"Preview only: names of RUNNING sequences on this list that would enroll the new prospects."},"summary":{"type":"string","description":"Preview only: human summary."},"imported":{"type":"boolean","description":"Run only: always true."},"requested":{"type":"integer","description":"Run only: URLs submitted."},"resolved":{"type":"integer","description":"Run only: URLs resolved to a profile."},"added":{"type":"integer","description":"Run only: new prospects added (after dedupe)."},"enrolledIntoRunning":{"type":"integer","description":"Run only: prospects enrolled into running sequences (outreach starts now)."},"startedSequences":{"type":"array","items":{"type":"string","description":"Sequence name."},"description":"Run only: names of the running sequences that enrolled them."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","list"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/sequences/{id}/delete":{"post":{"operationId":"delete_linkedin_sequence","summary":"Delete a sequence and all its per-prospect progress and stats","description":"Delete a sequence and all its per-prospect progress and stats. IRREVERSIBLE — pause_linkedin_sequence is almost always the better choice. The prospect list is kept. PREVIEW FIRST.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Sequence id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["linkedin_sequence"],"description":"Preview only."},"targetId":{"type":"string","description":"Preview only: sequence id."},"sequence":{"type":"string","description":"Preview only: sequence name."},"status":{"type":"string","enum":["draft","running","paused","finished"],"description":"Preview only: current run state."},"counts":{"type":"object","properties":{"total":{"type":"integer","description":"Prospects enrolled at launch."},"pending":{"type":"integer","description":"Enrolled, first action not started yet."},"inprogress":{"type":"integer","description":"Mid-cadence."},"finished":{"type":"integer","description":"Completed the cadence (incl. not accepted / not connected)."},"failed":{"type":"integer","description":"Failed permanently."},"excluded":{"type":"integer","description":"Skipped at launch (exclusion list / blacklist / already contacted)."},"paused":{"type":"integer","description":"Paused individually."},"replied":{"type":"integer","description":"Replied (never re-enrolled)."}},"additionalProperties":true,"description":"Preview only: enrollment breakdown that will be lost."},"summary":{"type":"string","description":"Preview only: human summary."},"deleted":{"type":"boolean","description":"Run only: always true."},"id":{"type":"string","description":"Run only: deleted sequence id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/linkedin/lists/{listId}/delete":{"post":{"operationId":"delete_linkedin_list","summary":"Delete a prospect list and its prospects","description":"Delete a prospect list and its prospects. IRREVERSIBLE. PREVIEW FIRST: without confirm it reports the prospect count and warns if any sequence still targets the list.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"listId","in":"path","required":true,"description":"List id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["linkedin_list"],"description":"Preview only."},"targetId":{"type":"string","description":"Preview only: list id."},"list":{"type":"string","description":"Preview only: list name."},"prospects":{"type":"integer","description":"Preview only: prospects that will be deleted with it."},"usedBySequences":{"type":"array","items":{"type":"string","description":"Sequence name (status)."},"description":"Preview only: \"name (status)\" of sequences still targeting the list."},"summary":{"type":"string","description":"Preview only: human summary."},"deleted":{"type":"boolean","description":"Run only: always true."},"listId":{"type":"string","description":"Run only: deleted list id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/wallet":{"get":{"operationId":"get_wallet_overview","summary":"Overview of the Wallet loyalty module: every club card (loyalty / stamps / coupon / gift / membership) with its exact funnel — members, installed in Apple/Google Wallet, visited, redeemed, open points — plus recent club activity (joins, scans, redemptions, pushes)","description":"Overview of the Wallet loyalty module: every club card (loyalty / stamps / coupon / gift / membership) with its exact funnel — members, installed in Apple/Google Wallet, visited, redeemed, open points — plus recent club activity (joins, scans, redemptions, pushes). Use it for \"how is the club doing\", \"how many joined\", \"which card performs best\". Numbers are exact, derived from the passes themselves.\n\nRequired scope: `wallet.read`. Risk level: `read`.","tags":["wallet"],"security":[{"bearerAuth":["wallet.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"cards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Card template id; pass as cardId to search_wallet_members."},"name":{"type":"string","description":"Card name."},"type":{"type":"string","description":"Card type, e.g. loyalty, stamp, gift, coupon."},"brand":{"type":["string","null"],"description":"Brand label, or null."},"members":{"type":"integer","description":"Members who joined this card."},"installedInWallets":{"type":"integer","description":"Members who added it to Apple/Google Wallet."},"visited":{"type":"integer","description":"Members scanned at least once."},"redeemed":{"type":"integer","description":"Members who redeemed a reward."},"openPoints":{"type":"number","description":"Outstanding points across members."}},"additionalProperties":true,"required":["id","name","type","brand","members","installedInWallets","visited","redeemed","openPoints"]},"description":"Wallet card templates (loyalty / stamp / gift / coupon) with their funnel."},"installedDevices":{"type":"integer","description":"Devices with a pass installed, across all cards."},"recentActivity":{"type":"array","items":{"type":"object","properties":{"op":{"type":"string","description":"Operation, e.g. issue, push, nudge, birthday, season-on."},"at":{"type":["string","null"],"description":"ISO 8601, or null."},"member":{"type":["string","null"],"description":"Member email when the entry concerns one, else null."},"card":{"type":["string","null"],"description":"Card template id, or null."},"members":{"type":"integer","description":"Members affected (bulk operations only)."},"text":{"type":"string","description":"Message text sent (push/nudge only)."}},"additionalProperties":true,"required":["op","at","member","card"]},"description":"Last 10 ledger entries, newest first."}},"additionalProperties":true,"required":["ok","requestId","cards","installedDevices","recentActivity"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/wallet/members":{"get":{"operationId":"search_wallet_members","summary":"Search club members by name, email, phone or member id, optionally within one card","description":"Search club members by name, email, phone or member id, optionally within one card. Returns per member: tier, points/stamps/balance, how many devices installed the pass, join source (utm), join date and last visit. Use get_wallet_overview first to learn the card ids.\n\nRequired scope: `wallet.read`. Risk level: `read`.","tags":["wallet"],"security":[{"bearerAuth":["wallet.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Free text: name, email, phone or member id. Empty = newest members.","schema":{"type":"string","maxLength":120}},{"name":"cardId","in":"query","required":false,"description":"Restrict to one club card (id from get_wallet_overview).","schema":{"type":"string","maxLength":40}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"total":{"type":"integer","description":"Members matching the query before paging (server caps the read at 500)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"1-based page number that was returned."},"pageSize":{"type":"integer","description":"Rows per page (max 100)."},"total":{"type":"integer","description":"Total matching rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"True when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the (already filtered and sorted) result set."},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pass id."},"name":{"type":["string","null"],"description":"Member name, or null."},"email":{"type":"string","description":"Member email."},"phone":{"type":["string","null"],"description":"Member phone, or null."},"cardId":{"type":"string","description":"Card template id."},"status":{"type":"string","description":"Pass status, e.g. active, revoked."},"tier":{"type":["string","null"],"description":"Loyalty tier, or null."},"points":{"type":"number","description":"Current points balance."},"stamps":{"type":"number","description":"Current stamp count."},"balance":{"type":"number","description":"Gift-card balance."},"installedDevices":{"type":"integer","description":"Devices the pass is installed on."},"source":{"type":["string","null"],"description":"Join source (UTM source or issue source), or null."},"joinedAt":{"type":["string","null"],"description":"ISO 8601 issue time, or null."},"lastVisitAt":{"type":["string","null"],"description":"ISO 8601 of the last scan, or null."}},"additionalProperties":true,"required":["id","name","email","phone","cardId","status","tier","points","stamps","balance","installedDevices","source","joinedAt","lastVisitAt"]},"description":"Matching wallet members (passes), most recently joined first."}},"additionalProperties":true,"required":["ok","requestId","total","pagination","members"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/projects":{"get":{"operationId":"list_projects","summary":"The Projects boards visible to this user: name, key, item count, groups, columns and the status labels each board uses","description":"The Projects boards visible to this user: name, key, item count, groups, columns and the status labels each board uses. Call this first — create/update tools need a projectId, valid status names and group/column ids from here.\n\nRequired scope: `projects.read`. Risk level: `read`.","tags":["projects"],"security":[{"bearerAuth":["projects.read"]}],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Project (board) id."},"name":{"type":"string","description":"Board name (\"\" if unset)."},"key":{"type":"string","description":"Short key used in item refs, e.g. \"PROJ\" → PROJ-12."},"color":{"type":"string","description":"Board colour, hex or \"\"."},"itemCount":{"type":"integer","description":"Number of items on the board."},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Group id."},"name":{"type":"string","description":"Group name."}},"additionalProperties":true,"required":["id"]},"description":"Row groups (sections) of the board."},"columns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Column id (accepted in create/update values)."},"title":{"type":"string","description":"Column title (also accepted in values)."},"type":{"type":"string","description":"Column type, e.g. status, people, date, text, number."}},"additionalProperties":true,"required":["id"]},"description":"Board columns; values are keyed by column title in item.values."},"statuses":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Status label name."},"done":{"type":"boolean","description":"true when this status means completed."},"cancelled":{"type":"boolean","description":"true when this status means cancelled."}},"additionalProperties":true,"required":["name","done","cancelled"]},"description":"Labels of the status column; use these names for item status."},"visibility":{"type":"string","description":"Board visibility, \"shared\" by default."},"owner":{"type":"string","description":"Owner email (\"\" if unknown)."}},"additionalProperties":true,"required":["id","name","key","color","itemCount","groups","columns","statuses","visibility","owner"],"description":"A project board (its metadata, not its items)."},"description":"Boards visible to this token."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","projects","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_project","summary":"Create a new board with a People column, a Status column (default labels Backlog / Todo / In Progress / Done, or your own), a Due date column and groups (default To-Do / Completed)","description":"Create a new board with a People column, a Status column (default labels Backlog / Todo / In Progress / Done, or your own), a Due date column and groups (default To-Do / Completed). Reversible — a board can be deleted in the app.\n\nRequired scope: `projects.write`. Risk level: `write`.","tags":["projects"],"security":[{"bearerAuth":["projects.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Board name.","schema":{"type":"string","maxLength":120}},{"name":"key","in":"query","required":false,"description":"Short prefix for item refs, e.g. CAMP. Default: derived from the name.","schema":{"type":"string","maxLength":6}},{"name":"statuses","in":"query","required":false,"description":"Status labels in order (first = default for new items; a label named \"Done\" counts as done).","schema":{"type":"array","maxItems":12,"items":{"type":"string"}}},{"name":"groups","in":"query","required":false,"description":"Group names in order.","schema":{"type":"array","maxItems":12,"items":{"type":"string"}}},{"name":"color","in":"query","required":false,"description":"Hex color for the board.","schema":{"type":"string","maxLength":9}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true on success."},"project":{"type":"object","properties":{"id":{"type":"string","description":"Project (board) id."},"name":{"type":"string","description":"Board name (\"\" if unset)."},"key":{"type":"string","description":"Short key used in item refs, e.g. \"PROJ\" → PROJ-12."},"color":{"type":"string","description":"Board colour, hex or \"\"."},"itemCount":{"type":"integer","description":"Number of items on the board."},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Group id."},"name":{"type":"string","description":"Group name."}},"additionalProperties":true,"required":["id"]},"description":"Row groups (sections) of the board."},"columns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Column id (accepted in create/update values)."},"title":{"type":"string","description":"Column title (also accepted in values)."},"type":{"type":"string","description":"Column type, e.g. status, people, date, text, number."}},"additionalProperties":true,"required":["id"]},"description":"Board columns; values are keyed by column title in item.values."},"statuses":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Status label name."},"done":{"type":"boolean","description":"true when this status means completed."},"cancelled":{"type":"boolean","description":"true when this status means cancelled."}},"additionalProperties":true,"required":["name","done","cancelled"]},"description":"Labels of the status column; use these names for item status."},"visibility":{"type":"string","description":"Board visibility, \"shared\" by default."},"owner":{"type":"string","description":"Owner email (\"\" if unknown)."}},"additionalProperties":true,"required":["id","name","key","color","itemCount","groups","columns","statuses","visibility","owner"],"description":"A project board (its metadata, not its items)."},"targetType":{"type":"string","enum":["project"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"New board id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","project","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/projects/{id}":{"get":{"operationId":"get_project","summary":"One board with its items: each item has a ref (KEY-number), title, status, priority, assignees, due date, group, and the values of the board's custom columns keyed by column title","description":"One board with its items: each item has a ref (KEY-number), title, status, priority, assignees, due date, group, and the values of the board's custom columns keyed by column title. Filter by status or group; paged.\n\nRequired scope: `projects.read`. Risk level: `read`.","tags":["projects"],"security":[{"bearerAuth":["projects.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Project (board) id from list_projects.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":false,"description":"Only items in this status (exact label).","schema":{"type":"string","maxLength":60}},{"name":"groupId","in":"query","required":false,"description":"Only items in this group id.","schema":{"type":"string","maxLength":60}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"project":{"type":"object","properties":{"id":{"type":"string","description":"Project (board) id."},"name":{"type":"string","description":"Board name (\"\" if unset)."},"key":{"type":"string","description":"Short key used in item refs, e.g. \"PROJ\" → PROJ-12."},"color":{"type":"string","description":"Board colour, hex or \"\"."},"itemCount":{"type":"integer","description":"Number of items on the board."},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Group id."},"name":{"type":"string","description":"Group name."}},"additionalProperties":true,"required":["id"]},"description":"Row groups (sections) of the board."},"columns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Column id (accepted in create/update values)."},"title":{"type":"string","description":"Column title (also accepted in values)."},"type":{"type":"string","description":"Column type, e.g. status, people, date, text, number."}},"additionalProperties":true,"required":["id"]},"description":"Board columns; values are keyed by column title in item.values."},"statuses":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Status label name."},"done":{"type":"boolean","description":"true when this status means completed."},"cancelled":{"type":"boolean","description":"true when this status means cancelled."}},"additionalProperties":true,"required":["name","done","cancelled"]},"description":"Labels of the status column; use these names for item status."},"visibility":{"type":"string","description":"Board visibility, \"shared\" by default."},"owner":{"type":"string","description":"Owner email (\"\" if unknown)."}},"additionalProperties":true,"required":["id","name","key","color","itemCount","groups","columns","statuses","visibility","owner"],"description":"A project board (its metadata, not its items)."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Item id."},"ref":{"type":"string","description":"Human ref \"<KEY>-<num>\", e.g. PROJ-12."},"projectId":{"type":"string","description":"Board id the item belongs to."},"projectName":{"type":"string","description":"Board name."},"title":{"type":"string","description":"Item title."},"status":{"type":"string","description":"Status label name (\"\" if none)."},"priority":{"type":"string","description":"Urgent | High | Medium | Low | None."},"assignees":{"type":"array","items":{"type":"string","description":"Assignee."},"description":"Assignee emails/names."},"dueDate":{"type":"string","description":"Due date YYYY-MM-DD or \"\"."},"groupId":{"type":"string","description":"Group id (\"\" if none)."},"group":{"type":"string","description":"Group name (\"\" if none)."},"labels":{"type":"array","items":{"description":"Label."},"description":"Item labels."},"values":{"type":"object","additionalProperties":true,"description":"Non-empty column values keyed by column title (or id when untitled)."},"comments":{"type":"integer","description":"Number of comments."},"subItems":{"type":"integer","description":"Number of sub-items."},"createdAt":{"type":"string","description":"ISO 8601 creation time or \"\"."}},"additionalProperties":true,"required":["id","ref","projectId","projectName","title","status","priority","assignees","dueDate","groupId","group","labels","values","comments","subItems","createdAt"],"description":"A project item (issue/task) on a board."},"description":"Items on the board (filtered by status/groupId)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","project","items","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/projects/items":{"get":{"operationId":"search_project_items","summary":"Search items across every visible board by text (title, ref like CAMP-12, or any column value), status or assignee","description":"Search items across every visible board by text (title, ref like CAMP-12, or any column value), status or assignee. Use it for \"what is Dana working on\", \"everything still In Progress\", \"find the item about X\".\n\nRequired scope: `projects.read`. Risk level: `read`.","tags":["projects"],"security":[{"bearerAuth":["projects.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Free text or an item ref (KEY-number).","schema":{"type":"string","maxLength":120}},{"name":"projectId","in":"query","required":false,"description":"Restrict to one board.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":false,"description":"Exact status label.","schema":{"type":"string","maxLength":60}},{"name":"assignee","in":"query","required":false,"description":"Assignee email or name (substring).","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Item id."},"ref":{"type":"string","description":"Human ref \"<KEY>-<num>\", e.g. PROJ-12."},"projectId":{"type":"string","description":"Board id the item belongs to."},"projectName":{"type":"string","description":"Board name."},"title":{"type":"string","description":"Item title."},"status":{"type":"string","description":"Status label name (\"\" if none)."},"priority":{"type":"string","description":"Urgent | High | Medium | Low | None."},"assignees":{"type":"array","items":{"type":"string","description":"Assignee."},"description":"Assignee emails/names."},"dueDate":{"type":"string","description":"Due date YYYY-MM-DD or \"\"."},"groupId":{"type":"string","description":"Group id (\"\" if none)."},"group":{"type":"string","description":"Group name (\"\" if none)."},"labels":{"type":"array","items":{"description":"Label."},"description":"Item labels."},"values":{"type":"object","additionalProperties":true,"description":"Non-empty column values keyed by column title (or id when untitled)."},"comments":{"type":"integer","description":"Number of comments."},"subItems":{"type":"integer","description":"Number of sub-items."},"createdAt":{"type":"string","description":"ISO 8601 creation time or \"\"."}},"additionalProperties":true,"required":["id","ref","projectId","projectName","title","status","priority","assignees","dueDate","groupId","group","labels","values","comments","subItems","createdAt"],"description":"A project item (issue/task) on a board."},"description":"Matching items across boards, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","items","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/projects/{projectId}/items":{"post":{"operationId":"create_project_item","summary":"Add an item to a board","description":"Add an item to a board. status must be one of the board's labels (see list_projects); group accepts a group id or name; values is an object keyed by column id or title (numbers, text, dropdown arrays, ratings…). Unknown statuses, groups or columns are rejected with the valid options — nothing is silently dropped.\n\nRequired scope: `projects.write`. Risk level: `write`.","tags":["projects"],"security":[{"bearerAuth":["projects.write"]}],"parameters":[{"name":"projectId","in":"path","required":true,"description":"Board id.","schema":{"type":"string","maxLength":60}},{"name":"title","in":"query","required":true,"description":"Item title.","schema":{"type":"string","maxLength":300}},{"name":"description","in":"query","required":false,"description":"Longer description.","schema":{"type":"string","maxLength":5000}},{"name":"status","in":"query","required":false,"description":"Status label. Default: the board's first open status.","schema":{"type":"string","maxLength":60}},{"name":"priority","in":"query","required":false,"description":"Priority.","schema":{"type":"string","enum":["Urgent","High","Medium","Low","None"]}},{"name":"assignees","in":"query","required":false,"description":"Assignee emails.","schema":{"type":"array","maxItems":10,"items":{"type":"string"}}},{"name":"dueDate","in":"query","required":false,"description":"YYYY-MM-DD.","schema":{"type":"string","maxLength":10}},{"name":"group","in":"query","required":false,"description":"Group id or name. Default: the first group.","schema":{"type":"string","maxLength":60}},{"name":"values","in":"query","required":false,"description":"Custom column values keyed by column id or title.","schema":{"type":"string"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true on success."},"item":{"type":"object","properties":{"id":{"type":"string","description":"Item id."},"ref":{"type":"string","description":"Human ref \"<KEY>-<num>\", e.g. PROJ-12."},"projectId":{"type":"string","description":"Board id the item belongs to."},"projectName":{"type":"string","description":"Board name."},"title":{"type":"string","description":"Item title."},"status":{"type":"string","description":"Status label name (\"\" if none)."},"priority":{"type":"string","description":"Urgent | High | Medium | Low | None."},"assignees":{"type":"array","items":{"type":"string","description":"Assignee."},"description":"Assignee emails/names."},"dueDate":{"type":"string","description":"Due date YYYY-MM-DD or \"\"."},"groupId":{"type":"string","description":"Group id (\"\" if none)."},"group":{"type":"string","description":"Group name (\"\" if none)."},"labels":{"type":"array","items":{"description":"Label."},"description":"Item labels."},"values":{"type":"object","additionalProperties":true,"description":"Non-empty column values keyed by column title (or id when untitled)."},"comments":{"type":"integer","description":"Number of comments."},"subItems":{"type":"integer","description":"Number of sub-items."},"createdAt":{"type":"string","description":"ISO 8601 creation time or \"\"."}},"additionalProperties":true,"required":["id","ref","projectId","projectName","title","status","priority","assignees","dueDate","groupId","group","labels","values","comments","subItems","createdAt"],"description":"A project item (issue/task) on a board."},"targetType":{"type":"string","enum":["project_item"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"New item id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","item","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/projects/{projectId}/items/{itemId}/update":{"post":{"operationId":"update_project_item","summary":"Change an item: title, status, priority, assignees (full replacement), due date, group, column values (merged), or add a comment","description":"Change an item: title, status, priority, assignees (full replacement), due date, group, column values (merged), or add a comment. Only the fields you pass change; each change is logged in the item's activity. itemId accepts the item id or its ref (KEY-number).\n\nRequired scope: `projects.write`. Risk level: `write`.","tags":["projects"],"security":[{"bearerAuth":["projects.write"]}],"parameters":[{"name":"projectId","in":"path","required":true,"description":"Board id.","schema":{"type":"string","maxLength":60}},{"name":"itemId","in":"path","required":true,"description":"Item id or ref.","schema":{"type":"string","maxLength":60}},{"name":"title","in":"query","required":false,"description":"New title.","schema":{"type":"string","maxLength":300}},{"name":"status","in":"query","required":false,"description":"New status label.","schema":{"type":"string","maxLength":60}},{"name":"priority","in":"query","required":false,"description":"New priority.","schema":{"type":"string","enum":["Urgent","High","Medium","Low","None"]}},{"name":"assignees","in":"query","required":false,"description":"FULL replacement assignee list ([] to unassign).","schema":{"type":"array","maxItems":10,"items":{"type":"string"}}},{"name":"dueDate","in":"query","required":false,"description":"YYYY-MM-DD, or \"\" to clear.","schema":{"type":"string","maxLength":10}},{"name":"group","in":"query","required":false,"description":"Move to this group (id or name).","schema":{"type":"string","maxLength":60}},{"name":"values","in":"query","required":false,"description":"Column values to merge, keyed by column id or title.","schema":{"type":"string"}},{"name":"comment","in":"query","required":false,"description":"Append a comment.","schema":{"type":"string","maxLength":4000}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"updated":{"type":"boolean","description":"Always true on success."},"changes":{"type":"array","items":{"type":"string","description":"Change, e.g. \"changed status to Done\"."},"description":"Human-readable list of what changed."},"item":{"type":"object","properties":{"id":{"type":"string","description":"Item id."},"ref":{"type":"string","description":"Human ref \"<KEY>-<num>\", e.g. PROJ-12."},"projectId":{"type":"string","description":"Board id the item belongs to."},"projectName":{"type":"string","description":"Board name."},"title":{"type":"string","description":"Item title."},"status":{"type":"string","description":"Status label name (\"\" if none)."},"priority":{"type":"string","description":"Urgent | High | Medium | Low | None."},"assignees":{"type":"array","items":{"type":"string","description":"Assignee."},"description":"Assignee emails/names."},"dueDate":{"type":"string","description":"Due date YYYY-MM-DD or \"\"."},"groupId":{"type":"string","description":"Group id (\"\" if none)."},"group":{"type":"string","description":"Group name (\"\" if none)."},"labels":{"type":"array","items":{"description":"Label."},"description":"Item labels."},"values":{"type":"object","additionalProperties":true,"description":"Non-empty column values keyed by column title (or id when untitled)."},"comments":{"type":"integer","description":"Number of comments."},"subItems":{"type":"integer","description":"Number of sub-items."},"createdAt":{"type":"string","description":"ISO 8601 creation time or \"\"."}},"additionalProperties":true,"required":["id","ref","projectId","projectName","title","status","priority","assignees","dueDate","groupId","group","labels","values","comments","subItems","createdAt"],"description":"A project item (issue/task) on a board."},"targetType":{"type":"string","enum":["project_item"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Item id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","updated","changes","item","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/projects/{projectId}/items/{itemId}/delete":{"post":{"operationId":"delete_project_item","summary":"Remove an item from a board (with its comments and sub-items)","description":"Remove an item from a board (with its comments and sub-items). PREVIEW FIRST: without confirm it shows the item that would be removed. The board keeps a restorable version snapshot in the app, but the item is gone from the board immediately.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"projectId","in":"path","required":true,"description":"Board id.","schema":{"type":"string","maxLength":60}},{"name":"itemId","in":"path","required":true,"description":"Item id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willDelete":{"type":"object","properties":{"id":{"type":"string","description":"Item id."},"ref":{"type":"string","description":"Human ref \"<KEY>-<num>\", e.g. PROJ-12."},"projectId":{"type":"string","description":"Board id the item belongs to."},"projectName":{"type":"string","description":"Board name."},"title":{"type":"string","description":"Item title."},"status":{"type":"string","description":"Status label name (\"\" if none)."},"priority":{"type":"string","description":"Urgent | High | Medium | Low | None."},"assignees":{"type":"array","items":{"type":"string","description":"Assignee."},"description":"Assignee emails/names."},"dueDate":{"type":"string","description":"Due date YYYY-MM-DD or \"\"."},"groupId":{"type":"string","description":"Group id (\"\" if none)."},"group":{"type":"string","description":"Group name (\"\" if none)."},"labels":{"type":"array","items":{"description":"Label."},"description":"Item labels."},"values":{"type":"object","additionalProperties":true,"description":"Non-empty column values keyed by column title (or id when untitled)."},"comments":{"type":"integer","description":"Number of comments."},"subItems":{"type":"integer","description":"Number of sub-items."},"createdAt":{"type":"string","description":"ISO 8601 creation time or \"\"."}},"additionalProperties":true,"required":["id","ref","projectId","projectName","title","status","priority","assignees","dueDate","groupId","group","labels","values","comments","subItems","createdAt"],"description":"Preview only: the item that would be removed."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"deleted":{"type":"boolean","description":"Run only: true on success."},"itemId":{"type":"string","description":"Run only: removed item id."},"targetType":{"type":"string","enum":["project_item"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Item id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/landing-pages":{"get":{"operationId":"list_landing_pages","summary":"The workspace's landing pages with performance: views, clicks, leads captured, conversion rate, average time on page and 14-day daily views","description":"The workspace's landing pages with performance: views, clicks, leads captured, conversion rate, average time on page and 14-day daily views. Leads captured by a page are also searchable with search_leads (source landing_page).\n\nRequired scope: `pages.read`. Risk level: `read`.","tags":["pages"],"security":[{"bearerAuth":["pages.read"]}],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"pages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Landing page id."},"name":{"type":"string","description":"Page name (falls back to title)."},"slug":{"type":"string","description":"URL slug or \"\"."},"url":{"type":"string","description":"Public URL or \"\"."},"published":{"type":"boolean","description":"false only when explicitly unpublished."},"listId":{"type":"string","description":"Landing-page list id or \"\"."},"createdAt":{"description":"Creation time: ISO 8601, epoch ms or \"\"."},"views":{"type":"number","description":"Page views."},"clicks":{"type":"number","description":"Clicks."},"leads":{"type":"number","description":"Leads captured."},"conversionRate":{"type":"number","description":"leads / views as a percentage, 1 decimal."},"avgDwellSeconds":{"type":"number","description":"Average time on page, seconds, 1 decimal."},"dailyViews":{"description":"Daily view series when the stats endpoint provides one."}},"additionalProperties":true,"required":["id","name","slug","url","published","listId","createdAt","views","clicks","leads","conversionRate","avgDwellSeconds"]},"description":"Landing pages with traffic stats, most viewed first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","pages","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/email-senders":{"get":{"operationId":"list_email_senders","summary":"The verified CAMPAIGN sending addresses and domains (SES) this workspace can send email from — what to pass as fromEmail to send_email_campaign","description":"The verified CAMPAIGN sending addresses and domains (SES) this workspace can send email from — what to pass as fromEmail to send_email_campaign. A domain entry authorises any mailbox at it. Lists only senders owned by this workspace, never those of other tenants. NOT the personal Gmail / Outlook mailboxes: for those (drafts, outreach) use list_connected_email_accounts.\n\nRequired scope: `messages.draft`. Risk level: `read`.","tags":["messages"],"security":[{"bearerAuth":["messages.draft"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Filter by address or domain substring.","schema":{"type":"string","maxLength":120}},{"name":"verifiedOnly","in":"query","required":false,"description":"Only identities that can send right now (default true).","schema":{"type":"boolean","default":true}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"senders":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","description":"Email address, or the bare domain for a domain identity."},"type":{"type":"string","description":"\"address\" or \"domain\"."},"verified":{"type":"boolean","description":"true when sends from it are accepted right now."},"isDefault":{"type":"boolean","description":"true for the platform default From address."}},"additionalProperties":true,"required":["address","type","verified","isDefault"]},"description":"Sending identities of this workspace that send_email_campaign accepts as fromEmail."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."},"defaultFrom":{"type":"string","description":"The default From address, when one is configured."},"note":{"type":"string","description":"How to use these with send_email_campaign."}},"additionalProperties":true,"required":["ok","requestId","senders","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/email-campaigns":{"get":{"operationId":"list_email_campaigns","summary":"Sent email campaigns with results: sent, unique opens and open rate, unique clicks and click rate, unsubscribes, bounces, complaints, attributed orders/revenue, A/B winner","description":"Sent email campaigns with results: sent, unique opens and open rate, unique clicks and click rate, unsubscribes, bounces, complaints, attributed orders/revenue, A/B winner. Newest first. Use it for \"how did last week's newsletter do\".\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Filter by campaign name or subject.","schema":{"type":"string","maxLength":120}},{"name":"includeArchived","in":"query","required":false,"description":"Include archived campaigns.","schema":{"type":"boolean","default":false}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"campaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id."},"name":{"type":"string","description":"Campaign name."},"subject":{"type":"string","description":"Email subject."},"from":{"type":"string","description":"Sender address."},"audience":{"description":"Audience / segment the campaign went to."},"sentAt":{"description":"Send time (epoch ms or ISO 8601)."},"sent":{"type":"number","description":"Recipients."},"opens":{"type":"number","description":"Unique opens."},"openRate":{"type":"number","description":"Unique opens / sent, percent, 1 decimal."},"clicks":{"type":"number","description":"Unique clicks."},"clickRate":{"type":"number","description":"Unique clicks / sent, percent, 1 decimal."},"unsubscribes":{"type":"number","description":"Unsubscribes."},"bounces":{"type":"number","description":"Bounces."},"complaints":{"type":"number","description":"Spam complaints."},"orders":{"type":"number","description":"Attributed orders."},"revenue":{"type":"number","description":"Attributed revenue, account currency (absent when 0)."},"abWinner":{"description":"Winning A/B variant when the campaign was a test."},"archived":{"type":"boolean","description":"true when archived."}},"additionalProperties":true,"required":["openRate","clickRate","orders","archived"]},"description":"Sent email campaigns with delivery stats."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","campaigns","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sms-campaigns":{"get":{"operationId":"list_sms_campaigns","summary":"Sent SMS campaigns with results: sent, delivered and delivery rate, failed, link clicks and click rate, unsubscribes, attributed orders/revenue","description":"Sent SMS campaigns with results: sent, delivered and delivery rate, failed, link clicks and click rate, unsubscribes, attributed orders/revenue. Newest first.\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Filter by campaign name or message text.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"campaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id."},"name":{"type":"string","description":"Campaign name."},"sender":{"type":"string","description":"Sender id."},"audience":{"description":"Audience / segment the campaign went to."},"sentAt":{"description":"Send time (epoch ms or ISO 8601)."},"message":{"type":"string","description":"Message text, first 300 chars."},"sent":{"type":"number","description":"Recipients."},"delivered":{"type":"number","description":"Delivered."},"deliveryRate":{"type":"number","description":"delivered / sent, percent, 1 decimal."},"failed":{"type":"number","description":"Failed deliveries."},"clicks":{"type":"number","description":"Link clicks."},"clickRate":{"type":"number","description":"clicks / delivered, percent, 1 decimal."},"unsubscribes":{"type":"number","description":"Unsubscribes."},"orders":{"type":"number","description":"Attributed orders."},"revenue":{"type":"number","description":"Attributed revenue, account currency (absent when 0)."}},"additionalProperties":true,"required":["message","deliveryRate","clickRate","orders"]},"description":"Sent SMS campaigns with delivery stats, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","campaigns","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/landing-pages/{id}":{"get":{"operationId":"get_landing_page","summary":"One landing page with its settings (URL, list, SEO, expiry) and its HTML (capped; pass maxHtmlChars for more)","description":"One landing page with its settings (URL, list, SEO, expiry) and its HTML (capped; pass maxHtmlChars for more). Read it before editing so replaceText edits match the real markup.\n\nRequired scope: `pages.read`. Risk level: `read`.","tags":["pages"],"security":[{"bearerAuth":["pages.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Page id from list_landing_pages.","schema":{"type":"string","maxLength":60}},{"name":"maxHtmlChars","in":"query","required":false,"description":"How much HTML to return (1000-60000, default 20000).","schema":{"type":"integer","minimum":1000,"maximum":60000}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"page":{"type":"object","properties":{"id":{"type":"string","description":"Landing page id."},"name":{"type":"string","description":"Internal page name."},"title":{"type":"string","description":"Page <title>."},"description":{"type":"string","description":"Meta description."},"pageType":{"type":"string","description":"Page type, e.g. minisite."},"kind":{"type":"string","description":"html (code page) or canvas."},"slug":{"type":"string","description":"URL slug (\"\" when served by id)."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/lp/{slug|id}."},"domain":{"type":"string","description":"Custom domain or \"\"."},"listId":{"type":"string","description":"Landing-page list id or \"\"."},"listName":{"type":"string","description":"Landing-page list name or \"\"."},"campaignName":{"type":"string","description":"Linked campaign name or \"\"."},"noindex":{"type":"boolean","description":"true when robots noindex is set."},"redirectUrl":{"type":"string","description":"Post-submit redirect URL or \"\"."},"expiresAt":{"type":"string","description":"Expiry date/time or \"\"."},"leadCount":{"type":"integer","description":"Leads captured by the page."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["id","name","title","description","pageType","kind","slug","url","domain","listId","listName","campaignName","noindex","redirectUrl","expiresAt","leadCount","createdAt","updatedAt"],"description":"Landing page metadata (no HTML)."},"htmlLength":{"type":"integer","description":"Full HTML length in chars."},"htmlTruncated":{"type":"boolean","description":"true when html was cut at maxHtmlChars."},"html":{"type":"string","description":"Page HTML, up to maxHtmlChars."},"canvasDesign":{"type":"boolean","description":"true when the page is a canvas design (HTML is generated)."}},"additionalProperties":true,"required":["ok","requestId","page","htmlLength","htmlTruncated","html","canvasDesign"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/landing-pages/generate":{"post":{"operationId":"generate_landing_page","summary":"Create a new landing page with the platform's AI page generator from a brief (prompt and/or title, description, paragraphs, image URLs), save it and return its URL","description":"Create a new landing page with the platform's AI page generator from a brief (prompt and/or title, description, paragraphs, image URLs), save it and return its URL. Takes 30-90 seconds. The page is live at its URL immediately but nothing is promoted; it can be edited with update_landing_page or removed with delete_landing_page. Leads submitted on it land in the CRM (and in listId if given).\n\nRequired scope: `pages.write`. Risk level: `write`.","tags":["pages"],"security":[{"bearerAuth":["pages.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Internal page name.","schema":{"type":"string","maxLength":120}},{"name":"prompt","in":"query","required":false,"description":"Brief for the generator: business, offer, audience, tone, sections wanted.","schema":{"type":"string","maxLength":8000}},{"name":"title","in":"query","required":false,"description":"Hero title.","schema":{"type":"string","maxLength":300}},{"name":"description","in":"query","required":false,"description":"Sub-headline / summary.","schema":{"type":"string","maxLength":2000}},{"name":"paragraphs","in":"query","required":false,"description":"Body paragraphs to include.","schema":{"type":"array","maxItems":40,"items":{"type":"string"}}},{"name":"imageUrls","in":"query","required":false,"description":"Image URLs the page may use.","schema":{"type":"array","maxItems":24,"items":{"type":"string"}}},{"name":"pageType","in":"query","required":false,"description":"Layout family.","schema":{"type":"string","enum":["minisite","landing","form"]}},{"name":"listId","in":"query","required":false,"description":"Landing-page list to route leads into (from list_landing_page_lists).","schema":{"type":"string","maxLength":60}},{"name":"listName","in":"query","required":false,"description":"Display name of that list.","schema":{"type":"string","maxLength":80}},{"name":"slug","in":"query","required":false,"description":"Custom URL slug (a-z, 0-9, dashes; must be free).","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true on success."},"page":{"type":"object","properties":{"id":{"type":"string","description":"Landing page id."},"name":{"type":"string","description":"Page name."},"title":{"type":"string","description":"Page <title>."},"description":{"type":"string","description":"Meta description."},"pageType":{"type":"string","description":"Page type, e.g. minisite."},"kind":{"type":"string","description":"html (code page) or canvas."},"slug":{"type":"string","description":"URL slug (\"\" when served by id)."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/lp/{slug|id}."},"domain":{"type":"string","description":"Custom domain or \"\"."},"listId":{"type":"string","description":"Landing-page list id or \"\"."},"listName":{"type":"string","description":"Landing-page list name or \"\"."},"campaignName":{"type":"string","description":"Linked campaign name or \"\"."},"noindex":{"type":"boolean","description":"true when robots noindex is set."},"redirectUrl":{"type":"string","description":"Post-submit redirect URL or \"\"."},"expiresAt":{"type":"string","description":"Expiry date/time or \"\"."},"leadCount":{"type":"integer","description":"Leads captured by the page."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["id","name","title","description","pageType","kind","slug","url","domain","listId","listName","campaignName","noindex","redirectUrl","expiresAt","leadCount","createdAt","updatedAt"],"description":"The new page; full metadata when it could be re-read, else just id and name."},"model":{"type":"string","description":"AI model that generated the page (\"\" if unknown)."},"targetType":{"type":"string","enum":["landing_page"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"New page id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","page","model","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/landing-pages/{id}/update":{"post":{"operationId":"update_landing_page","summary":"Edit a landing page: settings (name, slug, list, SEO title/og image, noindex, redirect, expiry) and/or content","description":"Edit a landing page: settings (name, slug, list, SEO title/og image, noindex, redirect, expiry) and/or content. Content edits: replaceText = exact find→replace pairs applied to the page HTML (a find string that matches nowhere is rejected, so a typo cannot silently do nothing), or html = full replacement. Read the page first with get_landing_page.\n\nRequired scope: `pages.write`. Risk level: `write`.","tags":["pages"],"security":[{"bearerAuth":["pages.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Page id.","schema":{"type":"string","maxLength":60}},{"name":"name","in":"query","required":false,"description":"Internal name.","schema":{"type":"string","maxLength":120}},{"name":"title","in":"query","required":false,"description":"SEO/hero title.","schema":{"type":"string","maxLength":300}},{"name":"description","in":"query","required":false,"description":"Meta description.","schema":{"type":"string","maxLength":2000}},{"name":"slug","in":"query","required":false,"description":"Custom URL slug, or \"\" to clear.","schema":{"type":"string","maxLength":60}},{"name":"listId","in":"query","required":false,"description":"Landing-page list id for new leads, or \"\" to clear.","schema":{"type":"string","maxLength":60}},{"name":"listName","in":"query","required":false,"description":"Display name of that list.","schema":{"type":"string","maxLength":80}},{"name":"ogTitle","in":"query","required":false,"description":"Open Graph title.","schema":{"type":"string","maxLength":200}},{"name":"ogImage","in":"query","required":false,"description":"Open Graph image URL.","schema":{"type":"string","maxLength":600}},{"name":"noindex","in":"query","required":false,"description":"Hide from search engines.","schema":{"type":"boolean"}},{"name":"redirectUrl","in":"query","required":false,"description":"Redirect after form submit.","schema":{"type":"string","maxLength":600}},{"name":"expiresAt","in":"query","required":false,"description":"ISO date-time after which the page shows expiredMsg.","schema":{"type":"string","maxLength":40}},{"name":"expiredMsg","in":"query","required":false,"description":"Message shown after expiry.","schema":{"type":"string","maxLength":400}},{"name":"replaceText","in":"query","required":false,"description":"Exact text edits: [{find, replace}] applied to the HTML in order.","schema":{"type":"array","maxItems":40,"items":{"type":"object"}}},{"name":"html","in":"query","required":false,"description":"FULL replacement HTML (use only when replaceText is not enough).","schema":{"type":"string","maxLength":400000}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"updated":{"type":"boolean","description":"Always true on success."},"page":{"type":"object","properties":{"id":{"type":"string","description":"Landing page id."},"name":{"type":"string","description":"Internal page name."},"title":{"type":"string","description":"Page <title>."},"description":{"type":"string","description":"Meta description."},"pageType":{"type":"string","description":"Page type, e.g. minisite."},"kind":{"type":"string","description":"html (code page) or canvas."},"slug":{"type":"string","description":"URL slug (\"\" when served by id)."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/lp/{slug|id}."},"domain":{"type":"string","description":"Custom domain or \"\"."},"listId":{"type":"string","description":"Landing-page list id or \"\"."},"listName":{"type":"string","description":"Landing-page list name or \"\"."},"campaignName":{"type":"string","description":"Linked campaign name or \"\"."},"noindex":{"type":"boolean","description":"true when robots noindex is set."},"redirectUrl":{"type":"string","description":"Post-submit redirect URL or \"\"."},"expiresAt":{"type":"string","description":"Expiry date/time or \"\"."},"leadCount":{"type":"integer","description":"Leads captured by the page."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["id","name","title","description","pageType","kind","slug","url","domain","listId","listName","campaignName","noindex","redirectUrl","expiresAt","leadCount","createdAt","updatedAt"],"description":"Landing page metadata (no HTML)."},"textEdits":{"type":"array","items":{"type":"object","properties":{"find":{"type":"string","description":"Search text (first 80 chars)."},"matches":{"type":"integer","description":"Occurrences replaced."}},"additionalProperties":true,"required":["find","matches"]},"description":"replaceText edits that were applied."},"htmlReplaced":{"type":"boolean","description":"true when the whole HTML was replaced."},"targetType":{"type":"string","enum":["landing_page"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Page id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","updated","page","textEdits","htmlReplaced","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/landing-pages/{id}/delete":{"post":{"operationId":"delete_landing_page","summary":"Take a landing page down (its URL stops serving)","description":"Take a landing page down (its URL stops serving). PREVIEW FIRST: without confirm it shows the page and how many leads it captured (they stay in the CRM).\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Page id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willDelete":{"type":"object","properties":{"id":{"type":"string","description":"Landing page id."},"name":{"type":"string","description":"Internal page name."},"title":{"type":"string","description":"Page <title>."},"description":{"type":"string","description":"Meta description."},"pageType":{"type":"string","description":"Page type, e.g. minisite."},"kind":{"type":"string","description":"html (code page) or canvas."},"slug":{"type":"string","description":"URL slug (\"\" when served by id)."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/lp/{slug|id}."},"domain":{"type":"string","description":"Custom domain or \"\"."},"listId":{"type":"string","description":"Landing-page list id or \"\"."},"listName":{"type":"string","description":"Landing-page list name or \"\"."},"campaignName":{"type":"string","description":"Linked campaign name or \"\"."},"noindex":{"type":"boolean","description":"true when robots noindex is set."},"redirectUrl":{"type":"string","description":"Post-submit redirect URL or \"\"."},"expiresAt":{"type":"string","description":"Expiry date/time or \"\"."},"leadCount":{"type":"integer","description":"Leads captured by the page."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["id","name","title","description","pageType","kind","slug","url","domain","listId","listName","campaignName","noindex","redirectUrl","expiresAt","leadCount","createdAt","updatedAt"],"description":"Preview only: the page that would be deleted."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"deleted":{"type":"boolean","description":"Run only: true on success."},"id":{"type":"string","description":"Run only: deleted page id."},"targetType":{"type":"string","enum":["landing_page"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Page id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/landing-pages/lists":{"get":{"operationId":"list_landing_page_lists","summary":"The landing-page lead lists (a page routes its leads into one), with lead counts","description":"The landing-page lead lists (a page routes its leads into one), with lead counts.\n\nRequired scope: `pages.read`. Risk level: `read`.","tags":["pages"],"security":[{"bearerAuth":["pages.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"List id (list_…)."},"name":{"type":"string","description":"List name."},"count":{"type":"integer","description":"Pages in the list."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["id","name","count","createdAt"]},"description":"Landing-page lists (folders)."}},"additionalProperties":true,"required":["ok","requestId","lists"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_landing_page_list","summary":"Create a landing-page lead list (returns the existing one if the name already exists)","description":"Create a landing-page lead list (returns the existing one if the name already exists).\n\nRequired scope: `pages.write`. Risk level: `write`.","tags":["pages"],"security":[{"bearerAuth":["pages.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"List name.","schema":{"type":"string","maxLength":80}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true (an existing list with the same name is returned instead)."},"list":{"type":"object","properties":{"id":{"type":"string","description":"List id (list_…)."},"name":{"type":"string","description":"List name."},"createdAt":{"type":"string","description":"ISO 8601."},"count":{"type":"integer","description":"Pages in the list."}},"additionalProperties":true,"required":["id","name","createdAt","count"],"description":"The list record."},"targetType":{"type":"string","enum":["lp_list"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"List id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","list","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/posts":{"get":{"operationId":"list_social_posts","summary":"Posts in the social calendar (the currently focused page/client): status (draft / pending / scheduled / published / rejected), copy, channels, schedule time, image, and real stats for published ones","description":"Posts in the social calendar (the currently focused page/client): status (draft / pending / scheduled / published / rejected), copy, channels, schedule time, image, and real stats for published ones.\n\nRequired scope: `social.read`. Risk level: `read`.","tags":["social"],"security":[{"bearerAuth":["social.read"]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Filter by status.","schema":{"type":"string","enum":["draft","pending","scheduled","published","rejected"]}},{"name":"query","in":"query","required":false,"description":"Text in title, headline or copy.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"A social calendar post."},"description":"Calendar posts (filtered by status/query)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","posts","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_social_post","summary":"Save a post to the calendar as a DRAFT (or pending client approval)","description":"Save a post to the calendar as a DRAFT (or pending client approval). Never publishes: scheduling and publishing are separate confirm-gated tools.\n\nRequired scope: `social.write`. Risk level: `write`.","tags":["social"],"security":[{"bearerAuth":["social.write"]}],"parameters":[{"name":"copy","in":"query","required":true,"description":"Post text.","schema":{"type":"string","maxLength":2200}},{"name":"title","in":"query","required":false,"description":"Internal title.","schema":{"type":"string","maxLength":200}},{"name":"headline","in":"query","required":false,"description":"Headline / first line.","schema":{"type":"string","maxLength":200}},{"name":"cta","in":"query","required":false,"description":"Call to action.","schema":{"type":"string","maxLength":60}},{"name":"hashtags","in":"query","required":false,"description":"Up to 8 hashtags.","schema":{"type":"array","maxItems":8,"items":{"type":"string"}}},{"name":"channels","in":"query","required":false,"description":"facebook / instagram / linkedin / groups / tiktok.","schema":{"type":"array","maxItems":5,"items":{"type":"string"}}},{"name":"lang","in":"query","required":false,"description":"Language code (default en).","schema":{"type":"string","maxLength":5}},{"name":"format","in":"query","required":false,"description":"image / video / carousel / text.","schema":{"type":"string","maxLength":20}},{"name":"ptype","in":"query","required":false,"description":"Post type.","schema":{"type":"string","enum":["post","story","reel"]}},{"name":"label","in":"query","required":false,"description":"Content label.","schema":{"type":"string","enum":["promo","edu","engage","bts","seasonal","other"]}},{"name":"image","in":"query","required":false,"description":"Hosted image URL.","schema":{"type":"string","maxLength":500}},{"name":"video","in":"query","required":false,"description":"Hosted video URL (reels).","schema":{"type":"string","maxLength":500}},{"name":"link","in":"query","required":false,"description":"Link to include.","schema":{"type":"string","maxLength":500}},{"name":"scheduledAt","in":"query","required":false,"description":"Intended time (ISO 8601) — stored only; schedule_social_post arms it.","schema":{"type":"string","maxLength":40}},{"name":"status","in":"query","required":false,"description":"draft (default) or pending (awaiting client approval).","schema":{"type":"string","enum":["draft","pending"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true on success."},"post":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"A social calendar post."},"approvalGated":{"type":"boolean","description":"true when client approval is required before it can go live."},"targetType":{"type":"string","enum":["social_post"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"New post id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","post","approvalGated","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/performance":{"get":{"operationId":"get_social_performance","summary":"Aggregate social performance of published posts (reach, impressions, engagement, clicks, leads) with the best channel / format / language and top posts","description":"Aggregate social performance of published posts (reach, impressions, engagement, clicks, leads) with the best channel / format / language and top posts. Refreshes stale insights first, so it can take ~10s.\n\nRequired scope: `social.read`. Risk level: `read`.","tags":["social"],"security":[{"bearerAuth":["social.read"]}],"parameters":[{"name":"lang","in":"query","required":false,"description":"Language for the narrative fields.","schema":{"type":"string","enum":["en","he"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"metrics":{"type":"object","properties":{"published":{"type":"integer","description":"Published posts."},"reach":{"type":"number","description":"Reach."},"engagement":{"type":"number","description":"Engagement."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."},"leads":{"type":"number","description":"Leads attributed to posts."}},"additionalProperties":true,"required":["published","reach","engagement","clicks","likes","comments","leads"],"description":"Totals over published posts (estimates when seeded=true)."},"bestChannel":{"type":"string","description":"Top channel by engagement."},"bestLang":{"type":"string","description":"Top language by engagement."},"bestFormat":{"type":"string","description":"Top format by engagement."},"insights":{"type":"array","items":{"type":"string","description":"Insight."},"description":"Short insight sentences in the requested language."},"seeded":{"type":"boolean","description":"true when no real stats exist yet and metrics are estimates."},"recommendation":{"type":"string","description":"One-line recommendation."},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Post id (sc_… or fb_… for posts imported from the page)."},"text":{"type":"string","description":"Post text excerpt (up to 160 chars, whitespace collapsed)."},"image":{"type":"string","description":"Image URL or empty."},"channels":{"type":"array","items":{"type":"string","description":"facebook / instagram / linkedin / groups / tiktok."},"description":"Channels it was published to."},"pageName":{"type":"string","description":"Page it was published from."},"format":{"type":"string","description":"image / video / carousel / text."},"publishedAt":{"type":"string","description":"ISO 8601 publish time, or empty."},"url":{"type":"string","description":"Live post URL when known."},"statsAt":{"type":"string","description":"ISO 8601 time the stats were last refreshed, or empty."},"metrics":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement (reactions + comments + shares + clicks)."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes / reactions."},"comments":{"type":"number","description":"Comments."},"leads":{"type":"number","description":"Leads attributed to this post."}},"additionalProperties":true,"required":["reach","impressions","engagement","clicks","likes","comments","leads"],"description":"Live metrics for this post."}},"additionalProperties":true,"required":["id","text","image","channels","pageName","format","publishedAt","url","statsAt","metrics"],"description":"A published post with its live stats (newest first)."},"description":"Up to 20 published posts, newest first."},"tiktokAccount":{"type":["object","null"],"properties":{"username":{"type":"string","description":"Handle."},"displayName":{"type":"string","description":"Display name."},"avatar":{"type":"string","description":"Profile image URL."},"followers":{"type":"number","description":"Followers."},"totalLikes":{"type":"number","description":"Total likes."},"videos":{"type":"number","description":"Video count."},"views7d":{"type":"number","description":"Video views, last 7 days."},"profileViews7d":{"type":"number","description":"Profile views, last 7 days."},"likes7d":{"type":"number","description":"Likes, last 7 days."},"comments7d":{"type":"number","description":"Comments, last 7 days."},"shares7d":{"type":"number","description":"Shares, last 7 days."},"newFollowers7d":{"type":"number","description":"New followers, last 7 days."}},"additionalProperties":true,"description":"TikTok account insights; null when not connected."}},"additionalProperties":true,"required":["ok","requestId","metrics","bestChannel","bestLang","bestFormat","insights","seeded","recommendation","posts","tiktokAccount"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/generate":{"post":{"operationId":"generate_social_posts","summary":"Ask the platform's social AI (brand-aware) for post ideas: topic/source, angle, audience, objective, tone, channels, format, languages","description":"Ask the platform's social AI (brand-aware) for post ideas: topic/source, angle, audience, objective, tone, channels, format, languages. Returns generated variants — nothing is saved until you call create_social_post with the one you want. Takes 20-60s.\n\nRequired scope: `social.write`. Risk level: `write`.","tags":["social"],"security":[{"bearerAuth":["social.write"]}],"parameters":[{"name":"topic","in":"query","required":false,"description":"What the post is about (a news item, product, event…).","schema":{"type":"string","maxLength":300}},{"name":"angle","in":"query","required":false,"description":"Angle or hook.","schema":{"type":"string","maxLength":300}},{"name":"audience","in":"query","required":false,"description":"Who it is for.","schema":{"type":"string","maxLength":300}},{"name":"focus","in":"query","required":false,"description":"Product/service to focus on.","schema":{"type":"string","maxLength":300}},{"name":"objective","in":"query","required":false,"description":"awareness / leads / engagement / sales.","schema":{"type":"string","maxLength":60}},{"name":"tone","in":"query","required":false,"description":"Tone of voice.","schema":{"type":"string","maxLength":60}},{"name":"channels","in":"query","required":false,"description":"Target channels.","schema":{"type":"array","maxItems":5,"items":{"type":"string"}}},{"name":"format","in":"query","required":false,"description":"image / video / carousel / text.","schema":{"type":"string","maxLength":20}},{"name":"langs","in":"query","required":false,"description":"Languages, e.g. [\"he\",\"en\"].","schema":{"type":"array","maxItems":4,"items":{"type":"string"}}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"ideas":{"type":"object","additionalProperties":true,"description":"Keyed by language code → { versions:[{id,label,copy,headline,cta,hashtags,bestTime,visual,channels}], qc?, error? }."},"historyId":{"type":"string","description":"Generation-history id when the result was saved."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","ideas"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/posts/{id}/update":{"post":{"operationId":"update_social_post","summary":"Edit a draft/pending/scheduled post (copy, headline, hashtags, channels, image, link, intended time…)","description":"Edit a draft/pending/scheduled post (copy, headline, hashtags, channels, image, link, intended time…). Only passed fields change; the previous content is kept as a version. Published posts cannot be edited.\n\nRequired scope: `social.write`. Risk level: `write`.","tags":["social"],"security":[{"bearerAuth":["social.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Post id.","schema":{"type":"string","maxLength":60}},{"name":"copy","in":"query","required":false,"description":"New text.","schema":{"type":"string","maxLength":2200}},{"name":"title","in":"query","required":false,"description":"New internal title.","schema":{"type":"string","maxLength":200}},{"name":"headline","in":"query","required":false,"description":"New headline.","schema":{"type":"string","maxLength":200}},{"name":"cta","in":"query","required":false,"description":"New call to action.","schema":{"type":"string","maxLength":60}},{"name":"hashtags","in":"query","required":false,"description":"FULL replacement hashtag list.","schema":{"type":"array","maxItems":8,"items":{"type":"string"}}},{"name":"channels","in":"query","required":false,"description":"FULL replacement channel list.","schema":{"type":"array","maxItems":5,"items":{"type":"string"}}},{"name":"lang","in":"query","required":false,"description":"Language code.","schema":{"type":"string","maxLength":5}},{"name":"format","in":"query","required":false,"description":"image / video / carousel / text.","schema":{"type":"string","maxLength":20}},{"name":"ptype","in":"query","required":false,"description":"Post type.","schema":{"type":"string","enum":["post","story","reel"]}},{"name":"label","in":"query","required":false,"description":"Content label.","schema":{"type":"string","enum":["promo","edu","engage","bts","seasonal","other"]}},{"name":"image","in":"query","required":false,"description":"Hosted image URL.","schema":{"type":"string","maxLength":500}},{"name":"video","in":"query","required":false,"description":"Hosted video URL.","schema":{"type":"string","maxLength":500}},{"name":"link","in":"query","required":false,"description":"Link.","schema":{"type":"string","maxLength":500}},{"name":"scheduledAt","in":"query","required":false,"description":"Intended time (ISO 8601), stored only.","schema":{"type":"string","maxLength":40}},{"name":"status","in":"query","required":false,"description":"draft or pending.","schema":{"type":"string","enum":["draft","pending"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"updated":{"type":"boolean","description":"Always true on success."},"post":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"A social calendar post."},"targetType":{"type":"string","enum":["social_post"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Post id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","updated","post","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/posts/{id}/status":{"post":{"operationId":"set_social_post_status","summary":"Move a post between draft, pending (client approval) and rejected","description":"Move a post between draft, pending (client approval) and rejected. Setting draft also un-schedules it. Use schedule_social_post / publish_social_post to go live.\n\nRequired scope: `social.write`. Risk level: `write`.","tags":["social"],"security":[{"bearerAuth":["social.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Post id.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":true,"description":"Target status.","schema":{"type":"string","enum":["draft","pending","rejected"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"post":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"A social calendar post."},"targetType":{"type":"string","enum":["social_post"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Post id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","post","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/posts/{id}/schedule":{"post":{"operationId":"schedule_social_post","summary":"Arm a post to publish automatically at scheduledAt on its channels","description":"Arm a post to publish automatically at scheduledAt on its channels. PREVIEW FIRST: without confirm it shows the post, channels and time. If the workspace requires client approval, the post goes to pending instead.\n\nRequired scope: `social.publish`. Risk level: `high`.","tags":["social"],"security":[{"bearerAuth":["social.publish"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Post id.","schema":{"type":"string","maxLength":60}},{"name":"scheduledAt","in":"query","required":true,"description":"ISO 8601 date-time in the future.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willSchedule":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"Preview only: the post that would be scheduled."},"at":{"type":"string","description":"Preview only: scheduled time, ISO 8601."},"channels":{"type":"array","items":{"type":"string","description":"Channel."},"description":"Preview only: channels it will go to."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"scheduled":{"type":"boolean","description":"Run only: true when scheduled (false when approval-gated)."},"pendingApproval":{"type":"boolean","description":"Run only: true when it now waits for client approval instead."},"post":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"Run only: the post after the status change."},"targetType":{"type":"string","enum":["social_post"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Post id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/posts/{id}/publish":{"post":{"operationId":"publish_social_post","summary":"Publish a post NOW to the connected Facebook Page / Instagram / LinkedIn / Groups / TikTok","description":"Publish a post NOW to the connected Facebook Page / Instagram / LinkedIn / Groups / TikTok. PREVIEW FIRST: without confirm it shows exactly what goes where. Cannot be recalled by this tool.\n\nRequired scope: `social.publish`. Risk level: `high`.","tags":["social"],"security":[{"bearerAuth":["social.publish"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Post id.","schema":{"type":"string","maxLength":60}},{"name":"channels","in":"query","required":false,"description":"Override the post's channels.","schema":{"type":"array","maxItems":5,"items":{"type":"string"}}},{"name":"pageId","in":"query","required":false,"description":"Facebook Page id to publish from (default: the focused/first page).","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willPublish":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"Preview only: the post that would be published."},"channels":{"type":"array","items":{"type":"string","description":"Channel."},"description":"Preview only: channels it will publish to."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"published":{"type":"boolean","description":"Run only: true when at least one channel succeeded."},"results":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"ok":{"type":"boolean","description":"true when that channel published."},"id":{"type":"string","description":"Network post id."},"url":{"type":"string","description":"Public URL of the live post."},"error":{"type":"string","description":"Failure reason when ok=false."},"note":{"type":"string","description":"Extra note from the network."},"group":{"type":"string","description":"Facebook group name (groups channel)."},"kind":{"type":"string","description":"e.g. \"reel\"."},"demo":{"type":"boolean","description":"true when the LinkedIn post was simulated."},"pending":{"type":"boolean","description":"TikTok: true while the network is still processing."}},"additionalProperties":true,"required":["channel","ok"]},"description":"Run only: one result per channel attempted."},"targetType":{"type":"string","enum":["social_post"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Post id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/social/posts/{id}/delete":{"post":{"operationId":"delete_social_post","summary":"Remove a post from the calendar","description":"Remove a post from the calendar. PREVIEW FIRST. For a published post only the calendar record is removed — the live post stays on the network.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Post id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willDelete":{"type":"object","properties":{"id":{"type":"string","description":"Post id."},"status":{"type":"string","description":"draft | pending | scheduled | published | rejected."},"title":{"type":"string","description":"Internal title."},"headline":{"type":"string","description":"Headline."},"copy":{"type":"string","description":"Post text (max 2200 chars)."},"cta":{"type":"string","description":"Call to action."},"hashtags":{"type":"array","items":{"type":"string","description":"Hashtag."},"description":"Hashtags."},"channels":{"type":"array","items":{"type":"string","description":"facebook | instagram | linkedin | groups | tiktok."},"description":"Target channels."},"lang":{"type":"string","description":"Language code, e.g. en, he."},"format":{"type":"string","description":"image | video | carousel | text."},"ptype":{"type":"string","description":"post | story | reel."},"label":{"type":"string","description":"Variant label (safe/creative/rtm) or \"\"."},"image":{"type":"string","description":"Image URL or \"\"."},"video":{"type":"string","description":"Video URL or \"\"."},"link":{"type":"string","description":"Link URL or \"\"."},"pageName":{"type":"string","description":"Connected page name or \"\"."},"scheduledAt":{"type":"string","description":"ISO 8601 or \"\"."},"publishedAt":{"type":"string","description":"ISO 8601 or \"\"."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"updatedAt":{"type":"string","description":"ISO 8601 or \"\"."},"clientApproved":{"type":"boolean","description":"Client approval flag."},"stats":{"type":"object","properties":{"reach":{"type":"number","description":"Reach."},"impressions":{"type":"number","description":"Impressions."},"engagement":{"type":"number","description":"Engagement count."},"clicks":{"type":"number","description":"Clicks."},"likes":{"type":"number","description":"Likes."},"comments":{"type":"number","description":"Comments."}},"additionalProperties":true,"description":"Live network stats when available."},"leads":{"type":"number","description":"Leads attributed to the post."}},"additionalProperties":true,"required":["id","status","title","headline","copy","cta","hashtags","channels","lang","format","ptype","label","image","video","link","pageName","scheduledAt","publishedAt","createdAt","updatedAt","clientApproved","leads"],"description":"Preview only: the post that would be removed."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"deleted":{"type":"boolean","description":"Run only: true on success."},"id":{"type":"string","description":"Run only: deleted post id."},"targetType":{"type":"string","enum":["social_post"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Post id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/coupons":{"get":{"operationId":"list_coupons","summary":"Coupons defined for the connected stores with their stats: codes issued, redeemed, attributed revenue, unused pool size (unique-code coupons), status and expiry","description":"Coupons defined for the connected stores with their stats: codes issued, redeemed, attributed revenue, unused pool size (unique-code coupons), status and expiry.\n\nRequired scope: `coupons.read`. Risk level: `read`.","tags":["coupons"],"security":[{"bearerAuth":["coupons.read"]}],"parameters":[{"name":"siteId","in":"query","required":false,"description":"Only coupons of this store (from list_stores).","schema":{"type":"string","maxLength":80}},{"name":"status","in":"query","required":false,"description":"active or paused.","schema":{"type":"string","enum":["active","paused"]}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"coupons":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Coupon id (cpn_…)."},"name":{"type":"string","description":"Coupon token name."},"siteId":{"type":"string","description":"Store (site) id."},"mode":{"type":"string","enum":["shared","unique"],"description":"shared = one code; unique = per-contact codes."},"type":{"type":"string","enum":["percent","fixed"],"description":"Discount type."},"value":{"type":"number","description":"Discount value (% or store currency)."},"minOrder":{"type":"number","description":"Minimum order amount, 0 = none."},"expiry":{"type":"object","properties":{"kind":{"type":"string","enum":["none","date","days"],"description":"Expiry kind."},"date":{"type":"string","description":"YYYY-MM-DD when kind=date."},"days":{"type":"integer","description":"Days valid after issue when kind=days."}},"additionalProperties":true,"required":["kind"],"description":"Expiry rule."},"code":{"type":"string","description":"The shared code (shared mode only)."},"prefix":{"type":"string","description":"Code prefix."},"usageLimit":{"type":"integer","description":"Max uses per code, 0 = unlimited."},"status":{"type":"string","enum":["active","paused"],"description":"Coupon status."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"stats":{"type":"object","properties":{"issued":{"type":"integer","description":"Codes issued."},"redeemed":{"type":"integer","description":"Codes redeemed."},"revenue":{"type":"number","description":"Revenue attributed, store currency, 2 decimals."}},"additionalProperties":true,"required":["issued","redeemed","revenue"],"description":"Usage totals."},"unusedCodesInPool":{"type":"integer","description":"Unused pre-generated codes (unique mode)."}},"additionalProperties":true,"required":["id","name","siteId","mode","type","value","minOrder","expiry","prefix","usageLimit","status","createdAt","stats"],"description":"A coupon definition."},"description":"Coupon definitions (filtered by siteId/status)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","coupons","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_coupon","summary":"Create a coupon on a connected store (WooCommerce/Shopify): shared (one code for everyone) or unique (a pool of one-per-contact codes, usable as {{coupon","description":"Create a coupon on a connected store (WooCommerce/Shopify): shared (one code for everyone) or unique (a pool of one-per-contact codes, usable as {{coupon.NAME}} in emails/SMS). Registers the code(s) in the store. The store must already be connected for coupons in the app.\n\nRequired scope: `coupons.write`. Risk level: `write`.","tags":["coupons"],"security":[{"bearerAuth":["coupons.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Token name (letters/numbers/underscore), e.g. SPRING20.","schema":{"type":"string","maxLength":40}},{"name":"siteId","in":"query","required":true,"description":"Store id from list_stores.","schema":{"type":"string","maxLength":80}},{"name":"mode","in":"query","required":false,"description":"shared (default) or unique.","schema":{"type":"string","enum":["shared","unique"]}},{"name":"type","in":"query","required":false,"description":"percent (default) or fixed amount.","schema":{"type":"string","enum":["percent","fixed"]}},{"name":"value","in":"query","required":true,"description":"Discount value.","schema":{"type":"number","minimum":0.01,"maximum":100000}},{"name":"minOrder","in":"query","required":false,"description":"Minimum order total.","schema":{"type":"number","minimum":0,"maximum":1000000}},{"name":"expiresOn","in":"query","required":false,"description":"Fixed expiry date YYYY-MM-DD.","schema":{"type":"string","maxLength":10}},{"name":"validDays","in":"query","required":false,"description":"Alternatively: valid this many days after issue.","schema":{"type":"integer","minimum":1,"maximum":365}},{"name":"code","in":"query","required":false,"description":"Shared mode: the exact code (default = name).","schema":{"type":"string","maxLength":30}},{"name":"prefix","in":"query","required":false,"description":"Unique mode: code prefix.","schema":{"type":"string","maxLength":12}},{"name":"usageLimit","in":"query","required":false,"description":"Max uses per code (0 = unlimited).","schema":{"type":"integer","minimum":0,"maximum":100000}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"created":{"type":"boolean","description":"Always true on success."},"coupon":{"type":"object","properties":{"id":{"type":"string","description":"Coupon id (cpn_…)."},"name":{"type":"string","description":"Coupon token name."},"siteId":{"type":"string","description":"Store (site) id."},"mode":{"type":"string","enum":["shared","unique"],"description":"shared = one code; unique = per-contact codes."},"type":{"type":"string","enum":["percent","fixed"],"description":"Discount type."},"value":{"type":"number","description":"Discount value (% or store currency)."},"minOrder":{"type":"number","description":"Minimum order amount, 0 = none."},"expiry":{"type":"object","properties":{"kind":{"type":"string","enum":["none","date","days"],"description":"Expiry kind."},"date":{"type":"string","description":"YYYY-MM-DD when kind=date."},"days":{"type":"integer","description":"Days valid after issue when kind=days."}},"additionalProperties":true,"required":["kind"],"description":"Expiry rule."},"code":{"type":"string","description":"The shared code (shared mode only)."},"prefix":{"type":"string","description":"Code prefix."},"usageLimit":{"type":"integer","description":"Max uses per code, 0 = unlimited."},"status":{"type":"string","enum":["active","paused"],"description":"Coupon status."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"stats":{"type":"object","properties":{"issued":{"type":"integer","description":"Codes issued."},"redeemed":{"type":"integer","description":"Codes redeemed."},"revenue":{"type":"number","description":"Revenue attributed, store currency, 2 decimals."}},"additionalProperties":true,"required":["issued","redeemed","revenue"],"description":"Usage totals."},"unusedCodesInPool":{"type":"integer","description":"Unused pre-generated codes (unique mode)."}},"additionalProperties":true,"required":["id","name","siteId","mode","type","value","minOrder","expiry","prefix","usageLimit","status","createdAt","stats"],"description":"The new coupon; unusedCodesInPool = codes pre-generated (unique mode)."},"targetType":{"type":"string","enum":["coupon"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"New coupon id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","created","coupon","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/coupons/{id}/status":{"post":{"operationId":"set_coupon_status","summary":"Pause a coupon (stops issuing new codes; existing codes keep working in the store) or re-activate it","description":"Pause a coupon (stops issuing new codes; existing codes keep working in the store) or re-activate it.\n\nRequired scope: `coupons.write`. Risk level: `write`.","tags":["coupons"],"security":[{"bearerAuth":["coupons.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Coupon id.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":true,"description":"active or paused.","schema":{"type":"string","enum":["active","paused"]}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"id":{"type":"string","description":"Coupon id."},"status":{"type":"string","enum":["active","paused"],"description":"New status."},"targetType":{"type":"string","enum":["coupon"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Coupon id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","id","status","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/coupons/{id}/issue":{"post":{"operationId":"issue_coupon_code","summary":"Get the code for one contact: shared coupons return the shared code; unique coupons reserve a code for that email (idempotent — the same contact always gets the same code)","description":"Get the code for one contact: shared coupons return the shared code; unique coupons reserve a code for that email (idempotent — the same contact always gets the same code).\n\nRequired scope: `coupons.write`. Risk level: `write`.","tags":["coupons"],"security":[{"bearerAuth":["coupons.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Coupon id.","schema":{"type":"string","maxLength":60}},{"name":"email","in":"query","required":true,"description":"Contact email the code is for.","schema":{"type":"string","maxLength":160}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"code":{"type":"string","description":"The coupon code for that contact."},"note":{"type":"string","description":"Whether the code is shared or reserved for the contact."},"targetType":{"type":"string","enum":["coupon"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Coupon id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","code","note","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/coupons/{id}/delete":{"post":{"operationId":"delete_coupon","summary":"Delete a coupon definition and its unused code pool","description":"Delete a coupon definition and its unused code pool. PREVIEW FIRST. Codes already registered in the store are left untouched (so codes already in inboxes keep working).\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Coupon id.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willDelete":{"type":"object","properties":{"id":{"type":"string","description":"Coupon id (cpn_…)."},"name":{"type":"string","description":"Coupon token name."},"siteId":{"type":"string","description":"Store (site) id."},"mode":{"type":"string","enum":["shared","unique"],"description":"shared = one code; unique = per-contact codes."},"type":{"type":"string","enum":["percent","fixed"],"description":"Discount type."},"value":{"type":"number","description":"Discount value (% or store currency)."},"minOrder":{"type":"number","description":"Minimum order amount, 0 = none."},"expiry":{"type":"object","properties":{"kind":{"type":"string","enum":["none","date","days"],"description":"Expiry kind."},"date":{"type":"string","description":"YYYY-MM-DD when kind=date."},"days":{"type":"integer","description":"Days valid after issue when kind=days."}},"additionalProperties":true,"required":["kind"],"description":"Expiry rule."},"code":{"type":"string","description":"The shared code (shared mode only)."},"prefix":{"type":"string","description":"Code prefix."},"usageLimit":{"type":"integer","description":"Max uses per code, 0 = unlimited."},"status":{"type":"string","enum":["active","paused"],"description":"Coupon status."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."},"stats":{"type":"object","properties":{"issued":{"type":"integer","description":"Codes issued."},"redeemed":{"type":"integer","description":"Codes redeemed."},"revenue":{"type":"number","description":"Revenue attributed, store currency, 2 decimals."}},"additionalProperties":true,"required":["issued","redeemed","revenue"],"description":"Usage totals."},"unusedCodesInPool":{"type":"integer","description":"Unused pre-generated codes (unique mode)."}},"additionalProperties":true,"required":["id","name","siteId","mode","type","value","minOrder","expiry","prefix","usageLimit","status","createdAt","stats"],"description":"Preview only: the coupon that would be deleted."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"deleted":{"type":"boolean","description":"Run only: true on success."},"id":{"type":"string","description":"Run only: deleted coupon id."},"note":{"type":"string","description":"Run only: what happened to codes already in the store."},"targetType":{"type":"string","enum":["coupon"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Coupon id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/meetings/pages":{"get":{"operationId":"list_booking_pages","summary":"The user's public booking pages (/book/{slug}): title, duration, buffer, availability windows per weekday (0=Sunday), horizon and public URL","description":"The user's public booking pages (/book/{slug}): title, duration, buffer, availability windows per weekday (0=Sunday), horizon and public URL.\n\nRequired scope: `meetings.read`. Risk level: `read`.","tags":["meetings"],"security":[{"bearerAuth":["meetings.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"pages":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/book/{slug}."},"title":{"type":"string","description":"Page title."},"description":{"type":"string","description":"Description or \"\"."},"durationMin":{"type":"number","description":"Meeting length in minutes."},"bufferMin":{"type":"number","description":"Buffer between meetings, minutes."},"daysAhead":{"type":"number","description":"How many days ahead can be booked."},"timezone":{"type":"string","description":"IANA timezone, default Asia/Jerusalem."},"availability":{"type":"object","additionalProperties":true,"description":"Weekday (0=Sun…6=Sat) → array of [start \"HH:MM\", end \"HH:MM\"] windows."},"active":{"type":"boolean","description":"false when the page is switched off."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["slug","url","title","description","bufferMin","timezone","availability","active","createdAt"],"description":"A public booking page."},"description":"Booking pages of this workspace."}},"additionalProperties":true,"required":["ok","requestId","pages"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"save_booking_page","summary":"Create or update a booking page (pass an existing slug to update)","description":"Create or update a booking page (pass an existing slug to update). availability maps weekday (0=Sunday…6=Saturday) to up to 3 [from, to] windows in HH:MM, Israel time; default Sun-Thu 09:00-17:00. Returns the public /book/ URL.\n\nRequired scope: `meetings.write`. Risk level: `write`.","tags":["meetings"],"security":[{"bearerAuth":["meetings.write"]}],"parameters":[{"name":"title","in":"query","required":true,"description":"Page title, e.g. \"Intro call\".","schema":{"type":"string","maxLength":120}},{"name":"slug","in":"query","required":false,"description":"URL slug (a-z, 0-9, dashes). Default: derived from the title.","schema":{"type":"string","maxLength":60}},{"name":"description","in":"query","required":false,"description":"Shown to invitees.","schema":{"type":"string","maxLength":300}},{"name":"durationMin","in":"query","required":false,"description":"Meeting length in minutes (10-240, default 30).","schema":{"type":"integer","minimum":10,"maximum":240}},{"name":"bufferMin","in":"query","required":false,"description":"Gap after each meeting (0-120).","schema":{"type":"integer","minimum":0,"maximum":120}},{"name":"daysAhead","in":"query","required":false,"description":"How far ahead invitees may book (1-60, default 30).","schema":{"type":"integer","minimum":1,"maximum":60}},{"name":"availability","in":"query","required":false,"description":"e.g. {\"0\":[[\"09:00\",\"13:00\"]],\"1\":[[\"09:00\",\"17:00\"]]}","schema":{"type":"string"}},{"name":"active","in":"query","required":false,"description":"false hides the page without deleting it.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"saved":{"type":"boolean","description":"Always true on success."},"page":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/book/{slug}."},"title":{"type":"string","description":"Page title."},"description":{"type":"string","description":"Description or \"\"."},"durationMin":{"type":"number","description":"Meeting length in minutes."},"bufferMin":{"type":"number","description":"Buffer between meetings, minutes."},"daysAhead":{"type":"number","description":"How many days ahead can be booked."},"timezone":{"type":"string","description":"IANA timezone, default Asia/Jerusalem."},"availability":{"type":"object","additionalProperties":true,"description":"Weekday (0=Sun…6=Sat) → array of [start \"HH:MM\", end \"HH:MM\"] windows."},"active":{"type":"boolean","description":"false when the page is switched off."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["slug","url","title","description","bufferMin","timezone","availability","active","createdAt"],"description":"A public booking page."},"url":{"type":"string","description":"Public booking URL."},"targetType":{"type":"string","enum":["booking_page"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Page slug."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","saved","page","url","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/meetings/bookings":{"get":{"operationId":"list_bookings","summary":"Meetings booked through the booking pages: who, when, for which page, status (confirmed / cancelled)","description":"Meetings booked through the booking pages: who, when, for which page, status (confirmed / cancelled). Soonest first; upcomingOnly hides past meetings.\n\nRequired scope: `meetings.read`. Risk level: `read`.","tags":["meetings"],"security":[{"bearerAuth":["meetings.read"]}],"parameters":[{"name":"status","in":"query","required":false,"description":"confirmed or cancelled.","schema":{"type":"string","enum":["confirmed","cancelled"]}},{"name":"upcomingOnly","in":"query","required":false,"description":"Only meetings in the future.","schema":{"type":"boolean","default":false}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"bookings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Booking id."},"pageSlug":{"type":"string","description":"Booking page slug."},"pageTitle":{"type":"string","description":"Booking page title or \"\"."},"start":{"type":"string","description":"Meeting start, ISO 8601."},"durationMin":{"type":"number","description":"Duration in minutes."},"name":{"type":"string","description":"Invitee name."},"email":{"type":"string","description":"Invitee email."},"phone":{"type":"string","description":"Invitee phone."},"note":{"type":"string","description":"Invitee note."},"status":{"type":"string","description":"confirmed (default) or cancelled."},"bookedAt":{"type":"string","description":"ISO 8601 when booked, or \"\"."}},"additionalProperties":true,"required":["id","pageSlug","pageTitle","start","durationMin","name","email","phone","note","status","bookedAt"],"description":"A booked meeting."},"description":"Bookings sorted by start time (filtered by status/upcomingOnly)."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","bookings","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/meetings/bookings/{id}/cancel":{"post":{"operationId":"cancel_booking","summary":"Cancel a booked meeting and free its slot","description":"Cancel a booked meeting and free its slot. PREVIEW FIRST. The invitee is not notified automatically.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Booking id from list_bookings.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willCancel":{"type":"object","properties":{"id":{"type":"string","description":"Booking id."},"pageSlug":{"type":"string","description":"Booking page slug."},"pageTitle":{"type":"string","description":"Booking page title or \"\"."},"start":{"type":"string","description":"Meeting start, ISO 8601."},"durationMin":{"type":"number","description":"Duration in minutes."},"name":{"type":"string","description":"Invitee name."},"email":{"type":"string","description":"Invitee email."},"phone":{"type":"string","description":"Invitee phone."},"note":{"type":"string","description":"Invitee note."},"status":{"type":"string","description":"confirmed (default) or cancelled."},"bookedAt":{"type":"string","description":"ISO 8601 when booked, or \"\"."}},"additionalProperties":true,"required":["id","pageSlug","pageTitle","start","durationMin","name","email","phone","note","status","bookedAt"],"description":"Preview only: the booking that would be cancelled."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"cancelled":{"type":"boolean","description":"Run only: true on success."},"id":{"type":"string","description":"Run only: cancelled booking id."},"targetType":{"type":"string","enum":["booking"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Booking id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/meetings/pages/{slug}/delete":{"post":{"operationId":"delete_booking_page","summary":"Delete a booking page (its public link stops working)","description":"Delete a booking page (its public link stops working). PREVIEW FIRST. Existing bookings are kept.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"slug","in":"path","required":true,"description":"Page slug.","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"willDelete":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug."},"url":{"type":"string","description":"Public URL https://app.fortvision.com/book/{slug}."},"title":{"type":"string","description":"Page title."},"description":{"type":"string","description":"Description or \"\"."},"durationMin":{"type":"number","description":"Meeting length in minutes."},"bufferMin":{"type":"number","description":"Buffer between meetings, minutes."},"daysAhead":{"type":"number","description":"How many days ahead can be booked."},"timezone":{"type":"string","description":"IANA timezone, default Asia/Jerusalem."},"availability":{"type":"object","additionalProperties":true,"description":"Weekday (0=Sun…6=Sat) → array of [start \"HH:MM\", end \"HH:MM\"] windows."},"active":{"type":"boolean","description":"false when the page is switched off."},"createdAt":{"type":"string","description":"ISO 8601 or \"\"."}},"additionalProperties":true,"required":["slug","url","title","description","bufferMin","timezone","availability","active","createdAt"],"description":"Preview only: the page that would be deleted."},"warning":{"type":"string","description":"Preview only: consequences of confirming."},"deleted":{"type":"boolean","description":"Run only: true on success."},"slug":{"type":"string","description":"Run only: deleted page slug."},"targetType":{"type":"string","enum":["booking_page"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Page slug."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/automations/{id}/enabled":{"post":{"operationId":"set_automation_enabled","summary":"Enable or pause an automation (journey)","description":"Enable or pause an automation (journey). Pausing stops the live run too — no new contacts enter and in-flight steps hold — and is fully reversible by enabling again. Does not edit the flow itself; use list_automations / get_automation to pick the id.\n\nRequired scope: `agents.write`. Risk level: `write`.","tags":["agents"],"security":[{"bearerAuth":["agents.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Automation id.","schema":{"type":"string","maxLength":60}},{"name":"enabled","in":"query","required":true,"description":"true to enable, false to pause.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"id":{"type":"string","description":"Automation id."},"name":{"type":"string","description":"Automation name (\"\" if unnamed)."},"enabled":{"type":"boolean","description":"State after the call."},"wasEnabled":{"type":"boolean","description":"State before the call."},"livePaused":{"type":"boolean","description":"When reported: true if in-flight journey runs were paused too."},"targetType":{"type":"string","enum":["automation"],"description":"Entity type of the affected record."},"targetId":{"type":"string","description":"Automation id."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","id","name","enabled","wasEnabled","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes":{"get":{"operationId":"list_quotes","summary":"Price quotes in this workspace, newest first, optionally only those of one contact (any contact identifier), company or deal, by status, or matching a text query (number, title, customer)","description":"Price quotes in this workspace, newest first, optionally only those of one contact (any contact identifier), company or deal, by status, or matching a text query (number, title, customer). Each row carries the quote id, number, status (draft / sent / viewed / accepted / declined / expired), total, the customer it belongs to and its customer link (url). Call get_quote for items, totals breakdown and the event log.\n\nRequired scope: `quotes.read`. Risk level: `read`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.read"]}],"parameters":[{"name":"contactId","in":"query","required":false,"description":"Only quotes of this contact: a record id (contactId from list_contacts_in_list) or a contact id from search_contacts.","schema":{"type":"string","maxLength":200}},{"name":"companyId","in":"query","required":false,"description":"Only quotes of this company (list_companies).","schema":{"type":"string","maxLength":40}},{"name":"dealId","in":"query","required":false,"description":"Only quotes of this deal (list_deals).","schema":{"type":"string","maxLength":40}},{"name":"status","in":"query","required":false,"description":"Only quotes in this effective status.","schema":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"]}},{"name":"query","in":"query","required":false,"description":"Text to match against number, title and customer name / e-mail.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"quotes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl"]},"description":"Quotes on this page, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list."},"statusCounts":{"type":"object","additionalProperties":true,"description":"Count of ALL the workspace's quotes per effective status (before filters)."}},"additionalProperties":true,"required":["ok","requestId","quotes","pagination","statusCounts"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_quote","summary":"Create a price quote as a DRAFT on an existing CRM record — a contact (contactId = the record id from list_contacts_in_list / search_contacts / get_contact), a company and/or a deal","description":"Create a price quote as a DRAFT on an existing CRM record — a contact (contactId = the record id from list_contacts_in_list / search_contacts / get_contact), a company and/or a deal. It is saved in the app's own quote store with the next quote number and the customer's details prefilled (name, e-mail, phone, linked company; a deal's line items), so it appears on that record's Quotes card in the app immediately. Returns the quote, its customer link (url), previewUrl and printUrl (PDF view). Nothing is sent — use send_quote when the user asks. Line items replace nothing (new quote). Recurring services: pass months on the item. Defaults (currency, VAT, validity, terms, intro, layout, language) come from get_quote_settings unless overridden here. Pass an idempotencyKey so a retry cannot create two quotes.\n\nRequired scope: `quotes.write`. Risk level: `write`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.write"]}],"parameters":[{"name":"contactId","in":"query","required":false,"description":"The customer's record id (contactId from list_contacts_in_list, or a contact id from search_contacts — its newest record is used). Required unless companyId or dealId is given.","schema":{"type":"string","maxLength":200}},{"name":"companyId","in":"query","required":false,"description":"Company id from list_companies (optional; inferred from the contact's linked company when omitted).","schema":{"type":"string","maxLength":40}},{"name":"dealId","in":"query","required":false,"description":"Deal id from list_deals (optional; the deal's line items prefill the quote when items is omitted).","schema":{"type":"string","maxLength":40}},{"name":"title","in":"query","required":false,"description":"Quote title / subject, e.g. \"אתר תדמית + אחזקה\".","schema":{"type":"string","maxLength":160}},{"name":"items","in":"query","required":false,"description":"Lines: [{ name, description?, sku?, quantity (default 1), unitPrice, discountPct? (0-100), months? }]. months = recurring: quantity = months, unitPrice = the monthly amount. Required unless a deal with line items is given.","schema":{"type":"array","maxItems":100,"items":{"type":"object"}}},{"name":"currency","in":"query","required":false,"description":"3-letter ISO currency (ILS, USD, EUR…); default = workspace setting.","schema":{"type":"string","maxLength":3}},{"name":"lang","in":"query","required":false,"description":"Document language: he (Hebrew, right-to-left) or en. Default = workspace setting.","schema":{"type":"string","enum":["he","en"]}},{"name":"discountType","in":"query","required":false,"description":"Quote-level discount kind (default percent).","schema":{"type":"string","enum":["percent","amount"]}},{"name":"discountValue","in":"query","required":false,"description":"Quote-level discount value (% or amount).","schema":{"type":"number","minimum":0}},{"name":"taxPct","in":"query","required":false,"description":"VAT percent for this quote; default = workspace setting.","schema":{"type":"number","minimum":0,"maximum":100}},{"name":"taxIncluded","in":"query","required":false,"description":"true when unit prices already include VAT.","schema":{"type":"boolean"}},{"name":"validUntil","in":"query","required":false,"description":"Validity date yyyy-mm-dd (default: today + the workspace's validDays).","schema":{"type":"string","maxLength":10}},{"name":"validDays","in":"query","required":false,"description":"Alternative to validUntil: valid for this many days from today.","schema":{"type":"integer","minimum":1,"maximum":365}},{"name":"intro","in":"query","required":false,"description":"Intro paragraph addressed to the customer (default from settings).","schema":{"type":"string","maxLength":1500}},{"name":"terms","in":"query","required":false,"description":"Terms text (default from settings).","schema":{"type":"string","maxLength":4000}},{"name":"notes","in":"query","required":false,"description":"Notes (delivery time, exclusions…).","schema":{"type":"string","maxLength":2000}},{"name":"payLink","in":"query","required":false,"description":"Payment link shown on the customer page (https).","schema":{"type":"string","maxLength":500}},{"name":"billTo","in":"query","required":false,"description":"Override the bill-to block: { name, company, email, phone, address, vatId }. Prefilled from the record.","schema":{"type":"string"}},{"name":"layout","in":"query","required":false,"description":"Document layout.","schema":{"type":"string","enum":["modern","classic","minimal"]}},{"name":"accent","in":"query","required":false,"description":"Accent colour hex (#rrggbb).","schema":{"type":"string","maxLength":7}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["quote"],"description":"Always quote."},"targetId":{"type":"string","description":"The new quote id."},"created":{"type":"boolean","description":"Always true on success."},"verified":{"type":"boolean","description":"true when the read-back shows a draft with the same lines and links."},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Line id (li_…), stable across edits when passed back."},"name":{"type":"string","description":"Line name."},"description":{"type":"string","description":"Line description (\"\" when none)."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (months for a recurring line)."},"unitPrice":{"type":"number","description":"Unit price in the quote currency."},"discountPct":{"type":"number","description":"Line discount percent (0-100)."},"amount":{"type":"number","description":"quantity × unitPrice × (1 − discountPct/100), rounded to 2 decimals."}},"additionalProperties":true,"required":["id","name","description","sku","quantity","unitPrice","discountPct","amount"]},"description":"Line items."},"discountType":{"type":"string","enum":["percent","amount"],"description":"Quote-level discount kind."},"discountValue":{"type":"number","description":"Quote-level discount value."},"taxPct":{"type":"number","description":"VAT percent."},"taxLabel":{"type":"string","description":"Tax line label (\"\" = language default)."},"taxIncluded":{"type":"boolean","description":"true when unit prices include VAT."},"totals":{"type":"object","properties":{"subtotal":{"type":"number","description":"Sum of line amounts."},"discount":{"type":"number","description":"Quote-level discount applied."},"net":{"type":"number","description":"subtotal − discount."},"tax":{"type":"number","description":"VAT on net (or the VAT contained in it when taxIncluded)."},"total":{"type":"number","description":"Amount payable."},"taxPct":{"type":"number","description":"VAT percent used."}},"additionalProperties":true,"required":["subtotal","discount","net","tax","total","taxPct"],"description":"Money math as lib/quoteDoc computeTotals does it (the editor, customer page and e-mail agree)."},"billTo":{"type":"object","properties":{"name":{"type":"string","description":"Customer name."},"company":{"type":"string","description":"Customer company."},"email":{"type":"string","description":"Customer e-mail."},"phone":{"type":"string","description":"Customer phone."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Customer tax id."}},"additionalProperties":true,"required":["name","company","email","phone","address","vatId"],"description":"Bill-to block."},"contactEmail":{"type":"string","description":"Linked contact e-mail."},"contactPhone":{"type":"string","description":"Linked contact phone."},"intro":{"type":"string","description":"Intro paragraph."},"terms":{"type":"string","description":"Terms text."},"notes":{"type":"string","description":"Notes."},"payLink":{"type":"string","description":"Payment link (\"\" when none)."},"preparedBy":{"type":"string","description":"Name shown as \"prepared by\"."},"design":{"type":"object","properties":{"layout":{"type":"string","description":"modern | classic | minimal."},"accent":{"type":"string","description":"Hex colour (\"\" = settings default)."}},"additionalProperties":true,"required":["layout","accent"],"description":"Layout and accent."},"createdBy":{"type":"string","description":"User e-mail."},"lastSentAt":{"type":"string","description":"ISO 8601 of the last send, \"\" when never."},"viewedAt":{"type":"string","description":"ISO 8601 of the first customer view, \"\" when none."},"acceptedBy":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Who accepted."},"manual":{"type":"boolean","description":"true when a user marked it accepted by hand."},"signed":{"type":"boolean","description":"true when an e-signature was drawn."}},"additionalProperties":true,"required":["name","manual","signed"],"description":"null until accepted."},"declinedAt":{"type":"string","description":"ISO 8601, \"\" when not declined."},"declineReason":{"type":"string","description":"Reason given, \"\" when none."},"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601."},"event":{"type":"string","description":"created | edited | duplicated | sent | viewed | accepted | declined | status:<x> (manual)."},"by":{"type":"string","description":"User e-mail, or the customer name for accepted / declined."},"to":{"type":"string","description":"sent: recipient."},"via":{"type":"string","description":"sent: platform | mailbox | whatsapp."},"from":{"type":"string","description":"duplicated: the source quote number."},"reason":{"type":"string","description":"declined: the reason given."},"signed":{"type":"boolean","description":"accepted: whether an e-signature was drawn."},"manual":{"type":"boolean","description":"true when a user set the status by hand."}},"additionalProperties":true,"required":["at","event","by"]},"description":"Event log, oldest first (last 40)."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl","items","discountType","discountValue","taxPct","taxLabel","taxIncluded","totals","billTo","contactEmail","contactPhone","intro","terms","notes","payLink","preparedBy","design","createdBy","lastSentAt","viewedAt","acceptedBy","declinedAt","declineReason","events"],"description":"The full quote."},"url":{"type":"string","description":"Customer link."},"previewUrl":{"type":"string","description":"Rep preview link (no view counted)."},"printUrl":{"type":"string","description":"Print / PDF view."},"linkedTo":{"type":"object","properties":{"contactId":{"type":"string","description":"Contact record id (\"\" when none)."},"contactName":{"type":"string","description":"Contact name."},"companyId":{"type":"string","description":"Company id."},"companyName":{"type":"string","description":"Company name."},"dealId":{"type":"string","description":"Deal id."},"dealName":{"type":"string","description":"Deal name."}},"additionalProperties":true,"required":["contactId","contactName","companyId","companyName","dealId","dealName"],"description":"The CRM records the quote hangs on."},"appLocation":{"type":"string","description":"Where the quote shows in the app."},"message":{"type":"string","description":"Summary for the user."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","verified","quote","url","previewUrl","printUrl","linkedTo","appLocation","message"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/{id}":{"get":{"operationId":"get_quote","summary":"One quote in full: line items (quantity, unit price, line discount, amount), quote-level discount, VAT (taxPct / taxIncluded), totals (subtotal, discount, net, tax, total), currency, language (he = RTL Hebrew document), validity, intro / terms / notes, the customer it belongs to, who prepared it, status, and the event log (created, edited, sent — to whom and how, viewed with view count, accepted — by whom, e-signed or not, declined with reason)","description":"One quote in full: line items (quantity, unit price, line discount, amount), quote-level discount, VAT (taxPct / taxIncluded), totals (subtotal, discount, net, tax, total), currency, language (he = RTL Hebrew document), validity, intro / terms / notes, the customer it belongs to, who prepared it, status, and the event log (created, edited, sent — to whom and how, viewed with view count, accepted — by whom, e-signed or not, declined with reason). Also its links: url (the customer page), previewUrl (does not count as a view), printUrl (print / PDF view).\n\nRequired scope: `quotes.read`. Risk level: `read`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id (from list_quotes / create_quote).","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Line id (li_…), stable across edits when passed back."},"name":{"type":"string","description":"Line name."},"description":{"type":"string","description":"Line description (\"\" when none)."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (months for a recurring line)."},"unitPrice":{"type":"number","description":"Unit price in the quote currency."},"discountPct":{"type":"number","description":"Line discount percent (0-100)."},"amount":{"type":"number","description":"quantity × unitPrice × (1 − discountPct/100), rounded to 2 decimals."}},"additionalProperties":true,"required":["id","name","description","sku","quantity","unitPrice","discountPct","amount"]},"description":"Line items."},"discountType":{"type":"string","enum":["percent","amount"],"description":"Quote-level discount kind."},"discountValue":{"type":"number","description":"Quote-level discount value."},"taxPct":{"type":"number","description":"VAT percent."},"taxLabel":{"type":"string","description":"Tax line label (\"\" = language default)."},"taxIncluded":{"type":"boolean","description":"true when unit prices include VAT."},"totals":{"type":"object","properties":{"subtotal":{"type":"number","description":"Sum of line amounts."},"discount":{"type":"number","description":"Quote-level discount applied."},"net":{"type":"number","description":"subtotal − discount."},"tax":{"type":"number","description":"VAT on net (or the VAT contained in it when taxIncluded)."},"total":{"type":"number","description":"Amount payable."},"taxPct":{"type":"number","description":"VAT percent used."}},"additionalProperties":true,"required":["subtotal","discount","net","tax","total","taxPct"],"description":"Money math as lib/quoteDoc computeTotals does it (the editor, customer page and e-mail agree)."},"billTo":{"type":"object","properties":{"name":{"type":"string","description":"Customer name."},"company":{"type":"string","description":"Customer company."},"email":{"type":"string","description":"Customer e-mail."},"phone":{"type":"string","description":"Customer phone."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Customer tax id."}},"additionalProperties":true,"required":["name","company","email","phone","address","vatId"],"description":"Bill-to block."},"contactEmail":{"type":"string","description":"Linked contact e-mail."},"contactPhone":{"type":"string","description":"Linked contact phone."},"intro":{"type":"string","description":"Intro paragraph."},"terms":{"type":"string","description":"Terms text."},"notes":{"type":"string","description":"Notes."},"payLink":{"type":"string","description":"Payment link (\"\" when none)."},"preparedBy":{"type":"string","description":"Name shown as \"prepared by\"."},"design":{"type":"object","properties":{"layout":{"type":"string","description":"modern | classic | minimal."},"accent":{"type":"string","description":"Hex colour (\"\" = settings default)."}},"additionalProperties":true,"required":["layout","accent"],"description":"Layout and accent."},"createdBy":{"type":"string","description":"User e-mail."},"lastSentAt":{"type":"string","description":"ISO 8601 of the last send, \"\" when never."},"viewedAt":{"type":"string","description":"ISO 8601 of the first customer view, \"\" when none."},"acceptedBy":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Who accepted."},"manual":{"type":"boolean","description":"true when a user marked it accepted by hand."},"signed":{"type":"boolean","description":"true when an e-signature was drawn."}},"additionalProperties":true,"required":["name","manual","signed"],"description":"null until accepted."},"declinedAt":{"type":"string","description":"ISO 8601, \"\" when not declined."},"declineReason":{"type":"string","description":"Reason given, \"\" when none."},"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601."},"event":{"type":"string","description":"created | edited | duplicated | sent | viewed | accepted | declined | status:<x> (manual)."},"by":{"type":"string","description":"User e-mail, or the customer name for accepted / declined."},"to":{"type":"string","description":"sent: recipient."},"via":{"type":"string","description":"sent: platform | mailbox | whatsapp."},"from":{"type":"string","description":"duplicated: the source quote number."},"reason":{"type":"string","description":"declined: the reason given."},"signed":{"type":"boolean","description":"accepted: whether an e-signature was drawn."},"manual":{"type":"boolean","description":"true when a user set the status by hand."}},"additionalProperties":true,"required":["at","event","by"]},"description":"Event log, oldest first (last 40)."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl","items","discountType","discountValue","taxPct","taxLabel","taxIncluded","totals","billTo","contactEmail","contactPhone","intro","terms","notes","payLink","preparedBy","design","createdBy","lastSentAt","viewedAt","acceptedBy","declinedAt","declineReason","events"],"description":"The full quote."}},"additionalProperties":true,"required":["ok","requestId","quote"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/settings":{"get":{"operationId":"get_quote_settings","summary":"The workspace's quote branding and defaults: seller block (business name, address, tax id, phone, e-mail, website, logo URL), default currency, VAT percent and whether prices include it, number prefix, default validity days, document language (he = Hebrew right-to-left, en), layout (modern / classic / minimal), accent colour, default intro / terms / notes, payment link and e-mail message","description":"The workspace's quote branding and defaults: seller block (business name, address, tax id, phone, e-mail, website, logo URL), default currency, VAT percent and whether prices include it, number prefix, default validity days, document language (he = Hebrew right-to-left, en), layout (modern / classic / minimal), accent colour, default intro / terms / notes, payment link and e-mail message. Also says whether server-side PDF rendering is configured on this deployment.\n\nRequired scope: `quotes.read`. Risk level: `read`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"settings":{"type":"object","properties":{"seller":{"type":"object","properties":{"name":{"type":"string","description":"Business name."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Tax id (ח.פ / ע.מ)."},"email":{"type":"string","description":"E-mail."},"phone":{"type":"string","description":"Phone."},"website":{"type":"string","description":"Website."},"logoUrl":{"type":"string","description":"Logo image URL (\"\" when none)."},"showNameWithLogo":{"type":"boolean","description":"Print the name next to the logo."}},"additionalProperties":true,"required":["name","address","vatId","email","phone","website","logoUrl","showNameWithLogo"],"description":"The business block printed on every quote."},"currency":{"type":"string","description":"Default currency."},"taxPct":{"type":"number","description":"Default VAT percent."},"taxLabel":{"type":"string","description":"Tax label override."},"taxIncluded":{"type":"boolean","description":"Prices include VAT by default."},"numberPrefix":{"type":"string","description":"Quote number prefix."},"validDays":{"type":"integer","description":"Default validity in days."},"lang":{"type":"string","enum":["he","en"],"description":"Default document language."},"layout":{"type":"string","description":"Default layout."},"accent":{"type":"string","description":"Default accent colour."},"intro":{"type":"string","description":"Default intro."},"terms":{"type":"string","description":"Default terms."},"notes":{"type":"string","description":"Default notes."},"payLink":{"type":"string","description":"Default payment link."},"emailMessage":{"type":"string","description":"Default e-mail message."}},"additionalProperties":true,"required":["seller","currency","taxPct","taxLabel","taxIncluded","numberPrefix","validDays","lang","layout","accent","intro","terms","notes","payLink","emailMessage"],"description":"Quote branding and defaults."},"layouts":{"type":"array","items":{"type":"string"},"description":"Available layouts."},"pdf":{"type":"string","description":"How PDF works on this deployment (print view vs server-rendered attachment)."},"rtl":{"type":"string","description":"How language / RTL and branding apply."}},"additionalProperties":true,"required":["ok","requestId","settings","layouts","pdf","rtl"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"update_quote_settings","summary":"Change the workspace's quote branding / defaults (see get_quote_settings)","description":"Change the workspace's quote branding / defaults (see get_quote_settings). Only the fields you pass change; existing quotes keep what they have — defaults apply to quotes created afterwards. The logo must be an https image URL (upload it in the app for a hosted one). Read back after saving; \"verified\" reports whether the store shows the new values.\n\nRequired scope: `quotes.write`. Risk level: `write`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.write"]}],"parameters":[{"name":"seller","in":"query","required":false,"description":"Seller block patch: { name, address, vatId, email, phone, website, logoUrl, showNameWithLogo }.","schema":{"type":"string"}},{"name":"currency","in":"query","required":false,"description":"Default 3-letter ISO currency (ILS, USD, EUR…).","schema":{"type":"string","maxLength":3}},{"name":"taxPct","in":"query","required":false,"description":"Default VAT percent (e.g. 18).","schema":{"type":"number","minimum":0,"maximum":100}},{"name":"taxLabel","in":"query","required":false,"description":"Label for the tax line (\"\" = the language default, מע״מ / Tax).","schema":{"type":"string","maxLength":30}},{"name":"taxIncluded","in":"query","required":false,"description":"true when unit prices already include VAT.","schema":{"type":"boolean"}},{"name":"numberPrefix","in":"query","required":false,"description":"Quote number prefix (Q → Q-0001).","schema":{"type":"string","maxLength":8}},{"name":"validDays","in":"query","required":false,"description":"Default validity in days.","schema":{"type":"integer","minimum":1,"maximum":365}},{"name":"lang","in":"query","required":false,"description":"Default document language.","schema":{"type":"string","enum":["he","en"]}},{"name":"layout","in":"query","required":false,"description":"Default layout.","schema":{"type":"string","enum":["modern","classic","minimal"]}},{"name":"accent","in":"query","required":false,"description":"Accent colour, hex like #3f76ff.","schema":{"type":"string","maxLength":7}},{"name":"intro","in":"query","required":false,"description":"Default intro paragraph.","schema":{"type":"string","maxLength":1500}},{"name":"terms","in":"query","required":false,"description":"Default terms.","schema":{"type":"string","maxLength":4000}},{"name":"notes","in":"query","required":false,"description":"Default notes.","schema":{"type":"string","maxLength":2000}},{"name":"payLink","in":"query","required":false,"description":"Default payment link (https), \"\" to clear.","schema":{"type":"string","maxLength":500}},{"name":"emailMessage","in":"query","required":false,"description":"Default message body of the quote e-mail.","schema":{"type":"string","maxLength":2000}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["quote_settings"],"description":"Always quote_settings."},"targetId":{"type":"string","description":"Always \"settings\"."},"updated":{"type":"boolean","description":"true when at least one value changed."},"changed":{"type":"array","items":{"type":"string"},"description":"Keys that changed."},"before":{"type":"object","properties":{"seller":{"type":"object","properties":{"name":{"type":"string","description":"Business name."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Tax id (ח.פ / ע.מ)."},"email":{"type":"string","description":"E-mail."},"phone":{"type":"string","description":"Phone."},"website":{"type":"string","description":"Website."},"logoUrl":{"type":"string","description":"Logo image URL (\"\" when none)."},"showNameWithLogo":{"type":"boolean","description":"Print the name next to the logo."}},"additionalProperties":true,"required":["name","address","vatId","email","phone","website","logoUrl","showNameWithLogo"],"description":"The business block printed on every quote."},"currency":{"type":"string","description":"Default currency."},"taxPct":{"type":"number","description":"Default VAT percent."},"taxLabel":{"type":"string","description":"Tax label override."},"taxIncluded":{"type":"boolean","description":"Prices include VAT by default."},"numberPrefix":{"type":"string","description":"Quote number prefix."},"validDays":{"type":"integer","description":"Default validity in days."},"lang":{"type":"string","enum":["he","en"],"description":"Default document language."},"layout":{"type":"string","description":"Default layout."},"accent":{"type":"string","description":"Default accent colour."},"intro":{"type":"string","description":"Default intro."},"terms":{"type":"string","description":"Default terms."},"notes":{"type":"string","description":"Default notes."},"payLink":{"type":"string","description":"Default payment link."},"emailMessage":{"type":"string","description":"Default e-mail message."}},"additionalProperties":true,"required":["seller","currency","taxPct","taxLabel","taxIncluded","numberPrefix","validDays","lang","layout","accent","intro","terms","notes","payLink","emailMessage"],"description":"Quote branding and defaults."},"after":{"type":"object","properties":{"seller":{"type":"object","properties":{"name":{"type":"string","description":"Business name."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Tax id (ח.פ / ע.מ)."},"email":{"type":"string","description":"E-mail."},"phone":{"type":"string","description":"Phone."},"website":{"type":"string","description":"Website."},"logoUrl":{"type":"string","description":"Logo image URL (\"\" when none)."},"showNameWithLogo":{"type":"boolean","description":"Print the name next to the logo."}},"additionalProperties":true,"required":["name","address","vatId","email","phone","website","logoUrl","showNameWithLogo"],"description":"The business block printed on every quote."},"currency":{"type":"string","description":"Default currency."},"taxPct":{"type":"number","description":"Default VAT percent."},"taxLabel":{"type":"string","description":"Tax label override."},"taxIncluded":{"type":"boolean","description":"Prices include VAT by default."},"numberPrefix":{"type":"string","description":"Quote number prefix."},"validDays":{"type":"integer","description":"Default validity in days."},"lang":{"type":"string","enum":["he","en"],"description":"Default document language."},"layout":{"type":"string","description":"Default layout."},"accent":{"type":"string","description":"Default accent colour."},"intro":{"type":"string","description":"Default intro."},"terms":{"type":"string","description":"Default terms."},"notes":{"type":"string","description":"Default notes."},"payLink":{"type":"string","description":"Default payment link."},"emailMessage":{"type":"string","description":"Default e-mail message."}},"additionalProperties":true,"required":["seller","currency","taxPct","taxLabel","taxIncluded","numberPrefix","validDays","lang","layout","accent","intro","terms","notes","payLink","emailMessage"],"description":"Quote branding and defaults."},"verified":{"type":"boolean","description":"true when the read-back shows every value you passed."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","changed","before","after","verified"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/preview":{"post":{"operationId":"preview_quote","summary":"Calculate a quote WITHOUT saving anything: per-line amounts, subtotal, quote-level discount, VAT and total, exactly as the app's editor and the customer page compute them (line = qty × unit price × (1 − line discount%); quote discount as % or amount on the subtotal; VAT on the net, or extracted when prices include it)","description":"Calculate a quote WITHOUT saving anything: per-line amounts, subtotal, quote-level discount, VAT and total, exactly as the app's editor and the customer page compute them (line = qty × unit price × (1 − line discount%); quote discount as % or amount on the subtotal; VAT on the net, or extracted when prices include it). Use it to show the customer's total before create_quote, or to check a change before update_quote. includeHtml returns the rendered document (Hebrew = RTL) for inspection.\n\nRequired scope: `quotes.read`. Risk level: `read`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.read"]}],"parameters":[{"name":"items","in":"query","required":true,"description":"Lines: [{ name, description?, sku?, quantity (default 1), unitPrice, discountPct? (0-100), months? }]. months = a recurring line: quantity becomes the number of months and unitPrice is the monthly amount.","schema":{"type":"array","maxItems":100,"items":{"type":"object"}}},{"name":"currency","in":"query","required":false,"description":"3-letter ISO currency; default = workspace setting.","schema":{"type":"string","maxLength":3}},{"name":"lang","in":"query","required":false,"description":"he (Hebrew, RTL) or en; default = workspace setting.","schema":{"type":"string","enum":["he","en"]}},{"name":"discountType","in":"query","required":false,"description":"Quote-level discount kind (default percent).","schema":{"type":"string","enum":["percent","amount"]}},{"name":"discountValue","in":"query","required":false,"description":"Quote-level discount (% or amount).","schema":{"type":"number","minimum":0}},{"name":"taxPct","in":"query","required":false,"description":"VAT percent; default = workspace setting.","schema":{"type":"number","minimum":0,"maximum":100}},{"name":"taxIncluded","in":"query","required":false,"description":"true when unit prices already include VAT.","schema":{"type":"boolean"}},{"name":"includeHtml","in":"query","required":false,"description":"true to also return the rendered document HTML.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"lang":{"type":"string","enum":["he","en"],"description":"Language used."},"currency":{"type":"string","description":"Currency used."},"rtl":{"type":"boolean","description":"true when the document renders right-to-left."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Line id (li_…), stable across edits when passed back."},"name":{"type":"string","description":"Line name."},"description":{"type":"string","description":"Line description (\"\" when none)."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (months for a recurring line)."},"unitPrice":{"type":"number","description":"Unit price in the quote currency."},"discountPct":{"type":"number","description":"Line discount percent (0-100)."},"amount":{"type":"number","description":"quantity × unitPrice × (1 − discountPct/100), rounded to 2 decimals."}},"additionalProperties":true,"required":["id","name","description","sku","quantity","unitPrice","discountPct","amount"]},"description":"Lines with computed amounts."},"discountType":{"type":"string","enum":["percent","amount"],"description":"Quote-level discount kind."},"discountValue":{"type":"number","description":"Quote-level discount value."},"taxPct":{"type":"number","description":"VAT percent used."},"taxIncluded":{"type":"boolean","description":"Prices include VAT."},"totals":{"type":"object","properties":{"subtotal":{"type":"number","description":"Sum of line amounts."},"discount":{"type":"number","description":"Quote-level discount applied."},"net":{"type":"number","description":"subtotal − discount."},"tax":{"type":"number","description":"VAT on net (or the VAT contained in it when taxIncluded)."},"total":{"type":"number","description":"Amount payable."},"taxPct":{"type":"number","description":"VAT percent used."}},"additionalProperties":true,"required":["subtotal","discount","net","tax","total","taxPct"],"description":"Money math as lib/quoteDoc computeTotals does it (the editor, customer page and e-mail agree)."},"totalFormatted":{"type":"string","description":"Total formatted for the language / currency (e.g. ‏12,000.00 ₪)."},"html":{"type":"string","description":"The rendered document (only with includeHtml)."}},"additionalProperties":true,"required":["ok","requestId","lang","currency","rtl","items","discountType","discountValue","taxPct","taxIncluded","totals","totalFormatted"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/{id}/update":{"post":{"operationId":"update_quote","summary":"Edit an existing quote: title, items (the list you pass REPLACES all lines — send the full list), discount, VAT, validity, intro / terms / notes, payment link, language, currency, layout, accent, bill-to, or re-link it to another contact / company / deal","description":"Edit an existing quote: title, items (the list you pass REPLACES all lines — send the full list), discount, VAT, validity, intro / terms / notes, payment link, language, currency, layout, accent, bill-to, or re-link it to another contact / company / deal. Only the fields you pass change. An accepted quote is locked (conflict) — duplicate_quote instead. The quote is read back after saving; \"verified\" reports whether the store shows the new values, and before/after give the totals.\n\nRequired scope: `quotes.write`. Risk level: `write`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id.","schema":{"type":"string","maxLength":40}},{"name":"title","in":"query","required":false,"description":"New title.","schema":{"type":"string","maxLength":160}},{"name":"items","in":"query","required":false,"description":"The COMPLETE new line list: [{ id? (keep an existing line id), name, description?, sku?, quantity, unitPrice, discountPct?, months? }].","schema":{"type":"array","maxItems":100,"items":{"type":"object"}}},{"name":"currency","in":"query","required":false,"description":"3-letter ISO currency.","schema":{"type":"string","maxLength":3}},{"name":"lang","in":"query","required":false,"description":"he or en.","schema":{"type":"string","enum":["he","en"]}},{"name":"discountType","in":"query","required":false,"description":"percent or amount.","schema":{"type":"string","enum":["percent","amount"]}},{"name":"discountValue","in":"query","required":false,"description":"Quote-level discount value.","schema":{"type":"number","minimum":0}},{"name":"taxPct","in":"query","required":false,"description":"VAT percent.","schema":{"type":"number","minimum":0,"maximum":100}},{"name":"taxIncluded","in":"query","required":false,"description":"true when unit prices include VAT.","schema":{"type":"boolean"}},{"name":"validUntil","in":"query","required":false,"description":"yyyy-mm-dd.","schema":{"type":"string","maxLength":10}},{"name":"validDays","in":"query","required":false,"description":"Valid for this many days from today.","schema":{"type":"integer","minimum":1,"maximum":365}},{"name":"intro","in":"query","required":false,"description":"Intro paragraph.","schema":{"type":"string","maxLength":1500}},{"name":"terms","in":"query","required":false,"description":"Terms.","schema":{"type":"string","maxLength":4000}},{"name":"notes","in":"query","required":false,"description":"Notes.","schema":{"type":"string","maxLength":2000}},{"name":"payLink","in":"query","required":false,"description":"Payment link (https), \"\" to clear.","schema":{"type":"string","maxLength":500}},{"name":"billTo","in":"query","required":false,"description":"Bill-to patch: { name, company, email, phone, address, vatId } — only the keys given change.","schema":{"type":"string"}},{"name":"layout","in":"query","required":false,"description":"Layout.","schema":{"type":"string","enum":["modern","classic","minimal"]}},{"name":"accent","in":"query","required":false,"description":"Accent colour hex.","schema":{"type":"string","maxLength":7}},{"name":"contactId","in":"query","required":false,"description":"Re-link to this contact record.","schema":{"type":"string","maxLength":200}},{"name":"companyId","in":"query","required":false,"description":"Re-link to this company.","schema":{"type":"string","maxLength":40}},{"name":"dealId","in":"query","required":false,"description":"Re-link to this deal.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["quote"],"description":"Always quote."},"targetId":{"type":"string","description":"Quote id."},"updated":{"type":"boolean","description":"true on success."},"verified":{"type":"boolean","description":"true when the read-back shows every field you passed."},"changed":{"type":"array","items":{"type":"string"},"description":"Fields that differ after the save."},"before":{"type":"object","properties":{"total":{"type":"number","description":"Total before."},"items":{"type":"integer","description":"Line count before."},"validUntil":{"type":"string","description":"Validity before."},"status":{"type":"string","description":"Status before."},"title":{"type":"string","description":"Title before."}},"additionalProperties":true,"required":["total","items","validUntil","status","title"],"description":"Totals / status before."},"after":{"type":"object","properties":{"total":{"type":"number","description":"Total after."},"items":{"type":"integer","description":"Line count after."},"validUntil":{"type":"string","description":"Validity after."},"status":{"type":"string","description":"Status after."},"title":{"type":"string","description":"Title after."}},"additionalProperties":true,"required":["total","items","validUntil","status","title"],"description":"Totals / status after."},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Line id (li_…), stable across edits when passed back."},"name":{"type":"string","description":"Line name."},"description":{"type":"string","description":"Line description (\"\" when none)."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (months for a recurring line)."},"unitPrice":{"type":"number","description":"Unit price in the quote currency."},"discountPct":{"type":"number","description":"Line discount percent (0-100)."},"amount":{"type":"number","description":"quantity × unitPrice × (1 − discountPct/100), rounded to 2 decimals."}},"additionalProperties":true,"required":["id","name","description","sku","quantity","unitPrice","discountPct","amount"]},"description":"Line items."},"discountType":{"type":"string","enum":["percent","amount"],"description":"Quote-level discount kind."},"discountValue":{"type":"number","description":"Quote-level discount value."},"taxPct":{"type":"number","description":"VAT percent."},"taxLabel":{"type":"string","description":"Tax line label (\"\" = language default)."},"taxIncluded":{"type":"boolean","description":"true when unit prices include VAT."},"totals":{"type":"object","properties":{"subtotal":{"type":"number","description":"Sum of line amounts."},"discount":{"type":"number","description":"Quote-level discount applied."},"net":{"type":"number","description":"subtotal − discount."},"tax":{"type":"number","description":"VAT on net (or the VAT contained in it when taxIncluded)."},"total":{"type":"number","description":"Amount payable."},"taxPct":{"type":"number","description":"VAT percent used."}},"additionalProperties":true,"required":["subtotal","discount","net","tax","total","taxPct"],"description":"Money math as lib/quoteDoc computeTotals does it (the editor, customer page and e-mail agree)."},"billTo":{"type":"object","properties":{"name":{"type":"string","description":"Customer name."},"company":{"type":"string","description":"Customer company."},"email":{"type":"string","description":"Customer e-mail."},"phone":{"type":"string","description":"Customer phone."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Customer tax id."}},"additionalProperties":true,"required":["name","company","email","phone","address","vatId"],"description":"Bill-to block."},"contactEmail":{"type":"string","description":"Linked contact e-mail."},"contactPhone":{"type":"string","description":"Linked contact phone."},"intro":{"type":"string","description":"Intro paragraph."},"terms":{"type":"string","description":"Terms text."},"notes":{"type":"string","description":"Notes."},"payLink":{"type":"string","description":"Payment link (\"\" when none)."},"preparedBy":{"type":"string","description":"Name shown as \"prepared by\"."},"design":{"type":"object","properties":{"layout":{"type":"string","description":"modern | classic | minimal."},"accent":{"type":"string","description":"Hex colour (\"\" = settings default)."}},"additionalProperties":true,"required":["layout","accent"],"description":"Layout and accent."},"createdBy":{"type":"string","description":"User e-mail."},"lastSentAt":{"type":"string","description":"ISO 8601 of the last send, \"\" when never."},"viewedAt":{"type":"string","description":"ISO 8601 of the first customer view, \"\" when none."},"acceptedBy":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Who accepted."},"manual":{"type":"boolean","description":"true when a user marked it accepted by hand."},"signed":{"type":"boolean","description":"true when an e-signature was drawn."}},"additionalProperties":true,"required":["name","manual","signed"],"description":"null until accepted."},"declinedAt":{"type":"string","description":"ISO 8601, \"\" when not declined."},"declineReason":{"type":"string","description":"Reason given, \"\" when none."},"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601."},"event":{"type":"string","description":"created | edited | duplicated | sent | viewed | accepted | declined | status:<x> (manual)."},"by":{"type":"string","description":"User e-mail, or the customer name for accepted / declined."},"to":{"type":"string","description":"sent: recipient."},"via":{"type":"string","description":"sent: platform | mailbox | whatsapp."},"from":{"type":"string","description":"duplicated: the source quote number."},"reason":{"type":"string","description":"declined: the reason given."},"signed":{"type":"boolean","description":"accepted: whether an e-signature was drawn."},"manual":{"type":"boolean","description":"true when a user set the status by hand."}},"additionalProperties":true,"required":["at","event","by"]},"description":"Event log, oldest first (last 40)."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl","items","discountType","discountValue","taxPct","taxLabel","taxIncluded","totals","billTo","contactEmail","contactPhone","intro","terms","notes","payLink","preparedBy","design","createdBy","lastSentAt","viewedAt","acceptedBy","declinedAt","declineReason","events"],"description":"The full quote."},"url":{"type":"string","description":"Customer link."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","verified","changed","before","after","quote","url"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/{id}/duplicate":{"post":{"operationId":"duplicate_quote","summary":"Copy a quote into a new DRAFT with the next number, a fresh customer link and a fresh validity date, on the same contact / company / deal","description":"Copy a quote into a new DRAFT with the next number, a fresh customer link and a fresh validity date, on the same contact / company / deal. This is how an accepted (locked) quote is revised. The source is not changed.\n\nRequired scope: `quotes.write`. Risk level: `write`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id to copy.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["quote"],"description":"Always quote."},"targetId":{"type":"string","description":"The NEW quote id."},"created":{"type":"boolean","description":"Always true on success."},"verified":{"type":"boolean","description":"true when the copy reads back as a draft."},"duplicatedFrom":{"type":"object","properties":{"id":{"type":"string","description":"Source quote id."},"number":{"type":"string","description":"Source quote number."}},"additionalProperties":true,"required":["id","number"],"description":"The source."},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Line id (li_…), stable across edits when passed back."},"name":{"type":"string","description":"Line name."},"description":{"type":"string","description":"Line description (\"\" when none)."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (months for a recurring line)."},"unitPrice":{"type":"number","description":"Unit price in the quote currency."},"discountPct":{"type":"number","description":"Line discount percent (0-100)."},"amount":{"type":"number","description":"quantity × unitPrice × (1 − discountPct/100), rounded to 2 decimals."}},"additionalProperties":true,"required":["id","name","description","sku","quantity","unitPrice","discountPct","amount"]},"description":"Line items."},"discountType":{"type":"string","enum":["percent","amount"],"description":"Quote-level discount kind."},"discountValue":{"type":"number","description":"Quote-level discount value."},"taxPct":{"type":"number","description":"VAT percent."},"taxLabel":{"type":"string","description":"Tax line label (\"\" = language default)."},"taxIncluded":{"type":"boolean","description":"true when unit prices include VAT."},"totals":{"type":"object","properties":{"subtotal":{"type":"number","description":"Sum of line amounts."},"discount":{"type":"number","description":"Quote-level discount applied."},"net":{"type":"number","description":"subtotal − discount."},"tax":{"type":"number","description":"VAT on net (or the VAT contained in it when taxIncluded)."},"total":{"type":"number","description":"Amount payable."},"taxPct":{"type":"number","description":"VAT percent used."}},"additionalProperties":true,"required":["subtotal","discount","net","tax","total","taxPct"],"description":"Money math as lib/quoteDoc computeTotals does it (the editor, customer page and e-mail agree)."},"billTo":{"type":"object","properties":{"name":{"type":"string","description":"Customer name."},"company":{"type":"string","description":"Customer company."},"email":{"type":"string","description":"Customer e-mail."},"phone":{"type":"string","description":"Customer phone."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Customer tax id."}},"additionalProperties":true,"required":["name","company","email","phone","address","vatId"],"description":"Bill-to block."},"contactEmail":{"type":"string","description":"Linked contact e-mail."},"contactPhone":{"type":"string","description":"Linked contact phone."},"intro":{"type":"string","description":"Intro paragraph."},"terms":{"type":"string","description":"Terms text."},"notes":{"type":"string","description":"Notes."},"payLink":{"type":"string","description":"Payment link (\"\" when none)."},"preparedBy":{"type":"string","description":"Name shown as \"prepared by\"."},"design":{"type":"object","properties":{"layout":{"type":"string","description":"modern | classic | minimal."},"accent":{"type":"string","description":"Hex colour (\"\" = settings default)."}},"additionalProperties":true,"required":["layout","accent"],"description":"Layout and accent."},"createdBy":{"type":"string","description":"User e-mail."},"lastSentAt":{"type":"string","description":"ISO 8601 of the last send, \"\" when never."},"viewedAt":{"type":"string","description":"ISO 8601 of the first customer view, \"\" when none."},"acceptedBy":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Who accepted."},"manual":{"type":"boolean","description":"true when a user marked it accepted by hand."},"signed":{"type":"boolean","description":"true when an e-signature was drawn."}},"additionalProperties":true,"required":["name","manual","signed"],"description":"null until accepted."},"declinedAt":{"type":"string","description":"ISO 8601, \"\" when not declined."},"declineReason":{"type":"string","description":"Reason given, \"\" when none."},"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601."},"event":{"type":"string","description":"created | edited | duplicated | sent | viewed | accepted | declined | status:<x> (manual)."},"by":{"type":"string","description":"User e-mail, or the customer name for accepted / declined."},"to":{"type":"string","description":"sent: recipient."},"via":{"type":"string","description":"sent: platform | mailbox | whatsapp."},"from":{"type":"string","description":"duplicated: the source quote number."},"reason":{"type":"string","description":"declined: the reason given."},"signed":{"type":"boolean","description":"accepted: whether an e-signature was drawn."},"manual":{"type":"boolean","description":"true when a user set the status by hand."}},"additionalProperties":true,"required":["at","event","by"]},"description":"Event log, oldest first (last 40)."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl","items","discountType","discountValue","taxPct","taxLabel","taxIncluded","totals","billTo","contactEmail","contactPhone","intro","terms","notes","payLink","preparedBy","design","createdBy","lastSentAt","viewedAt","acceptedBy","declinedAt","declineReason","events"],"description":"The full quote."},"url":{"type":"string","description":"The new customer link."},"message":{"type":"string","description":"Summary."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","verified","duplicatedFrom","quote","url","message"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/{id}/status":{"post":{"operationId":"set_quote_status","summary":"Set a quote's status by hand: draft, sent (e","description":"Set a quote's status by hand: draft, sent (e.g. it was handed over outside the platform), accepted (the customer agreed by phone — recorded as a manual acceptance, no signature) or declined (with a reason). The customer page and the automations see the same status. Resetting a customer-e-signed acceptance needs force:true. Reversible (set it back to draft).\n\nRequired scope: `quotes.write`. Risk level: `write`.","tags":["quotes"],"security":[{"bearerAuth":["quotes.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id.","schema":{"type":"string","maxLength":40}},{"name":"status","in":"query","required":true,"description":"New status.","schema":{"type":"string","enum":["draft","sent","accepted","declined"]}},{"name":"acceptedBy","in":"query","required":false,"description":"For accepted: who agreed (name).","schema":{"type":"string","maxLength":120}},{"name":"reason","in":"query","required":false,"description":"For declined: the reason.","schema":{"type":"string","maxLength":300}},{"name":"force","in":"query","required":false,"description":"true to overwrite an acceptance the customer e-signed.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["quote"],"description":"Always quote."},"targetId":{"type":"string","description":"Quote id."},"updated":{"type":"boolean","description":"true when the effective status changed."},"verified":{"type":"boolean","description":"true when the read-back shows the requested status."},"before":{"type":"object","properties":{"status":{"type":"string","description":"Effective status before."}},"additionalProperties":true,"required":["status"],"description":"Before."},"after":{"type":"object","properties":{"status":{"type":"string","description":"Effective status after."}},"additionalProperties":true,"required":["status"],"description":"After."},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Line id (li_…), stable across edits when passed back."},"name":{"type":"string","description":"Line name."},"description":{"type":"string","description":"Line description (\"\" when none)."},"sku":{"type":"string","description":"SKU (\"\" when none)."},"quantity":{"type":"number","description":"Quantity (months for a recurring line)."},"unitPrice":{"type":"number","description":"Unit price in the quote currency."},"discountPct":{"type":"number","description":"Line discount percent (0-100)."},"amount":{"type":"number","description":"quantity × unitPrice × (1 − discountPct/100), rounded to 2 decimals."}},"additionalProperties":true,"required":["id","name","description","sku","quantity","unitPrice","discountPct","amount"]},"description":"Line items."},"discountType":{"type":"string","enum":["percent","amount"],"description":"Quote-level discount kind."},"discountValue":{"type":"number","description":"Quote-level discount value."},"taxPct":{"type":"number","description":"VAT percent."},"taxLabel":{"type":"string","description":"Tax line label (\"\" = language default)."},"taxIncluded":{"type":"boolean","description":"true when unit prices include VAT."},"totals":{"type":"object","properties":{"subtotal":{"type":"number","description":"Sum of line amounts."},"discount":{"type":"number","description":"Quote-level discount applied."},"net":{"type":"number","description":"subtotal − discount."},"tax":{"type":"number","description":"VAT on net (or the VAT contained in it when taxIncluded)."},"total":{"type":"number","description":"Amount payable."},"taxPct":{"type":"number","description":"VAT percent used."}},"additionalProperties":true,"required":["subtotal","discount","net","tax","total","taxPct"],"description":"Money math as lib/quoteDoc computeTotals does it (the editor, customer page and e-mail agree)."},"billTo":{"type":"object","properties":{"name":{"type":"string","description":"Customer name."},"company":{"type":"string","description":"Customer company."},"email":{"type":"string","description":"Customer e-mail."},"phone":{"type":"string","description":"Customer phone."},"address":{"type":"string","description":"Address."},"vatId":{"type":"string","description":"Customer tax id."}},"additionalProperties":true,"required":["name","company","email","phone","address","vatId"],"description":"Bill-to block."},"contactEmail":{"type":"string","description":"Linked contact e-mail."},"contactPhone":{"type":"string","description":"Linked contact phone."},"intro":{"type":"string","description":"Intro paragraph."},"terms":{"type":"string","description":"Terms text."},"notes":{"type":"string","description":"Notes."},"payLink":{"type":"string","description":"Payment link (\"\" when none)."},"preparedBy":{"type":"string","description":"Name shown as \"prepared by\"."},"design":{"type":"object","properties":{"layout":{"type":"string","description":"modern | classic | minimal."},"accent":{"type":"string","description":"Hex colour (\"\" = settings default)."}},"additionalProperties":true,"required":["layout","accent"],"description":"Layout and accent."},"createdBy":{"type":"string","description":"User e-mail."},"lastSentAt":{"type":"string","description":"ISO 8601 of the last send, \"\" when never."},"viewedAt":{"type":"string","description":"ISO 8601 of the first customer view, \"\" when none."},"acceptedBy":{"type":["object","null"],"properties":{"name":{"type":"string","description":"Who accepted."},"manual":{"type":"boolean","description":"true when a user marked it accepted by hand."},"signed":{"type":"boolean","description":"true when an e-signature was drawn."}},"additionalProperties":true,"required":["name","manual","signed"],"description":"null until accepted."},"declinedAt":{"type":"string","description":"ISO 8601, \"\" when not declined."},"declineReason":{"type":"string","description":"Reason given, \"\" when none."},"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","description":"ISO 8601."},"event":{"type":"string","description":"created | edited | duplicated | sent | viewed | accepted | declined | status:<x> (manual)."},"by":{"type":"string","description":"User e-mail, or the customer name for accepted / declined."},"to":{"type":"string","description":"sent: recipient."},"via":{"type":"string","description":"sent: platform | mailbox | whatsapp."},"from":{"type":"string","description":"duplicated: the source quote number."},"reason":{"type":"string","description":"declined: the reason given."},"signed":{"type":"boolean","description":"accepted: whether an e-signature was drawn."},"manual":{"type":"boolean","description":"true when a user set the status by hand."}},"additionalProperties":true,"required":["at","event","by"]},"description":"Event log, oldest first (last 40)."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl","items","discountType","discountValue","taxPct","taxLabel","taxIncluded","totals","billTo","contactEmail","contactPhone","intro","terms","notes","payLink","preparedBy","design","createdBy","lastSentAt","viewedAt","acceptedBy","declinedAt","declineReason","events"],"description":"The full quote."},"note":{"type":"string","description":"Caveat when the effective status differs from the one written (expiry)."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","verified","before","after","quote"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/{id}/send":{"post":{"operationId":"send_quote","summary":"Send a quote to its customer by e-mail (from one of the user's connected mailboxes, or the platform sender with Reply-To = the user) or by WhatsApp (the business Cloud API number or a connected personal number — the same path as the contact card's WhatsApp popup, so the message lands in the Inbox thread)","description":"Send a quote to its customer by e-mail (from one of the user's connected mailboxes, or the platform sender with Reply-To = the user) or by WhatsApp (the business Cloud API number or a connected personal number — the same path as the contact card's WhatsApp popup, so the message lands in the Inbox thread). PREVIEW FIRST: without confirm it shows the recipient, sender, subject / message text with the customer link, whether a PDF will be attached, and any reason the send may fail (no sender connected, WhatsApp 24-hour window closed, quote expired). On confirm it sends, marks the quote sent, logs a note on the contact card and reports the result. Only call with confirm when the user asked to send.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id.","schema":{"type":"string","maxLength":40}},{"name":"channel","in":"query","required":false,"description":"email (default) or whatsapp.","schema":{"type":"string","enum":["email","whatsapp"],"default":"email"}},{"name":"to","in":"query","required":false,"description":"Recipient e-mail or phone; default = the quote's bill-to / contact e-mail or phone.","schema":{"type":"string","maxLength":200}},{"name":"from","in":"query","required":false,"description":"E-mail only: a connected mailbox address, or \"platform\" for the FORTVISION sender. Default = the user's default mailbox, else platform.","schema":{"type":"string","maxLength":200}},{"name":"via","in":"query","required":false,"description":"WhatsApp only: sender id — \"business\" (Meta Cloud API, default) or a personal number id (\"qr:…\") from get_contact_whatsapp_history.senders.","schema":{"type":"string","maxLength":80}},{"name":"subject","in":"query","required":false,"description":"E-mail subject (default: \"הצעת מחיר Q-0001 · title · business\").","schema":{"type":"string","maxLength":300}},{"name":"message","in":"query","required":false,"description":"The message body (e-mail intro text / WhatsApp text). Default = the workspace's quote e-mail message or a short Hebrew/English note; the quote link is always included.","schema":{"type":"string","maxLength":2000}},{"name":"attachPdf","in":"query","required":false,"description":"E-mail: attach the PDF when server-side rendering is configured (default true).","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["send_quote"],"description":"Preview only."},"targetType":{"type":"string","enum":["quote"],"description":"Always quote."},"targetId":{"type":"string","description":"Quote id."},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl"],"description":"The quote as list_quotes shows it."},"channel":{"type":"string","enum":["email","whatsapp"],"description":"Channel."},"url":{"type":"string","description":"The customer link carried by the message."},"warnings":{"type":"array","items":{"type":"string"},"description":"Things to tell the user before / after acting."},"to":{"type":"string","description":"Recipient e-mail or phone (E.164)."},"from":{"type":"string","description":"E-mail: mailbox address or \"platform\"."},"fromKind":{"type":"string","enum":["platform","mailbox"],"description":"E-mail preview: which sender path."},"replyTo":{"type":"string","description":"E-mail preview: where replies go."},"subject":{"type":"string","description":"E-mail subject."},"message":{"type":"string","description":"E-mail message body (preview) or the run summary (after send)."},"attachPdf":{"type":"boolean","description":"E-mail preview: whether a PDF will be attached."},"pdfAttached":{"type":"boolean","description":"E-mail run: whether a PDF was attached."},"mailboxMessageId":{"type":"string","description":"E-mail run via mailbox: the provider message id."},"via":{"type":"string","description":"WhatsApp: sender id used."},"viaLabel":{"type":"string","description":"WhatsApp: sender label."},"serviceWindowOpen":{"type":["boolean","null"],"description":"WhatsApp preview: Cloud API 24h window state (null for personal numbers)."},"lastInboundAt":{"type":"string","description":"WhatsApp preview: last message from the customer."},"text":{"type":"string","description":"WhatsApp: the message text sent / to send."},"whatsappMessage":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Meta message id."},"status":{"type":"string","description":"Initial status."},"at":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"description":"WhatsApp run: { id, status, at } of the message (null for personal numbers)."},"sent":{"type":"boolean","description":"Run: true once sent."},"loggedOnContactCard":{"type":"boolean","description":"Run: a note was added to the contact card."},"noteId":{"type":"string","description":"Run: the note id."},"verified":{"type":"boolean","description":"Run: the quote reads back as sent."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","quote","channel","url","to"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/quotes/{id}/delete":{"post":{"operationId":"delete_quote","summary":"Delete a quote","description":"Delete a quote. Its customer link stops working and it disappears from the record's Quotes card; an accepted quote loses its acceptance record and e-signature. PREVIEW FIRST: without confirm it reports the quote, its status, total and view count.\n\nRequired scope: `records.delete`. Risk level: `high`.","tags":["records"],"security":[{"bearerAuth":["records.delete"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Quote id.","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["delete_quote"],"description":"Preview only."},"targetType":{"type":"string","enum":["quote"],"description":"Always quote."},"targetId":{"type":"string","description":"Quote id."},"quote":{"type":"object","properties":{"id":{"type":"string","description":"Quote id (q_…)."},"number":{"type":"string","description":"Quote number (e.g. Q-0012)."},"title":{"type":"string","description":"Title (\"\" when none)."},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired"],"description":"Effective status (a sent/viewed quote past validUntil reads as expired)."},"lang":{"type":"string","enum":["he","en"],"description":"Document language; he renders right-to-left."},"currency":{"type":"string","description":"3-letter ISO currency."},"total":{"type":"number","description":"Amount payable."},"itemCount":{"type":"integer","description":"Number of lines."},"contactId":{"type":"string","description":"Linked contact record id (\"\" when none) — the record whose Quotes card shows it."},"contactName":{"type":"string","description":"Linked contact name."},"companyId":{"type":"string","description":"Linked company id (\"\" when none)."},"companyName":{"type":"string","description":"Linked company name."},"dealId":{"type":"string","description":"Linked deal id (\"\" when none)."},"dealName":{"type":"string","description":"Linked deal name."},"validUntil":{"type":"string","description":"Validity date yyyy-mm-dd."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"sentAt":{"type":"string","description":"ISO 8601 of the first send, \"\" when never sent."},"sentTo":{"type":"string","description":"Last recipient (e-mail or phone), \"\" when never sent."},"viewCount":{"type":"integer","description":"Times the customer opened the page."},"acceptedAt":{"type":"string","description":"ISO 8601 when accepted, \"\" otherwise."},"hasSignature":{"type":"boolean","description":"true when the customer drew an e-signature."},"locked":{"type":"boolean","description":"true when accepted — edits are refused; duplicate instead."},"url":{"type":"string","description":"The customer page (view, download PDF, accept / decline, e-sign). Share this link."},"previewUrl":{"type":"string","description":"Same page for the rep — does not count as a customer view."},"printUrl":{"type":"string","description":"Print / PDF view of the document."}},"additionalProperties":true,"required":["id","number","title","status","lang","currency","total","itemCount","contactId","contactName","companyId","companyName","dealId","dealName","validUntil","createdAt","updatedAt","sentAt","sentTo","viewCount","acceptedAt","hasSignature","locked","url","previewUrl","printUrl"],"description":"Preview: the quote about to be deleted."},"warnings":{"type":"array","items":{"type":"string"},"description":"Things to tell the user before / after acting."},"deleted":{"type":"boolean","description":"Run: true once removed."},"verified":{"type":"boolean","description":"Run: true when a read-back no longer finds it."},"number":{"type":"string","description":"Run: the deleted quote's number."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/whatsapp/contact-send":{"post":{"operationId":"send_whatsapp_to_contact","summary":"Send ONE WhatsApp message to ONE contact (by record id or phone) through the contact card's own path, so it appears in the Inbox thread and on the card: free text (Meta Cloud API only inside the 24-hour service window after the customer's last message; personal QR numbers have no window), an approved template with its variables (business number only), or files by https URL (documents, images, PDFs) with an optional caption","description":"Send ONE WhatsApp message to ONE contact (by record id or phone) through the contact card's own path, so it appears in the Inbox thread and on the card: free text (Meta Cloud API only inside the 24-hour service window after the customer's last message; personal QR numbers have no window), an approved template with its variables (business number only), or files by https URL (documents, images, PDFs) with an optional caption. PREVIEW FIRST: without confirm it resolves the contact, the sender (business or personal number — from get_contact_whatsapp_history.senders) and its live connection state, whether the service window is open, renders the template with its variables, and lists every reason the send would be refused. Numbers that opted out are refused. On confirm it sends and returns Meta's message id and initial status; get_contact_whatsapp_history shows delivered / read / failed afterwards.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"contactId","in":"query","required":false,"description":"Record id (contactId from list_contacts_in_list) or contact id; the phone comes from the CRM. Required unless phone is given.","schema":{"type":"string","maxLength":200}},{"name":"phone","in":"query","required":false,"description":"Recipient phone in international format (e.g. +9725xxxxxxx) when not addressing by contactId.","schema":{"type":"string","maxLength":40}},{"name":"text","in":"query","required":false,"description":"Free-text message, or the caption when files are sent.","schema":{"type":"string","maxLength":1000}},{"name":"templateName","in":"query","required":false,"description":"Approved template name or id (list_whatsapp_templates). Business number only.","schema":{"type":"string","maxLength":120}},{"name":"templateVariables","in":"query","required":false,"description":"Values for the template's {{1}}…{{n}}, in order.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"files","in":"query","required":false,"description":"Files to send: [{ url (https), name?, type? (mime) }], up to 10. The server downloads each file (6 MB personal / 16 MB business).","schema":{"type":"array","maxItems":10,"items":{"type":"object"}}},{"name":"via","in":"query","required":false,"description":"Sender: \"business\" (Meta Cloud API, default) or a personal number id \"qr:…\" from get_contact_whatsapp_history.senders.","schema":{"type":"string","maxLength":80}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","enum":["send_whatsapp_to_contact"],"description":"Preview only."},"targetType":{"type":"string","enum":["contact"],"description":"Always contact."},"targetId":{"type":"string","description":"Contact record id, or the phone when addressed by phone."},"contactId":{"type":"string","description":"Resolved contact record id."},"contactName":{"type":"string","description":"Preview: contact name."},"to":{"type":"string","description":"Recipient phone (E.164)."},"via":{"type":"string","description":"Sender id used."},"viaLabel":{"type":"string","description":"Sender label."},"senderKind":{"type":"string","enum":["business","personal"],"description":"Preview: Cloud API business number or personal QR number."},"mode":{"type":"string","enum":["text","template","media"],"description":"What is sent."},"text":{"type":"string","description":"The text (rendered template body for templates; caption for media)."},"template":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Template id."},"name":{"type":"string","description":"Name."},"language":{"type":"string","description":"Language code."},"category":{"type":"string","description":"Category."},"variables":{"type":"array","items":{"type":"string"},"description":"Values substituted."},"body":{"type":"string","description":"Raw template body."}},"additionalProperties":true,"required":["name","language","variables"],"description":"Template used (null for text / media)."},"files":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","description":"URL."},"name":{"type":"string","description":"File name."},"type":{"type":"string","description":"MIME type."}},"additionalProperties":true,"required":["url","name","type"]},"description":"Preview: files to send."},"serviceWindowOpen":{"type":["boolean","null"],"description":"Preview: Cloud API 24h window open (null for personal numbers)."},"lastInboundAt":{"type":"string","description":"Preview: last message from the customer, \"\" when none."},"warnings":{"type":"array","items":{"type":"string"},"description":"Reasons the send may be refused, and channel caveats."},"sent":{"type":"boolean","description":"Run: true once sent."},"filesSent":{"type":"integer","description":"Run: files sent."},"message":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Meta message id."},"status":{"type":"string","description":"Initial status."},"at":{"type":"string","description":"ISO 8601."},"text":{"type":"string","description":"Stored text."}},"additionalProperties":true,"description":"Run: the message record as the Inbox stores it (null for personal numbers)."},"tracking":{"type":"string","description":"Run: how delivery status can be followed."},"loggedIn":{"type":"string","description":"Run: where the message is recorded."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","to","via","viaLabel","mode","text"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/conversations/{conversationId}/reply":{"post":{"operationId":"reply_to_conversation","summary":"Answer a unified-inbox conversation from list_conversations / get_conversation: WhatsApp, SMS, Messenger or Instagram, through the same path the Inbox composer uses, so the reply lands in the thread","description":"Answer a unified-inbox conversation from list_conversations / get_conversation: WhatsApp, SMS, Messenger or Instagram, through the same path the Inbox composer uses, so the reply lands in the thread. PREVIEW FIRST: without confirm it resolves the recipient and sender and lists every reason the send would be refused (opt-outs, closed 24-hour window, no inbound message to answer). Email threads are answered with send_outreach_email instead.\n\nRequired scope: `messages.send`. Risk level: `high`.","tags":["messages"],"security":[{"bearerAuth":["messages.send"]}],"parameters":[{"name":"conversationId","in":"path","required":true,"description":"Conversation id exactly as list_conversations returned it (e.g. \"whatsapp:+9725…\", \"sms:+9725…\", \"facebook:<pageId>:<convId>\").","schema":{"type":"string","maxLength":200}},{"name":"text","in":"query","required":true,"description":"The reply text.","schema":{"type":"string","maxLength":2000}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: the tool name."},"targetType":{"type":"string","description":"Always \"conversation\"."},"targetId":{"type":"string","description":"The conversation id."},"conversationId":{"type":"string","description":"The conversation id."},"channel":{"type":"string","description":"whatsapp / sms / facebook / instagram."},"text":{"type":"string","description":"The reply text."},"to":{"type":"string","description":"Preview: recipient phone (WhatsApp / SMS)."},"via":{"type":"string","description":"Preview: WhatsApp sender id."},"viaLabel":{"type":"string","description":"Preview: WhatsApp sender label."},"serviceWindowOpen":{"description":"Preview: WhatsApp 24-hour window state."},"pageId":{"type":"string","description":"Preview: Facebook / Instagram page id."},"convId":{"type":"string","description":"Preview: Messenger / Instagram conversation id."},"recipientId":{"type":"string","description":"Preview: the customer id the reply goes to."},"lastInboundAt":{"type":"string","description":"Preview: when the customer last wrote."},"lastInboundText":{"type":"string","description":"Preview: what the customer last wrote."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview: reasons the send may fail."},"sent":{"type":"boolean","description":"Run: true once sent."},"message":{"type":"object","additionalProperties":true,"description":"Run: { id, status } of the sent message."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","conversationId","channel","text"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/booking-pages/{slug}/slots":{"get":{"operationId":"get_booking_slots","summary":"The open time slots of one booking page on one day — the exact list a guest would see — as ISO datetimes, plus the page timezone","description":"The open time slots of one booking page on one day — the exact list a guest would see — as ISO datetimes, plus the page timezone. Use before create_booking.\n\nRequired scope: `meetings.read`. Risk level: `read`.","tags":["meetings"],"security":[{"bearerAuth":["meetings.read"]}],"parameters":[{"name":"slug","in":"path","required":true,"description":"Booking page slug from list_booking_pages.","schema":{"type":"string","maxLength":80}},{"name":"day","in":"query","required":true,"description":"Day as YYYY-MM-DD.","schema":{"type":"string","maxLength":10}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"slug":{"type":"string","description":"Booking page slug."},"day":{"type":"string","description":"The day asked for, YYYY-MM-DD."},"timezone":{"type":"string","description":"The page timezone the slots are expressed in."},"slots":{"type":"array","items":{"type":"string"},"description":"Open slot starts as ISO datetimes."}},"additionalProperties":true,"required":["ok","requestId","slug","day","slots"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/bookings":{"post":{"operationId":"create_booking","summary":"Book a slot on a booking page for a guest, exactly as the public page would: the slot is reserved, the owner calendar event is created and the guest is emailed the invite","description":"Book a slot on a booking page for a guest, exactly as the public page would: the slot is reserved, the owner calendar event is created and the guest is emailed the invite. PREVIEW FIRST: without confirm it checks the slot is still open that day and reports what would be sent. Use get_booking_slots for a valid start.\n\nRequired scope: `meetings.write`. Risk level: `high`.","tags":["meetings"],"security":[{"bearerAuth":["meetings.write"]}],"parameters":[{"name":"slug","in":"query","required":true,"description":"Booking page slug from list_booking_pages.","schema":{"type":"string","maxLength":80}},{"name":"start","in":"query","required":true,"description":"Slot start, ISO datetime from get_booking_slots.","schema":{"type":"string","maxLength":40}},{"name":"name","in":"query","required":true,"description":"Guest name.","schema":{"type":"string","maxLength":80}},{"name":"email","in":"query","required":false,"description":"Guest email (receives the invite). Required unless phone is given.","schema":{"type":"string","maxLength":120}},{"name":"phone","in":"query","required":false,"description":"Guest phone, international format. Required unless email is given.","schema":{"type":"string","maxLength":25}},{"name":"note","in":"query","required":false,"description":"Note shown to the owner.","schema":{"type":"string","maxLength":500}},{"name":"timezone","in":"query","required":false,"description":"Guest IANA timezone for the confirmation (default: the page timezone).","schema":{"type":"string","maxLength":60}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: the tool name."},"targetType":{"type":"string","description":"Always \"booking\"."},"targetId":{"type":"string","description":"slug@start before creation; the booking id after."},"slug":{"type":"string","description":"Booking page slug."},"start":{"type":"string","description":"Slot start."},"timezone":{"type":"string","description":"Page timezone (preview)."},"available":{"type":"boolean","description":"Preview: whether the slot is still open."},"openSlotsThatDay":{"type":"integer","description":"Preview: open slots on that day."},"guest":{"type":"object","additionalProperties":true,"description":"name / email / phone as they will be recorded."},"note":{"type":"string","description":"Preview: the note for the owner."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview: reasons the booking would fail or be incomplete."},"created":{"type":"boolean","description":"Run: true once the booking exists."},"id":{"type":"string","description":"Run: booking id."},"end":{"type":"string","description":"Run: slot end, ISO."},"meetLink":{"type":"string","description":"Run: video link when the page uses one."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/onsite-campaigns":{"get":{"operationId":"list_onsite_campaigns","summary":"On-site campaigns (popups, bars, embeds) the site tag runs on the workspace websites: id, name, type, status (live / paused / draft), the sites it runs on, last update","description":"On-site campaigns (popups, bars, embeds) the site tag runs on the workspace websites: id, name, type, status (live / paused / draft), the sites it runs on, last update. Newest first.\n\nRequired scope: `pages.read`. Risk level: `read`.","tags":["pages"],"security":[{"bearerAuth":["pages.read"]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Only this status.","schema":{"type":"string","enum":["live","paused","draft"]}},{"name":"query","in":"query","required":false,"description":"Filter by campaign name.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"campaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id."},"name":{"type":"string","description":"Campaign name."},"type":{"type":"string","description":"popup / bar / embed …"},"status":{"type":"string","description":"live, paused or draft."},"sites":{"type":"array","items":{"type":"string"},"description":"Site ids it runs on."},"updatedAt":{"type":"string","description":"ISO 8601."},"createdAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","status"]},"description":"On-site campaigns, newest first."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","campaigns","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/onsite-campaigns/{id}/status":{"post":{"operationId":"set_onsite_campaign_status","summary":"Set an on-site campaign live or paused","description":"Set an on-site campaign live or paused. Live means visitors of the selected websites start seeing it on the next page load. PREVIEW FIRST: without confirm it reports the current status, the sites affected and whether going live would be refused (no website selected).\n\nRequired scope: `pages.write`. Risk level: `high`.","tags":["pages"],"security":[{"bearerAuth":["pages.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign id from list_onsite_campaigns.","schema":{"type":"string","maxLength":60}},{"name":"status","in":"query","required":true,"description":"\"live\" or \"paused\".","schema":{"type":"string","enum":["live","paused"]}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: the tool name."},"targetType":{"type":"string","description":"Always \"onsite_campaign\"."},"targetId":{"type":"string","description":"Campaign id."},"name":{"type":"string","description":"Campaign name."},"from":{"type":"string","description":"Preview: status before."},"to":{"type":"string","description":"Preview: status after."},"sites":{"type":"integer","description":"Preview: number of sites it runs on."},"noChange":{"type":"boolean","description":"Preview: already in that status."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview: why the change would be refused."},"status":{"type":"string","description":"Run: status now."},"previous":{"type":"string","description":"Run: status before."},"changed":{"type":"boolean","description":"Run: false when it was already in that status."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/ad-rules":{"get":{"operationId":"list_ad_rules","summary":"The automated ad rules the hourly cron evaluates against live campaigns (pause / activate / duplicate / budget shift): id, name, enabled, action, platform, last update — plus the 10 most recent rule runs","description":"The automated ad rules the hourly cron evaluates against live campaigns (pause / activate / duplicate / budget shift): id, name, enabled, action, platform, last update — plus the 10 most recent rule runs.\n\nRequired scope: `campaigns.read`. Risk level: `read`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.read"]}],"parameters":[{"name":"enabled","in":"query","required":false,"description":"Only enabled (true) or only disabled (false) rules.","schema":{"type":"boolean"}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Rule id."},"name":{"type":"string","description":"Rule name."},"enabled":{"type":"boolean","description":"Whether the cron evaluates it."},"action":{"type":"string","description":"pause / activate / duplicate / budget-shift."},"platform":{"type":"string","description":"Ad platform or scope."},"level":{"type":"string","description":"Entity level it targets."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","enabled"]},"description":"Automated ad rules."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."},"recentRuns":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Most recent rule runs, newest first."}},"additionalProperties":true,"required":["ok","requestId","rules","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/ad-rules/{id}/enabled":{"post":{"operationId":"set_ad_rule_enabled","summary":"Enable or disable one automated ad rule","description":"Enable or disable one automated ad rule. An enabled rule acts on live ads every hour without further confirmation, so this is gated. PREVIEW FIRST: without confirm it reports the rule, its action and the current state.\n\nRequired scope: `campaigns.write`. Risk level: `high`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Rule id from list_ad_rules.","schema":{"type":"string","maxLength":60}},{"name":"enabled","in":"query","required":true,"description":"true to enable, false to disable.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: the tool name."},"targetType":{"type":"string","description":"Always \"ad_rule\"."},"targetId":{"type":"string","description":"Rule id."},"name":{"type":"string","description":"Rule name."},"ruleAction":{"type":"string","description":"Preview: what the rule does when it fires."},"from":{"type":"boolean","description":"Preview: enabled before."},"to":{"type":"boolean","description":"Preview: enabled after."},"noChange":{"type":"boolean","description":"Preview: already in that state."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview warnings."},"enabled":{"type":"boolean","description":"Run: enabled now."},"changed":{"type":"boolean","description":"Run: false when nothing changed."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/reports/budget-pacing":{"get":{"operationId":"get_budget_pacing","summary":"Month-to-date ad spend against each account monthly target: spent so far, what should have been spent by today, pace (1","description":"Month-to-date ad spend against each account monthly target: spent so far, what should have been spent by today, pace (1.0 = on plan), projected month-end spend and an on / over / under status per ad account. Use for \"are we on budget this month\".\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"asOf":{"type":"string","description":"When the snapshot was computed, ISO 8601."},"accounts":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"platform:accountId."},"platform":{"type":"string","description":"meta / google / dv360 / tiktok / linkedin."},"accountId":{"type":"string","description":"Ad account id."},"client":{"type":"string","description":"Client label."},"target":{"type":"number","description":"Monthly target, account currency."},"spentMonthToDate":{"type":"number","description":"Spend so far this month."},"expectedMonthToDate":{"type":"number","description":"What should have been spent by today."},"pace":{"type":"number","description":"spent / expected; 1.0 = on plan."},"projectedMonthEnd":{"type":"number","description":"Straight-line projection of month-end spend."},"status":{"type":"string","description":"on / over / under / none."},"conversions":{"type":"number","description":"Conversions so far this month."}},"additionalProperties":true,"required":["target","spentMonthToDate","status"]},"description":"One row per ad account with a monthly target."},"note":{"type":"string","description":"How to read pace and status."}},"additionalProperties":true,"required":["ok","requestId","asOf","accounts"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/client-accounts":{"get":{"operationId":"list_client_accounts","summary":"The client accounts of this workspace (an agency grouping of pages, sites, ad accounts, senders and users under one client name) with the count of each asset kind","description":"The client accounts of this workspace (an agency grouping of pages, sites, ad accounts, senders and users under one client name) with the count of each asset kind. Use the name to talk about one client at a time.\n\nRequired scope: `reports.read`. Risk level: `read`.","tags":["reports"],"security":[{"bearerAuth":["reports.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Filter by client name.","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client account id."},"name":{"type":"string","description":"Client name."},"workspaceId":{"type":"string","description":"Sub-workspace bound to it, when any."},"counts":{"type":"object","additionalProperties":true,"description":"pages / sites / metaAccounts / googleAccounts / emailSenders / users assigned."}},"additionalProperties":true,"required":["id","name"]},"description":"Client accounts of this workspace."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page after clamping."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list (lib/mcp/schema.js paginate)."}},"additionalProperties":true,"required":["ok","requestId","accounts","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/gbp/locations":{"get":{"operationId":"list_gbp_locations","summary":"The Google Business Profile locations connected to this workspace, with the account id needed by list_gbp_reviews","description":"The Google Business Profile locations connected to this workspace, with the account id needed by list_gbp_reviews.\n\nRequired scope: `social.read`. Risk level: `read`.","tags":["social"],"security":[{"bearerAuth":["social.read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"accountId":{"type":"string","description":"GBP account id to pass to list_gbp_reviews."},"locations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Location id."},"name":{"type":"string","description":"Location title."},"address":{"type":"string","description":"Address, when known."}},"additionalProperties":true,"required":["id"]},"description":"Connected Business Profile locations."}},"additionalProperties":true,"required":["ok","requestId","locations"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/gbp/reviews":{"get":{"operationId":"list_gbp_reviews","summary":"Google reviews of one Business Profile location: rating, reviewer, text, date and whether the business already replied","description":"Google reviews of one Business Profile location: rating, reviewer, text, date and whether the business already replied. Use reply_gbp_review to answer one.\n\nRequired scope: `social.read`. Risk level: `read`.","tags":["social"],"security":[{"bearerAuth":["social.read"]}],"parameters":[{"name":"accountId","in":"query","required":true,"description":"GBP account id from list_gbp_locations.","schema":{"type":"string","maxLength":40}},{"name":"locationId","in":"query","required":true,"description":"Location id from list_gbp_locations.","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"accountId":{"type":"string","description":"GBP account id."},"locationId":{"type":"string","description":"Location id."},"reviews":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Review id for reply_gbp_review."},"rating":{"type":"string","description":"Star rating as Google names it (e.g. FIVE)."},"reviewer":{"type":"string","description":"Reviewer display name."},"comment":{"type":"string","description":"Review text."},"at":{"type":"string","description":"ISO 8601."},"replied":{"type":"boolean","description":"Whether the business already replied."},"reply":{"type":"string","description":"The existing reply, when any."}},"additionalProperties":true,"required":["id"]},"description":"Reviews, newest first as Google returns them."},"averageRating":{"type":"number","description":"Location average rating, when Google reports it."},"totalReviews":{"type":"number","description":"Total review count, when Google reports it."}},"additionalProperties":true,"required":["ok","requestId","accountId","locationId","reviews"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/gbp/reviews/{reviewId}/reply":{"post":{"operationId":"reply_gbp_review","summary":"Post the business reply to one Google review","description":"Post the business reply to one Google review. The reply is public on the Business Profile. PREVIEW FIRST: without confirm it shows the exact text that would be published.\n\nRequired scope: `social.publish`. Risk level: `high`.","tags":["social"],"security":[{"bearerAuth":["social.publish"]}],"parameters":[{"name":"accountId","in":"query","required":true,"description":"GBP account id from list_gbp_locations.","schema":{"type":"string","maxLength":40}},{"name":"locationId","in":"query","required":true,"description":"Location id from list_gbp_locations.","schema":{"type":"string","maxLength":40}},{"name":"reviewId","in":"path","required":true,"description":"Review id from list_gbp_reviews.","schema":{"type":"string","maxLength":200}},{"name":"comment","in":"query","required":true,"description":"The reply text.","schema":{"type":"string","maxLength":4000}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: the tool name."},"targetType":{"type":"string","description":"Always \"gbp_review\"."},"targetId":{"type":"string","description":"Review id."},"accountId":{"type":"string","description":"GBP account id (preview)."},"locationId":{"type":"string","description":"Location id (preview)."},"comment":{"type":"string","description":"Preview: the reply that would be published."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview warnings."},"replied":{"type":"boolean","description":"Run: true once published."},"reply":{"type":"string","description":"Run: the reply as Google stored it."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/campaign-reports/links":{"post":{"operationId":"create_campaign_report_link","summary":"Create a public, login-free report link for one ad campaign (KPIs, daily chart, ads, keywords) to share with a client","description":"Create a public, login-free report link for one ad campaign (KPIs, daily chart, ads, keywords) to share with a client. The report reads the same server caches the Ads table reads. PREVIEW FIRST: without confirm it shows what the link would expose and for how long. Pass hideSpend:true to omit spend.\n\nRequired scope: `campaigns.write`. Risk level: `high`.","tags":["campaigns"],"security":[{"bearerAuth":["campaigns.write"]}],"parameters":[{"name":"platform","in":"query","required":true,"description":"Ad platform of the campaign.","schema":{"type":"string","enum":["meta","google","dv360","tiktok","linkedin"]}},{"name":"campaignId","in":"query","required":true,"description":"Campaign id from list_campaigns.","schema":{"type":"string","maxLength":80}},{"name":"name","in":"query","required":true,"description":"Title shown on the report.","schema":{"type":"string","maxLength":160}},{"name":"accountRef","in":"query","required":false,"description":"The owning account, e.g. { \"accountId\": \"act_…\" } for Meta, { \"customerId\": \"…\" } for Google, { \"advertiserId\": \"…\" } for DV360.","schema":{"type":"string"}},{"name":"dateRange","in":"query","required":false,"description":"Reporting window (default last_30d).","schema":{"type":"string","maxLength":30}},{"name":"hideSpend","in":"query","required":false,"description":"Omit spend figures from the report.","schema":{"type":"boolean"}},{"name":"expiryDays","in":"query","required":false,"description":"Days until the link stops working (1-90, default 30).","schema":{"type":"integer"}},{"name":"idempotencyKey","in":"query","required":true,"description":"A unique id for THIS action (required). Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}},{"name":"confirm","in":"query","required":false,"description":"Leave false (the default) to PREVIEW: nothing changes and you get a summary plus a confirmationToken. Set true and pass that token to actually perform the action.","schema":{"type":"boolean","default":false}},{"name":"confirmationToken","in":"query","required":false,"description":"The token returned by the preview call. Required when confirm is true. It is tied to the exact arguments you previewed, is single-use, and expires after 15 minutes.","schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"action":{"type":"string","description":"Preview only: the tool name."},"targetType":{"type":"string","description":"Always \"campaign_report\"."},"targetId":{"type":"string","description":"platform:campaignId."},"platform":{"type":"string","description":"Ad platform."},"campaignId":{"type":"string","description":"Campaign id."},"name":{"type":"string","description":"Report title."},"accountRef":{"type":"object","additionalProperties":true,"description":"Preview: the owning account reference."},"hideSpend":{"type":"boolean","description":"Whether spend is omitted."},"expiryDays":{"type":"integer","description":"Preview: days until expiry."},"dateRange":{"type":"string","description":"Preview: reporting window."},"warnings":{"type":"array","items":{"type":"string"},"description":"Preview warnings about public exposure."},"created":{"type":"boolean","description":"Run: true once the link exists."},"url":{"type":"string","description":"Run: the public report URL."},"expiresInDays":{"type":"integer","description":"Run: days until the link stops working."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."},"status":{"type":"string","enum":["preview"],"description":"Present on a preview call: nothing was changed yet."},"message":{"type":"string","description":"Preview instructions: call again with confirm:true and the confirmationToken to perform the action."},"confirmationToken":{"type":"string","description":"Single-use token bound to these exact arguments; expires after 15 minutes."},"expiresAt":{"type":"string","description":"ISO 8601 expiry of the confirmationToken."},"expiresInSeconds":{"type":"integer","description":"Seconds until the confirmationToken expires."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/companies":{"get":{"operationId":"list_companies","summary":"The CRM's Companies list, newest first: id, name, domain / website, industry, phone, e-mail, address, owner, tags, the ids of linked contacts and deals, and note count","description":"The CRM's Companies list, newest first: id, name, domain / website, industry, phone, e-mail, address, owner, tags, the ids of linked contacts and deals, and note count. Filter by text (name, domain, industry, e-mail) or industry. Use the id for get_company, create_quote (companyId) and add_note.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"query","in":"query","required":false,"description":"Text to match against name, domain, website, industry, e-mail.","schema":{"type":"string","maxLength":120}},{"name":"industry","in":"query","required":false,"description":"Exact industry value.","schema":{"type":"string","maxLength":80}},{"name":"page","in":"query","required":false,"description":"1-based page number.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1}},{"name":"pageSize","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"companies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Company id (co_…)."},"name":{"type":"string","description":"Name."},"domain":{"type":"string","description":"Web domain (\"\" when none)."},"website":{"type":"string","description":"Website URL."},"industry":{"type":"string","description":"Industry."},"phone":{"type":"string","description":"Phone."},"email":{"type":"string","description":"E-mail."},"address":{"type":"string","description":"Address."},"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."},"size":{"type":"string","description":"Size band."},"description":{"type":"string","description":"Description."},"owner":{"type":"string","description":"Owner e-mail."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact record ids."},"dealIds":{"type":"array","items":{"type":"string"},"description":"Linked deal ids."},"noteCount":{"type":"integer","description":"Notes on the company."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","name","domain","website","industry","phone","email","address","city","country","size","description","owner","tags","contactIds","dealIds","noteCount","createdAt","updatedAt"]},"description":"Companies on this page."},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Current page, 1-based."},"pageSize":{"type":"integer","description":"Rows per page."},"total":{"type":"integer","description":"Total rows across all pages."},"totalPages":{"type":"integer","description":"Number of pages (at least 1)."},"hasMore":{"type":"boolean","description":"true when a later page exists."}},"additionalProperties":true,"required":["page","pageSize","total","totalPages","hasMore"],"description":"Page window applied to the list."}},"additionalProperties":true,"required":["ok","requestId","companies","pagination"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"create_company","summary":"Create a CRM company (name required; domain, website, industry, phone, e-mail, address, city, country, size, description, owner, tags)","description":"Create a CRM company (name required; domain, website, industry, phone, e-mail, address, city, country, size, description, owner, tags). A company with the same name already existing is returned instead of duplicated unless allowDuplicateName is true. Read back after saving. Linking contacts to it is done in the app (or by create_quote / deals, which carry the company on the record).\n\nRequired scope: `contacts.write`. Risk level: `write`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Company name.","schema":{"type":"string","maxLength":160}},{"name":"domain","in":"query","required":false,"description":"Web domain (example.co.il).","schema":{"type":"string","maxLength":160}},{"name":"website","in":"query","required":false,"description":"Website URL.","schema":{"type":"string","maxLength":200}},{"name":"industry","in":"query","required":false,"description":"Industry.","schema":{"type":"string","maxLength":80}},{"name":"phone","in":"query","required":false,"description":"Main phone.","schema":{"type":"string","maxLength":40}},{"name":"email","in":"query","required":false,"description":"Main e-mail.","schema":{"type":"string","maxLength":200}},{"name":"address","in":"query","required":false,"description":"Street address.","schema":{"type":"string","maxLength":300}},{"name":"city","in":"query","required":false,"description":"City.","schema":{"type":"string","maxLength":80}},{"name":"country","in":"query","required":false,"description":"Country.","schema":{"type":"string","maxLength":80}},{"name":"size","in":"query","required":false,"description":"Company size band (free text, e.g. 11-50).","schema":{"type":"string","maxLength":40}},{"name":"description","in":"query","required":false,"description":"Free-text description.","schema":{"type":"string","maxLength":2000}},{"name":"owner","in":"query","required":false,"description":"Owner (user e-mail).","schema":{"type":"string","maxLength":120}},{"name":"tags","in":"query","required":false,"description":"Tags.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"allowDuplicateName","in":"query","required":false,"description":"true to create even when a company with this name exists.","schema":{"type":"boolean"}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["company"],"description":"Always company."},"targetId":{"type":"string","description":"Record id."},"created":{"type":"boolean","description":"false when an existing company with the same name was returned instead."},"verified":{"type":"boolean","description":"true when the read-back shows the new company."},"company":{"type":"object","properties":{"id":{"type":"string","description":"Company id (co_…)."},"name":{"type":"string","description":"Name."},"domain":{"type":"string","description":"Web domain (\"\" when none)."},"website":{"type":"string","description":"Website URL."},"industry":{"type":"string","description":"Industry."},"phone":{"type":"string","description":"Phone."},"email":{"type":"string","description":"E-mail."},"address":{"type":"string","description":"Address."},"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."},"size":{"type":"string","description":"Size band."},"description":{"type":"string","description":"Description."},"owner":{"type":"string","description":"Owner e-mail."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact record ids."},"dealIds":{"type":"array","items":{"type":"string"},"description":"Linked deal ids."},"noteCount":{"type":"integer","description":"Notes on the company."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","name","domain","website","industry","phone","email","address","city","country","size","description","owner","tags","contactIds","dealIds","noteCount","createdAt","updatedAt"],"description":"The company."},"message":{"type":"string","description":"Set when an existing company was returned."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","company"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/companies/{id}":{"get":{"operationId":"get_company","summary":"One company with its fields, notes (newest first), the linked contacts (with their record ids), deals (stage, amount) and quotes","description":"One company with its fields, notes (newest first), the linked contacts (with their record ids), deals (stage, amount) and quotes.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Company id from list_companies.","schema":{"type":"string","maxLength":40}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"company":{"type":"object","properties":{"id":{"type":"string","description":"Company id (co_…)."},"name":{"type":"string","description":"Name."},"domain":{"type":"string","description":"Web domain (\"\" when none)."},"website":{"type":"string","description":"Website URL."},"industry":{"type":"string","description":"Industry."},"phone":{"type":"string","description":"Phone."},"email":{"type":"string","description":"E-mail."},"address":{"type":"string","description":"Address."},"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."},"size":{"type":"string","description":"Size band."},"description":{"type":"string","description":"Description."},"owner":{"type":"string","description":"Owner e-mail."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact record ids."},"dealIds":{"type":"array","items":{"type":"string"},"description":"Linked deal ids."},"noteCount":{"type":"integer","description":"Notes on the company."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."},"notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Note id."},"text":{"type":"string","description":"Text."},"kind":{"type":"string","description":"note | call | email | meeting | linkedin | sms | other."},"author":{"type":"string","description":"Author e-mail."},"via":{"type":"string","description":"Token name when written through the API."},"createdAt":{"type":"string","description":"ISO 8601 (occurredAt when back-dated)."}},"additionalProperties":true,"required":["id","text","kind","author","createdAt"]},"description":"Notes, newest first."}},"additionalProperties":true,"required":["id","name","domain","website","industry","phone","email","address","city","country","size","description","owner","tags","contactIds","dealIds","noteCount","createdAt","updatedAt","notes"],"description":"The company with its notes."},"contacts":{"type":"array","items":{"type":"object","properties":{"contactId":{"type":"string","description":"Record id."},"name":{"type":"string","description":"Name."},"email":{"type":"string","description":"E-mail."},"phone":{"type":"string","description":"Phone."},"status":{"type":"string","description":"Pipeline status."},"owner":{"type":"string","description":"Owner."}},"additionalProperties":true,"required":["contactId","name","email","phone","status","owner"]},"description":"Linked contacts."},"deals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Deal id."},"name":{"type":"string","description":"Name."},"stage":{"type":"string","description":"Stage."},"open":{"type":"boolean","description":"Open?"},"amount":{"type":"number","description":"Amount."},"currency":{"type":"string","description":"Currency."}},"additionalProperties":true,"required":["id","name","stage","open","amount","currency"]},"description":"Linked deals."},"quotes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Quote id."},"number":{"type":"string","description":"Number."},"title":{"type":"string","description":"Title."},"status":{"type":"string","description":"Status."},"total":{"type":"number","description":"Total."},"currency":{"type":"string","description":"Currency."}},"additionalProperties":true,"required":["id","number","title","status","total","currency"]},"description":"Quotes on this company."}},"additionalProperties":true,"required":["ok","requestId","company","contacts","deals","quotes"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/companies/{id}/update":{"post":{"operationId":"update_company","summary":"Update a company's fields (name, domain, website, industry, phone, e-mail, address, city, country, size, description, owner, tags)","description":"Update a company's fields (name, domain, website, industry, phone, e-mail, address, city, country, size, description, owner, tags). Only the fields you pass change; contact / deal links and notes are untouched. Read back after saving; before / after and \"verified\" report the result.\n\nRequired scope: `contacts.write`. Risk level: `write`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Company id.","schema":{"type":"string","maxLength":40}},{"name":"name","in":"query","required":false,"description":"New name.","schema":{"type":"string","maxLength":160}},{"name":"domain","in":"query","required":false,"description":"Web domain.","schema":{"type":"string","maxLength":160}},{"name":"website","in":"query","required":false,"description":"Website URL.","schema":{"type":"string","maxLength":200}},{"name":"industry","in":"query","required":false,"description":"Industry.","schema":{"type":"string","maxLength":80}},{"name":"phone","in":"query","required":false,"description":"Main phone.","schema":{"type":"string","maxLength":40}},{"name":"email","in":"query","required":false,"description":"Main e-mail.","schema":{"type":"string","maxLength":200}},{"name":"address","in":"query","required":false,"description":"Street address.","schema":{"type":"string","maxLength":300}},{"name":"city","in":"query","required":false,"description":"City.","schema":{"type":"string","maxLength":80}},{"name":"country","in":"query","required":false,"description":"Country.","schema":{"type":"string","maxLength":80}},{"name":"size","in":"query","required":false,"description":"Size band.","schema":{"type":"string","maxLength":40}},{"name":"description","in":"query","required":false,"description":"Description.","schema":{"type":"string","maxLength":2000}},{"name":"owner","in":"query","required":false,"description":"Owner e-mail, \"\" to unassign.","schema":{"type":"string","maxLength":120}},{"name":"tags","in":"query","required":false,"description":"Replaces the tag list.","schema":{"type":"array","maxItems":20,"items":{"type":"string"}}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["company"],"description":"Always company."},"targetId":{"type":"string","description":"Record id."},"updated":{"type":"boolean","description":"true when at least one field changed."},"verified":{"type":"boolean","description":"true when the read-back shows every value you passed."},"changed":{"type":"array","items":{"type":"string"},"description":"Fields that changed."},"before":{"type":"object","properties":{"id":{"type":"string","description":"Company id (co_…)."},"name":{"type":"string","description":"Name."},"domain":{"type":"string","description":"Web domain (\"\" when none)."},"website":{"type":"string","description":"Website URL."},"industry":{"type":"string","description":"Industry."},"phone":{"type":"string","description":"Phone."},"email":{"type":"string","description":"E-mail."},"address":{"type":"string","description":"Address."},"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."},"size":{"type":"string","description":"Size band."},"description":{"type":"string","description":"Description."},"owner":{"type":"string","description":"Owner e-mail."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact record ids."},"dealIds":{"type":"array","items":{"type":"string"},"description":"Linked deal ids."},"noteCount":{"type":"integer","description":"Notes on the company."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","name","domain","website","industry","phone","email","address","city","country","size","description","owner","tags","contactIds","dealIds","noteCount","createdAt","updatedAt"],"description":"The company."},"after":{"type":"object","properties":{"id":{"type":"string","description":"Company id (co_…)."},"name":{"type":"string","description":"Name."},"domain":{"type":"string","description":"Web domain (\"\" when none)."},"website":{"type":"string","description":"Website URL."},"industry":{"type":"string","description":"Industry."},"phone":{"type":"string","description":"Phone."},"email":{"type":"string","description":"E-mail."},"address":{"type":"string","description":"Address."},"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."},"size":{"type":"string","description":"Size band."},"description":{"type":"string","description":"Description."},"owner":{"type":"string","description":"Owner e-mail."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact record ids."},"dealIds":{"type":"array","items":{"type":"string"},"description":"Linked deal ids."},"noteCount":{"type":"integer","description":"Notes on the company."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","name","domain","website","industry","phone","email","address","city","country","size","description","owner","tags","contactIds","dealIds","noteCount","createdAt","updatedAt"],"description":"The company."},"company":{"type":"object","properties":{"id":{"type":"string","description":"Company id (co_…)."},"name":{"type":"string","description":"Name."},"domain":{"type":"string","description":"Web domain (\"\" when none)."},"website":{"type":"string","description":"Website URL."},"industry":{"type":"string","description":"Industry."},"phone":{"type":"string","description":"Phone."},"email":{"type":"string","description":"E-mail."},"address":{"type":"string","description":"Address."},"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."},"size":{"type":"string","description":"Size band."},"description":{"type":"string","description":"Description."},"owner":{"type":"string","description":"Owner e-mail."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Linked contact record ids."},"dealIds":{"type":"array","items":{"type":"string"},"description":"Linked deal ids."},"noteCount":{"type":"integer","description":"Notes on the company."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","name","domain","website","industry","phone","email","address","city","country","size","description","owner","tags","contactIds","dealIds","noteCount","createdAt","updatedAt"],"description":"The company."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","updated","verified","changed","before","after","company"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/crm/custom-fields":{"get":{"operationId":"list_custom_fields","summary":"The CRM's custom field (property) definitions: id, which object they belong to (contact / company / deal), label, type (text, number, date, dropdown…) and dropdown options","description":"The CRM's custom field (property) definitions: id, which object they belong to (contact / company / deal), label, type (text, number, date, dropdown…) and dropdown options. Definitions only — a contact's values are the extra columns get_lead returns under `fields`.\n\nRequired scope: `contacts.read`. Risk level: `read`.","tags":["contacts"],"security":[{"bearerAuth":["contacts.read"]}],"parameters":[{"name":"object","in":"query","required":false,"description":"Only fields of this object.","schema":{"type":"string","enum":["contact","company","deal"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Field id."},"object":{"type":"string","description":"contact | company | deal."},"label":{"type":"string","description":"Label."},"type":{"type":"string","description":"text | number | date | dropdown | …"},"options":{"type":"array","items":{"type":"string"},"description":"Dropdown options."},"legacyId":{"type":"string","description":"Leads-table column id when imported from it."},"order":{"type":"integer","description":"Display order."}},"additionalProperties":true,"required":["id","object","label","type","options","order"]},"description":"Property definitions."},"note":{"type":"string","description":"Where the values live."}},"additionalProperties":true,"required":["ok","requestId","fields","note"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/crm/notes":{"post":{"operationId":"add_note","summary":"Add a note or a logged activity (call, e-mail, meeting, SMS, LinkedIn touch) to a contact, a company or a deal — the same timeline the app shows on that record's card","description":"Add a note or a logged activity (call, e-mail, meeting, SMS, LinkedIn touch) to a contact, a company or a deal — the same timeline the app shows on that record's card. Notes written through a token are stamped \"via <token name>\" so people can tell them from their own. For a contact this is the same store as add_lead_note.\n\nRequired scope: `notes.write`. Risk level: `write`.","tags":["notes"],"security":[{"bearerAuth":["notes.write"]}],"parameters":[{"name":"entityType","in":"query","required":true,"description":"contact, company or deal.","schema":{"type":"string","enum":["contact","company","deal"]}},{"name":"id","in":"query","required":true,"description":"The record id: a contact record id / contact id, a company id (list_companies) or a deal id (list_deals).","schema":{"type":"string","maxLength":200}},{"name":"text","in":"query","required":true,"description":"The note text.","schema":{"type":"string","maxLength":5000}},{"name":"kind","in":"query","required":false,"description":"What the note records (default note).","schema":{"type":"string","enum":["note","call","email","meeting","linkedin","sms","other"]}},{"name":"occurredAt","in":"query","required":false,"description":"ISO 8601 date/time the activity happened (back-dated entries).","schema":{"type":"string","maxLength":40}},{"name":"idempotencyKey","in":"query","required":false,"description":"A unique id for THIS action. Repeating a call with the same key returns the original result instead of acting twice — use it so a timeout or retry cannot duplicate the write.","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"requestId":{"type":"string"},"targetType":{"type":"string","enum":["contact","company","deal"],"description":"Entity type."},"targetId":{"type":"string","description":"Entity id."},"created":{"type":"boolean","description":"Always true on success."},"note":{"type":"object","properties":{"id":{"type":"string","description":"Note id."},"kind":{"type":"string","description":"Kind."},"text":{"type":"string","description":"First 200 chars."},"createdAt":{"type":"string","description":"ISO 8601."}},"additionalProperties":true,"required":["id","kind","text","createdAt"],"description":"The saved note."},"entity":{"type":"object","properties":{"type":{"type":"string","description":"Type."},"id":{"type":"string","description":"Id."},"name":{"type":"string","description":"Name."}},"additionalProperties":true,"required":["type","id","name"],"description":"The entity noted."},"idempotentReplay":{"type":"boolean","description":"true when this idempotencyKey was already used: the ORIGINAL result is returned and nothing ran again."}},"additionalProperties":true,"required":["ok","requestId","targetType","targetId","created","note","entity"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}}}}