{"openapi":"3.1.0","info":{"title":"ZenABM API","version":"1.0.0","description":"REST API for accessing ZenABM data. Generate an API token at https://app.zenabm.com/api-keys. Endpoints that return weekly breakdowns use Monday–Sunday weeks (weekStart/weekEnd dates).\n\n## Changelog\n\n### 2026-10\n\n- **New:** Campaign Schedules (Budget Saver). `GET /campaign-schedules`, `POST /campaign-schedules` (create, or update with `id`), `DELETE /campaign-schedules/{id}`, `GET /campaign-schedules/for-entity` and `GET /campaign-schedules/logs`. A schedule pauses in-scope Ad Sets on LinkedIn outside its weekly hours and resumes the ones it paused, right after a save and every 15 minutes.\n- **New:** `POST /conversation-ads` creates a LinkedIn Conversation Ad (message tree with reply buttons, links and lead forms) in a message Ad Set in one call. Written live to LinkedIn.\n\n### 2026-09\n\n- **New:** `POST /abm-stages/manage` applies one change to an ABM stage per call — create, rename, recolor, reorder or delete a stage, set how its blocks combine, or add, replace or remove a condition block or a single condition. Stages, CRM stages, properties and LinkedIn assets are addressed by name instead of id, and the response returns the updated stage with the same condition model as `GET /abm-stages/{id}` plus non-blocking `warnings`. This is the first write endpoint in v1; it is gated by the same API access plan feature as the read endpoints. The body may also be `{ \"operations\": [...] }` with up to 10 operations applied in order (not atomic: earlier steps stay applied when a later one fails), a new `set_stage_conditions` op replaces a stage’s whole rule in one step, and `data` now carries `applied` and `total` next to `stage` and `warnings`.\n- **New:** `hideExcludedCompanies` (boolean, default `false`) hides companies that have a COMPANY exclusion in this organization, matching the \"Excluded\" badge in the UI. Accepted on `GET /companies`, `GET /campaigns/{id}/companies`, `GET /campaign-groups/{id}/companies`, `GET /abm-campaigns/{id}/companies` and `GET /abm-stages/{id}/companies`. On the Ad Set and Campaign endpoints, only exclusions that apply to that Ad Set/Campaign are hidden (team-wide, or scoped specifically to it) — an exclusion scoped elsewhere is left alone.\n- **New:** `hasContacts` (boolean, default `false`) returns only companies that have at least one HubSpot contact. Accepted on `GET /companies`, `GET /campaigns/{id}/companies`, `GET /campaign-groups/{id}/companies`, `GET /abm-campaigns/{id}/companies` and `GET /abm-stages/{id}/companies`.\n- **New:** `GET /deals` returns `costBeforeDeal` and `costAfterDeal` next to the existing `impressionsBeforeDeal`/`clicksBeforeDeal`/`engagementsBeforeDeal`. Both are LinkedIn ad spend in USD, unlike `amount` which follows the team’s display currency.\n\n### 2026-08\n\n- **New:** `GET /abm-stages` and `GET /abm-stages/{id}` return each stage’s full condition model. `blockOperator` (`AND`/`OR`) joins the stage’s `conditionBlocks`, and each block joins its own `conditions` with its `operator`. Every condition carries a `type` and only the fields that type uses; null fields are omitted. Base fields and `currentCompaniesCount` are unchanged, so this is additive.\n- **New:** `CONTACT_PROPERTY` conditions test a HubSpot **contact** property instead of a company property. The condition’s `propertyMapping` carries `propertyObjectType: \"CONTACT\"` and `minMatchingContacts`; the company matches when at least that many of its associated contacts satisfy the mapping. HubSpot only, and the negative operators (`not_equals`, `not_contains`, `not_in_list`, `is_unknown`) stay company-only because an unset value would match almost every company.\n- **Breaking:** `GET /deals` no longer accepts `dealStatus=disqualified`. Deal status is now resolved natively from each CRM as `open`, `won`, `lost` or `any`; any other value returns 400. Deals previously matched by `disqualified` are now filtered by their native CRM status instead.\n- **Attio support.** Attio deals are included in `GET /deals` alongside HubSpot deals and Salesforce opportunities, tagged `source: \"attio\"` and scoped with `source=attio`. Company payloads carry `attioRecordId`, and the company list endpoints accept `attioMatchStatus` (`all`, `matched`, `unmatched`). `crmMatchStatus` keeps its generic name but filters HubSpot alone.\n- **New:** `GET /campaigns/{id}/suggested-bid` returns LinkedIn’s suggested bid for an Ad Set — the same number Campaign Manager shows — plus the allowed bid range, daily budget limits, and the current bid and budget. Read live from LinkedIn on every call. Returns 422 when the Ad Set cannot be priced and 502 when LinkedIn has no pricing for the targeting.\n- `GET /linkedin-metrics` accepts `timeGranularity` (`ALL`, `DAILY`, `MONTHLY`, `YEARLY`) and `metrics`. Either one switches the response from the flat totals object to the timeseries shape `{ startDate, endDate, timeGranularity, fields, rows, totals, truncated }`. It also accepts `linkedInCampaignGroupId` for campaign-level metrics; `linkedInCampaignId` stays ad-set level and the two cannot be combined.\n- `GET /abm-stages/{id}/companies-entering` and `GET /abm-stages/{id}/companies-progressing` accept `campaignType` (`current_abm_stage`, `lifetime_abm_stage`, `specific_campaign`) with `campaignId`. The older `all_abm_campaigns` and `linkedin_influenced` values still work as aliases, and an unknown value falls back to `current_abm_stage` instead of returning an error.\n- Stage scoping is now explicit. On `GET /abm-campaigns/{id}/companies`, `abmStage` and the `abmStages` filter report the company’s stage inside that campaign (a manual override wins), while `lifetimeAbmStage` stays company-wide. `GET /companies` follows the same rule when `abmCampaigns` holds exactly one ID.\n\n## For agents\n\n- Every operation has a unique `operationId`, typed parameters and a response schema, so this document can be converted straight into function-calling tool definitions.\n- Operations tagged **Website** are public and need no authentication. They are served from https://zenabm.com (see the `servers` entry on those paths).\n- Every other operation needs `Authorization: Bearer <token>`, generated at https://app.zenabm.com/api-keys, and returns only the data of the workspace that token belongs to.\n- Errors are always JSON. Public content API errors use the `SiteApiError` schema: a stable `code`, a `message`, a `hint` and a `documentation` link.\n- Rate limits: the public content API allows 60 requests per minute per IP. Authenticated endpoints are limited per workspace; a `429` response means back off and retry.\n- There is also an MCP server (Streamable HTTP) at https://app.zenabm.com/api/mcp — see https://zenabm.com/.well-known/mcp.json.\n","contact":{"name":"ZenABM","url":"https://zenabm.com/contact","email":"mj@zenabm.com"},"termsOfService":"https://zenabm.com/terms-of-use"},"servers":[{"url":"https://app.zenabm.com/api/v1","description":"ZenABM API"},{"url":"https://zenabm.com","description":"ZenABM website (public content API)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"API token generated at https://app.zenabm.com/api-keys. Pass as: Authorization: Bearer <token>"}},"schemas":{"Pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"pageSize":{"type":"integer","example":20},"totalCount":{"type":"integer","example":150},"totalPages":{"type":"integer","example":8}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"status":{"type":"integer","example":401},"code":{"type":"string","example":"UNAUTHORIZED"},"message":{"type":"string","example":"Invalid API token"}}}}},"Meta":{"type":"object","properties":{"timestamp":{"type":"string","example":"2024-01-15T10:30:00.000Z"}}},"AbmStageRef":{"type":"object","description":"Points at one stage by `id` or by `name` — send exactly one. Names match case-insensitively; a unique prefix or substring also resolves (`\"aware\"` finds `Aware`). An ambiguous or unknown name returns 422 `UNRESOLVED_REFERENCE`.","properties":{"id":{"type":"string","description":"Stage id (cuid)."},"name":{"type":"string","description":"Stage name, e.g. \"Aware\"."}},"oneOf":[{"required":["id"]},{"required":["name"]}]},"AbmStagePosition":{"type":"object","description":"Where a stage sits in the funnel — send exactly one of the three fields. Fixed stages cannot be displaced: `Identified` stays first and `Customer`, `Lost` and `Disqualified` stay last.","properties":{"beforeStageName":{"type":"string","description":"Place directly before this stage."},"afterStageName":{"type":"string","description":"Place directly after this stage."},"order":{"type":"integer","minimum":2,"description":"Explicit funnel position (2 = right after Identified)."}},"oneOf":[{"required":["beforeStageName"]},{"required":["afterStageName"]},{"required":["order"]}]},"AbmStageConditionLinkedinMetricInput":{"type":"object","description":"A LinkedIn metric threshold, evaluated over `windowDays` (omit for all-time) against the assets in `scope`. Stored as a `LINKEDIN_METRICS` condition.","required":["type","metric","comparison","minValue"],"properties":{"type":{"type":"string","enum":["linkedin_metric"]},"metric":{"type":"string","enum":["IMPRESSIONS","ENGAGEMENTS","CLICKS","CTR","CPC","COST"]},"comparison":{"type":"string","enum":["GREATER_THAN","GREATER_THAN_OR_EQUAL","LESS_THAN","LESS_THAN_OR_EQUAL","EQUALS","NOT_EQUALS","BETWEEN"]},"minValue":{"type":"integer","minimum":0,"description":"The value to compare against (the low end for `BETWEEN`)."},"maxValue":{"type":"integer","minimum":0,"description":"Required only for `BETWEEN`."},"windowDays":{"type":"integer","minimum":1,"maximum":365,"description":"Rolling window in days. Omit for all-time."},"scope":{"type":"string","enum":["INHERIT_CAMPAIGN","LINKEDIN_CAMPAIGN_GROUPS","LINKEDIN_AD_SETS","ABM_CAMPAIGNS"],"default":"INHERIT_CAMPAIGN","description":"`INHERIT_CAMPAIGN` (default) uses the ABM campaign's own assets. Any other scope needs at least one `scopeNames` entry."},"scopeNames":{"type":"array","items":{"type":"string"},"description":"Names of the Ad Sets / Campaigns / ABM campaigns for a non-inherit scope."}}},"AbmStageConditionLifecycleStageInput":{"type":"object","description":"Company is in one of the given HubSpot lifecycle stages. Stored as a `LIFECYCLE_STAGE` condition.","required":["type","lifecycleStageNames"],"properties":{"type":{"type":"string","enum":["lifecycle_stage"]},"lifecycleStageNames":{"type":"array","minItems":1,"items":{"type":"string"},"description":"HubSpot lifecycle stage names, e.g. `[\"Lead\", \"Customer\"]`."}}},"AbmStageConditionDealStageInput":{"type":"object","description":"Company has a HubSpot deal in one of the given stages, or any open deal. Send `dealStageNames` or `matchAnyOpenDeal: true` — not both. Stored as a `DEAL_STAGE` condition.","required":["type"],"properties":{"type":{"type":"string","enum":["deal_stage"]},"dealStageNames":{"type":"array","items":{"type":"string"},"description":"HubSpot deal stage names."},"pipelineNames":{"type":"array","items":{"type":"string"},"description":"Pipeline names. Required when a deal stage name repeats across pipelines, or to scope `matchAnyOpenDeal` to specific pipelines."},"matchAnyOpenDeal":{"type":"boolean","description":"Match any open deal instead of specific stages."}}},"AbmStageConditionAttioDealStageInput":{"type":"object","description":"Company has an Attio deal in one of the given statuses, or any open deal. Send `dealStatusNames` or `matchAnyOpenDeal: true` — not both. Stored as an `ATTIO_DEAL_STAGE` condition.","required":["type"],"properties":{"type":{"type":"string","enum":["attio_deal_stage"]},"dealStatusNames":{"type":"array","items":{"type":"string"},"description":"Attio deal status names."},"matchAnyOpenDeal":{"type":"boolean","description":"Match any open deal instead of specific statuses."}}},"AbmStageConditionCompanyPropertyInput":{"type":"object","description":"Tests a HubSpot company property. Value fields depend on `operator`: `value` for equals / contains / date operators, `values` for `in_list` / `not_in_list`, `numericThreshold` (and `numericThresholdMax` for `between`) for numeric operators, nothing for `is_known` / `is_unknown`. Stored as a `CUSTOM_PROPERTY` condition.","required":["type","propertyName","operator"],"properties":{"type":{"type":"string","enum":["company_property"]},"propertyName":{"type":"string","description":"HubSpot company property name or label."},"operator":{"type":"string","enum":["equals","contains","greater_than","greater_than_or_equal","less_than","less_than_or_equal","between","in_list","not_equals","not_contains","not_in_list","is_known","is_unknown"]},"value":{"type":"string","description":"Single value for equals / contains / date operators."},"values":{"type":"array","items":{"type":"string"},"description":"Value list for `in_list` / `not_in_list`."},"numericThreshold":{"type":"number","description":"Number for `greater_than` / `less_than` / `between` (low end)."},"numericThresholdMax":{"type":"number","description":"High end for `between`."}}},"AbmStageConditionContactPropertyInput":{"type":"object","description":"Tests a HubSpot contact property. The company matches when at least `minMatchingContacts` of its associated contacts satisfy it (default 1 = any contact). The negative operators (`not_equals`, `not_contains`, `not_in_list`, `is_unknown`) are not allowed here because an unset value would match almost every company — use a company property instead. Value fields follow the same rules as a company property. Stored as a `CONTACT_PROPERTY` condition.","required":["type","propertyName","operator"],"properties":{"type":{"type":"string","enum":["contact_property"]},"propertyName":{"type":"string","description":"HubSpot contact property name or label."},"operator":{"type":"string","enum":["equals","contains","greater_than","greater_than_or_equal","less_than","less_than_or_equal","between","in_list","is_known"]},"minMatchingContacts":{"type":"integer","minimum":1,"default":1,"description":"Company matches when at least this many contacts satisfy the condition."},"value":{"type":"string","description":"Single value for equals / contains / date operators."},"values":{"type":"array","items":{"type":"string"},"description":"Value list for `in_list`."},"numericThreshold":{"type":"number","description":"Number for `greater_than` / `less_than` / `between` (low end)."},"numericThresholdMax":{"type":"number","description":"High end for `between`."}}},"AbmStageConditionAttioCompanyPropertyInput":{"type":"object","description":"Tests an Attio company attribute. Value fields follow the same rules as a HubSpot company property. Stored as an `ATTIO_COMPANY_PROPERTY` condition.","required":["type","attribute","operator"],"properties":{"type":{"type":"string","enum":["attio_company_property"]},"attribute":{"type":"string","description":"Attio company attribute slug or title."},"operator":{"type":"string","enum":["equals","contains","greater_than","greater_than_or_equal","less_than","less_than_or_equal","between","in_list","not_equals","not_contains","not_in_list","is_known","is_unknown"]},"value":{"type":"string","description":"Single value for equals / contains / date operators."},"values":{"type":"array","items":{"type":"string"},"description":"Value list for `in_list` / `not_in_list`."},"numericThreshold":{"type":"number","description":"Number for `greater_than` / `less_than` / `between` (low end)."},"numericThresholdMax":{"type":"number","description":"High end for `between`."}}},"AbmStageConditionInput":{"description":"One condition, discriminated on `type`. Every reference (lifecycle stage, deal stage, pipeline, property, Attio attribute, LinkedIn asset, ABM campaign) is given by name and resolved against this team; an unknown or ambiguous name returns 422 `UNRESOLVED_REFERENCE` with the available candidates.","oneOf":[{"$ref":"#/components/schemas/AbmStageConditionLinkedinMetricInput"},{"$ref":"#/components/schemas/AbmStageConditionLifecycleStageInput"},{"$ref":"#/components/schemas/AbmStageConditionDealStageInput"},{"$ref":"#/components/schemas/AbmStageConditionAttioDealStageInput"},{"$ref":"#/components/schemas/AbmStageConditionCompanyPropertyInput"},{"$ref":"#/components/schemas/AbmStageConditionContactPropertyInput"},{"$ref":"#/components/schemas/AbmStageConditionAttioCompanyPropertyInput"}],"discriminator":{"propertyName":"type","mapping":{"linkedin_metric":"#/components/schemas/AbmStageConditionLinkedinMetricInput","lifecycle_stage":"#/components/schemas/AbmStageConditionLifecycleStageInput","deal_stage":"#/components/schemas/AbmStageConditionDealStageInput","attio_deal_stage":"#/components/schemas/AbmStageConditionAttioDealStageInput","company_property":"#/components/schemas/AbmStageConditionCompanyPropertyInput","contact_property":"#/components/schemas/AbmStageConditionContactPropertyInput","attio_company_property":"#/components/schemas/AbmStageConditionAttioCompanyPropertyInput"}}},"AbmStageOpCreateStage":{"type":"object","description":"Create a stage. Without `position` it lands right before the closing stages.","required":["op","name"],"properties":{"op":{"type":"string","enum":["create_stage"]},"name":{"type":"string","minLength":1},"color":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"Hex color like `#6B7280`. Defaults to `#6B7280`."},"position":{"$ref":"#/components/schemas/AbmStagePosition"}}},"AbmStageOpRenameStage":{"type":"object","description":"Rename a stage. Fixed stages cannot be renamed.","required":["op","stageRef","name"],"properties":{"op":{"type":"string","enum":["rename_stage"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"name":{"type":"string","minLength":1}}},"AbmStageOpRecolorStage":{"type":"object","description":"Change the color of a stage.","required":["op","stageRef","color"],"properties":{"op":{"type":"string","enum":["recolor_stage"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"color":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"Hex color like `#6B7280`."}}},"AbmStageOpDeleteStage":{"type":"object","description":"Delete a stage and its conditions. Fixed stages cannot be deleted. The response `stage` is `null`.","required":["op","stageRef"],"properties":{"op":{"type":"string","enum":["delete_stage"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"}}},"AbmStageOpReorderStage":{"type":"object","description":"Move a stage to a new funnel position. Fixed stages cannot move.","required":["op","stageRef","position"],"properties":{"op":{"type":"string","enum":["reorder_stage"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"position":{"$ref":"#/components/schemas/AbmStagePosition"}}},"AbmStageOpSetStageBlockOperator":{"type":"object","description":"Set how the stage's condition blocks combine (`blockOperator` in the read model).","required":["op","stageRef","operator"],"properties":{"op":{"type":"string","enum":["set_stage_block_operator"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"operator":{"type":"string","enum":["AND","OR"]}}},"AbmStageConditionGroupInput":{"type":"object","description":"One condition block for `set_stage_conditions`: how its conditions combine, plus at least one condition.","required":["conditions"],"properties":{"operator":{"type":"string","enum":["AND","OR"],"default":"OR","description":"How the conditions inside this block combine."},"conditions":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AbmStageConditionInput"}}}},"AbmStageOpSetStageConditions":{"type":"object","description":"Replace ALL of a stage's condition blocks in one step. This is the recommended way to rewrite a stage's rule — do not chain `remove_condition_block` + `add_condition_block`. Omit `blockOperator` to keep how the blocks combine today.","required":["op","stageRef","blocks"],"properties":{"op":{"type":"string","enum":["set_stage_conditions"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockOperator":{"type":"string","enum":["AND","OR"],"description":"How the new blocks combine (`blockOperator` in the read model). Omit to keep the current setting."},"blocks":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AbmStageConditionGroupInput"},"description":"The complete new set of condition blocks. Every existing block on the stage is removed first."}}},"AbmStageOpAddConditionBlock":{"type":"object","description":"Append a new condition block with one or more conditions.","required":["op","stageRef","conditions"],"properties":{"op":{"type":"string","enum":["add_condition_block"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockOperator":{"type":"string","enum":["AND","OR"],"default":"OR","description":"How the conditions inside this new block combine."},"conditions":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AbmStageConditionInput"}}}},"AbmStageOpRemoveConditionBlock":{"type":"object","description":"Remove one condition block and every condition in it.","required":["op","stageRef","blockIndex"],"properties":{"op":{"type":"string","enum":["remove_condition_block"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockIndex":{"type":"integer","minimum":0,"description":"0-based position in `conditionBlocks`."}}},"AbmStageOpSetBlockOperator":{"type":"object","description":"Set how the conditions inside one block combine.","required":["op","stageRef","blockIndex","operator"],"properties":{"op":{"type":"string","enum":["set_block_operator"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockIndex":{"type":"integer","minimum":0,"description":"0-based position in `conditionBlocks`."},"operator":{"type":"string","enum":["AND","OR"]}}},"AbmStageOpAddCondition":{"type":"object","description":"Append one condition to an existing block.","required":["op","stageRef","blockIndex","condition"],"properties":{"op":{"type":"string","enum":["add_condition"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockIndex":{"type":"integer","minimum":0,"description":"0-based position in `conditionBlocks`."},"condition":{"$ref":"#/components/schemas/AbmStageConditionInput"}}},"AbmStageOpReplaceCondition":{"type":"object","description":"Swap one condition in place. To edit a single field (threshold, window, value, `minMatchingContacts`), send the existing condition with only that field changed.","required":["op","stageRef","blockIndex","conditionIndex","condition"],"properties":{"op":{"type":"string","enum":["replace_condition"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockIndex":{"type":"integer","minimum":0,"description":"0-based position in `conditionBlocks`."},"conditionIndex":{"type":"integer","minimum":0,"description":"0-based position in that block's `conditions`."},"condition":{"$ref":"#/components/schemas/AbmStageConditionInput","description":"The full new condition."}}},"AbmStageOpRemoveCondition":{"type":"object","description":"Remove one condition from a block.","required":["op","stageRef","blockIndex","conditionIndex"],"properties":{"op":{"type":"string","enum":["remove_condition"]},"stageRef":{"$ref":"#/components/schemas/AbmStageRef"},"blockIndex":{"type":"integer","minimum":0,"description":"0-based position in `conditionBlocks`."},"conditionIndex":{"type":"integer","minimum":0,"description":"0-based position in that block's `conditions`."}}},"AbmStageOperation":{"description":"One operation for `POST /abm-stages/manage`, discriminated on `op`. Send it as the request body on its own, or send several inside `AbmStageManageBatchRequest`.","oneOf":[{"$ref":"#/components/schemas/AbmStageOpCreateStage"},{"$ref":"#/components/schemas/AbmStageOpRenameStage"},{"$ref":"#/components/schemas/AbmStageOpRecolorStage"},{"$ref":"#/components/schemas/AbmStageOpDeleteStage"},{"$ref":"#/components/schemas/AbmStageOpReorderStage"},{"$ref":"#/components/schemas/AbmStageOpSetStageBlockOperator"},{"$ref":"#/components/schemas/AbmStageOpSetStageConditions"},{"$ref":"#/components/schemas/AbmStageOpAddConditionBlock"},{"$ref":"#/components/schemas/AbmStageOpRemoveConditionBlock"},{"$ref":"#/components/schemas/AbmStageOpSetBlockOperator"},{"$ref":"#/components/schemas/AbmStageOpAddCondition"},{"$ref":"#/components/schemas/AbmStageOpReplaceCondition"},{"$ref":"#/components/schemas/AbmStageOpRemoveCondition"}],"discriminator":{"propertyName":"op","mapping":{"create_stage":"#/components/schemas/AbmStageOpCreateStage","rename_stage":"#/components/schemas/AbmStageOpRenameStage","recolor_stage":"#/components/schemas/AbmStageOpRecolorStage","delete_stage":"#/components/schemas/AbmStageOpDeleteStage","reorder_stage":"#/components/schemas/AbmStageOpReorderStage","set_stage_block_operator":"#/components/schemas/AbmStageOpSetStageBlockOperator","set_stage_conditions":"#/components/schemas/AbmStageOpSetStageConditions","add_condition_block":"#/components/schemas/AbmStageOpAddConditionBlock","remove_condition_block":"#/components/schemas/AbmStageOpRemoveConditionBlock","set_block_operator":"#/components/schemas/AbmStageOpSetBlockOperator","add_condition":"#/components/schemas/AbmStageOpAddCondition","replace_condition":"#/components/schemas/AbmStageOpReplaceCondition","remove_condition":"#/components/schemas/AbmStageOpRemoveCondition"}}},"AbmStageManageBatchRequest":{"type":"object","description":"A batch of 1–10 operations for `POST /abm-stages/manage`. Operations apply in order and each one sees the result of the one before it, so indexes shift after a remove. The batch is not atomic: when a step fails, the earlier steps stay applied.","required":["operations"],"properties":{"operations":{"type":"array","minItems":1,"maxItems":10,"items":{"$ref":"#/components/schemas/AbmStageOperation"}}}},"AbmStageManageResult":{"type":"object","description":"The `data` of a successful `POST /abm-stages/manage` call: how many operations ran, the stage re-read after the last one, plus non-blocking notes. A single (unwrapped) operation reports `applied: 1, total: 1`.","required":["applied","total","stage","warnings"],"properties":{"applied":{"type":"integer","example":1,"description":"Number of operations that were applied. Equals `total` on success."},"total":{"type":"integer","example":1,"description":"Number of operations in the request (1 for an unwrapped operation)."},"stage":{"type":["object","null"],"description":"The stage re-read after the last applied operation, with the same condition model as `GET /abm-stages/{id}`. `null` only when the last operation was `delete_stage`.","required":["id","name","color","displayOrder","isSystem","blockOperator","conditionBlocks"],"properties":{"id":{"type":"string","example":"cls1abc"},"name":{"type":"string","example":"Aware"},"color":{"type":"string","example":"#FFC107"},"displayOrder":{"type":"integer","example":2},"isSystem":{"type":"boolean","description":"True for the fixed stages (`Identified`, `Customer`, `Lost`, `Disqualified`)."},"blockOperator":{"type":"string","enum":["AND","OR"],"description":"How the `conditionBlocks` combine."},"conditionBlocks":{"type":"array","items":{"type":"object","required":["operator","conditions"],"properties":{"operator":{"type":"string","enum":["AND","OR"],"description":"How the `conditions` in this block combine."},"conditions":{"type":"array","items":{"type":"object","description":"Same shape as a condition in `GET /abm-stages/{id}`: a `type` plus only the fields that type uses (null fields are omitted).","required":["type"],"properties":{"type":{"type":"string","enum":["LINKEDIN_METRICS","LIFECYCLE_STAGE","DEAL_STAGE","CUSTOM_PROPERTY","CONTACT_PROPERTY","ATTIO_COMPANY_PROPERTY","ATTIO_DEAL_STAGE"]}},"additionalProperties":true}}}}}}},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking notes from every applied step. A `delete_stage` call reports what was deleted; an edit reports a condition that points at something that no longer exists (a deleted lifecycle stage, deal stage, property or LinkedIn asset)."}}},"SiteApiError":{"type":"object","required":["error"],"description":"Every failure from this API uses this shape.","properties":{"error":{"type":"object","required":["code","message","hint","status","documentation"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code.","enum":["bad_request","invalid_parameter","unauthorized","forbidden","not_found","method_not_allowed","not_acceptable","rate_limited","internal_error","upstream_unavailable"]},"message":{"type":"string","description":"Human-readable description of the failure."},"hint":{"type":"string","description":"How to make the request succeed."},"status":{"type":"integer","description":"HTTP status code, repeated in the body."},"documentation":{"type":"string","format":"uri","description":"Docs for this endpoint."},"parameter":{"type":"string","description":"The offending parameter, when the failure is about one."}}}}},"SiteIndex":{"type":"object","required":["name","description","endpoints","resources"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"version":{"type":"string"},"openapi":{"type":"string","format":"uri"},"whenToUse":{"type":"array","items":{"type":"string"},"description":"Jobs this API is the right tool for."},"endpoints":{"type":"array","items":{"type":"object","required":["method","path","description"],"properties":{"method":{"type":"string"},"path":{"type":"string"},"description":{"type":"string"}}}},"resources":{"type":"array","items":{"type":"object","required":["title","url","description"],"properties":{"title":{"type":"string"},"url":{"type":"string","format":"uri"},"description":{"type":"string"}}}}}},"SiteDocSummary":{"type":"object","required":["slug","title","description","section","url","markdownUrl"],"properties":{"slug":{"type":"string","description":"Path under /docs, e.g. `abm/stages`."},"title":{"type":"string"},"description":{"type":"string"},"section":{"type":"string","description":"Documentation section id."},"url":{"type":"string","format":"uri","description":"Human-readable page."},"markdownUrl":{"type":"string","format":"uri","description":"This API’s markdown source."}}},"SiteDocDetail":{"allOf":[{"$ref":"#/components/schemas/SiteDocSummary"},{"type":"object","required":["content"],"properties":{"content":{"type":"string","description":"Markdown (MDX) source of the page."}}}]},"SiteDocList":{"type":"object","required":["docs","total"],"properties":{"total":{"type":"integer"},"docs":{"type":"array","items":{"$ref":"#/components/schemas/SiteDocSummary"}}}},"SitePost":{"type":"object","required":["slug","title","excerpt","date","modified","url"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"excerpt":{"type":"string","description":"Plain-text summary, HTML stripped."},"date":{"type":"string","format":"date-time"},"modified":{"type":"string","format":"date-time"},"url":{"type":"string","format":"uri"}}},"SitePostDetail":{"allOf":[{"$ref":"#/components/schemas/SitePost"},{"type":"object","required":["contentHtml","contentText","contentMarkdown"],"properties":{"contentHtml":{"type":"string","description":"Post body as HTML."},"contentText":{"type":"string","description":"Post body as plain text, no markup."},"contentMarkdown":{"type":["string","null"],"description":"Post body as markdown — headings, lists, tables, code and images with their URLs. The best representation for an agent. `null` only while the blog is still served from WordPress."}}}]},"SitePostList":{"type":"object","required":["posts","page","perPage","total","totalPages"],"properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/SitePost"}},"page":{"type":"integer"},"perPage":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}}},"SitePage":{"type":"object","required":["url","path","type"],"properties":{"url":{"type":"string","format":"uri"},"path":{"type":"string"},"type":{"type":"string","enum":["page","docs","post"]},"title":{"type":"string"},"lastModified":{"type":"string","format":"date-time"}}},"SitePageList":{"type":"object","required":["pages","total"],"properties":{"total":{"type":"integer"},"pages":{"type":"array","items":{"$ref":"#/components/schemas/SitePage"}}}},"SiteSearchResult":{"type":"object","required":["id","kind","title","breadcrumb","href","url"],"properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["guide","api-page","api-section","api-endpoint","mcp","post"],"description":"`post` is a blog post; every other kind comes from the documentation index."},"title":{"type":"string"},"breadcrumb":{"type":"string"},"excerpt":{"type":"string"},"href":{"type":"string"},"url":{"type":"string","format":"uri"}}},"SiteSearchResults":{"type":"object","required":["query","results","total"],"properties":{"query":{"type":"string"},"total":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/SiteSearchResult"}}}}},"parameters":{"page":{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Page number (default: 1)"},"pageSize":{"name":"pageSize","in":"query","schema":{"type":"integer","default":20,"maximum":100},"description":"Items per page (default: 20, max: 100)"},"period":{"name":"period","in":"query","schema":{"type":"string","enum":["last7Days","last14Days","lastWeek","last30Days","thisMonth","lastMonth","last90Days","last3Months","thisQuarter","lastQuarter","yearToDate","lastYear","previousYear"],"default":"last30Days"},"description":"Time period preset. Ignored when startDate/endDate are provided."},"startDate":{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (YYYY-MM-DD). When provided with endDate, overrides the period parameter."},"endDate":{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (YYYY-MM-DD). When provided with startDate, overrides the period parameter."},"sortBy":{"name":"sortBy","in":"query","schema":{"type":"string"},"description":"Field to sort by (e.g. impressions, clicks, engagements)"},"sortOrder":{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sort direction"},"search":{"name":"search","in":"query","schema":{"type":"string"},"description":"Search filter"},"hideExcludedCompanies":{"name":"hideExcludedCompanies","in":"query","schema":{"type":"boolean","default":false},"description":"When `true`, hides companies that have a COMPANY exclusion in this organization (matches the \"Excluded\" badge in the UI)."},"hasContacts":{"name":"hasContacts","in":"query","schema":{"type":"boolean","default":false},"description":"When `true`, returns only companies that have at least one contact. Contacts come from HubSpot, so this returns no companies when HubSpot is not connected."},"jobTitleWeeklyStartDate":{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (YYYY-MM-DD). Must be sent together with endDate; a half-supplied range is ignored and the period preset applies instead. Job title interactions are stored as weekly totals, so a week is included when the day it ends on falls inside the range. Totals are never split across a partial week, and a range shorter than a week can return nothing."},"jobTitleWeeklyEndDate":{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (YYYY-MM-DD). Must be sent together with startDate. Selects whole weeks, exactly like startDate."}}},"paths":{"/companies":{"get":{"summary":"List companies with insights","description":"Returns a paginated list of companies with engagement metrics. Filter by campaigns, ABM stages, engagement scores, or CRM match status.","tags":["Companies"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"campaigns","in":"query","schema":{"type":"string"},"description":"Comma-separated Ad Sets IDs","example":"cm1abc,cm2def"},{"name":"campaignGroups","in":"query","schema":{"type":"string"},"description":"Comma-separated Campaigns IDs"},{"name":"abmCampaigns","in":"query","schema":{"type":"string"},"description":"Comma-separated ABM campaign IDs. With exactly one ID, `abmStage` and the `abmStages` filter are scoped to that campaign (same semantics as `GET /abm-campaigns/{id}/companies`); with several IDs they use the company's overall stage."},{"name":"abmStages","in":"query","schema":{"type":"string"},"description":"Comma-separated ABM stage IDs. Matches the same stage `abmStage` reports: campaign-scoped when `abmCampaigns` holds exactly one ID, otherwise the overall stage."},{"name":"intentId","in":"query","schema":{"type":"string"},"description":"Only return companies that show this intent signal. Takes a single intent ID — see `GET /intents`."},{"name":"campaignType","in":"query","schema":{"type":"string","enum":["all_abm_campaigns"]},"description":"Set to `all_abm_campaigns` to scope the list to companies targeted by any ABM campaign. Ignored when `campaigns`, `campaignGroups`, or `abmCampaigns` is supplied, because those filters are more specific.","example":"all_abm_campaigns"},{"name":"engagementScores","in":"query","schema":{"type":"string"},"description":"Comma-separated scores (1–5)","example":"3,4,5"},{"name":"minImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is greater than or equal to this value."},{"name":"maxImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is less than or equal to this value."},{"name":"minClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is greater than or equal to this value."},{"name":"maxClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is less than or equal to this value."},{"name":"minEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is greater than or equal to this value."},{"name":"maxEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is less than or equal to this value."},{"name":"minCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is greater than or equal to this value."},{"name":"maxCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is less than or equal to this value."},{"name":"minCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is greater than or equal to this value."},{"name":"maxCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is less than or equal to this value."},{"name":"minCpm","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per 1,000 impressions (CPM) is greater than or equal to this value."},{"name":"maxCpm","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per 1,000 impressions (CPM) is less than or equal to this value."},{"name":"minClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is greater than or equal to this value."},{"name":"maxClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is less than or equal to this value."},{"name":"minIntents","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of intent signals is greater than or equal to this value."},{"name":"maxIntents","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of intent signals is less than or equal to this value."},{"name":"crmMatchStatus","in":"query","schema":{"type":"string","enum":["all","matched","unmatched"],"default":"all"},"description":"Filters on the link to HubSpot. `matched` returns only companies that have a HubSpot company record, `unmatched` only companies that have none. The name is generic for historic reasons, but this parameter covers HubSpot alone — use `salesforceMatchStatus` or `attioMatchStatus` for the other CRMs."},{"name":"salesforceMatchStatus","in":"query","schema":{"type":"string","enum":["all","matched","unmatched"],"default":"all"},"description":"Salesforce match filter"},{"name":"attioMatchStatus","in":"query","schema":{"type":"string","enum":["all","matched","unmatched"],"default":"all"},"description":"Attio match filter"},{"$ref":"#/components/parameters/hideExcludedCompanies"},{"$ref":"#/components/parameters/hasContacts"},{"name":"includeWeekly","in":"query","schema":{"type":"boolean","default":false},"description":"When `true`, each company in the response is augmented with a `weeklyData[]` array — one entry per Sunday-anchored bucket in the date range (impressions, clicks, engagements, costInUsd). `pageSize` is automatically capped at 20 on this path to keep responses small.","example":true}],"responses":{"200":{"description":"Paginated list of companies with metrics. `weeklyData` is only present when `includeWeekly=true`.","content":{"application/json":{"example":{"data":[{"id":"1337","name":"Pied Piper","city":"Palo Alto","country":"US","website":"https://www.piedpiper.com/","linkedInOrgId":"4827017","hubspotCompanyId":"37411334702","salesforceId":"0015f00000AbCdEfGh","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","lifetimeEngagementScore":3,"abmStageId":"1337_interested","lifetimeAbmStageId":"1337_interested","logoUrl":"https://piedpiper.com/assets/images/logo.png","abmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3,"isManuallyOverridden":false,"overrideTimestamp":null},"lifetimeAbmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"intents":[{"id":"cm9iaw4a50001jr04wqc1k4dt","name":"Competitor"}],"impressions":109198,"clicks":468,"engagements":2769,"costInUsd":2797.37,"currentEngagementScore":2,"abmCampaigns":[{"id":"1337","name":"Techcrunch 2025"}],"exclusion":null,"weeklyData":[{"weekStart":"2026-03-03","weekEnd":"2026-03-09","impressions":142,"clicks":3,"engagements":2,"costInUsd":45.72},{"weekStart":"2026-03-10","weekEnd":"2026-03-16","impressions":511,"clicks":5,"engagements":12,"costInUsd":10.94}]}],"pagination":{"page":1,"pageSize":1,"totalCount":35960,"totalPages":35960},"meta":{"timestamp":"2026-03-09T18:08:06.901Z"}}}}},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"}},"operationId":"getCompanies"}},"/companies/{id}":{"get":{"summary":"Get company by ID","description":"Retrieve a single company by its ID, including full profile and current metrics.","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"}],"responses":{"200":{"description":"Company details","content":{"application/json":{"example":{"data":{"id":"1337","name":"Pied Piper","country":"US","city":"Palo Alto","website":"https://www.piedpiper.com/","logoUrl":"https://piedpiper.com/assets/images/logo.png","linkedInOrgId":"4827017","hubspotCompanyId":"37411334702","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","abmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"lifetimeAbmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"lifetimeEngagementScore":5,"exclusionCount":0},"meta":{"timestamp":"2026-03-09T18:34:17.198Z"}}}}}},"operationId":"getCompaniesById"}},"/companies/{id}/overview":{"get":{"summary":"Get company metrics overview","description":"Returns aggregated and weekly metrics for a company over a given time period.","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"Company overview with weekly metrics (weekStart, weekEnd)","content":{"application/json":{"example":{"data":{"summary":{"impressions":109198,"clicks":468,"engagements":2769,"costInUsd":2797.37},"weeklyData":[{"weekStart":"2025-03-03","weekEnd":"2025-03-09","impressions":142,"clicks":3,"engagements":2,"costInUsd":45.72},{"weekStart":"2025-03-10","weekEnd":"2025-03-16","impressions":3607,"clicks":31,"engagements":35,"costInUsd":106.35}]},"meta":{"timestamp":"2026-03-09T18:30:27.973Z"}}}}}},"operationId":"getCompaniesByIdOverview"}},"/companies/{id}/campaigns":{"get":{"summary":"List Ad Sets for a company","description":"Returns campaigns that a specific company has been exposed to, with per-company metrics.","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"}],"responses":{"200":{"description":"Paginated Ad Sets for company","content":{"application/json":{"example":{"data":[{"id":"1337_campaign_id","name":"Techcrunch 2025","format":"Single Image","impressions":5923,"clicks":31,"engagements":58,"costInUsd":436.58,"intents":[{"id":"1337","name":"Competitor"}]}],"pagination":{"page":1,"pageSize":20,"totalCount":114,"totalPages":6},"meta":{"timestamp":"2026-03-09T18:41:52.562Z"}}}}}},"operationId":"getCompaniesByIdCampaigns"}},"/companies/{id}/campaign-groups":{"get":{"summary":"List Campaigns for a company","description":"Optional filters: sortBy, sortOrder, search","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"}],"responses":{"200":{"description":"Paginated Campaigns for company","content":{"application/json":{"example":{"data":[{"id":"1337_campaign_group_id","name":"Techcrunch 2025 CG","impressions":47759,"clicks":273,"engagements":2380,"costInUsd":1580.19}],"pagination":{"page":1,"pageSize":20,"totalCount":35,"totalPages":2},"meta":{"timestamp":"2026-03-09T18:44:34.534Z"}}}}}},"operationId":"getCompaniesByIdCampaignGroups"}},"/companies/{id}/abm-campaigns":{"get":{"summary":"List ABM campaigns for a company","description":"Optional filters: sortBy, sortOrder","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"}],"responses":{"200":{"description":"Paginated ABM campaigns for company","content":{"application/json":{"example":{"data":[{"id":"1337_abm_campaign_id","name":"Silicon Valley 2025","status":"ACTIVE","impressions":111554,"clicks":462,"engagements":2763,"costInUsd":2232.13}],"pagination":{"page":1,"pageSize":20,"totalCount":8,"totalPages":1},"meta":{"timestamp":"2026-03-09T18:51:43.208Z"}}}}}},"operationId":"getCompaniesByIdAbmCampaigns"}},"/companies/{id}/timeline":{"get":{"summary":"Get company timeline","description":"Returns a chronological list of engagement events for a company within a date range.","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (ISO format, default: 30 days ago)"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (ISO format, default: today)"}],"responses":{"200":{"description":"Company timeline events","content":{"application/json":{"example":{"data":{"summary":{"impressions":109617,"clicks":468,"engagements":2769,"costInUsd":2797.37},"deals":[],"stageHistory":[{"stageId":"1337_identified","stageName":"Identified","stageColor":"#3B82F6","enteredAt":"2025-03-01T00:00:00.000Z","previousStageName":null},{"stageId":"1337_aware","stageName":"Aware","stageColor":"#A855F7","enteredAt":"2025-04-15T00:00:00.000Z","previousStageName":"Identified"}]},"meta":{"timestamp":"2026-03-09T19:00:28.135Z"}}}}}},"operationId":"getCompaniesByIdTimeline"}},"/companies/{id}/activity-log":{"get":{"summary":"Get company activity log","description":"Merged chronological feed of stage changes, deals, intents, and exclusions. Paginated via `page`/`pageSize`. Note: `totalCount`/`totalPages` are not returned because the feed is merged from multiple sources. Pass `startDate`/`endDate` (YYYY-MM-DD) to scope the feed to a window — when a date range is supplied, weekly LinkedIn ad-activity entries (`type: \"linkedin_activity_week\"`, carrying a `metrics` object with impressions/clicks/engagements/costInUsd) are merged into the feed.","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"Company activity log entries","content":{"application/json":{"example":{"data":[{"id":"linkedin-activity-clxyz789","type":"linkedin_activity_week","date":"2026-05-04T00:00:00.000Z","title":"LinkedIn ad activity","description":"4,210 impressions · 38 clicks · 12 engagements","metrics":{"impressions":4210,"clicks":38,"engagements":12,"costInUsd":142.87}},{"id":"lifetime-stage-1337","type":"lifetime_abm_stage_change","date":"2026-03-28T11:00:00.000Z","title":"Lifetime ABM Stage changed to Interested","description":"Previously: Aware","toStage":{"id":"1337_interested","name":"Interested","color":"#10B981"},"fromStage":{"id":"1337_aware","name":"Aware","color":"#A855F7"}},{"id":"lifetime-stage-1338","type":"lifetime_abm_stage_change","date":"2026-03-15T08:00:00.000Z","title":"Lifetime ABM Stage changed to Aware","description":"Previously: Identified","toStage":{"id":"1337_aware","name":"Aware","color":"#A855F7"},"fromStage":{"id":"1337_identified","name":"Identified","color":"#3B82F6"}}],"pagination":{"page":1,"pageSize":20},"meta":{"timestamp":"2026-04-12T19:02:02.855Z"}}}}}},"operationId":"getCompaniesByIdActivityLog"}},"/companies/{id}/deals":{"get":{"summary":"Get deals for a company","description":"Optional filters: sortBy, sortOrder","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","closedAt","dealName","companyName","amount","impressionsBeforeDeal","impressionsAfterDeal"],"default":"createdAt"},"description":"Field to sort by (default: createdAt)"},{"$ref":"#/components/parameters/sortOrder"}],"responses":{"200":{"description":"Deals for company","content":{"application/json":{"example":{"data":{"data":[{"id":"clxyz123abc","source":"hubspot","dealName":"Acme Corp - Enterprise License","externalId":"12345678","externalUrl":"https://app.hubspot.com/contacts/98765432/record/0-3/12345678/","amount":45000,"linkedinInfluenced":true,"abmInfluenced":true,"createdAt":"2025-03-15T10:30:00.000Z","closedAt":"2025-06-20T14:00:00.000Z","company":{"id":"1337","name":"Pied Piper","logoUrl":"https://piedpiper.com/assets/images/logo.png","website":"https://piedpiper.com","linkedInOrgId":"12345","hubspotCompanyId":"9876543","country":"United States","hubspotPortalId":"98765432"},"stage":{"id":"1337_closed_won","name":"Closed Won"},"campaigns":[{"id":"1337","name":"Q1 Enterprise ABM Campaign"}],"impressionsBeforeDeal":8450,"impressionsAfterDeal":3200,"linkedinImpressionsBeforeDeal":5200,"abmImpressionsBeforeDeal":3250,"linkedinImpressionsAfterDeal":1800,"abmImpressionsAfterDeal":1400,"clicksBeforeDeal":142,"clicksAfterDeal":58,"linkedinClicksBeforeDeal":89,"abmClicksBeforeDeal":53,"linkedinClicksAfterDeal":34,"abmClicksAfterDeal":24,"engagementsBeforeDeal":312,"engagementsAfterDeal":95,"linkedinEngagementsBeforeDeal":198,"abmEngagementsBeforeDeal":114,"linkedinEngagementsAfterDeal":60,"abmEngagementsAfterDeal":35,"costBeforeDeal":891.45,"costAfterDeal":246.03}],"count":3},"pagination":{"page":1,"pageSize":20,"totalCount":3,"totalPages":1},"meta":{"timestamp":"2026-04-12T12:00:00.000Z"}}}}}},"operationId":"getCompaniesByIdDeals"}},"/companies/{id}/abm-stages":{"get":{"summary":"Get ABM stages for a company","description":"Returns the ABM stage history for a company, showing progression through your funnel.","tags":["Companies"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Company ID"}],"responses":{"200":{"description":"ABM stage history for company","content":{"application/json":{"example":{"data":[{"context":"overall","abmStage":{"id":"cls1abc123","name":"Engaged","color":"#4CAF50"},"previousStage":{"id":"cls2def456","name":"Aware","color":"#FFC107"},"campaign":null,"stageHistory":[{"stageId":"cls1abc123","stageName":"Engaged","color":"#4CAF50","date":"2025-08-12T09:30:00.000Z"},{"stageId":"cls2def456","stageName":"Aware","color":"#FFC107","date":"2025-04-20T14:15:00.000Z"}],"latestChangeDate":"2025-08-12T09:30:00.000Z"},{"context":"lifetime","abmStage":{"id":"cls1abc123","name":"Engaged","color":"#4CAF50"},"previousStage":null,"campaign":null,"stageHistory":[],"latestChangeDate":null},{"context":"campaign","abmStage":{"id":"cls3ghi789","name":"MQL","color":"#2196F3"},"previousStage":{"id":"cls1abc123","name":"Engaged","color":"#4CAF50"},"campaign":{"id":"cm7abmcamp1","name":"Q1 Enterprise ABM Campaign"},"stageHistory":[{"stageId":"cls3ghi789","stageName":"MQL","color":"#2196F3","date":"2025-09-01T11:00:00.000Z"},{"stageId":"cls1abc123","stageName":"Engaged","color":"#4CAF50","date":"2025-06-15T08:45:00.000Z"}],"latestChangeDate":"2025-09-01T11:00:00.000Z"}],"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getCompaniesByIdAbmStages"}},"/campaigns":{"get":{"summary":"List Ad Sets with insights","description":"Returns a paginated list of LinkedIn Ad Sets with aggregated performance metrics for the requested date range. Filter by status (default: ACTIVE,PAUSED) or search by name. Each item includes both ZenABM's internal `id` (when the ad set has been imported) and the LinkedIn-native `linkedInId`. To list ad sets within a specific ABM campaign use `/abm-campaigns/{id}` instead.","tags":["Ad Sets"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Comma-separated statuses: ACTIVE,PAUSED,ARCHIVED,DRAFT,COMPLETED. Default: ACTIVE,PAUSED.","example":"ACTIVE,PAUSED"}],"responses":{"200":{"description":"Paginated list of Ad Sets","content":{"application/json":{"example":{"data":[{"id":"cmf8a9q2k0001of04w7v3lqz9","linkedInId":"1336","name":"Techcrunch 2025","status":"ACTIVE","format":"Single Image","servingStatuses":["RUNNABLE"],"parentCampaignLinkedInId":"1337","runScheduleStart":1735689600000,"runScheduleEnd":1767225600000,"totalBudgetAmount":"5000.00","totalBudgetCurrency":"USD","impressions":128157,"clicks":501,"engagements":809,"costInUsd":8202.59,"conversions":213,"ctr":0.39,"cpc":16.37}],"pagination":{"page":1,"pageSize":20,"totalCount":472,"totalPages":24},"meta":{"timestamp":"2026-03-09T19:06:51.685Z"}}}}}},"operationId":"getCampaigns"}},"/campaigns/{id}":{"get":{"summary":"Get Ad Set by ID","description":"Identity and relations only. Delivery settings (budgets, bid, objective, cost type, optimization target, pacing, Audience Expansion, LinkedIn Audience Network), audience size and targeting come from `/campaigns/{id}/settings`, which reads them live from LinkedIn Campaign Manager.","tags":["Ad Sets"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Ad Set ID"}],"responses":{"200":{"description":"Ad Set details","content":{"application/json":{"example":{"data":{"id":"1337","linkedInId":"330784953","name":"Techcrunch 2025","status":"ACTIVE","campaignId":"1337","syncStartDate":"2025-01-01T00:00:00.000Z","createdAt":"2025-01-01T00:00:00.000Z","updatedAt":"2025-09-15T00:00:00.000Z","teamId":"1337","intentId":null,"format":"Single Image","campaign":{"id":"1337","linkedInId":"710869393","name":"Techcrunch 2025","status":"ACTIVE","createdAt":"2025-01-01T00:00:00.000Z","updatedAt":"2025-09-15T00:00:00.000Z","teamId":"1337","syncStartDate":"2025-01-01T00:00:00.000Z","intentId":null},"intent":null},"meta":{"timestamp":"2026-03-09T19:09:39.624Z"}}}}}},"operationId":"getCampaignsById"}},"/campaigns/{id}/settings":{"get":{"summary":"Get Ad Set delivery and targeting settings","description":"Read LIVE from LinkedIn Campaign Manager on every call, not from ZenABM's sync, so it reflects an edit made minutes ago. Fields listed in `unknownSettings` were not returned by LinkedIn — treat them as unknown, never as \"off\". `audienceSize` is the estimated ADDRESSABLE audience, not reach: `impressions / audienceSize` is only a lower bound on frequency, and exclusions are left out of it (see `audienceSizeExcludesApplied`). Each targeting facet reports `count` (values targeted), `values` (readable names only) and `unnamed` (values with no name available, most often specific geographic locations). Returns 502 if LinkedIn is unreachable rather than falling back to synced values.","tags":["Ad Sets"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Ad Set ID"}],"responses":{"200":{"description":"Live Ad Set settings","content":{"application/json":{"example":{"data":{"id":"1337","linkedInId":"330784953","name":"Techcrunch 2025","status":"ACTIVE","format":"Single Image","campaignId":"1337","campaign":{"id":"1337","name":"Techcrunch 2025"},"source":"linkedin","delivery":{"dailyBudget":90,"totalBudget":null,"unitCost":16,"currency":"USD","objectiveType":"WEBSITE_VISIT","costType":"CPM","optimizationTarget":"MAX_CLICK","pacingStrategy":"LIFETIME_EVEN_PACED","audienceExpansion":false,"offsiteDelivery":false},"audienceSize":84000,"audienceSizeUnavailableReason":null,"unknownSettings":[],"targeting":{"included":{"jobTitles":{"count":12,"values":["Head of Marketing","VP Marketing"],"truncated":false,"unnamed":0},"seniorities":{"count":2,"values":["Director","VP"],"truncated":false,"unnamed":0},"locations":{"count":3,"values":["European Union"],"truncated":false,"unnamed":2}},"excluded":{"jobTitles":{"count":1,"values":["Intern"],"truncated":false,"unnamed":0}}}},"meta":{"timestamp":"2026-07-26T09:12:00.000Z"}}}}}},"operationId":"getCampaignsByIdSettings"}},"/campaigns/{id}/suggested-bid":{"get":{"summary":"Get LinkedIn's suggested bid for an Ad Set","description":"LinkedIn's suggested bid for the Ad Set — the same number Campaign Manager shows — plus the allowed bid range and daily budget limits. Read LIVE on every call: the Ad Set's current targeting, objective and cost type are echoed into LinkedIn's pricing finder, so the answer reflects edits made minutes ago. Also returns the current bid and daily budget for context. Not available for Dynamic Ads. Returns 422 when the Ad Set cannot be priced (Dynamic Ads, unsupported cost/campaign type, missing or oversized targeting), 502 when LinkedIn is unreachable or has no pricing for the targeting.","tags":["Ad Sets"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Ad Set ID"}],"responses":{"200":{"description":"Suggested bid and limits","content":{"application/json":{"example":{"data":{"success":true,"linkedInId":"330784953","adSetName":"Techcrunch 2025","currency":"USD","suggestedBid":{"default":7.1,"min":7.1,"max":11.14},"bidLimits":{"min":4,"max":100},"dailyBudgetLimits":{"default":25,"min":10,"max":1000000},"currentBid":16,"currentDailyBudget":90,"costType":"CPM","optimizationTargetType":"MAX_CLICK"},"meta":{"timestamp":"2026-08-05T09:12:00.000Z"}}}}}},"operationId":"getCampaignsByIdSuggestedBid"}},"/campaigns/{id}/overview":{"get":{"summary":"Get Ad Set metrics overview","description":"Performance totals for a single Ad Set over the requested date range (no weekly breakdown).","tags":["Ad Sets"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Ad Set ID"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"Ad Set performance summary for the date range","content":{"application/json":{"example":{"data":{"startDate":"2026-04-13","endDate":"2026-05-13","format":"Single Image","impressions":102666,"clicks":264,"engagements":1136,"costInUsd":4571.02,"conversions":200,"ctr":0.26,"cpc":17.32},"meta":{"timestamp":"2026-05-13T19:08:06.843Z"}}}}}},"operationId":"getCampaignsByIdOverview"}},"/campaigns/{id}/companies":{"get":{"summary":"List companies for a Ad Set","description":"Optional filters: sortBy, sortOrder, search","tags":["Ad Sets"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Ad Set ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"hideExcludedCompanies","in":"query","schema":{"type":"boolean","default":false},"description":"When `true`, hides companies with a COMPANY exclusion that applies to this Ad Set — a team-wide exclusion, or one scoped specifically to this Ad Set (matches the \"Excluded\" badge in the UI). An exclusion scoped to a different Ad Set or Campaign does not apply here."},{"$ref":"#/components/parameters/hasContacts"}],"responses":{"200":{"description":"Paginated companies for Ad Set","content":{"application/json":{"example":{"data":[{"id":"1337","name":"Pied Piper","city":"San Francisco","country":"US","website":"https://www.piedpiper.com/","linkedInOrgId":"4827017","hubspotCompanyId":"37411334702","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","logoUrl":"https://piedpiper.com/assets/images/logo.png","lifetimeEngagementScore":2,"abmStage":{"id":"1337_aware","name":"Aware","color":"#A855F7","displayOrder":2},"lifetimeAbmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"impressions":0,"clicks":0,"engagements":0,"costInUsd":0,"clickThroughRate":0,"costPerClick":0,"cpm":0,"intents":[]}],"pagination":{"page":1,"pageSize":20,"totalCount":501,"totalPages":26},"meta":{"timestamp":"2026-03-09T19:10:47.810Z"}}}}}},"operationId":"getCampaignsByIdCompanies"}},"/campaigns/{id}/job-titles":{"get":{"summary":"Get job title insights for a Ad Set","description":"Returns job title engagement breakdown for a specific campaign.","tags":["Ad Sets"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Ad Set ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"minImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is greater than or equal to this value."},{"name":"maxImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is less than or equal to this value."},{"name":"minClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is greater than or equal to this value."},{"name":"maxClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is less than or equal to this value."},{"name":"minEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is greater than or equal to this value."},{"name":"maxEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is less than or equal to this value."},{"name":"minCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is greater than or equal to this value."},{"name":"maxCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is less than or equal to this value."},{"name":"minCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is greater than or equal to this value."},{"name":"maxCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is less than or equal to this value."},{"name":"minClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is greater than or equal to this value."},{"name":"maxClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is less than or equal to this value."}],"responses":{"200":{"description":"Job title insights for Ad Set","content":{"application/json":{"example":{"data":[{"jobTitleUrn":"urn:li:title:1337","jobTitleName":"CEO","impressions":12450,"clicks":87,"engagements":342,"costInUsd":891.45,"averageDwellTime":4.2,"videoViews":null,"videoStarts":null,"videoFirstQuartileCompletions":null,"videoMidpointCompletions":null,"videoThirdQuartileCompletions":null,"videoCompletions":null,"exclusion":null}],"pagination":{"page":1,"pageSize":20,"totalCount":2,"totalPages":1},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getCampaignsByIdJobTitles"}},"/creatives":{"get":{"summary":"List ad creatives","description":"Returns a cursor-paginated catalog of the individual ad creatives (the actual ads) in the LinkedIn ad account. Each item includes the LinkedIn-native `linkedInId`, the full `creativeUrn`, name, ad format, status, serving state, and the parent ad set + campaign (with both ZenABM `id` — when imported — and `linkedInId`). Each response carries a `nextCursor`: pass it back as the `cursor` query parameter to fetch the next page (`hasMore` is false on the last page). Optionally scope to one ad set (`adSetId`) or campaign (`campaignId`).","tags":["Creatives"],"parameters":[{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Pagination cursor from a previous response's `nextCursor`. Omit to fetch the first page."},{"name":"pageSize","in":"query","schema":{"type":"integer","default":20,"maximum":100},"description":"Creatives per page (1–100, default: 20)."},{"name":"adSetId","in":"query","schema":{"type":"string"},"description":"Filter to a single ad set. Accepts the ZenABM ad set ID or the LinkedIn numeric ID."},{"name":"campaignId","in":"query","schema":{"type":"string"},"description":"Filter to a single campaign. Accepts the ZenABM campaign ID or the LinkedIn numeric ID."}],"responses":{"200":{"description":"Cursor-paginated catalog of ad creatives","content":{"application/json":{"example":{"data":[{"linkedInId":"415956593","creativeUrn":"urn:li:sponsoredCreative:415956593","name":"Techcrunch 2025 — Hero Image","format":"Single Image","status":"ACTIVE","isServing":true,"adLibraryUrl":"https://www.linkedin.com/ad-library/detail/415956593","adSetId":"cmf8a9q2k0001of04w7v3lqz9","adSetLinkedInId":"330784953","adSetName":"Techcrunch 2025","campaignId":"cmf8a9q2k0002of04abcd1234","campaignLinkedInId":"710869393","campaignName":"Techcrunch 2025 CG"}],"pagination":{"pageSize":20,"nextCursor":"DgFNuuqsfrRuO-q0RxpSj-yaR4TXEtmKuIF4U9-t404","hasMore":true},"meta":{"timestamp":"2026-05-14T19:06:51.685Z"}}}}}},"operationId":"getCreatives"}},"/conversation-ads":{"post":{"summary":"Create a conversation ad","description":"Creates a LinkedIn Conversation Ad in a message Ad Set (LinkedIn type `SPONSORED_INMAILS`): the conversation, its message tree, the guided-replies message content and the creative, in one call. Written live to LinkedIn; nothing is stored in ZenABM.\n\n**Tree.** The first entry in `messages` is the intro. Every other message must be reachable from it through `options[].next`, and loops are rejected. Limits: 25 messages, 5 options per message, 500 characters per message, 35 per button. All rule errors come back together in one 400.\n\n**Sender.** Defaults to the ad account company page. A `urn:li:person:…` sender must be approved as a sender in Campaign Manager.\n\n**Status.** `DRAFT` by default. `sendTest: true` sends the draft to the inbox of the LinkedIn member who connected ZenABM; a failed test does not fail the call (`testSent: false`, `testError`).\n\n**Errors.** 400 `INVALID_INPUT`, 403 `SCOPE_MISSING`, 404 `NOT_FOUND`, 422 `NO_AD_ACCOUNT`, 502 `LINKEDIN_REJECTED`. When a step fails after the conversation exists, the message lists the LinkedIn URNs already created; no ad was made, so retry the whole call.","tags":["Creatives"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["adSetLinkedInId","name","subject","messages"],"properties":{"adSetLinkedInId":{"type":"string","example":"330784953"},"name":{"type":"string"},"status":{"type":"string","enum":["DRAFT","ACTIVE","PAUSED"],"default":"DRAFT"},"sender":{"type":"string","example":"urn:li:person:B1U4S2MZ-C"},"subject":{"type":"string","maxLength":60},"headline":{"type":"string"},"customFooter":{"type":"string"},"bannerImageUrn":{"type":"string"},"messages":{"type":"array","minItems":1,"maxItems":25,"items":{"type":"object","required":["key"],"properties":{"key":{"type":"string","description":"Your own label. Options reference messages by it."},"text":{"type":"string","maxLength":500},"imageUrn":{"type":"string","example":"urn:li:image:C5506AQGB9e"},"leadFormId":{"type":"string","description":"Lead gen form id or `urn:li:adForm:…`. A lead form message has no `text` or `imageUrn`."},"options":{"type":"array","maxItems":5,"items":{"type":"object","required":["replyType","text"],"properties":{"replyType":{"type":"string","enum":["SIMPLE_REPLY","EXTERNAL_WEBSITE","LEAD_GENERATION","LEAD_GENERATION_THANK_YOU"],"description":"`SIMPLE_REPLY` opens another message (`next` required). `EXTERNAL_WEBSITE` opens `landingPage`. `LEAD_GENERATION` opens a lead form message (`next` required). `LEAD_GENERATION_THANK_YOU` is required on every lead form message and is only allowed there."},"text":{"type":"string","maxLength":35},"next":{"type":"string","description":"`key` of the message this button opens."},"landingPage":{"type":"string","format":"uri"}}}}}}},"sendTest":{"type":"boolean","default":false}}},"example":{"adSetLinkedInId":"330784953","name":"Q4 demo conversation","subject":"Quick question about your LinkedIn ABM","messages":[{"key":"intro","text":"Want to see how teams tie LinkedIn ads to pipeline?","options":[{"replyType":"SIMPLE_REPLY","text":"Show me","next":"demo"},{"replyType":"EXTERNAL_WEBSITE","text":"Read the guide","landingPage":"https://zenabm.com/guide"}]},{"key":"demo","text":"Book a 20 minute walkthrough.","options":[{"replyType":"EXTERNAL_WEBSITE","text":"Book a demo","landingPage":"https://zenabm.com/demo"}]}]}}}},"responses":{"200":{"description":"The created conversation ad","content":{"application/json":{"example":{"data":{"success":true,"creativeUrn":"urn:li:sponsoredCreative:415956593","adSetLinkedInId":"330784953","status":"DRAFT","conversationUrn":"urn:li:sponsoredConversation:186604","inMailContentUrn":"urn:li:adInMailContent:6684124","messageUrns":{"demo":"urn:li:sponsoredMessageContent:(urn:li:sponsoredConversation:186604,14277)","intro":"urn:li:sponsoredMessageContent:(urn:li:sponsoredConversation:186604,14278)"},"testSent":false},"meta":{"timestamp":"2026-10-05T10:30:00.000Z"}}}}}},"operationId":"postConversationAds"}},"/campaign-schedules":{"get":{"summary":"List campaign schedules","description":"Campaign Schedules (Budget Saver) hold the weekly hours when Ad Sets may run. Outside them, ZenABM pauses in-scope Ad Sets on LinkedIn and resumes them when the hours start again. `activeHours` are hour-of-week slots in the schedule `timezone`: slot = day × 24 + hour, day 0 = Monday … 6 = Sunday (0 = Mon 00:00, 167 = Sun 23:00). `hoursSummary` is a readable version. `scope` is `ALL` or `SPECIFIC`. `adSetIds`, `campaignIds` and `abmCampaignIds` are ZenABM IDs; `adSets`, `campaigns` and `abmCampaigns` add names (and LinkedIn IDs). `pausedAdSetCount` = Ad Sets that schedules have paused right now (team total; pauses are not stored per schedule). `stateNow`: `running_now` (enabled, inside its hours), `paused_now` (enabled, outside its hours), `off` (disabled).","tags":["Budget Savers"],"parameters":[{"name":"search","in":"query","schema":{"type":"string"},"description":"Forgiving word match: a schedule matches when any query word is the start of a word in its name or in the names of its targeted Ad Sets, Campaigns or ABM campaigns (\"work day\" finds \"Working hours\"). Best matches first."},{"name":"enabled","in":"query","schema":{"type":"boolean"}},{"name":"state","in":"query","schema":{"type":"string","enum":["running_now","paused_now","off"]}},{"name":"scope","in":"query","schema":{"type":"string","enum":["ALL","SPECIFIC"]}}],"responses":{"200":{"description":"Schedules of the team","content":{"application/json":{"example":{"data":{"pausedAdSetCount":3,"schedules":[{"id":"cmsched001","name":"Workdays 9–17","enabled":true,"timezone":"Europe/Warsaw","activeHours":[9,10,11,12,13,14,15,16,33,34,35,36,37,38,39,40],"hoursSummary":"Mon–Tue 09:00–17:00","stateNow":"running_now","scope":"SPECIFIC","adSetIds":[],"campaignIds":["cm7lcg001"],"abmCampaignIds":[],"adSets":[],"campaigns":[{"id":"cm7lcg001","linkedInId":"612345678","name":"Fintech Enterprise Group"}],"abmCampaigns":[],"latestLog":{"eventType":"PAUSED","message":"Paused \"Q4 Retargeting\" (outside schedule hours)","createdAt":"2026-10-08T17:00:12.000Z"},"updatedAt":"2026-10-08T08:12:40.000Z"}]},"meta":{"timestamp":"2026-10-08T10:30:00.000Z"}}}}}},"operationId":"getCampaignSchedules"},"post":{"summary":"Create or update a campaign schedule","description":"Creates a schedule, or updates the one named by `id`. **Update merges: send only fields you want to change.** Sending `activeHours` and/or `weekly` replaces all hours; each target list you send (`adSetIds`, `campaignIds`, `abmCampaignIds`) replaces only that list; a target list without `scope` sets `scope` to `SPECIFIC`. Create needs `name`, `timezone` and hours; `enabled` defaults to `true`, `scope` to `SPECIFIC` (then at least one target is required). **Writes to LinkedIn:** right after the save, and then every 15 minutes, in-scope ACTIVE Ad Sets outside the active hours are paused, and Ad Sets the schedule paused are resumed inside them. A schedule only resumes Ad Sets it paused itself; an Ad Set a user re-activates by hand is left alone. `enabled: false` or a delete resumes what it paused. With several schedules on one Ad Set, the most restrictive wins.\n\nTarget IDs accept the ZenABM ID or the numeric LinkedIn ID. Returns the saved schedule (same shape as the list).\n\n**Errors.** 404 `NOT_FOUND` (unknown `id`). 400 `INVALID_INPUT` (body shape, e.g. a window hour outside 0–24, unknown timezone) or `BAD_REQUEST` with a readable message: window `to` not after `from`; no hours left (\"A schedule needs at least one hour when ads may run\"); missing `name` / `timezone` on create; IDs not found in the team (all listed); `SPECIFIC` scope with no targets; `ALL` scope sent with target lists.","tags":["Budget Savers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Schedule to update. Omit to create. Update merges: send only fields you want to change."},"name":{"type":"string","maxLength":100,"description":"Required on create"},"enabled":{"type":"boolean","description":"Create default `true`"},"timezone":{"type":"string","example":"Europe/Warsaw","description":"IANA timezone. Required on create."},"activeHours":{"type":"array","items":{"type":"integer","minimum":0,"maximum":167},"description":"Hour-of-week slots when Ad Sets may run. With `weekly`, both are merged and replace all hours; omit both to keep the hours."},"weekly":{"type":"array","description":"Simple form of `activeHours`. `from` inclusive, `to` exclusive, hours 0–24, `to` > `from`.","items":{"type":"object","required":["days","from","to"],"properties":{"days":{"type":"array","items":{"type":"string","enum":["MON","TUE","WED","THU","FRI","SAT","SUN"]}},"from":{"type":"integer","minimum":0,"maximum":24},"to":{"type":"integer","minimum":0,"maximum":24}}}},"preset":{"type":"string","enum":["always","weekdays","workdays-9-17","workdays-8-18","daytime"],"description":"Ready-made hours; do not combine with `activeHours`/`weekly`. `always` = 24/7, `weekdays` = Mon–Fri all day, `workdays-9-17` = Mon–Fri 09:00–17:00, `workdays-8-18` = Mon–Fri 08:00–18:00, `daytime` = every day 07:00–22:00."},"scope":{"type":"string","enum":["ALL","SPECIFIC"],"description":"Create default `SPECIFIC`. A target list sent without `scope` sets `SPECIFIC`."},"adSetIds":{"type":"array","items":{"type":"string"},"description":"Ad Set IDs. Replaces the Ad Set targets."},"campaignIds":{"type":"array","items":{"type":"string"},"description":"Campaign IDs (covers every Ad Set inside). Replaces the Campaign targets."},"abmCampaignIds":{"type":"array","items":{"type":"string"},"description":"ABM Campaign IDs. Replaces the ABM Campaign targets."}}},"examples":{"create":{"summary":"Create for all Ad Sets","value":{"name":"Workdays 9–17","timezone":"Europe/Warsaw","weekly":[{"days":["MON","TUE","WED","THU","FRI"],"from":9,"to":17}],"scope":"ALL"}},"update":{"summary":"Update only the hours","value":{"id":"cmsched001","weekly":[{"days":["MON","TUE","WED","THU"],"from":8,"to":18}]}}}}}},"responses":{"200":{"description":"The saved schedule","content":{"application/json":{"example":{"data":{"id":"cmsched001","name":"Workdays 9–17","enabled":true,"timezone":"Europe/Warsaw","activeHours":[9,10,11,12,13,14,15,16,33,34,35,36,37,38,39,40],"hoursSummary":"Mon–Tue 09:00–17:00","stateNow":"running_now","scope":"SPECIFIC","adSetIds":[],"campaignIds":["cm7lcg001"],"abmCampaignIds":[],"adSets":[],"campaigns":[{"id":"cm7lcg001","linkedInId":"612345678","name":"Fintech Enterprise Group"}],"abmCampaigns":[],"latestLog":{"eventType":"PAUSED","message":"Paused \"Q4 Retargeting\" (outside schedule hours)","createdAt":"2026-10-08T17:00:12.000Z"},"updatedAt":"2026-10-08T08:12:40.000Z"},"meta":{"timestamp":"2026-10-08T10:30:00.000Z"}}}}}},"operationId":"postCampaignSchedules"}},"/campaign-schedules/{id}":{"delete":{"summary":"Delete a campaign schedule","description":"Deletes the schedule. Ad Sets that only this schedule paused are resumed on LinkedIn right after. 404 `NOT_FOUND` for an unknown ID.","tags":["Budget Savers"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"example":{"data":{"id":"cmsched001","deleted":true},"meta":{"timestamp":"2026-10-08T10:30:00.000Z"}}}}}},"operationId":"deleteCampaignSchedulesById"}},"/campaign-schedules/for-entity":{"get":{"summary":"Schedules covering an Ad Set or Campaign","description":"Send exactly one of `adSetId` or `campaignId`; ZenABM or numeric LinkedIn ID. Schedules use the same shape as the list. Each schedule carries `reason`: `DIRECT`, `CAMPAIGN` (via the parent Campaign), `ABM_CAMPAIGN`, `ALL` (team-wide) or `SOME_AD_SETS`. For an Ad Set, `pause` is set when a schedule paused it (`overriddenAt` = a user re-activated it by hand).","tags":["Budget Savers"],"parameters":[{"name":"adSetId","in":"query","schema":{"type":"string"}},{"name":"campaignId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Covering schedules","content":{"application/json":{"example":{"data":{"schedules":[{"id":"cmsched001","name":"Workdays 9–17","enabled":true,"timezone":"Europe/Warsaw","activeHours":[9,10,11,12,13,14,15,16,33,34,35,36,37,38,39,40],"hoursSummary":"Mon–Tue 09:00–17:00","stateNow":"running_now","scope":"SPECIFIC","adSetIds":[],"campaignIds":["cm7lcg001"],"abmCampaignIds":[],"adSets":[],"campaigns":[{"id":"cm7lcg001","linkedInId":"612345678","name":"Fintech Enterprise Group"}],"abmCampaigns":[],"latestLog":{"eventType":"PAUSED","message":"Paused \"Q4 Retargeting\" (outside schedule hours)","createdAt":"2026-10-08T17:00:12.000Z"},"updatedAt":"2026-10-08T08:12:40.000Z","reason":"CAMPAIGN","viaName":"Fintech Enterprise Group","coveredAdSetCount":null,"otherTargetCount":1}],"pause":{"pausedAt":"2026-10-08T17:00:12.000Z","overriddenAt":null}},"meta":{"timestamp":"2026-10-08T10:30:00.000Z"}}}}}},"operationId":"getCampaignSchedulesForEntity"}},"/campaign-schedules/logs":{"get":{"summary":"Campaign schedule activity log","description":"Newest first: CREATED, UPDATED, DELETED, PAUSED, RESUMED, OVERRIDDEN, FAILED. With `scheduleId`, returns that schedule plus team-level events.","tags":["Budget Savers"],"parameters":[{"name":"scheduleId","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":30}}],"responses":{"200":{"description":"Log entries","content":{"application/json":{"example":{"data":[{"id":"cmlog001","eventType":"PAUSED","message":"Paused \"Q4 Retargeting\" (outside schedule hours)","details":{},"createdAt":"2026-10-08T17:00:12.000Z"}],"meta":{"timestamp":"2026-10-08T10:30:00.000Z"}}}}}},"operationId":"getCampaignSchedulesLogs"}},"/campaign-groups":{"get":{"summary":"List Campaigns with insights","description":"Returns a paginated list of LinkedIn Campaigns with aggregated performance metrics for the requested date range. Filter by status (default: ACTIVE,PAUSED) or search by name. Each item includes both ZenABM's internal `id` (when the campaign has been imported) and the LinkedIn-native `linkedInId`. To list campaigns within a specific ABM campaign use `/abm-campaigns/{id}` instead.","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Comma-separated statuses: ACTIVE,PAUSED,ARCHIVED,DRAFT,COMPLETED. Default: ACTIVE,PAUSED.","example":"ACTIVE,PAUSED"}],"responses":{"200":{"description":"Paginated list of Campaigns","content":{"application/json":{"example":{"data":[{"id":"cmf7gpqd80002lv04x9zwt8mh","linkedInId":"1337","name":"TechCrunch 2025","status":"ACTIVE","servingStatuses":["RUNNABLE"],"runScheduleStart":1735689600000,"runScheduleEnd":1767225600000,"totalBudgetAmount":"50000.00","totalBudgetCurrency":"USD","impressions":583180,"clicks":4838,"engagements":30566,"costInUsd":25033.73,"conversions":1229,"ctr":0.83,"cpc":5.17}],"pagination":{"page":1,"pageSize":20,"totalCount":87,"totalPages":5},"meta":{"timestamp":"2026-03-09T19:22:18.111Z"}}}}}},"operationId":"getCampaignGroups"}},"/campaign-groups/{id}":{"get":{"summary":"Get Campaign by ID","description":"Returns a single Campaign with its child Ad Sets in the `adSets` array (id, linkedInId, name, status, human-readable format).","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Campaign ID"}],"responses":{"200":{"description":"Campaign details","content":{"application/json":{"example":{"data":{"id":"1337","linkedInId":"734789393","name":"TechCrunch 2025","status":"ACTIVE","createdAt":"2025-01-01T00:00:00.000Z","updatedAt":"2025-09-15T00:00:00.000Z","teamId":"1337","syncStartDate":"2025-01-01T00:00:00.000Z","intentId":"1337","intent":{"id":"1337","name":"Competitor","description":"","createdAt":"2025-01-01T00:00:00.000Z","updatedAt":"2025-09-15T00:00:00.000Z","teamId":"1337"},"adSets":[{"id":"cmf8a9q2k0001of04w7v3lqz9","linkedInId":"330784953","name":"Techcrunch 2025 — Decision Makers","status":"ACTIVE","format":"Single Image"},{"id":"cmf8a9q2k0002of04abcd1234","linkedInId":"330784954","name":"Techcrunch 2025 — Thought Leadership","status":"PAUSED","format":"Thought Leader Ad"}]},"meta":{"timestamp":"2026-03-09T19:26:12.572Z"}}}}}},"operationId":"getCampaignGroupsById"}},"/campaign-groups/{id}/overview":{"get":{"summary":"Get Campaign metrics overview","description":"Performance totals for a single Campaign over the requested date range — aggregated to a single `summary` (no weekly breakdown).","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Campaign ID"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"Campaign performance summary for the date range","content":{"application/json":{"example":{"data":{"startDate":"2026-04-13","endDate":"2026-05-13","impressions":583180,"clicks":4838,"engagements":30566,"costInUsd":25033.73,"conversions":1229,"ctr":0.83,"cpc":5.17},"meta":{"timestamp":"2026-05-13T19:27:07.553Z"}}}}}},"operationId":"getCampaignGroupsByIdOverview"}},"/campaign-groups/{id}/companies":{"get":{"summary":"List companies for a Campaign","description":"Optional filters: sortBy, sortOrder, search","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Campaign ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"hideExcludedCompanies","in":"query","schema":{"type":"boolean","default":false},"description":"When `true`, hides companies with a COMPANY exclusion that applies to this Campaign — a team-wide exclusion, or one scoped specifically to this Campaign (matches the \"Excluded\" badge in the UI). An exclusion scoped to a different Campaign or Ad Set does not apply here."},{"$ref":"#/components/parameters/hasContacts"}],"responses":{"200":{"description":"Paginated companies for Campaign","content":{"application/json":{"example":{"data":[{"id":"1337","name":"Pied Piper","city":"San Francisco","country":"US","website":"https://www.piedpiper.com/","linkedInOrgId":"4827017","hubspotCompanyId":"37411334702","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","logoUrl":"https://piedpiper.com/assets/images/logo.png","lifetimeEngagementScore":2,"impressions":47759,"clicks":273,"engagements":2380,"costInUsd":1580.19,"clickThroughRate":0.572,"costPerClick":5.79,"cpm":33.09,"intents":[{"id":"1337","name":"Competitor"}],"abmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"lifetimeAbmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3}}],"pagination":{"page":1,"pageSize":20,"totalCount":4101,"totalPages":206},"meta":{"timestamp":"2026-03-09T19:28:09.356Z"}}}}}},"operationId":"getCampaignGroupsByIdCompanies"}},"/campaign-groups/{id}/job-titles":{"get":{"summary":"Get job title insights for a campaign group","description":"Optional filters: sortBy, sortOrder","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Campaign ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"minImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is greater than or equal to this value."},{"name":"maxImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is less than or equal to this value."},{"name":"minClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is greater than or equal to this value."},{"name":"maxClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is less than or equal to this value."},{"name":"minEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is greater than or equal to this value."},{"name":"maxEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is less than or equal to this value."},{"name":"minCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is greater than or equal to this value."},{"name":"maxCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is less than or equal to this value."},{"name":"minCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is greater than or equal to this value."},{"name":"maxCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is less than or equal to this value."},{"name":"minClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is greater than or equal to this value."},{"name":"maxClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is less than or equal to this value."}],"responses":{"200":{"description":"Job title insights for campaign group","content":{"application/json":{"example":{"data":[{"jobTitleUrn":"urn:li:title:123","jobTitleName":"VP of Marketing","impressions":12450,"clicks":87,"engagements":342,"costInUsd":891.45,"averageDwellTime":4.2,"videoViews":null,"videoStarts":null,"videoFirstQuartileCompletions":null,"videoMidpointCompletions":null,"videoThirdQuartileCompletions":null,"videoCompletions":null,"exclusion":null}],"pagination":{"page":1,"pageSize":20,"totalCount":2,"totalPages":1},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getCampaignGroupsByIdJobTitles"}},"/deals":{"get":{"summary":"List deals with insights","description":"Returns a paginated list of CRM deals with influence attribution data. Deals from every connected CRM come back in one list: HubSpot deals, Salesforce opportunities and Attio deals. Each deal carries `source`, `externalId` (its record ID in that CRM) and `externalUrl` (a link straight to the record), so you can match a deal back to the CRM it came from. `costBeforeDeal`/`costAfterDeal` are LinkedIn ad spend in USD, always — unlike `amount`, they do not follow the team's display currency.","tags":["Deals"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","closedAt","dealName","companyName","amount","impressionsBeforeDeal","impressionsAfterDeal"],"default":"createdAt"},"description":"Field to sort by (default: createdAt)"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"source","in":"query","schema":{"type":"string","enum":["all","hubspot","salesforce","attio"],"default":"all"},"description":"Filter deals by CRM source (default: all). HubSpot deals, Salesforce opportunities and Attio deals are returned in one list."},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date filter (YYYY-MM-DD). Supply with `endDate`; a partial range is ignored. Preferred over `dateFrom`, which is kept for backward compatibility.","example":"2025-01-01"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date filter (YYYY-MM-DD). Supply with `startDate`; a partial range is ignored. Preferred over `dateTo`, which is kept for backward compatibility.","example":"2025-12-31"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"},"description":"Deprecated alias for `startDate`. Used only when `startDate` is absent.","example":"2025-01-01"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"},"description":"Deprecated alias for `endDate`. Used only when `endDate` is absent.","example":"2025-12-31"},{"name":"abmCampaignId","in":"query","schema":{"type":"string"},"description":"Filter by a single ABM campaign. When set, it overrides `abmCampaigns`."},{"name":"abmCampaigns","in":"query","schema":{"type":"string"},"description":"Comma-separated ABM campaign IDs. Ignored when `abmCampaignId` is set."},{"name":"minAmount","in":"query","schema":{"type":"number"},"description":"Only return rows where the deal amount is greater than or equal to this value."},{"name":"maxAmount","in":"query","schema":{"type":"number"},"description":"Only return rows where the deal amount is less than or equal to this value."},{"name":"dealStatus","in":"query","schema":{"type":"string"},"description":"Comma-separated deal statuses: `open`, `won`, `lost` or `any`. Resolved from each CRM natively — HubSpot stage `isClosed` + `probability`, Salesforce `IsClosed`/`IsWon`, Attio status title. Any other value returns 400.","example":"won,lost"},{"name":"influenceFilter","in":"query","schema":{"type":"string"},"description":"Attribution type filter","example":"LINKEDIN,ABM"},{"name":"hideZeroAmount","in":"query","schema":{"type":"boolean","default":true},"description":"Hide $0 deals (default: true)"}],"responses":{"200":{"description":"Paginated list of deals","content":{"application/json":{"example":{"data":[{"id":"clxyz789deal","source":"hubspot","dealName":"Hooli - Enterprise License","externalId":"12345678","externalUrl":"https://app.hubspot.com/contacts/98765432/record/0-3/12345678/","company":{"id":"cm7abc123","name":"Hooli","logoUrl":"https://media.licdn.com/dms/image/hooli-logo.png","website":"https://hooli.com","linkedInOrgId":"12345"},"amount":45000,"linkedinInfluenced":true,"abmInfluenced":true,"createdAt":"2025-03-15T10:30:00.000Z","closedAt":"2025-06-20T14:00:00.000Z","stage":{"id":"cls123stage","name":"Closed Won"},"campaigns":[{"id":"cm7abm1","name":"Q1 Enterprise ABM"}],"impressionsBeforeDeal":8450,"clicksBeforeDeal":142,"engagementsBeforeDeal":312,"costBeforeDeal":891.45,"costAfterDeal":246.03},{"id":"clxyz789opp","source":"salesforce","dealName":"Pied Piper - Platform Deal","externalId":"0065f00000AbCdEf","externalUrl":"https://mycompany.lightning.force.com/lightning/r/Opportunity/0065f00000AbCdEf/view","company":{"id":"cm7def456","name":"Pied Piper","logoUrl":"https://media.licdn.com/dms/image/pp-logo.png","website":"https://piedpiper.com","linkedInOrgId":"67890"},"amount":72000,"linkedinInfluenced":true,"abmInfluenced":false,"createdAt":"2025-04-02T09:15:00.000Z","closedAt":null,"stage":{"id":"sf-stage-Negotiation","name":"Negotiation"},"campaigns":[],"impressionsBeforeDeal":5100,"clicksBeforeDeal":74,"engagementsBeforeDeal":160,"costBeforeDeal":436.58,"costAfterDeal":112.9},{"id":"clxyz789attio","source":"attio","dealName":"Initech - Annual Contract","externalId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","externalUrl":"https://app.attio.com/initech/deals/record/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","company":{"id":"cm7ghi789","name":"Initech","logoUrl":"https://media.licdn.com/dms/image/initech-logo.png","website":"https://initech.com","linkedInOrgId":"24680"},"amount":31000,"linkedinInfluenced":false,"abmInfluenced":true,"createdAt":"2025-05-11T08:00:00.000Z","closedAt":null,"stage":{"id":"attio-status-in-progress","name":"In Progress"},"campaigns":[{"id":"cm7abm2","name":"Mid-Market ABM"}],"impressionsBeforeDeal":2400,"clicksBeforeDeal":38,"engagementsBeforeDeal":91,"costBeforeDeal":220.15,"costAfterDeal":58.4}],"pagination":{"page":1,"pageSize":20,"totalCount":3,"totalPages":1},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getDeals"}},"/job-titles":{"get":{"summary":"List job titles with insights","description":"Optional filters: Ad Sets (comma-separated IDs), Campaigns (comma-separated IDs)","tags":["Job Titles"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"campaigns","in":"query","schema":{"type":"string"},"description":"Filter by Ad Sets IDs"},{"name":"campaignGroups","in":"query","schema":{"type":"string"},"description":"Filter by Campaigns IDs"},{"name":"minImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is greater than or equal to this value."},{"name":"maxImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is less than or equal to this value."},{"name":"minClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is greater than or equal to this value."},{"name":"maxClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is less than or equal to this value."},{"name":"minEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is greater than or equal to this value."},{"name":"maxEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is less than or equal to this value."},{"name":"minCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is greater than or equal to this value."},{"name":"maxCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is less than or equal to this value."},{"name":"minCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is greater than or equal to this value."},{"name":"maxCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is less than or equal to this value."},{"name":"minClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is greater than or equal to this value."},{"name":"maxClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is less than or equal to this value."},{"name":"includeWeekly","in":"query","schema":{"type":"boolean","default":false},"description":"When `true`, each job title in the response is augmented with a `weeklyData[]` array — one entry per Sunday-anchored bucket in the date range (impressions, clicks, engagements, costInUsd). `pageSize` is automatically capped at 20 on this path to keep responses small.","example":true}],"responses":{"200":{"description":"Paginated list of job titles. `weeklyData` is only present when `includeWeekly=true`.","content":{"application/json":{"example":{"data":[{"jobTitleUrn":"urn:li:title:123","jobTitleName":"VP of Marketing","impressions":12450,"clicks":87,"engagements":342,"costInUsd":891.45,"averageDwellTime":4.2,"videoViews":null,"videoStarts":null,"videoFirstQuartileCompletions":null,"videoMidpointCompletions":null,"videoThirdQuartileCompletions":null,"videoCompletions":null,"exclusion":null,"weeklyData":[{"weekStart":"2026-03-03","weekEnd":"2026-03-09","impressions":1820,"clicks":12,"engagements":47,"costInUsd":132.18},{"weekStart":"2026-03-10","weekEnd":"2026-03-16","impressions":2010,"clicks":15,"engagements":52,"costInUsd":148.92}]}],"pagination":{"page":1,"pageSize":20,"totalCount":1,"totalPages":1},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getJobTitles"}},"/job-titles/{id}/overview":{"get":{"summary":"Get job title performance overview","description":"Performance totals for a single job title over the date range — aggregated across the whole ad account (impressions, clicks, engagements, cost, conversions, CTR, CPC). The path `id` is the job title URN. Returns zeroes if the job title had no activity in the window.","tags":["Job Titles"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job title URN"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"Job title performance summary for the date range","content":{"application/json":{"example":{"data":{"jobTitleUrn":"urn:li:title:123","startDate":"2026-04-13","endDate":"2026-05-13","impressions":18420,"clicks":96,"engagements":312,"costInUsd":742.18,"conversions":4,"ctr":0.52,"cpc":7.73},"meta":{"timestamp":"2026-05-13T12:00:00.000Z"}}}}}},"operationId":"getJobTitlesByIdOverview"}},"/job-titles/{id}/campaigns":{"get":{"summary":"Get Ad Set insights for a job title","description":"Ad sets this job title was exposed to, with per-job-title delivery metrics. The path `id` is the job title URN. Optional filters: sortBy, sortOrder, search. Job title interactions are stored as weekly totals anchored on the Sunday that ends each Monday–Sunday week, so a date range selects whole weeks rather than exact days. `meta.dateRange` reports what was actually summed: the range you asked for, the range covered, and how many weeks that was. When `weeksCovered` is 0 no week ended inside your range, so the totals are empty by definition — widen the range rather than reading it as no activity.","tags":["Job Titles"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job title URN"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/jobTitleWeeklyStartDate"},{"$ref":"#/components/parameters/jobTitleWeeklyEndDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"}],"responses":{"200":{"description":"Ad Set insights for job title","content":{"application/json":{"example":{"data":[{"id":"1337","name":"TechCrunch 2025","format":"Single Image","impressions":12450,"clicks":87,"engagements":342,"costInUsd":891.45,"ctr":0.7,"cpc":10.25,"averageDwellTime":4.2,"videoViews":0,"videoStarts":0,"videoFirstQuartileCompletions":0,"videoMidpointCompletions":0,"videoThirdQuartileCompletions":0,"videoCompletions":0}],"meta":{"timestamp":"2026-03-09T12:00:00.000Z","dateRange":{"granularity":"weekly","weekAnchor":"sunday","requestedStartDate":"2026-04-01","requestedEndDate":"2026-04-15","coveredStartDate":"2026-03-30","coveredEndDate":"2026-04-12","weeksCovered":2}}}}}}},"operationId":"getJobTitlesByIdCampaigns"}},"/job-titles/{id}/campaign-groups":{"get":{"summary":"Get Campaign insights for a job title","description":"Optional filters: sortBy, sortOrder, search. Job title interactions are stored as weekly totals anchored on the Sunday that ends each Monday–Sunday week, so a date range selects whole weeks rather than exact days. `meta.dateRange` reports what was actually summed: the range you asked for, the range covered, and how many weeks that was. When `weeksCovered` is 0 no week ended inside your range, so the totals are empty by definition — widen the range rather than reading it as no activity.","tags":["Job Titles"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job title ID"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/jobTitleWeeklyStartDate"},{"$ref":"#/components/parameters/jobTitleWeeklyEndDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"}],"responses":{"200":{"description":"Campaign insights for job title","content":{"application/json":{"example":{"data":[{"id":"1337","name":"TechCrunch 2025","impressions":12450,"clicks":87,"engagements":342,"costInUsd":891.45,"ctr":0.7,"cpc":10.25,"averageDwellTime":4.2,"videoViews":0,"videoStarts":0,"videoFirstQuartileCompletions":0,"videoMidpointCompletions":0,"videoThirdQuartileCompletions":0,"videoCompletions":0}],"meta":{"timestamp":"2026-03-09T12:00:00.000Z","dateRange":{"granularity":"weekly","weekAnchor":"sunday","requestedStartDate":"2026-04-01","requestedEndDate":"2026-04-15","coveredStartDate":"2026-03-30","coveredEndDate":"2026-04-12","weeksCovered":2}}}}}}},"operationId":"getJobTitlesByIdCampaignGroups"}},"/abm-campaigns":{"get":{"summary":"List ABM campaigns with insights","description":"Optional filters: status (ACTIVE,PAUSED,COMPLETED)","tags":["ABM Campaigns"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Comma-separated statuses: ACTIVE,PAUSED,COMPLETED","example":"ACTIVE"},{"name":"minNumberOfLinkedinCampaigns","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of Ad Sets (response field `numberOfAdSets`) is greater than or equal to this value."},{"name":"maxNumberOfLinkedinCampaigns","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of Ad Sets (response field `numberOfAdSets`) is less than or equal to this value."},{"name":"minNumberOfLinkedinCampaignGroups","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of Campaigns (response field `numberOfCampaigns`) is greater than or equal to this value."},{"name":"maxNumberOfLinkedinCampaignGroups","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of Campaigns (response field `numberOfCampaigns`) is less than or equal to this value."},{"name":"minCompaniesTargeted","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of companies targeted is greater than or equal to this value."},{"name":"maxCompaniesTargeted","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of companies targeted is less than or equal to this value."},{"name":"minTotalPipeline","in":"query","schema":{"type":"number"},"description":"Only return rows where total pipeline value is greater than or equal to this value."},{"name":"maxTotalPipeline","in":"query","schema":{"type":"number"},"description":"Only return rows where total pipeline value is less than or equal to this value."},{"name":"minTotalRevenue","in":"query","schema":{"type":"number"},"description":"Only return rows where total closed-won revenue is greater than or equal to this value."},{"name":"maxTotalRevenue","in":"query","schema":{"type":"number"},"description":"Only return rows where total closed-won revenue is less than or equal to this value."},{"name":"minTotalAdSpend","in":"query","schema":{"type":"number"},"description":"Only return rows where total ad spend is greater than or equal to this value."},{"name":"maxTotalAdSpend","in":"query","schema":{"type":"number"},"description":"Only return rows where total ad spend is less than or equal to this value."},{"name":"minRoas","in":"query","schema":{"type":"number"},"description":"Only return rows where return on ad spend (ROAS) is greater than or equal to this value."},{"name":"maxRoas","in":"query","schema":{"type":"number"},"description":"Only return rows where return on ad spend (ROAS) is less than or equal to this value."}],"responses":{"200":{"description":"Paginated list of ABM campaigns","content":{"application/json":{"example":{"data":[{"id":"cm7abm001","name":"Q1 Enterprise ABM Campaign","status":"ACTIVE","startDate":"2025-01-15T00:00:00.000Z","endDate":"2025-06-30T00:00:00.000Z","description":"Targeting enterprise accounts in fintech","teamId":"team123","numberOfTargetAccounts":120,"createdAt":"2025-01-10T08:00:00.000Z","updatedAt":"2025-03-01T12:00:00.000Z","numberOfAdSets":5,"numberOfCampaigns":2,"companiesTargeted":85,"totalPipeline":450000,"totalRevenue":180000,"totalAdSpend":12500,"pipePerSpent":36,"averageAcv":45000,"roas":14.4}],"pagination":{"page":1,"pageSize":20,"totalCount":1,"totalPages":1},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getAbmCampaigns"}},"/abm-campaigns/{id}":{"get":{"summary":"Get ABM campaign by ID","description":"Returns the ABM campaign plus the LinkedIn entities the user assigned to it. An ABM campaign can be backed by campaigns (`linkedinCampaigns`), ad sets (`linkedinAdSets`), or both — each array is a direct membership, not a parent/child hierarchy. Either can be empty.","tags":["ABM Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM campaign ID"}],"responses":{"200":{"description":"ABM campaign details","content":{"application/json":{"example":{"data":{"abmCampaign":{"id":"1337","name":"Silicon Valley 2025","status":"ACTIVE","startDate":"2025-01-15T00:00:00.000Z","endDate":"2025-06-30T00:00:00.000Z","description":"Targeting enterprise accounts in fintech","teamId":"team123","numberOfTargetAccounts":120,"createdAt":"2025-01-10T08:00:00.000Z","updatedAt":"2025-03-01T12:00:00.000Z"},"linkedinCampaigns":[{"id":"1337","name":"Silicon Valley 2025 CG"}],"linkedinAdSets":[{"id":"1337","name":"Silicon Valley 2025","format":"Single Image"}]},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getAbmCampaignsById"}},"/abm-campaigns/{id}/overview":{"get":{"summary":"Get ABM campaign performance overview","description":"Performance for the date range: `metrics` (LinkedIn delivery — impressions, clicks, engagements, cost, conversions, CTR, CPC across the ad sets + campaigns assigned to this ABM campaign) and `effectiveness` (business outcomes — companiesTargeted, totalPipeline, totalRevenue, totalAdSpend, pipePerSpent, averageAcv, roas). Currency note: `metrics.costInUsd` and `effectiveness.totalAdSpend` are always USD; `effectiveness.totalPipeline`, `totalRevenue`, and `averageAcv` are in the team `displayCurrency` (HubSpot deal amounts converted at sync time). `pipePerSpent` and `roas` are therefore ratios across the two currencies — treat as approximate unless `displayCurrency` is USD.","tags":["ABM Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM campaign ID"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"ABM campaign performance for the date range","content":{"application/json":{"example":{"data":{"id":"cmoga3ilc004vju04cjrajud2","name":"ABM Intent May 26","startDate":"2026-04-13","endDate":"2026-05-13","displayCurrency":"USD","metrics":{"impressions":231753,"clicks":555,"engagements":861,"costInUsd":2189.62,"conversions":3,"ctr":0.24,"cpc":3.95},"effectiveness":{"companiesTargeted":412,"totalPipeline":184000,"totalRevenue":52000,"totalAdSpend":2189.62,"pipePerSpent":84.03,"averageAcv":26000,"roas":23.75}},"meta":{"timestamp":"2026-05-13T12:00:00.000Z"}}}}}},"operationId":"getAbmCampaignsByIdOverview"}},"/abm-campaigns/{id}/stages-breakdown":{"get":{"summary":"Get ABM campaign stages breakdown","description":"Returns a breakdown of companies across each ABM funnel stage.","tags":["ABM Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM campaign ID"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"}],"responses":{"200":{"description":"Stages breakdown for ABM campaign","content":{"application/json":{"example":{"data":{"data":[{"stageId":"1337","stageName":"Aware","color":"#FFC107","isConfigured":true,"currentPeriod":45,"previousPeriod":32,"change":13,"changePercentage":40.6}],"viewType":"unified","periods":{"current":{"label":"Mar 2025","dateRange":{"from":"2025-03-01","to":"2025-03-31"}},"previous":{"label":"Feb 2025","dateRange":{"from":"2025-02-01","to":"2025-02-28"}}}},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getAbmCampaignsByIdStagesBreakdown"}},"/abm-campaigns/{id}/companies":{"get":{"summary":"List companies for an ABM campaign","description":"Returns a paginated list of companies with engagement metrics and intent data for a specific ABM campaign. Aggregates data from all linked LinkedIn campaigns and campaign groups. `abmStage` is the company's stage within this campaign — `null` until the company has one here — and a manual stage override on the company takes precedence; `lifetimeAbmStage` stays company-wide.","tags":["ABM Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM campaign ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"engagementScores","in":"query","schema":{"type":"string"},"description":"Comma-separated scores (1–5)","example":"3,4,5"},{"name":"abmStages","in":"query","schema":{"type":"string"},"description":"Comma-separated ABM stage IDs. Filters on the company's stage within this campaign (manual overrides take precedence), matching the `abmStage` field in the response."},{"name":"intentId","in":"query","schema":{"type":"string"},"description":"Only return companies that show this intent signal. Takes a single intent ID — see `GET /intents`."},{"name":"minImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is greater than or equal to this value."},{"name":"maxImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is less than or equal to this value."},{"name":"minClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is greater than or equal to this value."},{"name":"maxClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is less than or equal to this value."},{"name":"minEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is greater than or equal to this value."},{"name":"maxEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is less than or equal to this value."},{"name":"minCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is greater than or equal to this value."},{"name":"maxCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is less than or equal to this value."},{"name":"minCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is greater than or equal to this value."},{"name":"maxCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is less than or equal to this value."},{"name":"minCpm","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per 1,000 impressions (CPM) is greater than or equal to this value."},{"name":"maxCpm","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per 1,000 impressions (CPM) is less than or equal to this value."},{"name":"minClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is greater than or equal to this value."},{"name":"maxClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is less than or equal to this value."},{"name":"minIntents","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of intent signals is greater than or equal to this value."},{"name":"maxIntents","in":"query","schema":{"type":"number"},"description":"Only return rows where the number of intent signals is less than or equal to this value."},{"name":"crmMatchStatus","in":"query","schema":{"type":"string","enum":["all","matched","unmatched"],"default":"all"},"description":"Filters on the link to HubSpot. `matched` returns only companies that have a HubSpot company record, `unmatched` only companies that have none. The name is generic for historic reasons, but this parameter covers HubSpot alone — use `salesforceMatchStatus` or `attioMatchStatus` for the other CRMs."},{"name":"salesforceMatchStatus","in":"query","schema":{"type":"string","enum":["all","matched","unmatched"],"default":"all"},"description":"Salesforce match filter"},{"name":"attioMatchStatus","in":"query","schema":{"type":"string","enum":["all","matched","unmatched"],"default":"all"},"description":"Attio match filter"},{"$ref":"#/components/parameters/hideExcludedCompanies"},{"$ref":"#/components/parameters/hasContacts"}],"responses":{"200":{"description":"Paginated companies for this ABM campaign","content":{"application/json":{"example":{"data":[{"id":"1337","name":"Pied Piper","city":"Palo Alto","country":"US","website":"https://www.piedpiper.com/","linkedInOrgId":"4827017","hubspotCompanyId":"37411334702","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","lifetimeEngagementScore":3,"logoUrl":"https://piedpiper.com/assets/images/logo.png","abmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"lifetimeAbmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"intents":[{"id":"cm9iaw4a50001jr04wqc1k4dt","name":"Competitor"}],"impressions":109198,"clicks":468,"engagements":2769,"costInUsd":2797.37,"currentEngagementScore":2}],"pagination":{"page":1,"pageSize":20,"totalCount":85,"totalPages":5},"meta":{"timestamp":"2026-03-10T12:00:00.000Z"}}}}},"404":{"description":"ABM campaign not found"}},"operationId":"getAbmCampaignsByIdCompanies"}},"/abm-campaigns/{id}/job-titles":{"get":{"summary":"List job titles for an ABM campaign","description":"Returns a paginated list of job titles with engagement metrics for a specific ABM campaign. Aggregates data from all linked LinkedIn campaigns and campaign groups.","tags":["ABM Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM campaign ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"name":"minImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is greater than or equal to this value."},{"name":"maxImpressions","in":"query","schema":{"type":"number"},"description":"Only return rows where impressions is less than or equal to this value."},{"name":"minClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is greater than or equal to this value."},{"name":"maxClicks","in":"query","schema":{"type":"number"},"description":"Only return rows where clicks is less than or equal to this value."},{"name":"minEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is greater than or equal to this value."},{"name":"maxEngagements","in":"query","schema":{"type":"number"},"description":"Only return rows where engagements is less than or equal to this value."},{"name":"minCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is greater than or equal to this value."},{"name":"maxCostInUsd","in":"query","schema":{"type":"number"},"description":"Only return rows where cost in USD is less than or equal to this value."},{"name":"minCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is greater than or equal to this value."},{"name":"maxCostPerClick","in":"query","schema":{"type":"number"},"description":"Only return rows where cost per click (CPC) is less than or equal to this value."},{"name":"minClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is greater than or equal to this value."},{"name":"maxClickThroughRate","in":"query","schema":{"type":"number"},"description":"Only return rows where click-through rate (CTR, as a percentage) is less than or equal to this value."}],"responses":{"200":{"description":"Paginated job titles for this ABM campaign","content":{"application/json":{"example":{"data":[{"jobTitleUrn":"urn:li:title:123","jobTitleName":"VP of Marketing","impressions":12450,"clicks":87,"engagements":342,"costInUsd":891.45,"averageDwellTime":4.2,"videoViews":null,"videoStarts":null,"videoFirstQuartileCompletions":null,"videoMidpointCompletions":null,"videoThirdQuartileCompletions":null,"videoCompletions":null,"exclusion":null}],"pagination":{"page":1,"pageSize":20,"totalCount":45,"totalPages":3},"meta":{"timestamp":"2026-03-10T12:00:00.000Z"}}}}},"404":{"description":"ABM campaign not found"}},"operationId":"getAbmCampaignsByIdJobTitles"}},"/abm-stages":{"get":{"summary":"List ABM stages","description":"Returns every ABM stage for the team, each with its full condition model. `blockOperator` (`AND`/`OR`) joins the stage's `conditionBlocks`; each block joins its own `conditions` with its `operator` (`AND`/`OR`). Each condition carries a `type` plus only the fields relevant to that type (null fields are omitted). Condition types: `LINKEDIN_METRICS`, `LIFECYCLE_STAGE`, `DEAL_STAGE`, `CUSTOM_PROPERTY` (HubSpot company property), `CONTACT_PROPERTY` (HubSpot contact property, matches when at least `minMatchingContacts` of the company's contacts satisfy the mapping), `ATTIO_COMPANY_PROPERTY`, `ATTIO_DEAL_STAGE`. Property-mapping `operator` values include `equals`, `not_equals`, `contains`, `not_contains`, `greater_than`, `greater_than_or_equal`, `less_than`, `less_than_or_equal`, `between`, `in_list`, `not_in_list`, `is_known`, `is_unknown`. All ids returned (`scopeIds`, `dealStageIds`, `pipelineIds`, `lifecycleStageIds`, mapping ids) are this team's own ids.","tags":["ABM Stages"],"responses":{"200":{"description":"List of ABM stages with their condition model","content":{"application/json":{"example":{"data":[{"id":"cls1abc","name":"Aware","color":"#FFC107","displayOrder":1,"createdAt":"2025-01-05T08:00:00.000Z","updatedAt":"2025-01-05T08:00:00.000Z","blockOperator":"OR","conditionBlocks":[{"operator":"OR","conditions":[{"type":"LINKEDIN_METRICS","metric":"IMPRESSIONS","comparison":"GREATER_THAN_OR_EQUAL","minValue":100,"windowDays":30,"scope":"INHERIT_CAMPAIGN"}]}]},{"id":"cls2def","name":"Engaged","color":"#4CAF50","displayOrder":2,"createdAt":"2025-01-05T08:00:00.000Z","updatedAt":"2025-01-05T08:00:00.000Z","blockOperator":"AND","conditionBlocks":[{"operator":"AND","conditions":[{"type":"CONTACT_PROPERTY","propertyMapping":{"id":"map_contact_1","hubspotPropertyName":"seniority","operator":"is_known","propertyObjectType":"CONTACT","minMatchingContacts":2}},{"type":"DEAL_STAGE","dealStageIds":["hs_stage_123"],"matchAnyOpenDeal":false}]}]}],"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getAbmStages"}},"/abm-stages/manage":{"post":{"summary":"Manage an ABM stage","description":"Applies one or more changes to the ABM stage funnel. The body is either a single operation object (not wrapped) or `{ \"operations\": [...] }` with 1–10 of them. Each operation is discriminated on `op`: `create_stage`, `rename_stage`, `recolor_stage`, `delete_stage`, `reorder_stage`, `set_stage_block_operator`, `set_stage_conditions`, `add_condition_block`, `remove_condition_block`, `set_block_operator`, `add_condition`, `replace_condition`, `remove_condition`. This is the first write endpoint in v1. It is gated by the same API access plan feature as the read endpoints.\n\n**Batches.** Operations in `operations` apply in order, and each one sees the result of the one before it — so after a `remove_condition_block` the later block indexes shift, and a stage created earlier in the batch can be addressed by name later in it. A batch is **not atomic**: when a step fails, the earlier steps stay applied and the error reports which step failed. Read the stage back before you retry. To rewrite a whole rule, prefer one `set_stage_conditions` over a batch of remove + add operations.\n\n**Names, not ids.** Stages, lifecycle stages, deal stages, pipelines, properties, Attio attributes, Ad Sets, Campaigns and ABM campaigns are all addressed by name. Stage names match case-insensitively; a unique prefix or substring also resolves. A `stageRef` may carry an `id` instead when you already have one. An unknown or ambiguous name returns 422 `UNRESOLVED_REFERENCE` and the message lists the available candidates.\n\n**Fixed stages.** `Identified` is always first and `Customer`, `Lost` and `Disqualified` are always last. They cannot be moved, renamed or deleted, and a `position` that would displace them returns 422 `INVALID_OPERATION`.\n\n**Indexes.** `blockIndex` and `conditionIndex` are 0-based positions in `conditionBlocks` and in a block’s `conditions`, exactly as `GET /abm-stages/{id}` returns them. Read the stage first, then address the block or condition by position. An out-of-range index returns 422 `INVALID_OPERATION`. `replace_condition` swaps one condition in place: send the full new condition, or the existing one with a single field changed. `set_stage_conditions` replaces every block on the stage with the `blocks` you send (and optionally sets `blockOperator`), so no index is needed.\n\n**Conditions.** A `contact_property` condition matches when at least `minMatchingContacts` (default 1) of the company’s contacts satisfy it. A `deal_stage` condition needs `pipelineNames` when the same stage name repeats across pipelines. A `linkedin_metric` condition with a scope other than `INHERIT_CAMPAIGN` needs at least one entry in `scopeNames`.\n\n**Response.** `data.applied` and `data.total` count the operations that ran and the operations in the request (both `1` for a single operation). `data.stage` is the stage re-read after the last operation, with the same condition model as `GET /abm-stages/{id}` (`null` only when the last operation was `delete_stage`). `data.warnings` is non-blocking: it names what a `delete_stage` removed, and it flags a condition that points at something that no longer exists (a deleted lifecycle stage, deal stage, property or LinkedIn asset) so you can fix it with `replace_condition` or `set_stage_conditions`.\n\n**Errors.** A failed step uses the same status codes as a single operation: 400 `INVALID_INPUT`, 422 `UNRESOLVED_REFERENCE` / `INVALID_OPERATION`, 403 `FEATURE_NOT_AVAILABLE` / `PLAN_NOT_ALLOWED`, 404 `NOT_FOUND`, 502 `CRM_UNAVAILABLE`. When the request holds more than one operation, the message starts with `Step N of M (<op>): `.","tags":["ABM Stages"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AbmStageOperation"},{"$ref":"#/components/schemas/AbmStageManageBatchRequest"}]},"examples":{"renameStage":{"summary":"Rename a stage by name","value":{"op":"rename_stage","stageRef":{"name":"Aware"},"name":"Engaged"}},"addLinkedInCondition":{"summary":"Add a LinkedIn clicks condition scoped to one ABM campaign","value":{"op":"add_condition","stageRef":{"name":"Engaged"},"blockIndex":0,"condition":{"type":"linkedin_metric","metric":"CLICKS","comparison":"GREATER_THAN_OR_EQUAL","minValue":3,"windowDays":30,"scope":"ABM_CAMPAIGNS","scopeNames":["Q1 Enterprise ABM"]}}},"replaceContactCondition":{"summary":"Replace a condition with a contact property test that needs 2 matching contacts","value":{"op":"replace_condition","stageRef":{"name":"Engaged"},"blockIndex":0,"conditionIndex":1,"condition":{"type":"contact_property","propertyName":"seniority","operator":"is_known","minMatchingContacts":2}}},"rewriteRule":{"summary":"Rewrite a stage's whole rule in one step with set_stage_conditions","value":{"op":"set_stage_conditions","stageRef":{"name":"Engaged"},"blockOperator":"AND","blocks":[{"operator":"OR","conditions":[{"type":"linkedin_metric","metric":"CLICKS","comparison":"GREATER_THAN_OR_EQUAL","minValue":3,"windowDays":30},{"type":"linkedin_metric","metric":"ENGAGEMENTS","comparison":"GREATER_THAN_OR_EQUAL","minValue":5,"windowDays":30}]},{"conditions":[{"type":"lifecycle_stage","lifecycleStageNames":["Marketing Qualified Lead"]}]}]}},"batch":{"summary":"Batch: recolor then rename one stage","value":{"operations":[{"op":"recolor_stage","stageRef":{"name":"Aware"},"color":"#4CAF50"},{"op":"rename_stage","stageRef":{"name":"Aware"},"name":"Engaged"}]}}}}}},"responses":{"200":{"description":"Every operation was applied. `stage` is the stage after the last one (`null` when that was `delete_stage`), plus any non-blocking warnings.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AbmStageManageResult"},"meta":{"$ref":"#/components/schemas/Meta"}}},"example":{"data":{"applied":1,"total":1,"stage":{"id":"cls2def","name":"Engaged","color":"#4CAF50","displayOrder":2,"isSystem":false,"blockOperator":"AND","conditionBlocks":[{"operator":"AND","conditions":[{"type":"LINKEDIN_METRICS","metric":"CLICKS","comparison":"GREATER_THAN_OR_EQUAL","minValue":3,"windowDays":30,"scope":"ABM_CAMPAIGNS","scopeIds":["cm7abm001"]},{"type":"CONTACT_PROPERTY","propertyMapping":{"id":"map_contact_1","hubspotPropertyName":"seniority","operator":"is_known","propertyObjectType":"CONTACT","minMatchingContacts":2}}]}]},"warnings":[]},"meta":{"timestamp":"2026-09-01T12:00:00.000Z"}}}}},"400":{"description":"The body does not match the operation or batch schema (`INVALID_INPUT`). The message names the failing path. In a batch it starts with `Step N of M (<op>): `.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"status":400,"code":"INVALID_INPUT","message":"BETWEEN needs maxValue. at condition.maxValue"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Either API access is not included in the plan (`FEATURE_NOT_AVAILABLE`), or the operation edits an already-configured custom stage, which needs the Growth or Pro plan (`PLAN_NOT_ALLOWED`). A pristine system stage can still be edited on any plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"status":403,"code":"PLAN_NOT_ALLOWED","message":"This action is only available on Growth and Pro plans"}}}}},"404":{"description":"The stage or a referenced object was not found (`NOT_FOUND`). In a batch the earlier steps stay applied and the message starts with `Step N of M (<op>): `.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"status":404,"code":"NOT_FOUND","message":"Stage not found."}}}}},"405":{"description":"Method not allowed — only POST is accepted"},"422":{"description":"The operation cannot be applied. `UNRESOLVED_REFERENCE`: a name did not resolve to exactly one record; the message lists the available candidates. `INVALID_OPERATION`: a fixed stage cannot be moved, renamed or deleted, an index is out of range, or a position would displace a fixed stage. In a batch the earlier steps stay applied and the message starts with `Step N of M (<op>): `.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"status":422,"code":"UNRESOLVED_REFERENCE","message":"Step 2 of 2 (add_condition): No lifecycle stage matches \"SQL\". Available lifecycle stages: Subscriber, Lead, Marketing Qualified Lead, Sales Qualified Lead, Opportunity, Customer."}}}}},"429":{"description":"Rate limit exceeded"},"502":{"description":"The CRM could not be reached while resolving a name (`CRM_UNAVAILABLE`), for example a HubSpot lifecycle stage, deal stage, pipeline or property lookup failed. Retry later. In a batch the earlier steps stay applied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"status":502,"code":"CRM_UNAVAILABLE","message":"HubSpot did not respond while loading deal pipelines. Try again in a few minutes."}}}}}},"operationId":"postAbmStagesManage"}},"/abm-stages/{id}":{"get":{"summary":"Get ABM stage by ID","description":"Returns the ABM stage with `currentCompaniesCount` (companies currently in this stage) and its full condition model. `blockOperator` (`AND`/`OR`) joins the `conditionBlocks`; each block joins its `conditions` with its `operator` (`AND`/`OR`). Each condition carries a `type` plus only the fields relevant to that type (null fields are omitted):\n- `LINKEDIN_METRICS`: `metric`, `comparison`, `minValue`, `maxValue`, `windowDays` (rolling window; omitted = since campaign start), `scope` (`INHERIT_CAMPAIGN` | `LINKEDIN_CAMPAIGN_GROUPS` | `LINKEDIN_AD_SETS` | `ABM_CAMPAIGNS`), `scopeIds`.\n- `LIFECYCLE_STAGE`: `lifecycleStageIds`.\n- `DEAL_STAGE`: `dealStageIds`, `pipelineIds` (pipelines that scope a `matchAnyOpenDeal` condition; omitted means any tracked pipeline), `matchAnyOpenDeal`.\n- `ATTIO_DEAL_STAGE`: `attioDealStatusIds`, `attioMatchAnyOpenDeal`.\n- `CUSTOM_PROPERTY` (HubSpot company) / `CONTACT_PROPERTY` (HubSpot contact): a `propertyMapping` with `hubspotPropertyName`, `operator`, `propertyObjectType` (`COMPANY` | `CONTACT`), `minMatchingContacts` (contact-property match threshold), and any of `expectedValue`, `expectedValues`, `numericThreshold`, `numericThresholdMax`.\n- `ATTIO_COMPANY_PROPERTY`: an `attioPropertyMapping` with `attributeSlug`, `attributeTitle`, `operator`, and value fields.\nProperty-mapping `operator` values include `equals`, `not_equals`, `contains`, `not_contains`, `greater_than`, `greater_than_or_equal`, `less_than`, `less_than_or_equal`, `between`, `in_list`, `not_in_list`, `is_known`, `is_unknown`.","tags":["ABM Stages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM stage ID"}],"responses":{"200":{"description":"ABM stage details with its condition model","content":{"application/json":{"example":{"data":{"id":"cls1abc","name":"Aware","color":"#FFC107","displayOrder":1,"createdAt":"2025-01-05T08:00:00.000Z","updatedAt":"2025-01-05T08:00:00.000Z","blockOperator":"OR","conditionBlocks":[{"operator":"AND","conditions":[{"type":"LINKEDIN_METRICS","metric":"ENGAGEMENTS","comparison":"GREATER_THAN_OR_EQUAL","minValue":5,"windowDays":90,"scope":"LINKEDIN_AD_SETS","scopeIds":["512103383"]},{"type":"CONTACT_PROPERTY","propertyMapping":{"id":"map_contact_1","hubspotPropertyName":"seniority","operator":"is_known","propertyObjectType":"CONTACT","minMatchingContacts":2}}]},{"operator":"OR","conditions":[{"type":"LIFECYCLE_STAGE","lifecycleStageIds":["hs_lifecycle_mql"]},{"type":"DEAL_STAGE","dealStageIds":["hs_stage_123"],"matchAnyOpenDeal":false},{"type":"CUSTOM_PROPERTY","propertyMapping":{"id":"map_company_1","hubspotPropertyName":"numberofemployees","operator":"between","propertyObjectType":"COMPANY","minMatchingContacts":1,"numericThreshold":50,"numericThresholdMax":500}}]}],"currentCompaniesCount":45},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}},"404":{"description":"ABM stage not found"}},"operationId":"getAbmStagesById"}},"/abm-stages/{id}/companies":{"get":{"summary":"List companies currently in an ABM stage","description":"Returns a paginated list of companies whose current ABM stage matches the given stage ID. Supports search and sorting.","tags":["ABM Stages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM stage ID"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/sortBy"},{"$ref":"#/components/parameters/sortOrder"},{"$ref":"#/components/parameters/search"},{"$ref":"#/components/parameters/hideExcludedCompanies"},{"$ref":"#/components/parameters/hasContacts"}],"responses":{"200":{"description":"Paginated companies in this ABM stage","content":{"application/json":{"example":{"data":[{"id":"1337","name":"Pied Piper","city":"Palo Alto","country":"US","website":"https://www.piedpiper.com/","linkedInOrgId":"4827017","hubspotCompanyId":"37411334702","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","logoUrl":"https://piedpiper.com/assets/images/logo.png","lifetimeEngagementScore":3,"abmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3},"lifetimeAbmStage":{"id":"1337_interested","name":"Interested","color":"#10B981","displayOrder":3}}],"pagination":{"page":1,"pageSize":20,"totalCount":45,"totalPages":3},"meta":{"timestamp":"2026-03-10T12:00:00.000Z"}}}}},"404":{"description":"ABM stage not found"}},"operationId":"getAbmStagesByIdCompanies"}},"/abm-stages/{id}/companies-entering":{"get":{"summary":"Get companies entering an ABM stage","tags":["ABM Stages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM stage ID"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (ISO format, default: 30 days ago)"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (ISO format, default: today)"},{"name":"campaignType","in":"query","schema":{"type":"string","enum":["current_abm_stage","lifetime_abm_stage","specific_campaign","all_abm_campaigns","linkedin_influenced"]},"description":"Which stage to read (default: `current_abm_stage`).\n\n- `current_abm_stage` — the stage the company is in now.\n- `lifetime_abm_stage` — the furthest stage the company has ever reached.\n- `specific_campaign` — the stage the company holds inside one ABM campaign. Send `campaignId` with it; without a campaign id it falls back to `current_abm_stage`.\n\nTwo older values still work. `all_abm_campaigns` now means the same as `current_abm_stage`. `linkedin_influenced` now means the same as `lifetime_abm_stage`, and no longer restricts the result to companies with a LinkedIn page. An unknown value falls back to `current_abm_stage` instead of returning an error.","example":"current_abm_stage"},{"name":"campaignId","in":"query","schema":{"type":"string"},"description":"ABM campaign ID. Used only with `campaignType=specific_campaign`."},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"}],"responses":{"200":{"description":"Companies entering stage","content":{"application/json":{"example":{"data":{"companies":[{"id":"cm7abc123","name":"Acme Corp","logoUrl":"https://media.licdn.com/dms/image/acme-logo.png","website":"https://acme.com","hubspotCompanyId":"9876543","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","country":"United States","previousStage":{"id":"cls1abc","name":"Aware","color":"#FFC107"},"dateEntered":"2026-03-12T09:30:00.000Z"},{"id":"cm7xyz456","name":"Globex Industries","logoUrl":"https://media.licdn.com/dms/image/globex-logo.png","website":"https://globex.com","hubspotCompanyId":"1234567","attioRecordId":null,"country":"Germany","previousStage":null,"dateEntered":"2026-03-08T14:15:00.000Z"}],"hubspotPortalId":"98765432","attioWorkspaceSlug":"acme-gmbh","totalCount":42},"pagination":{"page":1,"pageSize":20,"totalCount":42,"totalPages":3},"meta":{"timestamp":"2026-04-12T12:00:00.000Z"}}}}}},"operationId":"getAbmStagesByIdCompaniesEntering"}},"/abm-stages/{id}/companies-progressing":{"get":{"summary":"Get companies progressing from an ABM stage","tags":["ABM Stages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM stage ID"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (ISO format, default: 30 days ago)"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (ISO format, default: today)"},{"name":"campaignType","in":"query","schema":{"type":"string","enum":["current_abm_stage","lifetime_abm_stage","specific_campaign","all_abm_campaigns","linkedin_influenced"]},"description":"Which stage to read (default: `current_abm_stage`).\n\n- `current_abm_stage` — the stage the company is in now.\n- `lifetime_abm_stage` — the furthest stage the company has ever reached.\n- `specific_campaign` — the stage the company holds inside one ABM campaign. Send `campaignId` with it; without a campaign id it falls back to `current_abm_stage`.\n\nTwo older values still work. `all_abm_campaigns` now means the same as `current_abm_stage`. `linkedin_influenced` now means the same as `lifetime_abm_stage`, and no longer restricts the result to companies with a LinkedIn page. An unknown value falls back to `current_abm_stage` instead of returning an error.","example":"current_abm_stage"},{"name":"campaignId","in":"query","schema":{"type":"string"},"description":"ABM campaign ID. Used only with `campaignType=specific_campaign`."},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"}],"responses":{"200":{"description":"Companies progressing from stage","content":{"application/json":{"example":{"data":{"companies":[{"id":"cm7abc123","name":"Acme Corp","website":"https://acme.com","country":"United States","linkedInOrgId":"12345","logoUrl":"https://media.licdn.com/dms/image/acme-logo.png","hubspotCompanyId":"9876543","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","nextStage":{"id":"cls3ghi","name":"MQL","color":"#2196F3"},"dateLeft":"2026-03-25T11:00:00.000Z"}],"hubspotPortalId":"98765432","attioWorkspaceSlug":"acme-gmbh","totalCount":1},"pagination":{"page":1,"pageSize":20,"totalCount":1,"totalPages":1},"meta":{"timestamp":"2026-04-12T12:00:00.000Z"}}}}}},"operationId":"getAbmStagesByIdCompaniesProgressing"}},"/abm-stages/{id}/history":{"get":{"summary":"Get ABM stage history","tags":["ABM Stages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ABM stage ID"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (ISO format, default: 30 days ago)"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (ISO format, default: today)"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"}],"responses":{"200":{"description":"Stage transition events — each entry is one company moving from `previousStage` to `abmStage`. `previousStage` is null for the company’s first stage entry.","content":{"application/json":{"example":{"data":[{"eventDate":"2026-03-28T09:30:00.000Z","company":{"id":"cm7abc123","name":"Acme Corp"},"abmStage":{"id":"cls2def","name":"Engaged","color":"#4CAF50"},"previousStage":{"id":"cls1abc","name":"Aware","color":"#FFC107"}},{"eventDate":"2026-03-20T14:15:00.000Z","company":{"id":"cm7xyz456","name":"Globex Industries"},"abmStage":{"id":"cls2def","name":"Engaged","color":"#4CAF50"},"previousStage":null}],"pagination":{"page":1,"pageSize":20,"totalCount":92,"totalPages":5},"meta":{"timestamp":"2026-04-12T12:00:00.000Z"}}}}}},"operationId":"getAbmStagesByIdHistory"}},"/intents":{"get":{"summary":"List intents","tags":["Intents"],"responses":{"200":{"description":"List of intents for team","content":{"application/json":{"example":{"data":[{"id":"int001","name":"Product Demo Interest","description":"","companyCount":142,"adSets":[{"id":"cm7lc001","name":"Evergreen 2025 - Competitor Switching"}],"campaigns":[{"id":"cm7lcg001","name":"Fintech Enterprise Group"}]}],"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getIntents"}},"/intents/{id}":{"get":{"summary":"Get intent by ID","description":"Returns the intent with the ad sets and campaigns it is assigned to, plus `companyCount` — the number of companies tagged with this intent.","tags":["Intents"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Intent ID"}],"responses":{"200":{"description":"Intent details","content":{"application/json":{"example":{"data":{"id":"int001","name":"Product Demo Interest","description":"","companyCount":142,"adSets":[{"id":"cm7lc001","name":"Evergreen 2025 - Competitor Switching"}],"campaigns":[{"id":"cm7lcg001","name":"Fintech Enterprise Group"}]},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getIntentsById"}},"/contacts":{"get":{"summary":"List contacts with source touchpoints","description":"Returns a paginated list of HubSpot contacts with source touchpoint totals, company context, ABM stage context, and related deals.","tags":["Contacts"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/search"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of the source event window (inclusive). ISO-8601 string.","example":"2026-04-01T00:00:00.000Z"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of the source event window (inclusive). ISO-8601 string.","example":"2026-05-01T00:00:00.000Z"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","companyName","totalClicks","lastEventAt"],"default":"totalClicks"}},{"$ref":"#/components/parameters/sortOrder"},{"name":"touchpoints","in":"query","schema":{"type":"string"},"description":"Comma-separated touchpoint keys. Examples: PAID_SEARCH, PAID_SOCIAL|LinkedIn Ads, AI_REFERRALS|AI: ChatGPT.","example":"PAID_SEARCH,AI_REFERRALS|AI: ChatGPT"},{"name":"currentAbmStages","in":"query","schema":{"type":"string"},"description":"Comma-separated current ABM stage IDs."},{"name":"lifetimeAbmStages","in":"query","schema":{"type":"string"},"description":"Comma-separated lifetime ABM stage IDs."},{"name":"hasDeal","in":"query","schema":{"type":"string","enum":["all","any","open","won","lost","none","created_in_period","won_in_period","lost_in_period"],"default":"all"},"description":"Filter contacts by their company's deal status. `*_in_period` variants use the page's `startDate`/`endDate` window — `created_in_period` matches `hubspotCreatedAt`, `won_in_period`/`lost_in_period` match `hubspotClosedAt` on won / lost deals. Won and lost are resolved from each CRM natively — HubSpot stage `isClosed` + `probability`, Salesforce `IsClosed`/`IsWon`, Attio status title."}],"responses":{"200":{"description":"Paginated contacts with source touchpoints","content":{"application/json":{"example":{"data":[{"id":"cnt001","hubspotContactId":"5510123","firstName":"Ada","lastName":"Lovelace","name":"Ada Lovelace","email":"ada@piedpiper.com","companyId":"cmp001","companyName":"Pied Piper","companyLogoUrl":"https://piedpiper.com/logo.png","companyHubspotId":"37411334702","companyAbmStage":{"id":"stage_interested","name":"Interested","color":"#10B981","displayOrder":3},"companyLifetimeAbmStage":{"id":"stage_evaluating","name":"Evaluating","color":"#6366F1","displayOrder":4},"companyHasAnyDeal":true,"companyDeals":[{"id":"deal001","hubspotId":"982173","hubspotPortalId":243811,"dealName":"Pied Piper - Enterprise","hubspotCreatedAt":"2026-04-15T10:00:00.000Z","hubspotClosedAt":null,"status":"open"}],"totalClicks":12,"touchpoints":[{"sourceType":"PAID_SEARCH","label":"PAID_SEARCH","count":6},{"sourceType":"AI_REFERRALS","label":"AI: ChatGPT","count":4}],"touchpointEvents":[{"id":"evt001","sourceType":"PAID_SEARCH","label":"PAID_SEARCH","detail1":"google","detail2":"brand campaign","eventTimestamp":"2026-04-29T12:30:00.000Z"}],"lastEventAt":"2026-04-29T12:30:00.000Z"}],"pagination":{"page":1,"pageSize":20,"totalCount":42,"totalPages":3},"meta":{"timestamp":"2026-05-04T12:00:00.000Z"}}}}}},"operationId":"getContacts"}},"/contacts/{id}":{"get":{"summary":"Get contact journey","description":"Returns a single contact with company context, source events, related deals, and a weekly source-event timeline.","tags":["Contacts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Contact ID"}],"responses":{"200":{"description":"Contact journey detail","content":{"application/json":{"example":{"data":{"id":"cnt001","hubspotContactId":"5510123","hubspotPortalId":"243811","firstName":"Ada","lastName":"Lovelace","email":"ada@piedpiper.com","company":{"id":"cmp001","name":"Pied Piper","website":"https://piedpiper.com","hubspotCompanyId":"37411334702","logoUrl":"https://piedpiper.com/logo.png"},"sourceEvents":[{"sourceType":"AI_REFERRALS","label":"AI: ChatGPT","detail1":"chatgpt.com","detail2":"/pricing","eventTimestamp":"2026-04-30T15:12:00.000Z"},{"sourceType":"PAID_SEARCH","label":"PAID_SEARCH","detail1":"google","detail2":"brand campaign","eventTimestamp":"2026-04-29T12:30:00.000Z"}],"deals":[{"id":"deal001","hubspotId":"982173","hubspotPortalId":243811,"dealName":"Pied Piper - Enterprise","amount":25000,"hubspotCreatedAt":"2026-04-15T10:00:00.000Z","hubspotClosedAt":null,"stageName":"Proposal","isWon":false,"isLost":false}],"weeklyTimeline":[{"weekStart":"2026-04-27","clicks":8},{"weekStart":"2026-05-04","clicks":4}],"totalClicks":12},"meta":{"timestamp":"2026-05-04T12:00:00.000Z"}}}}},"404":{"description":"Contact not found","content":{"application/json":{"example":{"error":{"status":404,"code":"NOT_FOUND","message":"Contact not found"}}}}}},"operationId":"getContactsById"}},"/sources":{"get":{"summary":"List contact source aggregates","description":"Returns aggregated contact source events grouped by source type. Each row reports total clicks, distinct contacts, and distinct companies. Filter by an optional date range.","tags":["Sources"],"parameters":[{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of the event window (inclusive). ISO-8601 string.","example":"2026-04-01T00:00:00.000Z"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of the event window (inclusive). ISO-8601 string.","example":"2026-05-01T00:00:00.000Z"}],"responses":{"200":{"description":"Aggregated source totals","content":{"application/json":{"example":{"data":[{"key":"PAID_SEARCH","sourceType":"PAID_SEARCH","label":"PAID_SEARCH","clicks":1240,"contacts":87,"companies":54},{"key":"AI_REFERRALS:AI: ChatGPT","sourceType":"AI_REFERRALS","label":"AI: ChatGPT","clicks":612,"contacts":45,"companies":38}],"meta":{"timestamp":"2026-05-04T12:00:00.000Z"}}}}}},"operationId":"getSources"}},"/sources/{sourceType}":{"get":{"summary":"Get source detail by type","description":"Returns the contacts, companies, and weekly timeline for a single source type within an optional date range. Capped at the most recent 500 events.","tags":["Sources"],"parameters":[{"name":"sourceType","in":"path","required":true,"schema":{"type":"string"},"description":"Source type identifier (e.g. PAID_SEARCH, PAID_SOCIAL, ORGANIC_SEARCH, AI_REFERRALS, REFERRALS, DIRECT_TRAFFIC, EMAIL_MARKETING, SOCIAL_MEDIA, OFFLINE, OTHER_CAMPAIGNS).","example":"PAID_SEARCH"},{"name":"label","in":"query","schema":{"type":"string"},"description":"Optional label filter. Use for split source rows such as PAID_SOCIAL|LinkedIn Ads or AI_REFERRALS|AI: ChatGPT.","example":"AI: ChatGPT"},{"$ref":"#/components/parameters/period"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of the event window (inclusive). ISO-8601 string. Supply with `endDate` to override `period`.","example":"2026-04-01T00:00:00.000Z"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of the event window (inclusive). ISO-8601 string.","example":"2026-05-01T00:00:00.000Z"}],"responses":{"200":{"description":"Source detail with contact and company breakdowns","content":{"application/json":{"example":{"data":{"contacts":[{"contactId":"cnt001","hubspotContactId":"5510123","name":"Ada Lovelace","email":"ada@piedpiper.com","companyName":"Pied Piper","companyId":"cmp001","clicks":12,"lastEvent":"2026-05-03T19:11:24.000Z"}],"companies":[{"companyId":"cmp001","name":"Pied Piper","website":"https://piedpiper.com","clicks":41,"contacts":7}],"timeline":[{"weekStart":"2026-04-27","clicks":18},{"weekStart":"2026-05-04","clicks":23}],"totalClicks":41,"totalContacts":7,"totalCompanies":1},"meta":{"timestamp":"2026-05-04T12:00:00.000Z"}}}}}},"operationId":"getSourcesBySourceType"}},"/ad-spend":{"get":{"summary":"Ad Set monthly spend","description":"Returns ad spend for LinkedIn Ad Sets within the requested date range. Response includes a `summary` of totals across the whole range and a `byAdSet` array — one entry per ad set, each carrying its own totals plus monthly buckets (`year`, `month`, `period` like `\"2026-05\"`). Pagination scopes `byAdSet` (summary always reflects the full range). Each ad set includes both ZenABM's internal `id` (when imported) and the LinkedIn-native `linkedInId`. Filter to a single ad set with the `linkedInId` query param.","tags":["Ad Sets"],"parameters":[{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/period"},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"name":"linkedInId","in":"query","schema":{"type":"string"},"description":"Filter to a single Ad Set by its LinkedIn numeric ID.","example":"123456"}],"responses":{"200":{"description":"Ad spend summary + per-ad-set monthly breakdown","content":{"application/json":{"example":{"data":{"summary":{"costInUsd":18420.5,"impressions":412000,"clicks":1980,"engagements":3640,"monthCount":3,"adSetCount":4,"startDate":"2026-03-01","endDate":"2026-05-31"},"byAdSet":[{"id":"cmf8a9q2k0001of04w7v3lqz9","linkedInId":"123456","name":"Techcrunch 2025","status":"ACTIVE","format":"Single Image","totals":{"costInUsd":9871.25,"impressions":220000,"clicks":1102,"engagements":1840},"monthly":[{"year":2026,"month":5,"period":"2026-05","costInUsd":4250.75,"impressions":102000,"clicks":540,"engagements":810},{"year":2026,"month":4,"period":"2026-04","costInUsd":3120,"impressions":68000,"clicks":312,"engagements":540},{"year":2026,"month":3,"period":"2026-03","costInUsd":2500.5,"impressions":50000,"clicks":250,"engagements":490}]}]},"pagination":{"page":1,"pageSize":20,"totalCount":4,"totalPages":1},"meta":{"timestamp":"2026-05-13T19:06:51.685Z"}}}}}},"operationId":"getAdSpend"}},"/linkedin-metrics":{"get":{"summary":"Aggregated LinkedIn metrics for a date range","description":"Returns aggregated impressions, clicks, engagements, conversions, and cost for the specified date range, read live from LinkedIn. Optionally filter by a single LinkedIn ad set or campaign ID. Set `includeReach=true` to also get unique member reach and frequency.\n\n**Two response shapes.** With `timeGranularity=ALL` (the default) and no `metrics` parameter, the response is the flat totals object shown below. Setting `timeGranularity` to `DAILY`/`MONTHLY`/`YEARLY` **or** passing `metrics` switches the response to the timeseries shape: `{ startDate, endDate, timeGranularity, fields, rows, totals, truncated }`, where `rows` holds one `{ periodStart, periodEnd, <metric>: number }` object per period and `totals` sums each requested metric over the whole range. `includeReach` only works with the flat shape.","tags":["Ad Sets"],"parameters":[{"$ref":"#/components/parameters/period"},{"name":"timeGranularity","in":"query","schema":{"type":"string","enum":["ALL","DAILY","MONTHLY","YEARLY"],"default":"ALL"},"description":"How to split the range. ALL returns one total (flat response shape). DAILY/MONTHLY/YEARLY return one row per period (timeseries response shape). LinkedIn keeps DAILY data for 6 months only; older ranges fall back to month boundaries."},{"name":"metrics","in":"query","schema":{"type":"string"},"description":"Comma-separated metric fields to fetch (e.g. `impressions,clicks,oneClickLeads`), max 19 per request. Passing this switches the response to the timeseries shape even with `timeGranularity=ALL`. Defaults to impressions, clicks, costInUsd, totalEngagements.","example":"impressions,clicks,costInUsd"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start of date range (inclusive). Format: YYYY-MM-DD. Supply with `endDate` to override `period`. When neither is supplied, the range falls back to `period` (last 30 days by default).","example":"2026-03-31"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End of date range (inclusive). Format: YYYY-MM-DD. Supply with `startDate` to override `period`.","example":"2026-04-06"},{"name":"linkedInCampaignId","in":"query","schema":{"type":"string"},"description":"LinkedIn's own ad set ID (numeric, from urn:li:sponsoredCampaign). When provided, metrics are returned for this ad set only. Cannot be combined with linkedInCampaignGroupId.","example":"123456"},{"name":"linkedInCampaignGroupId","in":"query","schema":{"type":"string"},"description":"LinkedIn's own campaign ID (numeric, from urn:li:sponsoredCampaignGroup). When provided, metrics are returned for this campaign only. Cannot be combined with linkedInCampaignId.","example":"654321"},{"name":"includeReach","in":"query","schema":{"type":"boolean","default":false},"description":"Set to `true` to also return `reach` (unique members who saw an ad) and `frequency` (impressions / reach). Off by default because it costs one extra LinkedIn request; without it both fields come back null. Reach is deduplicated within one response and can NEVER be added up: reach for two ranges, or for several campaigns, does not sum to the reach of the whole, because a member seen twice is still one person. Whenever reach is null, `reachUnavailableReason` says why — the other totals are always returned.","example":"true"}],"responses":{"200":{"description":"Aggregated metrics for the date range","content":{"application/json":{"example":{"data":{"startDate":"2026-03-31","endDate":"2026-04-06","costInUsd":2450.75,"impressions":45200,"clicks":890,"engagements":2100,"conversions":34,"reach":8000,"frequency":5.65},"meta":{"timestamp":"2026-04-08T12:00:00.000Z"}}}}}},"operationId":"getLinkedinMetrics"}},"/ad-library/by-advertiser":{"get":{"summary":"Search the LinkedIn Ad Library by advertiser","description":"Profile a competitor's ads. Searches LinkedIn's public Ad Library by advertiser name (fuzzy match) and returns normalized ad metadata (format, EU/EEA impression ranges + per-country split, first/last impression dates, and which targeting facets were used). LinkedIn's advertiser search is fuzzy, so responses include an `advertisers` list — pick the right `companyId` from it and pass it back to filter to the exact advertiser. Country and date filters are applied over the returned ads. Impression/targeting data is EU/EEA-only (DSA); US-only advertisers return null statistics (treat as unknown, not zero).","tags":["Ad Library"],"parameters":[{"name":"company","in":"query","required":true,"schema":{"type":"string"},"description":"Advertiser name, vanity slug, or a linkedin.com/company/... URL to search for."},{"name":"companyId","in":"query","schema":{"type":"string"},"description":"Canonical LinkedIn company ID to filter results to the exact advertiser (guards against fuzzy-name collisions). Auto-derived when `company` is a /company/<id> URL."},{"name":"countries","in":"query","schema":{"type":"string"},"description":"Comma-separated ISO 3166-1 alpha-2 codes (e.g. \"DE,FR\"). Keeps ads with EU/EEA impressions in any listed country."},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"maximum":100},"description":"Max ads to return after filtering (default: 25, max: 100)."}],"responses":{"200":{"description":"Ad Library search results","content":{"application/json":{"example":{"data":{"ads":[{"adId":"1443175013","adUrl":"https://www.linkedin.com/ad-library/detail/1443175013","isRestricted":false,"type":"SPONSORED_VIDEO","advertiser":{"name":"Userpilot","url":"https://www.linkedin.com/company/27027108","companyId":"27027108","payer":"Userpilot Inc"},"statistics":{"firstImpressionAt":1781795275387,"latestImpressionAt":1783846658226,"totalImpressions":{"from":0,"to":1000},"impressionsByCountry":[{"country":"DE","percentage":4.45}]},"targeting":[{"facet":"Location","isIncluded":true,"isExcluded":false,"includedSegments":["Germany"],"excludedSegments":[]}]}],"advertisers":[{"name":"Userpilot","url":"https://www.linkedin.com/company/27027108","companyId":"27027108","adCount":24}],"total":1617,"scanned":25,"returned":1,"truncated":true},"meta":{"timestamp":"2026-07-12T12:00:00.000Z"}}}}},"400":{"description":"Missing company parameter or no LinkedIn connection","content":{"application/json":{"example":{"error":{"status":400,"code":"BAD_REQUEST","message":"The \"company\" query parameter is required."}}}}}},"operationId":"getAdLibraryByAdvertiser"}},"/ad-library/by-keyword":{"get":{"summary":"Search the LinkedIn Ad Library by keyword","description":"Discover who advertises on a topic. Full-text searches LinkedIn's public Ad Library ad copy and returns the same normalized ad metadata as /ad-library/by-advertiser. Optionally narrow to a single advertiser. Country and date filters are applied over the returned ads. Impression/targeting data is EU/EEA-only (DSA).","tags":["Ad Library"],"parameters":[{"name":"keyword","in":"query","required":true,"schema":{"type":"string"},"description":"Full-text phrase to match in ad copy."},{"name":"advertiser","in":"query","schema":{"type":"string"},"description":"Optional advertiser name to narrow keyword results (ANDed with the keyword)."},{"name":"countries","in":"query","schema":{"type":"string"},"description":"Comma-separated ISO 3166-1 alpha-2 codes (e.g. \"DE,FR\"). Keeps ads with EU/EEA impressions in any listed country."},{"$ref":"#/components/parameters/startDate"},{"$ref":"#/components/parameters/endDate"},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"maximum":100},"description":"Max ads to return after filtering (default: 25, max: 100)."}],"responses":{"200":{"description":"Ad Library search results","content":{"application/json":{"example":{"data":{"ads":[{"adId":"1442648153","adUrl":"https://www.linkedin.com/ad-library/detail/1442648153","isRestricted":false,"type":"SPONSORED_STATUS_UPDATE","advertiser":{"name":"Personio","url":"https://www.linkedin.com/company/10180448","companyId":"10180448","payer":"Personio SE & Co. KG"},"statistics":null,"targeting":[]}],"advertisers":[{"name":"Personio","url":"https://www.linkedin.com/company/10180448","companyId":"10180448","adCount":12}],"total":410199,"scanned":25,"returned":1,"truncated":true},"meta":{"timestamp":"2026-07-12T12:00:00.000Z"}}}}},"400":{"description":"Missing keyword parameter or no LinkedIn connection","content":{"application/json":{"example":{"error":{"status":400,"code":"BAD_REQUEST","message":"The \"keyword\" query parameter is required."}}}}}},"operationId":"getAdLibraryByKeyword"}},"/dashboard":{"get":{"summary":"Get dashboard overview","description":"Returns a high-level overview with top companies, total metrics, and ad spend for the given date range.","tags":["Dashboard"],"parameters":[{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start date (default: 30 days ago)"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"End date (default: today)"}],"responses":{"200":{"description":"Dashboard overview with top companies, metrics, and ad spend","content":{"application/json":{"example":{"data":{"topEngagedCompanies":[{"id":"1337","name":"Pied Piper","city":"San Francisco","country":"United States","website":"https://piedpiper.com","logoUrl":"https://piedpiper.com/assets/images/logo.png","linkedInOrgId":"12345","hubspotCompanyId":"9876543","salesforceId":"0015f00000AbCdEfGh","attioRecordId":"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","impressions":24500,"clicks":312,"engagements":890,"costInUsd":3450.75,"lifetimeEngagementScore":87,"lifetimeAbmStage":null,"abmStage":{"id":"cls2def","name":"Engaged","color":"#4CAF50","displayOrder":2},"intents":[{"id":"int001","name":"Product Demo Interest"}],"abmCampaigns":[{"id":"cm7abm001","name":"Q1 Enterprise ABM"}]}],"linkedInMetrics":{"current":{"impressions":145000,"clicks":2100,"engagements":5800,"costInUsd":28500},"previous":{"impressions":120000,"clicks":1800,"engagements":4900,"costInUsd":24000}}},"meta":{"timestamp":"2026-03-09T12:00:00.000Z"}}}}}},"operationId":"getDashboard"}},"/api/public/v1":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"getSiteApiIndex","tags":["Website"],"summary":"List the public content API endpoints","description":"Machine-readable index of this API: every endpoint, the OpenAPI specification URL, and the other agent entry points on zenabm.com. Start here when you do not yet know which endpoint you need.","security":[],"responses":{"200":{"description":"API index.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteIndex"}}}}}}},"/api/public/v1/docs":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"listSiteDocs","tags":["Website"],"summary":"List ZenABM product documentation pages","description":"Returns every documentation page with its slug, title, description and section. Use it to find the slug for `getSiteDoc`.","security":[],"parameters":[{"name":"section","in":"query","required":false,"description":"Only return pages in this documentation section id, e.g. `abm`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Documentation pages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteDocList"}}}},"404":{"description":"The requested resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"406":{"description":"No acceptable representation for the requested `Accept` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"503":{"description":"An upstream content source is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}}}}},"/api/public/v1/docs/{slug}":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"getSiteDoc","tags":["Website"],"summary":"Get one documentation page as markdown","description":"Returns the markdown source of a single documentation page, plus its metadata. `slug` may contain slashes, e.g. `getting-started/first-steps`.","security":[],"parameters":[{"name":"slug","in":"path","required":true,"description":"Documentation slug, e.g. `abm/stages`.","schema":{"type":"string"},"example":"abm/stages"}],"responses":{"200":{"description":"Documentation page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteDocDetail"}}}},"404":{"description":"The requested resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"406":{"description":"No acceptable representation for the requested `Accept` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"503":{"description":"An upstream content source is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}}}}},"/api/public/v1/posts":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"listSitePosts","tags":["Website"],"summary":"List ZenABM blog posts","description":"Paginated list of published blog posts with plain-text excerpts. Supports full-text search across the blog.","security":[],"parameters":[{"name":"page","in":"query","required":false,"description":"Page number, starting at 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"perPage","in":"query","required":false,"description":"Posts per page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"search","in":"query","required":false,"description":"Full-text search term.","schema":{"type":"string"}}],"responses":{"200":{"description":"Blog posts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitePostList"}}}},"400":{"description":"A query parameter is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"404":{"description":"The requested resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"406":{"description":"No acceptable representation for the requested `Accept` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"503":{"description":"An upstream content source is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}}}}},"/api/public/v1/posts/{slug}":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"getSitePost","tags":["Website"],"summary":"Get one blog post","description":"Returns a published blog post as markdown (`contentMarkdown`, the representation to prefer), HTML and plain text.","security":[],"parameters":[{"name":"slug","in":"path","required":true,"description":"Blog post slug, without `/blog/`.","schema":{"type":"string"},"example":"linkedin-abm-strategy"}],"responses":{"200":{"description":"Blog post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitePostDetail"}}}},"404":{"description":"The requested resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"406":{"description":"No acceptable representation for the requested `Accept` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"503":{"description":"An upstream content source is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}}}}},"/api/public/v1/pages":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"listSitePages","tags":["Website"],"summary":"List every indexable URL on zenabm.com","description":"The same URL inventory the XML sitemap is built from, as JSON. Each entry can also be fetched as markdown by sending `Accept: text/markdown`.","security":[],"parameters":[{"name":"type","in":"query","required":false,"description":"Restrict the inventory to one kind of URL.","schema":{"type":"string","enum":["page","docs","post"]}}],"responses":{"200":{"description":"Indexable URLs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitePageList"}}}},"400":{"description":"A query parameter is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"404":{"description":"The requested resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"406":{"description":"No acceptable representation for the requested `Accept` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"503":{"description":"An upstream content source is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}}}}},"/api/public/v1/search":{"servers":[{"url":"https://zenabm.com","description":"ZenABM website"}],"get":{"operationId":"searchSiteDocs","tags":["Website"],"summary":"Search the documentation, API reference, MCP tools and blog","description":"Keyword search over the same index the docs search palette uses — guides, REST endpoints and MCP tools — plus published blog posts (`kind: post`).","security":[],"parameters":[{"name":"q","in":"query","required":true,"description":"Search query.","schema":{"type":"string","minLength":2},"example":"abm stages"},{"name":"limit","in":"query","required":false,"description":"Maximum number of results.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}}],"responses":{"200":{"description":"Search results.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteSearchResults"}}}},"400":{"description":"`q` is missing or too short.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"404":{"description":"The requested resource does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"406":{"description":"No acceptable representation for the requested `Accept` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}},"503":{"description":"An upstream content source is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteApiError"}}}}}}}},"externalDocs":{"description":"ZenABM API documentation","url":"https://zenabm.com/docs/api"},"tags":[{"name":"Website","description":"Public, unauthenticated endpoints served from zenabm.com."}]}