{
  "tools": [
    {
      "name": "get_plans",
      "title": "Plans and prices",
      "description": "Returns the plans of MyDataHub by Emailmovers, the UK B2B count engine: credit packs, credit rules, licence terms, the bounce warranty and the free trial, in GBP excluding VAT. Use it when the user asks what a list costs or which plan fits; it is free and needs no account. One credit buys one complete UK record at the same price in the app, the API and here. Call get_account for the caller's own balance, or count_audience to size a list. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string"
          },
          "valid_from": {
            "type": "string",
            "format": "date"
          },
          "currency": {
            "type": "string",
            "const": "GBP"
          },
          "vat_treatment": {
            "type": "string"
          },
          "credit_definition": {
            "type": "string"
          },
          "price_scale": {
            "$ref": "#/$defs/PriceScale"
          },
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/Plan"
            }
          },
          "credit_packs": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/CreditPack"
            }
          },
          "credit_rules": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/CreditRule"
            }
          },
          "licence": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/LicenceTerms"
            }
          },
          "guarantee": {
            "type": "object",
            "properties": {
              "current": {
                "$ref": "#/$defs/Warranty"
              },
              "proposed": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/Warranty"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "refunds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "current",
              "proposed",
              "refunds"
            ]
          },
          "trial": {
            "type": "object",
            "properties": {
              "credits": {
                "type": "integer",
                "minimum": 0
              },
              "card_required": {
                "type": "boolean"
              },
              "expires": {
                "type": "boolean"
              }
            },
            "required": [
              "credits",
              "card_required",
              "expires"
            ]
          },
          "promises": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/PricingPromise"
            }
          },
          "meters": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/Meter"
            },
            "description": "What agents and code are metered on, in credits, the same on every surface."
          },
          "action_path": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/ActionPathStep"
            },
            "description": "How to buy: quote_order for a machine quote, create_order with a confirmation, and the top-up page when the balance is short."
          }
        },
        "required": [
          "version",
          "valid_from",
          "currency",
          "vat_treatment",
          "credit_definition",
          "price_scale",
          "plans",
          "credit_packs",
          "credit_rules",
          "licence",
          "guarantee",
          "trial",
          "promises",
          "meters",
          "action_path"
        ],
        "description": "The per-contact scale, plans, credit packs, credit rules, licence terms, the guarantee and the promises, in GBP excluding VAT. The same content as https://mydatahub.emailmovers.com/pricing.json.",
        "$defs": {
          "ActionPathStep": {
            "type": "object",
            "properties": {
              "step": {
                "type": "integer",
                "minimum": 1
              },
              "action": {
                "type": "string",
                "description": "An MCP tool, a REST operation or a URL."
              },
              "rest": {
                "description": "The REST operation, such as POST /v1/quotes.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "description": {
                "type": "string"
              }
            },
            "required": [
              "step",
              "action",
              "rest",
              "description"
            ],
            "description": "One step from a price to a delivered order."
          },
          "CreditPack": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
                "description": "Such as free, pay_as_you_go or plan_12_month."
              },
              "name": {
                "type": "string"
              },
              "kind": {
                "type": "string",
                "const": "pack"
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed",
                  "to_confirm"
                ],
                "description": "confirmed is in force; proposed awaits a decision; to_confirm is a figure still being checked."
              },
              "available_to": {
                "type": "string",
                "enum": [
                  "everyone",
                  "new_customers",
                  "existing_customers"
                ],
                "description": "everyone; new_customers only (the subscription); existing_customers only, who keep their prices (pay as you go and the 12-month plan)."
              },
              "price_gbp_ex_vat": {
                "type": "number",
                "minimum": 0,
                "description": "Pounds sterling excluding VAT, to two decimal places."
              },
              "billing_period": {
                "type": "string",
                "const": "once"
              },
              "contract_months": {
                "description": "The contract's length in months, such as 12; absent when there is none.",
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "annual_price_gbp_ex_vat": {
                "anyOf": [
                  {
                    "type": "number",
                    "minimum": 0,
                    "description": "Pounds sterling excluding VAT, to two decimal places."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "credits": {
                "type": "integer",
                "minimum": 0,
                "description": "Credits per billing period, or once."
              },
              "per_record_gbp": {
                "anyOf": [
                  {
                    "type": "number",
                    "minimum": 0,
                    "description": "Pounds sterling excluding VAT, to two decimal places."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Price per record at full use of the allowance; null for the free plan."
              },
              "rollover_cap_credits": {
                "description": "Subscription credits roll over while subscribed, up to this many; 0 when each period's credits are used or lost.",
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "credits_expire": {
                "type": "boolean"
              },
              "for_whom": {
                "type": "string"
              },
              "notes": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name",
              "kind",
              "status",
              "available_to",
              "price_gbp_ex_vat",
              "billing_period",
              "credits",
              "per_record_gbp",
              "credits_expire",
              "for_whom"
            ],
            "description": "A one-off prepaid bundle of credits, usable on any plan. Credit pack credits never expire and survive cancellation."
          },
          "CreditRule": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
              },
              "label": {
                "type": "string"
              },
              "credits": {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              "unit": {
                "type": "string",
                "enum": [
                  "call",
                  "record",
                  "match"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed",
                  "to_confirm"
                ],
                "description": "confirmed is in force; proposed awaits a decision; to_confirm is a figure still being checked."
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "action",
              "label",
              "credits",
              "unit",
              "status"
            ],
            "description": "What one action costs in credits."
          },
          "LicenceTerms": {
            "type": "object",
            "properties": {
              "licence_type": {
                "type": "string",
                "enum": [
                  "multi_use_12m",
                  "outright"
                ],
                "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed"
                ]
              },
              "credits_per_record": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "permitted_channels": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "email",
                    "telephone",
                    "post"
                  ]
                }
              },
              "reuse_months": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "12 for multi_use_12m; null for outright."
              },
              "resale_prohibited": {
                "type": "boolean"
              },
              "warranty_url": {
                "type": "string",
                "format": "uri"
              },
              "terms_version": {
                "type": "string"
              }
            },
            "required": [
              "licence_type",
              "status",
              "credits_per_record",
              "permitted_channels",
              "reuse_months",
              "resale_prohibited",
              "warranty_url",
              "terms_version"
            ],
            "description": "Licence terms for a plan, as in licence.json."
          },
          "Meter": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
                "description": "What is metered, such as record or enrich_contact."
              },
              "unit": {
                "type": "string",
                "enum": [
                  "record",
                  "match",
                  "call"
                ]
              },
              "credits": {
                "type": "number",
                "minimum": 0,
                "description": "Credits per unit."
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed",
                  "to_confirm"
                ],
                "description": "confirmed is in force; proposed awaits a decision; to_confirm is a figure still being checked."
              }
            },
            "required": [
              "action",
              "unit",
              "credits",
              "status"
            ],
            "description": "One metered action and its price in credits."
          },
          "Plan": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
                "description": "Such as free, pay_as_you_go or plan_12_month."
              },
              "name": {
                "type": "string"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "free",
                  "subscription",
                  "pack"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed",
                  "to_confirm"
                ],
                "description": "confirmed is in force; proposed awaits a decision; to_confirm is a figure still being checked."
              },
              "available_to": {
                "type": "string",
                "enum": [
                  "everyone",
                  "new_customers",
                  "existing_customers"
                ],
                "description": "everyone; new_customers only (the subscription); existing_customers only, who keep their prices (pay as you go and the 12-month plan)."
              },
              "price_gbp_ex_vat": {
                "type": "number",
                "minimum": 0,
                "description": "Pounds sterling excluding VAT, to two decimal places."
              },
              "billing_period": {
                "type": "string",
                "enum": [
                  "once",
                  "month",
                  "year"
                ]
              },
              "contract_months": {
                "description": "The contract's length in months, such as 12; absent when there is none.",
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "annual_price_gbp_ex_vat": {
                "anyOf": [
                  {
                    "type": "number",
                    "minimum": 0,
                    "description": "Pounds sterling excluding VAT, to two decimal places."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "credits": {
                "type": "integer",
                "minimum": 0,
                "description": "Credits per billing period, or once."
              },
              "per_record_gbp": {
                "anyOf": [
                  {
                    "type": "number",
                    "minimum": 0,
                    "description": "Pounds sterling excluding VAT, to two decimal places."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Price per record at full use of the allowance; null for the free plan."
              },
              "rollover_cap_credits": {
                "description": "Subscription credits roll over while subscribed, up to this many; 0 when each period's credits are used or lost.",
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "credits_expire": {
                "type": "boolean"
              },
              "for_whom": {
                "type": "string"
              },
              "notes": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name",
              "kind",
              "status",
              "available_to",
              "price_gbp_ex_vat",
              "billing_period",
              "credits",
              "per_record_gbp",
              "credits_expire",
              "for_whom"
            ],
            "description": "A plan: free, a rolling subscription or a credit pack. No seats on any plan."
          },
          "PriceBand": {
            "type": "object",
            "properties": {
              "from_records": {
                "type": "integer",
                "minimum": 0
              },
              "to_records": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "null for the last band."
              },
              "gbp_per_record": {
                "type": "number",
                "minimum": 0,
                "description": "Pounds sterling excluding VAT, to two decimal places."
              }
            },
            "required": [
              "from_records",
              "to_records",
              "gbp_per_record"
            ],
            "description": "One band of the per-contact scale."
          },
          "PriceScale": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "const": "per_contact_scale"
              },
              "name": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed",
                  "to_confirm"
                ],
                "description": "confirmed is in force; proposed awaits a decision; to_confirm is a figure still being checked."
              },
              "available_to": {
                "type": "string",
                "enum": [
                  "everyone",
                  "new_customers",
                  "existing_customers"
                ],
                "description": "everyone; new_customers only (the subscription); existing_customers only, who keep their prices (pay as you go and the 12-month plan)."
              },
              "minimum_order_records": {
                "type": "integer",
                "minimum": 0
              },
              "rule": {
                "type": "string",
                "description": "How a purchase is priced, in words."
              },
              "bands": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/PriceBand"
                }
              }
            },
            "required": [
              "id",
              "name",
              "status",
              "available_to",
              "minimum_order_records",
              "rule",
              "bands"
            ],
            "description": "The per-contact scale: 1 credit buys 1 record at the rate of the band the purchase falls in. A quote's purchase options compare it with the credit pack and lead with the cheapest."
          },
          "PricingPromise": {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
              },
              "statement": {
                "type": "string"
              },
              "in_practice": {
                "type": "string"
              }
            },
            "required": [
              "key",
              "statement",
              "in_practice"
            ],
            "description": "One of the seven promises on the pricing page."
          },
          "Warranty": {
            "type": "object",
            "properties": {
              "policy": {
                "type": "string",
                "enum": [
                  "replace_over_threshold_hard_bounce",
                  "replace_any_hard_bounce_30d"
                ],
                "description": "replace_over_threshold_hard_bounce is the current policy: records are replaced when hard bounces exceed threshold_percent of an order. replace_any_hard_bounce_30d is proposed and not yet in force. The current policy's id replaced one that named the threshold, a change to this public enum made before v2 went live."
              },
              "threshold_percent": {
                "description": "replace_over_threshold_hard_bounce only, and required there: the share of an order, in percent, that hard bounces must exceed before records are replaced. It is the threshold the document was issued under.",
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "policy",
              "url"
            ],
            "description": "The bounce warranty that covers delivered records, with the threshold it was issued under.",
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "policy": {
                      "const": "replace_over_threshold_hard_bounce"
                    }
                  },
                  "required": [
                    "policy"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "threshold_percent": true
                  },
                  "required": [
                    "threshold_percent"
                  ]
                },
                "else": {
                  "type": "object",
                  "not": {
                    "type": "object",
                    "properties": {
                      "threshold_percent": true
                    },
                    "required": [
                      "threshold_percent"
                    ]
                  }
                }
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_account",
      "title": "Account and balance",
      "description": "Returns the organisation's credit balance by source, plan, per-action prices and rate limit, and for an agent key its monthly budget and per-order cap. Use it before quoting a large order, or when a spend is refused, to see what remains. Free; it needs a token with account:read. Top-ups happen on mydatahub.emailmovers.com, never inside a tool. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "organisation": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an organisation id: org_ followed by a 26 character ULID in upper case Crockford base32, such as org_01JA0Q2V7XN3M9R6T1Y5W8ZAK8.",
                "examples": [
                  "org_01JA0Q2V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "name": {
                "type": "string"
              },
              "business_details": {
                "$ref": "#/$defs/BusinessDetails"
              }
            },
            "required": [
              "id",
              "name",
              "business_details"
            ]
          },
          "user": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                    "description": "Format: a user id: usr_ followed by a 26 character ULID in upper case Crockford base32, such as usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8.",
                    "examples": [
                      "usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8"
                    ]
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "name"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The signed-in person; null when the caller is an API key."
          },
          "mode": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ],
            "description": "live keys (mdh_live_) spend real credits; test keys (mdh_test_) return synthetic data and never charge."
          },
          "plan": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
              },
              "name": {
                "type": "string"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "free",
                  "subscription",
                  "pack"
                ]
              },
              "renews_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "cancel_at_period_end": {
                "type": "boolean"
              }
            },
            "required": [
              "id",
              "name",
              "kind",
              "renews_at",
              "cancel_at_period_end"
            ]
          },
          "balance": {
            "type": "object",
            "properties": {
              "credits": {
                "type": "number",
                "description": "Credits available to spend now."
              },
              "pack_credits": {
                "type": "number",
                "description": "From credit packs: never expire."
              },
              "subscription_credits": {
                "type": "number",
                "description": "From the plan: roll over while subscribed, up to the cap."
              },
              "rollover_cap": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "low_threshold": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The credits.low webhook fires when the balance crosses this."
              }
            },
            "required": [
              "credits",
              "pack_credits",
              "subscription_credits",
              "rollover_cap",
              "low_threshold"
            ],
            "description": "Credits by source."
          },
          "prices": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/CreditRule"
            },
            "description": "What each action costs in credits."
          },
          "gbp_per_credit": {
            "type": "number",
            "minimum": 0,
            "description": "Your plan's price per credit, excluding VAT."
          },
          "rate_limit": {
            "$ref": "#/$defs/RateLimit"
          },
          "key": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                    "description": "Format: an API key id: key_ followed by a 26 character ULID in upper case Crockford base32, such as key_01JB3Z4Q2V7XN3M9R6T1Y5W8ZA.",
                    "examples": [
                      "key_01JB3Z4Q2V7XN3M9R6T1Y5W8ZA"
                    ]
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "agent"
                    ]
                  },
                  "budget": {
                    "anyOf": [
                      {
                        "$ref": "#/$defs/Budget"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "per_order_max_credits": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 0
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "expires_at": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date-time"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "id",
                  "kind",
                  "budget",
                  "per_order_max_credits",
                  "expires_at"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The calling key and, for an agent key, its budget; null for a person."
          },
          "account_manager": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "calendar_url": {
                    "type": "string",
                    "format": "uri"
                  }
                },
                "required": [
                  "name",
                  "calendar_url"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The named person behind Talk to us."
          },
          "agreements": {
            "type": "object",
            "properties": {
              "dlsa": {
                "$ref": "#/$defs/Agreement"
              },
              "dpa": {
                "$ref": "#/$defs/Agreement"
              }
            },
            "required": [
              "dlsa",
              "dpa"
            ],
            "description": "The Data Licence and Sharing Agreement (accepted with every order, or with an agent key that orders on its own) and the Article 28 DPA (accepted with the first suppression list)."
          }
        },
        "required": [
          "organisation",
          "user",
          "mode",
          "plan",
          "balance",
          "prices",
          "gbp_per_credit",
          "rate_limit",
          "key",
          "account_manager",
          "agreements"
        ],
        "description": "Balance, plan, per-action prices, rate limit and the calling key's budget.",
        "$defs": {
          "Agreement": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string",
                "description": "The version in force: draft until the text is approved."
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "accepted": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "version": {
                        "type": "string"
                      },
                      "accepted_at": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "accepted_by": {
                        "type": "string",
                        "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                        "description": "Format: a user id: usr_ followed by a 26 character ULID in upper case Crockford base32, such as usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8.",
                        "examples": [
                          "usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8"
                        ]
                      }
                    },
                    "required": [
                      "version",
                      "accepted_at",
                      "accepted_by"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The organisation's acceptance of the latest version it accepted: which version, when and by whom, first time for that version. null until one is accepted. When version (the one in force) differs, the agreement is accepted again."
              }
            },
            "required": [
              "name",
              "version",
              "url",
              "accepted"
            ]
          },
          "Budget": {
            "type": "object",
            "properties": {
              "monthly_credits": {
                "type": "integer",
                "minimum": 0
              },
              "spent": {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              "remaining": {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              "resets_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "monthly_credits",
              "spent",
              "remaining",
              "resets_at"
            ],
            "description": "An agent key's monthly budget in credits."
          },
          "BusinessDetails": {
            "type": "object",
            "properties": {
              "confirmed_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When a person confirmed the business name and that it is a UK business; null until then."
              },
              "required_before_order": {
                "type": "boolean",
                "description": "true: an order or an enrichment is refused with business-details-required until a person who owns the account confirms them with PATCH /v1/account. Only an organisation made by self-serve sign-up needs them, and whether it does is set when it is made."
              },
              "name_editable": {
                "type": "boolean",
                "description": "true for an organisation made by self-serve sign-up, whose business name PATCH /v1/account sets. false for one Emailmovers set up, which keeps the name staff gave it and needs no business details before an order."
              }
            },
            "required": [
              "confirmed_at",
              "required_before_order",
              "name_editable"
            ],
            "description": "Whether the business name and a UK business confirmation are on record, which a self-serve account needs before its first order."
          },
          "CreditRule": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
              },
              "label": {
                "type": "string"
              },
              "credits": {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              "unit": {
                "type": "string",
                "enum": [
                  "call",
                  "record",
                  "match"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed",
                  "to_confirm"
                ],
                "description": "confirmed is in force; proposed awaits a decision; to_confirm is a figure still being checked."
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "action",
              "label",
              "credits",
              "unit",
              "status"
            ],
            "description": "What one action costs in credits."
          },
          "RateLimit": {
            "type": "object",
            "properties": {
              "tier": {
                "type": "string",
                "enum": [
                  "anonymous",
                  "free",
                  "paid"
                ]
              },
              "counts_per_minute": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "counts_per_hour": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "counts_per_day": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "remaining": {
                "type": "integer",
                "minimum": 0
              },
              "resets_at": {
                "type": "string",
                "format": "date-time"
              },
              "status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "to_confirm"
                ]
              }
            },
            "required": [
              "tier",
              "counts_per_minute",
              "counts_per_hour",
              "counts_per_day",
              "remaining",
              "resets_at",
              "status"
            ],
            "description": "The caller's count limits and what remains in the window."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_filters",
      "title": "Filter catalogue",
      "description": "Lists every filterable field of the audience definition (mydatahub.audience/1) with its group, type, operators, value count and default, plus the datasets. Use it first to learn field names such as company.employee_band or site.town before building an audience by hand. Free and needs no account; the same catalogue is the mydatahub://catalogue resource. Call search_filter_values to find the codes for one field. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          }
        },
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/FilterDimension"
            }
          },
          "operators": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/OperatorInfo"
            }
          },
          "datasets": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/Dataset"
            }
          }
        },
        "required": [
          "dataset",
          "dataset_version",
          "fields",
          "operators",
          "datasets"
        ],
        "description": "Every filterable field with its type, operators and value count, plus the datasets.",
        "$defs": {
          "Dataset": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "name": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "live",
                  "planned",
                  "through_our_team"
                ],
                "description": "live is served; planned is not yet served; through_our_team is sold through the bespoke service only."
              },
              "owner": {
                "type": "string"
              },
              "source": {
                "type": "string"
              },
              "licence": {
                "type": "string"
              },
              "refresh": {
                "type": "string"
              },
              "residency": {
                "type": "string"
              },
              "regulator": {
                "type": "string"
              },
              "warranty": {
                "type": "string"
              },
              "credits_per_record": {
                "type": "number",
                "minimum": 0,
                "description": "1 for owned UK and Irish data."
              },
              "credits_status": {
                "type": "string",
                "enum": [
                  "confirmed",
                  "proposed"
                ]
              },
              "current_version": {
                "anyOf": [
                  {
                    "type": "string",
                    "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                    "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                    "examples": [
                      "2026-W39"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "versions_available": {
                "type": "integer",
                "minimum": 0,
                "description": "Immutable weekly versions still queryable (the last 52)."
              }
            },
            "required": [
              "id",
              "name",
              "status",
              "owner",
              "source",
              "licence",
              "refresh",
              "residency",
              "regulator",
              "warranty",
              "credits_per_record",
              "credits_status",
              "current_version",
              "versions_available"
            ],
            "description": "A dataset with owner, source, licence, refresh, residency, regulator, warranty and credits per record."
          },
          "FilterDimension": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "description": "The field name, also the dimension slug."
              },
              "group": {
                "type": "string",
                "enum": [
                  "company",
                  "site",
                  "contact",
                  "email",
                  "phone",
                  "signal"
                ]
              },
              "type": {
                "type": "string",
                "enum": [
                  "enum",
                  "text",
                  "number",
                  "date",
                  "geo",
                  "hashed_list",
                  "boolean",
                  "band"
                ]
              },
              "label": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "operators": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "in",
                    "between",
                    "gte",
                    "lte",
                    "matches",
                    "within_radius",
                    "in_list",
                    "since"
                  ]
                }
              },
              "facet": {
                "type": "boolean",
                "description": "Usable in breakdown_by."
              },
              "value_count": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Distinct values in this dataset version; null for free text and numbers."
              },
              "default": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "examples": {
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ]
                }
              },
              "values_url": {
                "description": "Where to search the values, or null when the field has none to list.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "field",
              "group",
              "type",
              "label",
              "description",
              "operators",
              "facet",
              "value_count",
              "default",
              "examples",
              "values_url"
            ],
            "description": "One filterable field."
          },
          "OperatorInfo": {
            "type": "object",
            "properties": {
              "op": {
                "type": "string",
                "enum": [
                  "in",
                  "between",
                  "gte",
                  "lte",
                  "matches",
                  "within_radius",
                  "in_list",
                  "since",
                  "all",
                  "any",
                  "not"
                ]
              },
              "applies_to": {
                "type": "string"
              },
              "description": {
                "type": "string"
              }
            },
            "required": [
              "op",
              "applies_to",
              "description"
            ],
            "description": "An operator of the audience definition."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "search_filter_values",
      "title": "Search filter values",
      "description": "Searches the values of one field by text, such as towns matching leeds, and returns each code with its contact and company counts plus did_you_mean for near misses. Use the returned code in a filter rather than guessing one. Free and needs no account; results are paged with next_cursor. Call count_audience once the filters are chosen. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "dimension": {
            "type": "string",
            "pattern": "^(company|site|contact|email|phone|signal)\\.[a-z0-9_]+$",
            "description": "A field name from list_filters, such as site.town or company.sic_2007."
          },
          "q": {
            "description": "Text to search for.",
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          },
          "limit": {
            "description": "Items per page, 1 to 100. Default 25.",
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "An opaque cursor from next_cursor. Pass it back unchanged."
          }
        },
        "required": [
          "dimension"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string"
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/FilterValue"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 512,
                "description": "An opaque cursor from next_cursor. Pass it back unchanged."
              },
              {
                "type": "null"
              }
            ]
          },
          "did_you_mean": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "disclosure": {
            "$ref": "#/$defs/Disclosure"
          }
        },
        "required": [
          "field",
          "dataset_version",
          "data",
          "has_more",
          "next_cursor",
          "disclosure"
        ],
        "description": "A page of values in one field, best match first when q is given.",
        "$defs": {
          "CellCount": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "const": "under 10"
              },
              {
                "type": "string",
                "const": "suppressed"
              }
            ],
            "description": "A whole number; \"under 10\" when disclosure control withholds a small cell; or \"suppressed\" when secondary suppression hides a cell of 10 or more in a cross-tab or breakdown, so totals cannot be differenced. Anonymous and trial callers see cells rounded to the nearest 5.",
            "examples": [
              4120,
              "under 10",
              "suppressed"
            ]
          },
          "Disclosure": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string",
                "enum": [
                  "exact",
                  "rounded"
                ],
                "description": "exact for authenticated paid callers; rounded for anonymous and trial callers, whose counts under 100 and every cell are rounded to the nearest 5."
              },
              "rounded_to": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "5 when numbers are rounded; null when they are exact."
              },
              "secondary_suppression": {
                "type": "boolean",
                "description": "True when cross-tab or breakdown cells of 10 or more were hidden as \"suppressed\" so totals cannot be differenced."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "level",
              "rounded_to",
              "secondary_suppression",
              "notes"
            ],
            "description": "Whether these numbers are exact or protected: \"under 10\" cells, rounding to 5 and secondary suppression for anonymous and trial callers."
          },
          "FilterValue": {
            "type": "object",
            "properties": {
              "code": {
                "description": "The value to use in a filter.",
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "number"
                  },
                  {
                    "type": "boolean"
                  }
                ]
              },
              "label": {
                "type": "string"
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              },
              "companies": {
                "$ref": "#/$defs/CellCount"
              },
              "parent": {
                "description": "The parent code for hierarchical fields, such as SIC division 62 under J.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "code",
              "label",
              "contacts",
              "companies"
            ],
            "description": "One value of a field, with its counts."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "expand_job_titles",
      "title": "Expand job titles",
      "description": "Expands title keywords into every matching title (plurals, department synonyms, ampersands, abbreviations such as CEO), each with a count, or shows what a bundle such as sdm resolves to. Use it before counting so the user can see and edit which titles a keyword covers; nothing is expanded silently. Free and needs no account. Put the returned filter into the audience, then call count_audience. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "terms": {
            "description": "Title keywords to expand, such as marketing manager.",
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "bundle": {
            "description": "A title bundle to show: sdm, manager_and_above or owner_managed.",
            "type": "string",
            "enum": [
              "sdm",
              "manager_and_above",
              "owner_managed"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "contains",
              "starts_with",
              "exact"
            ],
            "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
          },
          "expand": {
            "description": "Expansion sets to apply, each once. Left out, the four default sets apply.",
            "uniqueItems": true,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "plural_singular",
                "department_synonyms",
                "ampersand_and",
                "abbreviations",
                "permutations"
              ]
            }
          },
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          }
        },
        "additionalProperties": false,
        "description": "Keywords or a bundle to expand into an editable title list: exactly one of terms or bundle.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "terms": true
            },
            "required": [
              "terms"
            ]
          },
          {
            "type": "object",
            "properties": {
              "bundle": true
            },
            "required": [
              "bundle"
            ]
          }
        ]
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "contains",
              "starts_with",
              "exact"
            ],
            "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
          },
          "expand": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "plural_singular",
                "department_synonyms",
                "ampersand_and",
                "abbreviations",
                "permutations"
              ]
            }
          },
          "terms": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/ExpandedTerm"
            }
          },
          "total_contacts": {
            "$ref": "#/$defs/CellCount"
          },
          "bundle": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "enum": [
                      "sdm",
                      "manager_and_above",
                      "owner_managed"
                    ]
                  },
                  "label": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "confirmed",
                      "proposed",
                      "to_confirm"
                    ]
                  },
                  "resolves_to": {
                    "$ref": "#/$defs/WhereNode"
                  }
                },
                "required": [
                  "id",
                  "label",
                  "status",
                  "resolves_to"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "filter": {
            "anyOf": [
              {
                "$ref": "#/$defs/Filter"
              },
              {
                "type": "null"
              }
            ],
            "description": "A ready matches filter for the terms, or null for a bundle."
          },
          "disclosure": {
            "$ref": "#/$defs/Disclosure"
          }
        },
        "required": [
          "dataset_version",
          "mode",
          "expand",
          "terms",
          "total_contacts",
          "bundle",
          "filter",
          "disclosure"
        ],
        "description": "Every expanded title with a count, or what a bundle resolves to. Nothing is resolved silently.",
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "CellCount": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "const": "under 10"
              },
              {
                "type": "string",
                "const": "suppressed"
              }
            ],
            "description": "A whole number; \"under 10\" when disclosure control withholds a small cell; or \"suppressed\" when secondary suppression hides a cell of 10 or more in a cross-tab or breakdown, so totals cannot be differenced. Anonymous and trial callers see cells rounded to the nearest 5.",
            "examples": [
              4120,
              "under 10",
              "suppressed"
            ]
          },
          "Disclosure": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string",
                "enum": [
                  "exact",
                  "rounded"
                ],
                "description": "exact for authenticated paid callers; rounded for anonymous and trial callers, whose counts under 100 and every cell are rounded to the nearest 5."
              },
              "rounded_to": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "5 when numbers are rounded; null when they are exact."
              },
              "secondary_suppression": {
                "type": "boolean",
                "description": "True when cross-tab or breakdown cells of 10 or more were hidden as \"suppressed\" so totals cannot be differenced."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "level",
              "rounded_to",
              "secondary_suppression",
              "notes"
            ],
            "description": "Whether these numbers are exact or protected: \"under 10\" cells, rounding to 5 and secondary suppression for anonymous and trial callers."
          },
          "ExpandedTerm": {
            "type": "object",
            "properties": {
              "term": {
                "type": "string",
                "description": "A matched title."
              },
              "from_term": {
                "type": "string",
                "description": "The input term it came from."
              },
              "expansion_set": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "plural_singular",
                      "department_synonyms",
                      "ampersand_and",
                      "abbreviations",
                      "permutations"
                    ]
                  },
                  {
                    "type": "string",
                    "const": "input"
                  }
                ],
                "description": "The expansion set that produced it, or input for the term itself."
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              },
              "excluded": {
                "description": "True when exclude_terms removed it from the audience.",
                "type": "boolean"
              }
            },
            "required": [
              "term",
              "from_term",
              "expansion_set",
              "contacts"
            ],
            "description": "One title a matches filter covers, with its count."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "resolve_location",
      "title": "Resolve a location",
      "description": "Turns free text such as 20 miles of Leeds, Yorkshire or LS1 into region, county, town, postcode or radius filters, each with a count and a ready filter. Ambiguous places come back as candidates with a question, so ask the user which they meant rather than choosing. Free and needs no account, though a radius under 5 miles needs an account. Add the chosen filter to the audience, then call count_audience. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Free text such as \"20 miles of Leeds\", \"Yorkshire\" or \"SW1\"."
          },
          "radius_miles": {
            "type": "number",
            "minimum": 1,
            "maximum": 100
          },
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false,
        "description": "A place to resolve into geography filters."
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string"
          },
          "ambiguous": {
            "type": "boolean",
            "description": "True when more than one candidate fits; ask the person which they meant."
          },
          "question": {
            "type": [
              "string",
              "null"
            ]
          },
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/LocationCandidate"
            }
          },
          "disclosure": {
            "$ref": "#/$defs/Disclosure"
          }
        },
        "required": [
          "text",
          "ambiguous",
          "question",
          "candidates",
          "disclosure"
        ],
        "description": "Candidates for a place. Ambiguous names come back as candidates, never a silent choice.",
        "$defs": {
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "CellCount": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "const": "under 10"
              },
              {
                "type": "string",
                "const": "suppressed"
              }
            ],
            "description": "A whole number; \"under 10\" when disclosure control withholds a small cell; or \"suppressed\" when secondary suppression hides a cell of 10 or more in a cross-tab or breakdown, so totals cannot be differenced. Anonymous and trial callers see cells rounded to the nearest 5.",
            "examples": [
              4120,
              "under 10",
              "suppressed"
            ]
          },
          "Disclosure": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string",
                "enum": [
                  "exact",
                  "rounded"
                ],
                "description": "exact for authenticated paid callers; rounded for anonymous and trial callers, whose counts under 100 and every cell are rounded to the nearest 5."
              },
              "rounded_to": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "5 when numbers are rounded; null when they are exact."
              },
              "secondary_suppression": {
                "type": "boolean",
                "description": "True when cross-tab or breakdown cells of 10 or more were hidden as \"suppressed\" so totals cannot be differenced."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "level",
              "rounded_to",
              "secondary_suppression",
              "notes"
            ],
            "description": "Whether these numbers are exact or protected: \"under 10\" cells, rounding to 5 and secondary suppression for anonymous and trial callers."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LocationCandidate": {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "region",
                  "county",
                  "town",
                  "local_authority",
                  "postcode_area",
                  "postcode_district",
                  "postcode_sector",
                  "postcode_unit",
                  "geography_set",
                  "radius"
                ]
              },
              "code": {
                "type": "string",
                "description": "The filter code, or the ONS code for a centre."
              },
              "label": {
                "type": "string"
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              },
              "centre": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "lat": {
                        "type": "number"
                      },
                      "lon": {
                        "type": "number"
                      }
                    },
                    "required": [
                      "lat",
                      "lon"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "filter": {
                "description": "A ready filter for this candidate.",
                "$ref": "#/$defs/Filter"
              }
            },
            "required": [
              "kind",
              "code",
              "label",
              "contacts",
              "centre",
              "filter"
            ],
            "description": "One reading of the text."
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "compile_audience",
      "title": "Compile a brief",
      "description": "Compiles a plain English brief, such as 300 finance directors at law firms in Manchester, into an audience definition with a one-sentence readback, editable chips and any questions to answer first. Use it first for a request in words, read the readback to the user and settle the questions before counting. Words that match no filter come back in unrecognised, never guessed. Free and needs no account; pass the audience to count_audience next. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "brief": {
            "type": "string",
            "minLength": 3,
            "maxLength": 2000,
            "description": "A plain English brief, such as \"300 finance directors at law firms in Manchester\"."
          },
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          }
        },
        "required": [
          "brief"
        ],
        "additionalProperties": false,
        "description": "A brief to compile into an audience definition."
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "audience": {
            "$ref": "#/$defs/Audience"
          },
          "readback": {
            "type": "string",
            "description": "The audience in one sentence, to confirm with the person."
          },
          "chips": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/Chip"
            }
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/BriefQuestion"
            }
          },
          "unrecognised": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Words of the brief that matched no filter, shown rather than guessed."
          },
          "quantity": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "description": "A quantity named in the brief, such as 300, for quote_order limit."
          }
        },
        "required": [
          "audience",
          "readback",
          "chips",
          "questions",
          "unrecognised",
          "quantity"
        ],
        "description": "An audience definition from a brief, with its chips and any questions.",
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BriefQuestion": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "text": {
                "type": "string"
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "filter": {
                      "$ref": "#/$defs/Filter"
                    }
                  },
                  "required": [
                    "label",
                    "filter"
                  ]
                }
              }
            },
            "required": [
              "id",
              "text",
              "options"
            ],
            "description": "An ambiguity to answer before counting."
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "Chip": {
            "type": "object",
            "properties": {
              "label": {
                "type": "string",
                "description": "What the chip reads, such as Within 20 miles of Leeds."
              },
              "pointer": {
                "type": "string",
                "description": "JSON pointer to the filter inside audience."
              },
              "from_brief": {
                "type": "string",
                "description": "The words of the brief it came from."
              }
            },
            "required": [
              "label",
              "pointer",
              "from_brief"
            ],
            "description": "One visible, editable filter compiled from the brief."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "count_audience",
      "title": "Count an audience",
      "description": "Counts UK contacts and companies matching an audience, inline or a saved aud_ id, and returns Total, New to you and Emailable, up to three breakdowns, quality, the compliance summary, a price estimate and a count id. Use it whenever a filter changes, and before preview_records or quote_order, which both take the count id. Free and needs no account; anonymous and trial callers see counts under 100 and breakdown cells rounded to the nearest 5 (disclosure says which), and exact small counts need a paid plan. It returns no contact details, and over MCP a cross-tab holds at most 200 cells (truncated true; GET /v1/counts/{id} has the rest). Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "audience": {
            "$ref": "#/$defs/AudienceRef"
          },
          "level": {
            "default": "contact",
            "type": "string",
            "enum": [
              "contact",
              "company"
            ],
            "description": "contact (the default) or company. Contacts and companies come back together either way."
          },
          "breakdown_by": {
            "maxItems": 3,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "company.sic_2007",
                "company.business_class",
                "company.employee_band",
                "company.turnover_band",
                "company.fleet_band",
                "company.type",
                "company.status",
                "company.subscriber_class",
                "site.region",
                "site.county",
                "site.town",
                "site.postcode",
                "contact.title_family",
                "contact.job_function",
                "contact.job_level_rank",
                "email.exists",
                "email.type",
                "phone.exists",
                "phone.tps_ctps_status"
              ],
              "description": "A field a count can be broken down by."
            },
            "description": "Up to three fields to break the count down by, each once, such as industry by seniority by region. Returns the top 50 cells per field plus other.",
            "uniqueItems": true
          }
        },
        "required": [
          "audience"
        ],
        "additionalProperties": false,
        "description": "An audience, a level and up to three breakdown fields. Free, and needs no account.",
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "AudienceRef": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^aud_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an audience id: aud_ followed by a 26 character ULID in upper case Crockford base32, such as aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA"
                ]
              },
              {
                "$ref": "#/$defs/Audience"
              }
            ],
            "description": "An audience definition (mydatahub.audience/1) inline, or the aud_ id of a saved audience."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^cnt_[A-Z2-7]{20}$",
            "description": "Format: a count id: cnt_ followed by 20 base32 characters (A to Z and 2 to 7), such as cnt_7K2PQ4MAXN3R6TBY5WDZ.",
            "examples": [
              "cnt_7K2PQ4MAXN3R6TBY5WDZ"
            ]
          },
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "engine_rules_version": {
            "type": "string",
            "minLength": 1,
            "description": "The engine rules (title expansion, defaults, geography sets) the count ran under; part of what the count id hashes, such as 2026.09.1."
          },
          "as_of": {
            "description": "The date the dataset version was built, for as-of statements.",
            "type": "string",
            "format": "date"
          },
          "level": {
            "type": "string",
            "enum": [
              "contact",
              "company"
            ],
            "description": "contact (the default) or company. Contacts and companies come back together either way."
          },
          "credits_per_record": {
            "type": "number",
            "minimum": 0,
            "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
          },
          "contacts": {
            "type": "integer",
            "minimum": 0,
            "description": "Total: every matching contact."
          },
          "companies": {
            "type": "integer",
            "minimum": 0
          },
          "emailable": {
            "type": "integer",
            "minimum": 0,
            "description": "A named email scoring 70 or more at a corporate subscriber."
          },
          "new_to_you": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "description": "Excludes your earlier orders and CRM overlap; null when signed out."
          },
          "premium": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "description": "Premium: the contacts of all_records that are premium records (contact.premium true). At launch, a premium record is in the premium export of a stated date. Null when the dataset version carries no premium data, or withheld when the premium records are at a single company and the caller has no account; premium_note says which."
          },
          "all_records": {
            "type": "integer",
            "minimum": 0,
            "description": "All records: every matching contact with the audience's top-level premium filters taken out (a premium filter inside any or not stays), so the premium figure always has the full figure beside it. The same as contacts when the audience has no premium filter."
          },
          "premium_note": {
            "type": "string",
            "minLength": 1,
            "description": "What premium means on this dataset version, or why premium is null: no premium data on the version, or withheld because the premium records are at a single company."
          },
          "views": {
            "$ref": "#/$defs/CountViews"
          },
          "quality": {
            "$ref": "#/$defs/Quality"
          },
          "breakdowns": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/Breakdown"
            }
          },
          "crosstab": {
            "anyOf": [
              {
                "$ref": "#/$defs/Crosstab"
              },
              {
                "type": "null"
              }
            ]
          },
          "compliance_summary": {
            "$ref": "#/$defs/ComplianceSummary"
          },
          "defaults": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/CountDefault"
            },
            "description": "Every default with the number behind its toggle: dissolved and insolvent, generic emails, individual subscribers, TPS and CTPS registered."
          },
          "estimate": {
            "$ref": "#/$defs/PriceEstimate"
          },
          "expanded_terms": {
            "description": "Every title a matches filter covered, with a count per term.",
            "type": "array",
            "items": {
              "$ref": "#/$defs/ExpandedTerm"
            }
          },
          "disclosure": {
            "$ref": "#/$defs/Disclosure"
          },
          "effective_audience": {
            "description": "The definition after defaults and bundles, as hashed into the id.",
            "$ref": "#/$defs/Audience"
          },
          "plan": {
            "$ref": "#/$defs/CompiledPlan"
          },
          "current": {
            "description": "On a replay: the same audience on the current dataset version.",
            "anyOf": [
              {
                "$ref": "#/$defs/CurrentCount"
              },
              {
                "type": "null"
              }
            ]
          },
          "removed_since": {
            "description": "On a replay: records since removed by objections and erasure.",
            "type": "integer",
            "minimum": 0
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "The id replays until then (12 months)."
          }
        },
        "required": [
          "id",
          "dataset",
          "dataset_version",
          "engine_rules_version",
          "credits_per_record",
          "contacts",
          "companies",
          "emailable",
          "new_to_you",
          "premium",
          "all_records",
          "premium_note",
          "quality",
          "breakdowns",
          "compliance_summary",
          "defaults",
          "estimate",
          "disclosure",
          "expires_at"
        ],
        "description": "Total, New to you and Emailable, the premium figure beside all records, with companies, breakdowns, quality, the compliance summary, the defaults behind the toggles, disclosure and a price estimate. The id is content addressed, so the same definition from chips, REST or MCP gives the same id.",
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "Breakdown": {
            "type": "object",
            "properties": {
              "by": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ],
                "description": "A field a count can be broken down by."
              },
              "cells": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/BreakdownCell"
                }
              },
              "other": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/OtherBucket"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "by",
              "cells"
            ],
            "description": "A count split by one field: the top 50 cells plus other. Cells under 10 read \"under 10\"."
          },
          "BreakdownCell": {
            "type": "object",
            "properties": {
              "value": {
                "description": "The cell's code as shown, such as director or C. To add the cell to the audience as a filter, use filter_value when present, otherwise value.",
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "number"
                  },
                  {
                    "type": "boolean"
                  }
                ]
              },
              "filter_value": {
                "description": "The value a filter takes when it differs from value, such as 6 for director on contact.job_level_rank (filters take ranks).",
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "number"
                  },
                  {
                    "type": "boolean"
                  }
                ]
              },
              "label": {
                "type": "string"
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              },
              "companies": {
                "$ref": "#/$defs/CellCount"
              }
            },
            "required": [
              "value",
              "contacts"
            ],
            "description": "One cell of a breakdown."
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "CellCount": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "const": "under 10"
              },
              {
                "type": "string",
                "const": "suppressed"
              }
            ],
            "description": "A whole number; \"under 10\" when disclosure control withholds a small cell; or \"suppressed\" when secondary suppression hides a cell of 10 or more in a cross-tab or breakdown, so totals cannot be differenced. Anonymous and trial callers see cells rounded to the nearest 5.",
            "examples": [
              4120,
              "under 10",
              "suppressed"
            ]
          },
          "CompiledPlan": {
            "type": "object",
            "properties": {
              "engine_rules_version": {
                "type": "string"
              },
              "defaults_applied": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
                },
                "description": "Defaults the server filled, such as active_companies and named_emails."
              },
              "expanded_terms": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/ExpandedTerm"
                }
              },
              "centres": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/ResolvedCentre"
                }
              },
              "sic_codes": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "SIC codes behind any business class filter."
              },
              "geography_sets": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "suppressions": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/SuppressionChecksum"
                }
              }
            },
            "required": [
              "engine_rules_version",
              "defaults_applied",
              "expanded_terms",
              "centres",
              "sic_codes",
              "geography_sets",
              "suppressions"
            ],
            "description": "How the definition was run: expanded terms, resolved centres, SIC codes behind a business class and suppression checksums."
          },
          "ComplianceSummary": {
            "type": "object",
            "properties": {
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ]
              },
              "corporate_subscriber": {
                "type": "integer",
                "minimum": 0,
                "description": "Records at corporate subscribers."
              },
              "individual_subscriber_excluded": {
                "type": "integer",
                "minimum": 0,
                "description": "Sole traders and ordinary partnerships left out of an email audience."
              },
              "tps_ctps_excluded": {
                "type": "integer",
                "minimum": 0,
                "description": "TPS or CTPS registered numbers left out when phone is requested."
              },
              "article14_notified": {
                "type": "integer",
                "minimum": 0
              },
              "article14_pending_within_window": {
                "type": "integer",
                "minimum": 0,
                "description": "Records inside the one month Article 14 window, not yet notified."
              },
              "suppressed_removed": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/SuppressionRemoval"
                }
              },
              "jurisdiction_excluded": {
                "description": "Partner datasets only: records the jurisdiction policy table left out (Germany, Canada and California by policy), reported like suppression removals.",
                "type": "array",
                "items": {
                  "$ref": "#/$defs/JurisdictionExclusion"
                }
              }
            },
            "required": [
              "lawful_basis",
              "corporate_subscriber",
              "individual_subscriber_excluded",
              "tps_ctps_excluded",
              "article14_notified",
              "article14_pending_within_window",
              "suppressed_removed"
            ],
            "description": "Beside every count, so a person or an agent can reason before spending. Individual subscribers and TPS and CTPS registered numbers are excluded by default, as visible toggles; numbers not screened are kept."
          },
          "CountDefault": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "enum": [
                  "active_companies",
                  "named_emails",
                  "corporate_subscribers",
                  "no_registered_phones"
                ],
                "description": "active_companies, named_emails, corporate_subscribers or no_registered_phones."
              },
              "applied": {
                "type": "boolean",
                "description": "False when the audience filters the same field itself, or turned it off."
              },
              "views": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "total",
                    "new_to_you",
                    "emailable"
                  ]
                },
                "description": "The headline views the default shapes; named emails and corporate subscribers shape Emailable only."
              },
              "removed": {
                "description": "What the toggle shows: the dissolved and insolvent count, the generic (info@, sales@) count, the individual subscriber count or the TPS and CTPS registered count.",
                "$ref": "#/$defs/CellCount"
              },
              "screened_at": {
                "description": "no_registered_phones only: the version's TPS and CTPS screen date.",
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "applied",
              "views",
              "removed"
            ],
            "description": "A default the count applied, and the records it removed, for its toggle."
          },
          "CountView": {
            "type": "object",
            "properties": {
              "contacts": {
                "type": "integer",
                "minimum": 0
              },
              "companies": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "contacts",
              "companies"
            ],
            "description": "Contacts and companies in one headline view."
          },
          "CountViews": {
            "type": "object",
            "properties": {
              "total": {
                "$ref": "#/$defs/CountView"
              },
              "new_to_you": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/CountView"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Removes records from earlier orders and a connected CRM; null when signed out."
              },
              "emailable": {
                "description": "A named email scoring 70 or more at a corporate subscriber.",
                "$ref": "#/$defs/CountView"
              },
              "premium": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/CountView"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The premium records of all_records (contact.premium true); null when the dataset version carries no premium data, or withheld when they are at a single company and the caller has no account."
              },
              "all_records": {
                "description": "The full figure: the audience with its top-level premium filters taken out (one inside any or not stays). The same as total when it has none.",
                "$ref": "#/$defs/CountView"
              }
            },
            "required": [
              "total",
              "new_to_you",
              "emailable",
              "premium",
              "all_records"
            ],
            "description": "Contacts and companies for the three headline views, and the premium figure beside all records."
          },
          "Crosstab": {
            "type": "object",
            "properties": {
              "by": {
                "minItems": 2,
                "maxItems": 3,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "company.sic_2007",
                    "company.business_class",
                    "company.employee_band",
                    "company.turnover_band",
                    "company.fleet_band",
                    "company.type",
                    "company.status",
                    "company.subscriber_class",
                    "site.region",
                    "site.county",
                    "site.town",
                    "site.postcode",
                    "contact.title_family",
                    "contact.job_function",
                    "contact.job_level_rank",
                    "email.exists",
                    "email.type",
                    "phone.exists",
                    "phone.tps_ctps_status"
                  ],
                  "description": "A field a count can be broken down by."
                }
              },
              "cells": {
                "maxItems": 5000,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/CrosstabCell"
                }
              },
              "other": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/OtherBucket"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "truncated": {
                "type": "boolean",
                "description": "True when a cap cut the table: 5,000 cells, or fewer over MCP to keep a result under about 8,000 tokens."
              }
            },
            "required": [
              "by",
              "cells",
              "other",
              "truncated"
            ],
            "description": "Two or three fields as one grouped table (industry by seniority by region), top 50 values per field, capped at 5,000 cells. For anonymous and trial callers, secondary suppression hides enough further cells, each reading \"suppressed\", that no total can be differenced to reveal a cell under 10."
          },
          "CrosstabCell": {
            "type": "object",
            "properties": {
              "values": {
                "minItems": 2,
                "maxItems": 3,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ]
                }
              },
              "filter_values": {
                "description": "The values filters take, when any differs from values (ranks for seniority).",
                "minItems": 2,
                "maxItems": 3,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ]
                }
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              }
            },
            "required": [
              "values",
              "contacts"
            ],
            "description": "One cell of a cross-tab, one value per field."
          },
          "CurrentCount": {
            "type": "object",
            "properties": {
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "contacts": {
                "type": "integer",
                "minimum": 0
              },
              "companies": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "dataset_version",
              "contacts",
              "companies"
            ],
            "description": "The same audience on the current dataset version."
          },
          "Disclosure": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string",
                "enum": [
                  "exact",
                  "rounded"
                ],
                "description": "exact for authenticated paid callers; rounded for anonymous and trial callers, whose counts under 100 and every cell are rounded to the nearest 5."
              },
              "rounded_to": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "5 when numbers are rounded; null when they are exact."
              },
              "secondary_suppression": {
                "type": "boolean",
                "description": "True when cross-tab or breakdown cells of 10 or more were hidden as \"suppressed\" so totals cannot be differenced."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "level",
              "rounded_to",
              "secondary_suppression",
              "notes"
            ],
            "description": "Whether these numbers are exact or protected: \"under 10\" cells, rounding to 5 and secondary suppression for anonymous and trial callers."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "ExpandedTerm": {
            "type": "object",
            "properties": {
              "term": {
                "type": "string",
                "description": "A matched title."
              },
              "from_term": {
                "type": "string",
                "description": "The input term it came from."
              },
              "expansion_set": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "plural_singular",
                      "department_synonyms",
                      "ampersand_and",
                      "abbreviations",
                      "permutations"
                    ]
                  },
                  {
                    "type": "string",
                    "const": "input"
                  }
                ],
                "description": "The expansion set that produced it, or input for the term itself."
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              },
              "excluded": {
                "description": "True when exclude_terms removed it from the audience.",
                "type": "boolean"
              }
            },
            "required": [
              "term",
              "from_term",
              "expansion_set",
              "contacts"
            ],
            "description": "One title a matches filter covers, with its count."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "JurisdictionExclusion": {
            "type": "object",
            "properties": {
              "jurisdiction": {
                "type": "string",
                "description": "An ISO 3166 code, such as DE, CA or US-CA."
              },
              "removed": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "jurisdiction",
              "removed"
            ],
            "description": "Records one policy removed."
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "OtherBucket": {
            "type": "object",
            "properties": {
              "cells": {
                "type": "integer",
                "minimum": 0,
                "description": "How many cells were folded into other."
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              },
              "companies": {
                "$ref": "#/$defs/CellCount"
              }
            },
            "required": [
              "cells",
              "contacts"
            ],
            "description": "Every cell beyond the top 50, summed."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "PriceEstimate": {
            "type": "object",
            "properties": {
              "credits": {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              "gbp_ex_vat": {
                "type": "object",
                "propertyNames": {
                  "type": "string",
                  "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
                },
                "additionalProperties": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Pounds sterling excluding VAT, to two decimal places."
                },
                "description": "The price in GBP excluding VAT: per_contact_scale (every credit at the scale) and cheapest (the cheapest real purchase, at the scale or with credit packs)."
              }
            },
            "required": [
              "credits",
              "gbp_ex_vat"
            ],
            "description": "What ordering the whole count would cost. An estimate; quote_order gives the machine quote."
          },
          "Quality": {
            "type": "object",
            "properties": {
              "email_coverage_pct": {
                "type": "number",
                "minimum": 0,
                "maximum": 100,
                "description": "Records with a named email as a share of the count."
              },
              "verified_90d_pct": {
                "type": "number",
                "minimum": 0,
                "maximum": 100,
                "description": "Share of emails with a provider result of ok in the last 90 days."
              },
              "verified_measured_at": {
                "type": "string",
                "format": "date"
              },
              "deliverability": {
                "description": "Score distribution: good 70 to 100, risky 40 to 69, poor under 40.",
                "type": "object",
                "properties": {
                  "good": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "risky": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "poor": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  }
                },
                "required": [
                  "good",
                  "risky",
                  "poor"
                ]
              },
              "avg_days_since_verification": {
                "type": "number",
                "minimum": 0
              },
              "phone_coverage_pct": {
                "description": "Share with a validated number, when phone is requested.",
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "tps_ctps_screened_at": {
                "description": "The version's TPS and CTPS screen date, when phone is requested and a number in it is screened; each number carries its own status and screen date.",
                "type": "string",
                "format": "date"
              }
            },
            "required": [
              "email_coverage_pct",
              "verified_90d_pct"
            ],
            "description": "Quality signals shown with every count."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "ResolvedCentre": {
            "type": "object",
            "properties": {
              "label": {
                "type": "string"
              },
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "lat": {
                "type": "number"
              },
              "lon": {
                "type": "number"
              },
              "radius_miles": {
                "type": "number"
              },
              "postcode_districts_matched": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "label",
              "code",
              "lat",
              "lon",
              "radius_miles",
              "postcode_districts_matched"
            ],
            "description": "A radius centre as the engine resolved it."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "SuppressionChecksum": {
            "type": "object",
            "properties": {
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              },
              "checksum": {
                "type": "string"
              },
              "row_count": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "list_id",
              "checksum",
              "row_count"
            ],
            "description": "A suppression list as the count read it."
          },
          "SuppressionRemoval": {
            "type": "object",
            "properties": {
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              },
              "removed": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "list_id",
              "removed"
            ],
            "description": "Records one suppression list removed."
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "preview_records",
      "title": "Preview sample records",
      "description": "Returns up to 25 masked sample rows (10 by default) for an audience or a count id, each with verification badges, why it matches and a provenance card. Use it after count_audience to show the user what the records look like before quoting. Free: emails and phones are masked on the server, a repeat returns the same rows, and no rows come back when the count is under 25. Call quote_order next to price the records. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "audience": {
            "$ref": "#/$defs/AudienceRef"
          },
          "count_id": {
            "description": "A count id instead of an audience.",
            "type": "string",
            "pattern": "^cnt_[A-Za-z2-7]{20}$",
            "examples": [
              "cnt_7K2PQ4MAXN3R6TBY5WDZ"
            ]
          },
          "limit": {
            "description": "Rows to return, 1 to 25. Default 10.",
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 25
          },
          "shuffle": {
            "description": "Draw a new seed. Counts against your rate budget and is logged. Default false, so a repeat returns the same rows.",
            "default": false,
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "The audience or count to sample: exactly one of audience or count_id.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "audience": true
            },
            "required": [
              "audience"
            ]
          },
          {
            "type": "object",
            "properties": {
              "count_id": true
            },
            "required": [
              "count_id"
            ]
          }
        ],
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "AudienceRef": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^aud_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an audience id: aud_ followed by a 26 character ULID in upper case Crockford base32, such as aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA"
                ]
              },
              {
                "$ref": "#/$defs/Audience"
              }
            ],
            "description": "An audience definition (mydatahub.audience/1) inline, or the aud_ id of a saved audience."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^prv_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a preview id: prv_ followed by a 26 character ULID in upper case Crockford base32, such as prv_01JB4H3M7Q2V7XN3M9R6T1Y5W8.",
            "examples": [
              "prv_01JB4H3M7Q2V7XN3M9R6T1Y5W8"
            ]
          },
          "count_id": {
            "type": "string",
            "pattern": "^cnt_[A-Z2-7]{20}$",
            "description": "Format: a count id: cnt_ followed by 20 base32 characters (A to Z and 2 to 7), such as cnt_7K2PQ4MAXN3R6TBY5WDZ.",
            "examples": [
              "cnt_7K2PQ4MAXN3R6TBY5WDZ"
            ]
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "seed": {
            "type": "string",
            "description": "The seed the rows came from; the same audience gives the same seed."
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "The count the rows were drawn from, rounded as disclosure says."
          },
          "disclosure": {
            "$ref": "#/$defs/Disclosure"
          },
          "rows": {
            "maxItems": 25,
            "type": "array",
            "items": {
              "$ref": "#/$defs/PreviewRow"
            }
          },
          "withheld": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "rows": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "reason": {
                    "type": "string"
                  }
                },
                "required": [
                  "rows",
                  "reason"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Rows held back: all of them when the count is under 25, or rows whose title fewer than 10 people hold."
          },
          "masked": {
            "type": "boolean",
            "const": true
          },
          "watermark": {
            "description": "The account id watermarked into sample CSVs; null when signed out.",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "count_id",
          "dataset_version",
          "seed",
          "count",
          "disclosure",
          "rows",
          "withheld",
          "masked",
          "watermark",
          "created_at"
        ],
        "description": "A free, masked sample of up to 25 rows. Repeating a sample returns the same rows.",
        "$defs": {
          "ComplianceObject": {
            "type": "object",
            "properties": {
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ],
                "description": "UK GDPR Article 6(1)(f) legitimate interests, with the LIA in lia_ref."
              },
              "lia_ref": {
                "type": "string",
                "description": "The published legitimate interests assessment."
              },
              "subscriber_class": {
                "type": "string",
                "enum": [
                  "ltd",
                  "plc",
                  "llp",
                  "scottish_partnership",
                  "public_body",
                  "charity_incorporated",
                  "sole_trader",
                  "ordinary_partnership",
                  "unknown"
                ],
                "description": "PECR subscriber class: ltd, plc, llp, scottish_partnership, public_body, charity_incorporated, sole_trader, ordinary_partnership, unknown."
              },
              "corporate_subscriber": {
                "type": "boolean",
                "description": "True for companies, LLPs, Scottish partnerships and public bodies, where the PECR regulation 22 consent rule does not apply."
              },
              "email_marketing_basis": {
                "type": "string",
                "enum": [
                  "pecr_corporate_subscriber",
                  "consent_required"
                ]
              },
              "subscriber_evidence": {
                "type": "object",
                "properties": {
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "company_type": {
                    "type": "string"
                  }
                },
                "required": [
                  "companies_house_number",
                  "company_type"
                ],
                "description": "The register entry behind subscriber_class."
              },
              "article14_status": {
                "type": "string",
                "enum": [
                  "notified",
                  "publicly_notified_disproportionate_effort",
                  "pending_within_window"
                ],
                "description": "Article 14 notice status: notified, publicly_notified_disproportionate_effort, pending_within_window."
              },
              "article14_notified_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "notice_version": {
                "type": "string",
                "description": "The privacy notice version sent."
              },
              "provenance": {
                "$ref": "#/$defs/Provenance"
              },
              "tps_ctps_status": {
                "type": "string",
                "enum": [
                  "clear",
                  "tps_registered",
                  "ctps_registered",
                  "tps_or_ctps_registered",
                  "not_screened"
                ],
                "description": "Telephone screen: clear, tps_registered, ctps_registered, tps_or_ctps_registered, not_screened. The result of the screen on tps_ctps_screened_at, valid until tps_ctps_valid_until. In a sample, an order's records (each time they are fetched, downloaded or pushed) and an enrichment, a clear number reads not_screened, with no dates, once that screen is more than 28 days before the day the record is served; a registered number stays registered."
              },
              "tps_ctps_screened_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The date of the screen the status is as of; null when not screened."
              },
              "tps_ctps_valid_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "28 days after tps_ctps_screened_at, when this screen stops being valid. Null when not screened. Screen the numbers you are supplied yourself before calling, and again every 28 days."
              },
              "suppression_status": {
                "type": "string",
                "enum": [
                  "none",
                  "objected_to_emailmovers",
                  "objected_to_licensee",
                  "deceased",
                  "left_company"
                ]
              },
              "record_age_days": {
                "type": "integer",
                "minimum": 0,
                "description": "Days since the record was compiled."
              },
              "attribution": {
                "description": "The OGL v3.0 attribution for Companies House company data. Officer names are personal data outside the OGL, so they carry article14_status instead.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "lawful_basis",
              "lia_ref",
              "subscriber_class",
              "corporate_subscriber",
              "email_marketing_basis",
              "subscriber_evidence",
              "article14_status",
              "article14_notified_at",
              "notice_version",
              "provenance",
              "tps_ctps_status",
              "tps_ctps_screened_at",
              "tps_ctps_valid_until",
              "suppression_status",
              "record_age_days",
              "attribution"
            ],
            "description": "Carried by every preview row, order record, lookup and enrichment, and repeated as CSV columns and as the MyDataHub property group on CRM push.",
            "examples": [
              {
                "lawful_basis": "legitimate_interests_art6_1_f",
                "lia_ref": "EM-LIA-2026-03",
                "subscriber_class": "ltd",
                "corporate_subscriber": true,
                "email_marketing_basis": "pecr_corporate_subscriber",
                "subscriber_evidence": {
                  "companies_house_number": "05046417",
                  "company_type": "ltd"
                },
                "article14_status": "notified",
                "article14_notified_at": "2026-06-14",
                "notice_version": "2026-02",
                "provenance": {
                  "company": {
                    "source": "companies_house",
                    "as_of": "2026-09-21"
                  },
                  "contact": {
                    "source": "emailmovers_research",
                    "compiled_at": "2026-05-02",
                    "last_verified_at": "2026-08-30",
                    "method": "telephone"
                  },
                  "email": {
                    "verified_at": "2026-09-10",
                    "result": "ok",
                    "provider_location": "EU"
                  }
                },
                "tps_ctps_status": "clear",
                "tps_ctps_screened_at": "2026-09-12",
                "tps_ctps_valid_until": "2026-10-10",
                "suppression_status": "none",
                "record_age_days": 147,
                "attribution": "Contains public sector information licensed under the Open Government Licence v3.0"
              }
            ]
          },
          "Disclosure": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string",
                "enum": [
                  "exact",
                  "rounded"
                ],
                "description": "exact for authenticated paid callers; rounded for anonymous and trial callers, whose counts under 100 and every cell are rounded to the nearest 5."
              },
              "rounded_to": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "5 when numbers are rounded; null when they are exact."
              },
              "secondary_suppression": {
                "type": "boolean",
                "description": "True when cross-tab or breakdown cells of 10 or more were hidden as \"suppressed\" so totals cannot be differenced."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "level",
              "rounded_to",
              "secondary_suppression",
              "notes"
            ],
            "description": "Whether these numbers are exact or protected: \"under 10\" cells, rounding to 5 and secondary suppression for anonymous and trial callers."
          },
          "OtherBadge": {
            "type": "object",
            "properties": {
              "badge": {
                "type": "string",
                "enum": [
                  "re_checking",
                  "unverified",
                  "suppressed"
                ]
              },
              "date": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The date behind the badge, if any."
              },
              "label": {
                "type": "string",
                "description": "Such as Verified 12 September 2026."
              }
            },
            "required": [
              "badge",
              "date",
              "label"
            ],
            "description": "Re-checking, unverified or suppressed."
          },
          "PreviewRow": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^prv_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "A session-scoped id standing in for the record. It never reveals contact_ ids.",
                "examples": [
                  "prv_01JB4H3M7Q2V7XN3M9R6T1Y5W8"
                ]
              },
              "title": {
                "type": "string"
              },
              "job_level": {
                "description": "The level, such as Director; null when the level is not known.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "job_function": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "company": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string"
                  },
                  "employee_band": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "sic_2007": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "name",
                  "companies_house_number",
                  "status",
                  "employee_band",
                  "sic_2007"
                ]
              },
              "site": {
                "type": "object",
                "properties": {
                  "town": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "postcode_district": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "region": {
                    "type": "string"
                  }
                },
                "required": [
                  "town",
                  "postcode_district",
                  "region"
                ]
              },
              "email_masked": {
                "description": "First character of the local part plus the top level domain, such as j••••@••••.co.uk.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "email_type": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "named",
                      "generic_local_part",
                      "generic_domain"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "phone_masked": {
                "description": "To the area code, such as 0113 ••• •••1.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tps_ctps_status": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "clear",
                      "tps_registered",
                      "ctps_registered",
                      "tps_or_ctps_registered",
                      "not_screened"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "badges": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/VerificationBadge"
                }
              },
              "why_it_matches": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhyItMatches"
                }
              },
              "provenance": {
                "$ref": "#/$defs/ProvenanceCard"
              },
              "compliance": {
                "$ref": "#/$defs/ComplianceObject"
              }
            },
            "required": [
              "id",
              "title",
              "job_level",
              "job_function",
              "company",
              "site",
              "email_masked",
              "email_type",
              "phone_masked",
              "tps_ctps_status",
              "badges",
              "why_it_matches",
              "provenance",
              "compliance"
            ],
            "description": "One masked sample record."
          },
          "Provenance": {
            "type": "object",
            "properties": {
              "company": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": [
                      "emailmovers_research",
                      "companies_house",
                      "onspd",
                      "ukbizdirectory",
                      "partner_rampedup"
                    ]
                  },
                  "as_of": {
                    "type": "string",
                    "format": "date"
                  }
                },
                "required": [
                  "source",
                  "as_of"
                ],
                "description": "Where the company facts came from and the snapshot date."
              },
              "contact": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "source": {
                        "type": "string",
                        "enum": [
                          "emailmovers_research",
                          "companies_house",
                          "onspd",
                          "ukbizdirectory",
                          "partner_rampedup"
                        ]
                      },
                      "compiled_at": {
                        "type": "string",
                        "format": "date"
                      },
                      "last_verified_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "method": {
                        "type": "string",
                        "enum": [
                          "telephone",
                          "web",
                          "register"
                        ]
                      }
                    },
                    "required": [
                      "source",
                      "compiled_at",
                      "last_verified_at",
                      "method"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Who compiled the contact, when, and how it was last confirmed."
              },
              "email": {
                "description": "The latest email verification: date, provider result and location.",
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "verified_at": {
                        "type": "string",
                        "format": "date"
                      },
                      "result": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "catch_all",
                          "unknown",
                          "invalid",
                          "disposable"
                        ]
                      },
                      "provider_location": {
                        "type": "string",
                        "enum": [
                          "UK",
                          "EU",
                          "US"
                        ]
                      }
                    },
                    "required": [
                      "verified_at",
                      "result",
                      "provider_location"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "company",
              "contact"
            ],
            "description": "Source per entity, answering the ICO questions who compiled it and where from."
          },
          "ProvenanceCard": {
            "type": "object",
            "properties": {
              "sources": {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string",
                  "enum": [
                    "emailmovers_research",
                    "companies_house",
                    "onspd",
                    "ukbizdirectory",
                    "partner_rampedup"
                  ]
                },
                "description": "The source of each field shown, such as title: emailmovers_research."
              },
              "first_seen_at": {
                "type": "string",
                "format": "date"
              },
              "last_verified_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "method": {
                "type": "string",
                "enum": [
                  "telephone",
                  "web",
                  "register"
                ]
              },
              "companies_house_number": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "company_status": {
                "type": "string"
              },
              "article14_status": {
                "type": "string",
                "enum": [
                  "notified",
                  "publicly_notified_disproportionate_effort",
                  "pending_within_window"
                ]
              },
              "tps_ctps_screened_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ]
              }
            },
            "required": [
              "sources",
              "first_seen_at",
              "last_verified_at",
              "method",
              "companies_house_number",
              "company_status",
              "article14_status",
              "tps_ctps_screened_at",
              "lawful_basis"
            ],
            "description": "The ICO due diligence answers for one record, as shown on the sample row."
          },
          "VerificationBadge": {
            "oneOf": [
              {
                "$ref": "#/$defs/VerifiedBadge"
              },
              {
                "$ref": "#/$defs/OtherBadge"
              }
            ],
            "description": "A badge on a sample row. Every verified has a date."
          },
          "VerifiedBadge": {
            "type": "object",
            "properties": {
              "badge": {
                "type": "string",
                "const": "verified"
              },
              "date": {
                "type": "string",
                "format": "date",
                "description": "The verification date. Every verified has one."
              },
              "label": {
                "type": "string",
                "description": "Such as Verified 12 September 2026."
              }
            },
            "required": [
              "badge",
              "date",
              "label"
            ],
            "description": "Verified, with the date it was verified."
          },
          "WhyItMatches": {
            "type": "object",
            "properties": {
              "pointer": {
                "type": "string",
                "description": "JSON pointer to the filter in the audience."
              },
              "field": {
                "type": "string"
              },
              "value": {
                "description": "The record's actual value.",
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "number"
                  },
                  {
                    "type": "boolean"
                  }
                ]
              },
              "explanation": {
                "type": "string",
                "description": "Such as Marketing Director matched marketing manager through expansion."
              }
            },
            "required": [
              "pointer",
              "field",
              "value",
              "explanation"
            ],
            "description": "One predicate the record satisfies, with its value."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "save_audience",
      "title": "Save an audience",
      "description": "Saves an audience definition under a name, shared across the organisation, or updates a saved one when audience_id is given. Use it when the user wants to keep, share or recount a list later; saving is free and needs audiences:write. Repeating the same call returns the same saved audience. Call list_audiences to find it again, or count_audience with its aud_ id. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "audience_id": {
            "description": "A saved audience to update. Leave it out to save a new one.",
            "type": "string",
            "pattern": "^aud_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "examples": [
              "aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "audience": {
            "$ref": "#/$defs/Audience"
          },
          "brief": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false,
        "description": "Save a new audience (name and audience, brief optional) or update one (audience_id and at least one of name, audience or brief).",
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "name": true,
              "audience": true,
              "brief": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "audience"
            ],
            "not": {
              "type": "object",
              "properties": {
                "audience_id": true
              },
              "required": [
                "audience_id"
              ]
            }
          },
          {
            "type": "object",
            "properties": {
              "audience_id": true
            },
            "required": [
              "audience_id"
            ],
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "name": true
                },
                "required": [
                  "name"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "audience": true
                },
                "required": [
                  "audience"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "brief": true
                },
                "required": [
                  "brief"
                ]
              }
            ]
          }
        ],
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^aud_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: an audience id: aud_ followed by a 26 character ULID in upper case Crockford base32, such as aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA.",
            "examples": [
              "aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA"
            ]
          },
          "name": {
            "type": "string"
          },
          "audience": {
            "$ref": "#/$defs/Audience"
          },
          "brief": {
            "description": "The brief it was compiled from, if any.",
            "type": [
              "string",
              "null"
            ]
          },
          "current_count": {
            "anyOf": [
              {
                "$ref": "#/$defs/AudienceCountSummary"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_refreshed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_by": {
            "type": "string",
            "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a user id: usr_ followed by a 26 character ULID in upper case Crockford base32, such as usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8.",
            "examples": [
              "usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The audience in the app, mydatahub.emailmovers.com/audiences/{id}."
          }
        },
        "required": [
          "id",
          "name",
          "audience",
          "brief",
          "current_count",
          "last_refreshed_at",
          "created_at",
          "updated_at",
          "created_by",
          "url"
        ],
        "description": "A named audience shared across the organisation, with its current count.",
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "AudienceCountSummary": {
            "type": "object",
            "properties": {
              "count_id": {
                "type": "string",
                "pattern": "^cnt_[A-Z2-7]{20}$",
                "description": "Format: a count id: cnt_ followed by 20 base32 characters (A to Z and 2 to 7), such as cnt_7K2PQ4MAXN3R6TBY5WDZ.",
                "examples": [
                  "cnt_7K2PQ4MAXN3R6TBY5WDZ"
                ]
              },
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "contacts": {
                "type": "integer",
                "minimum": 0
              },
              "companies": {
                "type": "integer",
                "minimum": 0
              },
              "emailable": {
                "type": "integer",
                "minimum": 0
              },
              "counted_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "count_id",
              "dataset_version",
              "contacts",
              "companies",
              "emailable",
              "counted_at"
            ],
            "description": "The headline numbers of one count of an audience."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_audiences",
      "title": "List saved audiences",
      "description": "Lists the organisation's saved audiences with their current counts and last refresh, newest first, optionally filtered by name. Use it to find an aud_ id to count, quote or share. Free; it needs audiences:read. Pass an aud_ id to count_audience for a fresh count. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "q": {
            "description": "Filter by name.",
            "type": "string",
            "maxLength": 100
          },
          "limit": {
            "description": "Items per page, 1 to 100. Default 25.",
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "An opaque cursor from next_cursor. Pass it back unchanged."
          }
        },
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/SavedAudience"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "Whether another page follows."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 512,
                "description": "An opaque cursor from next_cursor. Pass it back unchanged."
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as cursor to fetch the next page; null on the last page."
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "description": "A page of saved audiences, newest first.",
        "$defs": {
          "AllGroup": {
            "type": "object",
            "properties": {
              "all": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "all"
            ],
            "additionalProperties": false,
            "description": "AND: every node inside must match."
          },
          "AnyGroup": {
            "type": "object",
            "properties": {
              "any": {
                "minItems": 1,
                "type": "array",
                "items": {
                  "$ref": "#/$defs/WhereNode"
                }
              }
            },
            "required": [
              "any"
            ],
            "additionalProperties": false,
            "description": "OR: at least one node inside must match."
          },
          "Audience": {
            "type": "object",
            "properties": {
              "schema": {
                "type": "string",
                "const": "mydatahub.audience/1",
                "description": "The definition's namespace and version. Older versions are upgraded by a pure function."
              },
              "dataset": {
                "type": "string",
                "enum": [
                  "uk_contacts",
                  "ie_contacts",
                  "global_contacts"
                ],
                "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
              },
              "dataset_version": {
                "description": "The weekly build to count against, such as 2026-W39. Left out, the current version is filled in and returned.",
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "examples": [
                  "2026-W39"
                ]
              },
              "where": {
                "description": "The filters. Left out, the audience is the whole dataset after the defaults.",
                "$ref": "#/$defs/WhereNode"
              },
              "email_policy": {
                "$ref": "#/$defs/EmailPolicy"
              },
              "dedupe": {
                "type": "string",
                "enum": [
                  "none",
                  "one_per_company",
                  "one_per_site"
                ],
                "description": "none keeps every matching contact, one_per_company keeps one contact per company, one_per_site keeps one per site. Default none."
              }
            },
            "required": [
              "schema"
            ],
            "additionalProperties": false,
            "title": "MyDataHub audience definition (mydatahub.audience/1)",
            "description": "Who you want, as filters grouped by entity (company., site., contact., email., phone., signal.). The server fills its defaults (active companies, named emails, corporate subscribers, the current dataset_version) and returns the effective definition with every count."
          },
          "AudienceCountSummary": {
            "type": "object",
            "properties": {
              "count_id": {
                "type": "string",
                "pattern": "^cnt_[A-Z2-7]{20}$",
                "description": "Format: a count id: cnt_ followed by 20 base32 characters (A to Z and 2 to 7), such as cnt_7K2PQ4MAXN3R6TBY5WDZ.",
                "examples": [
                  "cnt_7K2PQ4MAXN3R6TBY5WDZ"
                ]
              },
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "contacts": {
                "type": "integer",
                "minimum": 0
              },
              "companies": {
                "type": "integer",
                "minimum": 0
              },
              "emailable": {
                "type": "integer",
                "minimum": 0
              },
              "counted_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "count_id",
              "dataset_version",
              "contacts",
              "companies",
              "emailable",
              "counted_at"
            ],
            "description": "The headline numbers of one count of an audience."
          },
          "BetweenFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "between"
              },
              "from": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              },
              "to": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "from",
              "to"
            ],
            "additionalProperties": false,
            "description": "The field lies from one value to another inclusive, over the field's order.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "between",
                "from": "10-19",
                "to": "200-349"
              }
            ]
          },
          "BundleNode": {
            "type": "object",
            "properties": {
              "bundle": {
                "type": "string",
                "enum": [
                  "sdm",
                  "manager_and_above",
                  "owner_managed"
                ]
              }
            },
            "required": [
              "bundle"
            ],
            "additionalProperties": false,
            "description": "A title bundle, resolved to its filters in the effective definition: sdm (senior decision makers), manager_and_above (managers and above), owner_managed (owner managed)."
          },
          "EmailPolicy": {
            "type": "object",
            "properties": {
              "min_deliverability_score": {
                "description": "Lowest deliverability score counted, 0 to 100. Default 70.",
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "allow_catch_all": {
                "description": "Whether catch-all addresses count. Default false.",
                "type": "boolean"
              }
            },
            "additionalProperties": false,
            "description": "Email quality floor. Defaults: min_deliverability_score 70, allow_catch_all false."
          },
          "Filter": {
            "oneOf": [
              {
                "$ref": "#/$defs/InFilter"
              },
              {
                "$ref": "#/$defs/BetweenFilter"
              },
              {
                "$ref": "#/$defs/GteFilter"
              },
              {
                "$ref": "#/$defs/LteFilter"
              },
              {
                "$ref": "#/$defs/MatchesFilter"
              },
              {
                "$ref": "#/$defs/WithinRadiusFilter"
              },
              {
                "$ref": "#/$defs/InListFilter"
              },
              {
                "$ref": "#/$defs/SinceFilter"
              }
            ],
            "description": "One criterion: a field from GET /v1/catalogue/filters, an operator and its operands. Exclusions nest under not."
          },
          "GteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "gte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or after the value in its order: for bands, the band and every larger one.",
            "examples": [
              {
                "field": "company.employee_band",
                "op": "gte",
                "value": "50-99"
              }
            ]
          },
          "InFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.sic_2007",
                  "company.business_class",
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "company.type",
                  "company.status",
                  "company.subscriber_class",
                  "company.companies_house_number",
                  "site.region",
                  "site.county",
                  "site.town",
                  "site.postcode",
                  "contact.title_family",
                  "contact.job_function",
                  "contact.job_level_rank",
                  "contact.premium",
                  "email.exists",
                  "email.type",
                  "phone.exists",
                  "phone.tps_ctps_status"
                ]
              },
              "op": {
                "type": "string",
                "const": "in"
              },
              "values": {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    }
                  ],
                  "description": "A code, a rank or a boolean, as the field's catalogue lists it."
                }
              }
            },
            "required": [
              "field",
              "op",
              "values"
            ],
            "additionalProperties": false,
            "description": "The field holds one of the listed codes.",
            "examples": [
              {
                "field": "company.sic_2007",
                "op": "in",
                "values": [
                  "C"
                ]
              }
            ]
          },
          "InListFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.companies_house_number",
                  "contact.title",
                  "email.address_sha256",
                  "email.domain_sha256",
                  "phone.e164_sha256"
                ]
              },
              "op": {
                "type": "string",
                "const": "in_list"
              },
              "list_id": {
                "type": "string",
                "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                ]
              }
            },
            "required": [
              "field",
              "op",
              "list_id"
            ],
            "additionalProperties": false,
            "description": "The record's hashed email, domain, phone, company number or title term is on a suppression list. Usually nested under not; each list reports the records it removed.",
            "examples": [
              {
                "field": "email.address_sha256",
                "op": "in_list",
                "list_id": "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
              }
            ]
          },
          "LteFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "company.employee_band",
                  "company.turnover_band",
                  "company.fleet_band",
                  "contact.job_level_rank",
                  "contact.company_contact_rank",
                  "email.deliverability_score"
                ]
              },
              "op": {
                "type": "string",
                "const": "lte"
              },
              "value": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  {
                    "type": "number"
                  }
                ],
                "description": "A band code or a number from the field's order."
              }
            },
            "required": [
              "field",
              "op",
              "value"
            ],
            "additionalProperties": false,
            "description": "The field is at or before the value in its order. Rank 1 is the most senior, so Director and above is contact.job_level_rank lte 6.",
            "examples": [
              {
                "field": "contact.job_level_rank",
                "op": "lte",
                "value": 6
              }
            ]
          },
          "MatchesFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.title"
                ]
              },
              "op": {
                "type": "string",
                "const": "matches"
              },
              "terms": {
                "minItems": 1,
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "contains",
                  "starts_with",
                  "exact"
                ],
                "description": "contains (the default) matches titles containing a term, starts_with matches titles beginning with it, exact takes verbatim titles with no expansion."
              },
              "expand": {
                "description": "Expansion sets to apply, each once: plural_singular, department_synonyms, ampersand_and, abbreviations, permutations. Left out, the first four apply; an empty list applies none. Not used with mode exact.",
                "uniqueItems": true,
                "maxItems": 5,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "plural_singular",
                    "department_synonyms",
                    "ampersand_and",
                    "abbreviations",
                    "permutations"
                  ]
                }
              },
              "exclude_terms": {
                "description": "Expanded terms removed by hand. Kept in the definition so the count stays reproducible when the title dictionary changes.",
                "maxItems": 500,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "terms"
            ],
            "additionalProperties": false,
            "description": "Job title keyword match. mode contains (the default) or starts_with expands each term with the expansion sets; mode exact matches verbatim titles. Every expanded term is returned with the count.",
            "examples": [
              {
                "field": "contact.title",
                "op": "matches",
                "terms": [
                  "marketing manager"
                ],
                "mode": "contains",
                "expand": [
                  "plural_singular",
                  "department_synonyms",
                  "ampersand_and",
                  "abbreviations"
                ]
              }
            ],
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "const": "exact"
                    }
                  },
                  "required": [
                    "mode"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "expand": {
                      "type": "array",
                      "maxItems": 0
                    },
                    "exclude_terms": {
                      "type": "array",
                      "maxItems": 0
                    }
                  }
                }
              }
            ]
          },
          "NotGroup": {
            "type": "object",
            "properties": {
              "not": {
                "$ref": "#/$defs/WhereNode"
              }
            },
            "required": [
              "not"
            ],
            "additionalProperties": false,
            "description": "Negation: the single node inside must not match."
          },
          "PlaceCentre": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "description": "A place name, resolved with resolve_location, such as Leeds."
              },
              "code": {
                "description": "The ONS geography code of the chosen candidate when resolve_location found more than one, such as E08000035 for the Leeds district.",
                "type": "string",
                "minLength": 1,
                "maxLength": 20
              }
            },
            "required": [
              "place"
            ],
            "additionalProperties": false,
            "description": "A named place. Ambiguous names come back from resolve_location as candidates, never a silent choice."
          },
          "PointCentre": {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "minimum": 49,
                "maximum": 61
              },
              "lon": {
                "type": "number",
                "minimum": -9,
                "maximum": 2
              }
            },
            "required": [
              "lat",
              "lon"
            ],
            "additionalProperties": false,
            "description": "A latitude and longitude in WGS84 degrees."
          },
          "PostcodeCentre": {
            "type": "object",
            "properties": {
              "postcode": {
                "type": "string",
                "pattern": "^[A-Za-z]{1,2}([0-9][0-9A-Za-z]?( [0-9]([A-Za-z]{2})?| ?[0-9][A-Za-z]{2})?)?$",
                "description": "The centroid of a postcode unit, sector, district or area, such as LS1 4AP."
              }
            },
            "required": [
              "postcode"
            ],
            "additionalProperties": false,
            "description": "A postcode centroid from ONSPD."
          },
          "RadiusCentre": {
            "anyOf": [
              {
                "$ref": "#/$defs/PlaceCentre"
              },
              {
                "$ref": "#/$defs/PostcodeCentre"
              },
              {
                "$ref": "#/$defs/PointCentre"
              }
            ],
            "description": "The centre of a radius: a place, a postcode or a latitude and longitude."
          },
          "SavedAudience": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^aud_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an audience id: aud_ followed by a 26 character ULID in upper case Crockford base32, such as aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA.",
                "examples": [
                  "aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA"
                ]
              },
              "name": {
                "type": "string"
              },
              "audience": {
                "$ref": "#/$defs/Audience"
              },
              "brief": {
                "description": "The brief it was compiled from, if any.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "current_count": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/AudienceCountSummary"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "last_refreshed_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "updated_at": {
                "type": "string",
                "format": "date-time"
              },
              "created_by": {
                "type": "string",
                "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a user id: usr_ followed by a 26 character ULID in upper case Crockford base32, such as usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8.",
                "examples": [
                  "usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The audience in the app, mydatahub.emailmovers.com/audiences/{id}."
              }
            },
            "required": [
              "id",
              "name",
              "audience",
              "brief",
              "current_count",
              "last_refreshed_at",
              "created_at",
              "updated_at",
              "created_by",
              "url"
            ],
            "description": "A named audience shared across the organisation, with its current count."
          },
          "SinceFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "contact.last_validated_at",
                  "email.last_verified_at",
                  "signal.type",
                  "signal.observed_at"
                ]
              },
              "op": {
                "type": "string",
                "const": "since"
              },
              "days": {
                "type": "integer",
                "minimum": 1,
                "maximum": 3650
              },
              "values": {
                "description": "For signal.type only: the signal types to look for, such as company.incorporated.",
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              }
            },
            "required": [
              "field",
              "op",
              "days"
            ],
            "additionalProperties": false,
            "description": "Within the last N days: a date field, or a Companies House signal of the listed types on signal.type.",
            "examples": [
              {
                "field": "signal.type",
                "op": "since",
                "values": [
                  "company.incorporated"
                ],
                "days": 90
              }
            ]
          },
          "WhereNode": {
            "anyOf": [
              {
                "$ref": "#/$defs/AllGroup"
              },
              {
                "$ref": "#/$defs/AnyGroup"
              },
              {
                "$ref": "#/$defs/NotGroup"
              },
              {
                "$ref": "#/$defs/BundleNode"
              },
              {
                "$ref": "#/$defs/Filter"
              }
            ],
            "description": "A group (all, any, not), a title bundle or a filter. Groups nest up to 32 deep, and a where tree holds up to 1,000 filters, groups and bundles."
          },
          "WithinRadiusFilter": {
            "type": "object",
            "properties": {
              "field": {
                "type": "string",
                "enum": [
                  "site.location"
                ]
              },
              "op": {
                "type": "string",
                "const": "within_radius"
              },
              "centre": {
                "$ref": "#/$defs/RadiusCentre"
              },
              "radius_miles": {
                "type": "number",
                "minimum": 1,
                "maximum": 100,
                "description": "Radius in miles, 1 to 100. Under 5 miles needs an account."
              }
            },
            "required": [
              "field",
              "op",
              "centre",
              "radius_miles"
            ],
            "additionalProperties": false,
            "description": "Sites within radius_miles of the centre. The count reports the centroid used and the postcodes matched.",
            "examples": [
              {
                "field": "site.location",
                "op": "within_radius",
                "centre": {
                  "place": "Leeds"
                },
                "radius_miles": 20
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_field_sets",
      "title": "List field sets",
      "description": "Lists the field sets an order can deliver, such as standard or standard_telephone, with their exact columns. Every field set costs 1 credit a record, with no telephone, download or API surcharge. Use it to pick the field_set for quote_order; it is free and needs no account. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "limit": {
            "description": "Items per page, 1 to 100. Default 25.",
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "An opaque cursor from next_cursor. Pass it back unchanged."
          }
        },
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/FieldSet"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "Whether another page follows."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 512,
                "description": "An opaque cursor from next_cursor. Pass it back unchanged."
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as cursor to fetch the next page; null on the last page."
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "description": "A page of field sets, newest first.",
        "$defs": {
          "FieldSet": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
                "description": "Such as standard, standard_telephone or full."
              },
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "credits_per_record": {
                "type": "number",
                "minimum": 0,
                "description": "Every field set costs 1 credit a record."
              },
              "columns": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "name",
                    "description"
                  ]
                }
              }
            },
            "required": [
              "id",
              "name",
              "description",
              "credits_per_record",
              "columns"
            ],
            "description": "The named bundle of fields delivered with an order, with its exact columns."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "quote_order",
      "title": "Quote an order",
      "description": "Creates a machine quote for a count: the records you would receive after removing ones already held and suppressed, the credits and GBP price, the licence, the warranty and any blockers. The quote_id lasts 24 hours and is bound to the dataset version; it is not a human sales quote, which is a 14 day PDF made in the app. Free and needs no account, and nothing is charged. Show the credits and price to the user, then call create_order with the quote_id. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "count_id": {
            "type": "string",
            "pattern": "^cnt_[A-Za-z2-7]{20}$",
            "description": "A count id from POST /v1/counts or count_audience. Either case is accepted; responses use upper case.",
            "examples": [
              "cnt_7K2PQ4MAXN3R6TBY5WDZ"
            ]
          },
          "field_set": {
            "type": "string",
            "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
            "description": "A field set id from GET /v1/field-sets, such as standard."
          },
          "limit": {
            "description": "Records to buy; left out, the whole count.",
            "type": "integer",
            "minimum": 1,
            "maximum": 1000000
          },
          "dedupe_against": {
            "description": "Remove records you already hold: from earlier orders, from a connected CRM, or both. Default previous_orders when signed in. crm and previous_orders_and_crm need connection_id.",
            "default": "previous_orders",
            "type": "string",
            "enum": [
              "none",
              "previous_orders",
              "crm",
              "previous_orders_and_crm"
            ]
          },
          "connection_id": {
            "description": "The CRM connection to check, only with dedupe_against crm or previous_orders_and_crm.",
            "type": "string",
            "pattern": "^conn_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "examples": [
              "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G"
            ]
          },
          "licence": {
            "default": "multi_use_12m",
            "type": "string",
            "enum": [
              "multi_use_12m",
              "outright"
            ],
            "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
          }
        },
        "required": [
          "count_id",
          "field_set"
        ],
        "additionalProperties": false,
        "description": "What to price: a count, a field set, how many records and the licence. Free, and needs no account.",
        "allOf": [
          {
            "if": {
              "type": "object",
              "properties": {
                "dedupe_against": {
                  "enum": [
                    "crm",
                    "previous_orders_and_crm"
                  ]
                }
              },
              "required": [
                "dedupe_against"
              ]
            },
            "then": {
              "type": "object",
              "properties": {
                "connection_id": true
              },
              "required": [
                "connection_id"
              ]
            }
          },
          {
            "if": {
              "type": "object",
              "properties": {
                "connection_id": true
              },
              "required": [
                "connection_id"
              ]
            },
            "then": {
              "type": "object",
              "properties": {
                "dedupe_against": {
                  "enum": [
                    "crm",
                    "previous_orders_and_crm"
                  ]
                }
              },
              "required": [
                "dedupe_against"
              ]
            }
          }
        ]
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^qte_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a quote id: qte_ followed by a 26 character ULID in upper case Crockford base32, such as qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3.",
            "examples": [
              "qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3"
            ]
          },
          "kind": {
            "type": "string",
            "const": "machine"
          },
          "organisation_id": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^org_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an organisation id: org_ followed by a 26 character ULID in upper case Crockford base32, such as org_01JA0Q2V7XN3M9R6T1Y5W8ZAK8.",
                "examples": [
                  "org_01JA0Q2V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The organisation the quote belongs to; create_order settles it only there. null for a quote made without an account, which the first organisation to confirm it takes."
          },
          "count_id": {
            "type": "string",
            "pattern": "^cnt_[A-Z2-7]{20}$",
            "description": "The count the quote was priced from.",
            "examples": [
              "cnt_7K2PQ4MAXN3R6TBY5WDZ"
            ]
          },
          "dataset": {
            "type": "string",
            "enum": [
              "uk_contacts",
              "ie_contacts",
              "global_contacts"
            ],
            "description": "The dataset an audience draws from. uk_contacts is live; ie_contacts and global_contacts are listed but not yet served."
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "field_set": {
            "type": "string",
            "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
          },
          "records": {
            "type": "integer",
            "minimum": 0,
            "description": "Records after overlap and suppression; what you would receive."
          },
          "removed": {
            "type": "object",
            "properties": {
              "already_held": {
                "type": "integer",
                "minimum": 0
              },
              "suppressed": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "already_held",
              "suppressed"
            ],
            "description": "Records left out and never charged."
          },
          "credits_per_record": {
            "type": "number",
            "minimum": 0,
            "description": "1 for a complete UK record; 1.8 outright (proposed)."
          },
          "credits_required": {
            "type": "number",
            "minimum": 0,
            "description": "records times credits_per_record (creditsFor)."
          },
          "credits_available": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              {
                "type": "null"
              }
            ],
            "description": "Your balance; null when signed out."
          },
          "balance_after": {
            "description": "credits_available less credits_required; negative means a top-up is needed; null when signed out.",
            "type": [
              "number",
              "null"
            ]
          },
          "gbp_ex_vat": {
            "type": "number",
            "minimum": 0,
            "description": "What credits_required cost bought the cheapest way, at the per-contact scale or with credit packs, excluding VAT. The same for every caller; purchase says what this caller needs to buy."
          },
          "purchase": {
            "$ref": "#/$defs/Purchase"
          },
          "licence": {
            "$ref": "#/$defs/Licence"
          },
          "warranty": {
            "$ref": "#/$defs/Warranty"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "24 hours after creation."
          },
          "blockers": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/QuoteBlocker"
            }
          },
          "signature": {
            "$ref": "#/$defs/QuoteSignature"
          }
        },
        "required": [
          "id",
          "kind",
          "organisation_id",
          "count_id",
          "dataset_version",
          "records",
          "removed",
          "credits_per_record",
          "credits_required",
          "credits_available",
          "balance_after",
          "gbp_ex_vat",
          "purchase",
          "licence",
          "warranty",
          "expires_at",
          "blockers",
          "signature"
        ],
        "description": "A machine quote: a signed price, valid 24 hours, bound to a dataset version and an organisation. create_order needs its id plus a human confirmation or a pre-authorised agent key; a confirmed flag set by a model is never consent.",
        "$defs": {
          "Licence": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "multi_use_12m",
                  "outright"
                ],
                "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
              },
              "reuse_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Order date plus 12 months; null for outright."
              },
              "resale_prohibited": {
                "type": "boolean"
              },
              "permitted_channels": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "email",
                    "telephone",
                    "post"
                  ]
                },
                "description": "email, telephone and post on standard terms."
              },
              "warranty_url": {
                "type": "string",
                "format": "uri"
              },
              "terms_version": {
                "type": "string",
                "description": "The version of the Data Licence and Sharing Agreement the licence is under, such as 1.0."
              },
              "terms_url": {
                "description": "Where that version of the Data Licence and Sharing Agreement is published.",
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "type",
              "reuse_until",
              "resale_prohibited",
              "permitted_channels",
              "warranty_url",
              "terms_version"
            ],
            "description": "Licence terms as data, on every quote, order, records page and receipt. Records stay usable, pushable and re-downloadable free until reuse_until."
          },
          "Purchase": {
            "type": "object",
            "properties": {
              "credits_to_buy": {
                "type": "integer",
                "minimum": 0,
                "description": "credits_required less the balance: all of it when signed out, 0 when the balance covers the order."
              },
              "cheapest": {
                "anyOf": [
                  {
                    "type": "string",
                    "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The id of the cheapest option; null when nothing needs buying."
              },
              "gbp_ex_vat": {
                "type": "number",
                "minimum": 0,
                "description": "What the cheapest option costs, excluding VAT; 0 when nothing needs buying."
              },
              "options": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/PurchaseOption"
                },
                "description": "Cheapest first: the per-contact scale, and the credit pack (with any rest at the scale) when it is on sale. At the same price, the option that buys more credits comes first."
              }
            },
            "required": [
              "credits_to_buy",
              "cheapest",
              "gbp_ex_vat",
              "options"
            ],
            "description": "How to buy the credits the order needs, worked out by one function (cheapestPurchase) everywhere a price is shown. The caller's own, like the balance: read fresh on every read of the quote."
          },
          "PurchaseLine": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
                "description": "A credit pack id, or per_contact_scale."
              },
              "quantity": {
                "type": "integer",
                "minimum": 0,
                "description": "Credit packs bought, or credits bought at the scale."
              },
              "credits": {
                "type": "integer",
                "minimum": 0
              },
              "gbp_ex_vat": {
                "type": "number",
                "minimum": 0,
                "description": "Pounds sterling excluding VAT, to two decimal places."
              }
            },
            "required": [
              "id",
              "quantity",
              "credits",
              "gbp_ex_vat"
            ],
            "description": "One thing bought: credit packs, or credits at the scale."
          },
          "PurchaseOption": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
                "description": "per_contact_scale, or the id of the credit pack the option is built on (with any rest at the scale). The same between quotes, so a choice survives a fresh quote."
              },
              "label": {
                "type": "string",
                "description": "Such as 12,000 records at 22p."
              },
              "credits": {
                "type": "integer",
                "minimum": 0,
                "description": "Credits the option buys."
              },
              "gbp_ex_vat": {
                "type": "number",
                "minimum": 0,
                "description": "Pounds sterling excluding VAT, to two decimal places."
              },
              "credits_left_over": {
                "type": "integer",
                "minimum": 0,
                "description": "Credits that stay in the balance after the order."
              },
              "lines": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/PurchaseLine"
                }
              }
            },
            "required": [
              "id",
              "label",
              "credits",
              "gbp_ex_vat",
              "credits_left_over",
              "lines"
            ],
            "description": "One way to buy the credits the order needs."
          },
          "QuoteBlocker": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "insufficient_credits",
                  "account_required",
                  "agent_budget_exceeded",
                  "dataset_unavailable",
                  "count_expired"
                ]
              },
              "detail": {
                "type": "string"
              },
              "top_up_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "code",
              "detail"
            ],
            "description": "Something that stops create_order until it is fixed."
          },
          "QuoteSignature": {
            "type": "object",
            "properties": {
              "alg": {
                "type": "string",
                "const": "ES256"
              },
              "kid": {
                "type": "string",
                "description": "The signing key id in jwks_url."
              },
              "jwks_url": {
                "type": "string",
                "format": "uri"
              },
              "jws": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$",
                "description": "A compact JWS whose payload is the quote's id, organisation_id, count_id, dataset_version, records, credits_required, gbp_ex_vat, licence, expires_at."
              }
            },
            "required": [
              "alg",
              "kid",
              "jwks_url",
              "jws"
            ],
            "description": "The signature over the machine quote's price, so an agent can hand the quote to another agent and both can check it. Verify it with the key at jwks_url."
          },
          "Warranty": {
            "type": "object",
            "properties": {
              "policy": {
                "type": "string",
                "enum": [
                  "replace_over_threshold_hard_bounce",
                  "replace_any_hard_bounce_30d"
                ],
                "description": "replace_over_threshold_hard_bounce is the current policy: records are replaced when hard bounces exceed threshold_percent of an order. replace_any_hard_bounce_30d is proposed and not yet in force. The current policy's id replaced one that named the threshold, a change to this public enum made before v2 went live."
              },
              "threshold_percent": {
                "description": "replace_over_threshold_hard_bounce only, and required there: the share of an order, in percent, that hard bounces must exceed before records are replaced. It is the threshold the document was issued under.",
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "policy",
              "url"
            ],
            "description": "The bounce warranty that covers delivered records, with the threshold it was issued under.",
            "allOf": [
              {
                "if": {
                  "type": "object",
                  "properties": {
                    "policy": {
                      "const": "replace_over_threshold_hard_bounce"
                    }
                  },
                  "required": [
                    "policy"
                  ]
                },
                "then": {
                  "type": "object",
                  "properties": {
                    "threshold_percent": true
                  },
                  "required": [
                    "threshold_percent"
                  ]
                },
                "else": {
                  "type": "object",
                  "not": {
                    "type": "object",
                    "properties": {
                      "threshold_percent": true
                    },
                    "required": [
                      "threshold_percent"
                    ]
                  }
                }
              }
            ]
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_order",
      "title": "Create an order (spends credits)",
      "description": "Spends 1 credit per complete UK record against a live machine quote from quote_order, and queues the order. It needs the quote_id and an idempotency_key to reuse on any retry, so a retry never charges twice; a flag set by a model is never consent. Where the host supports elicitation the user confirms the spend in a form or on mydatahub.emailmovers.com; otherwise an agent key must cover it within its per-order cap and monthly budget. If neither applies nothing is charged: the result is a confirmation-required error with an approval_url to give the user, so keep the quote_id; a short balance returns a top_up_url. Call get_order until the status is ready, then fetch_order_records. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "quote_id": {
            "type": "string",
            "pattern": "^qte_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "A live machine quote from quote_order. Without one nothing is charged.",
            "examples": [
              "qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "delivery": {
            "description": "api (fetch records), csv (signed download) and google_sheets. Default api.",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "api",
                "csv",
                "google_sheets"
              ]
            }
          },
          "confirmation_token": {
            "type": "string",
            "minLength": 16,
            "maxLength": 2000,
            "description": "The token the approval page on mydatahub.emailmovers.com returns once the signed-in person approves. It is bound to that person (their sub), this spend (the machine quote_id, or the enrichment or push) and an expiry no later than the quote's, and it is redeemable once."
          },
          "idempotency_key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Any unique string, such as a V4 UUID. Reuse it when retrying the same order so it is never charged twice; a different order needs a new key."
          }
        },
        "required": [
          "quote_id",
          "idempotency_key"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "building",
              "verifying",
              "ready",
              "failed",
              "cancelled"
            ],
            "description": "queued, building, verifying, ready; failed if processing failed; cancelled (only while queued)."
          },
          "name": {
            "type": "string"
          },
          "quote_id": {
            "type": "string",
            "pattern": "^qte_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The machine quote the order settled.",
            "examples": [
              "qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3"
            ]
          },
          "count_id": {
            "type": "string",
            "pattern": "^cnt_[A-Z2-7]{20}$",
            "description": "The count the machine quote was priced from.",
            "examples": [
              "cnt_7K2PQ4MAXN3R6TBY5WDZ"
            ]
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "field_set": {
            "type": "string",
            "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
          },
          "delivery": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "api",
                "csv",
                "google_sheets"
              ]
            }
          },
          "records": {
            "type": "integer",
            "minimum": 0
          },
          "credits_charged": {
            "type": "number",
            "minimum": 0,
            "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
          },
          "credits_remaining": {
            "type": "number",
            "minimum": 0,
            "description": "The balance right after this order was charged."
          },
          "cost_gbp": {
            "type": "number",
            "minimum": 0,
            "description": "The charge in GBP excluding VAT at your plan's rate."
          },
          "licence_expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the licence ends; null for outright ownership."
          },
          "licence": {
            "$ref": "#/$defs/Licence"
          },
          "confirmed_by": {
            "$ref": "#/$defs/ConfirmedBy"
          },
          "verification": {
            "description": "The real-time check at delivery, such as 4,102 checked, 4,071 passed.",
            "type": "object",
            "properties": {
              "checked": {
                "type": "integer",
                "minimum": 0
              },
              "passed": {
                "type": "integer",
                "minimum": 0
              },
              "replaced": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "checked",
              "passed",
              "replaced"
            ]
          },
          "records_url": {
            "type": "string",
            "pattern": "^\\/v1\\/[A-Za-z0-9_\\-./]+$",
            "format": "uri-reference",
            "description": "A path on https://mydatahub.emailmovers.com starting /v1/. Resolve it against the origin (RFC 3986), not by appending it to the server URL."
          },
          "download_url": {
            "description": "302 to a single-use signed URL that lives 5 minutes.",
            "type": "string",
            "pattern": "^\\/v1\\/[A-Za-z0-9_\\-./]+$",
            "format": "uri-reference"
          },
          "receipt_url": {
            "type": "string",
            "pattern": "^\\/v1\\/[A-Za-z0-9_\\-./]+$",
            "format": "uri-reference",
            "description": "A path on https://mydatahub.emailmovers.com starting /v1/. Resolve it against the origin (RFC 3986), not by appending it to the server URL."
          },
          "validation_report": {
            "description": "Present once the order is ready.",
            "$ref": "#/$defs/ValidationReportLinks"
          },
          "buyer_kit": {
            "$ref": "#/$defs/BuyerKit"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "ready_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "failure": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "status",
          "quote_id",
          "count_id",
          "records",
          "credits_charged",
          "credits_remaining",
          "cost_gbp",
          "licence_expires_at",
          "licence",
          "confirmed_by",
          "records_url"
        ],
        "description": "The purchase and its delivery: status, records, charges, the licence, links to records, download, the validation report and the signed compliance receipt.",
        "$defs": {
          "BuyerKit": {
            "type": "object",
            "properties": {
              "draft_lia_url": {
                "type": "string",
                "format": "uri"
              },
              "first_email_wording_url": {
                "type": "string",
                "format": "uri"
              },
              "article30_stub_url": {
                "type": "string",
                "format": "uri"
              },
              "due_diligence_file_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "draft_lia_url",
              "first_email_wording_url",
              "article30_stub_url",
              "due_diligence_file_url"
            ],
            "description": "Four signed documents that help the buyer use the list lawfully."
          },
          "ConfirmedBy": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "elicitation_form",
                  "approval_url",
                  "agent_key",
                  "app"
                ],
                "description": "elicitation_form (the MCP form), approval_url (the approval page's confirmation_token), agent_key (a pre-authorised agent key within its limits) or app (a person ordering in the app itself, a first-party session; third-party OAuth clients never count)."
              },
              "key_id": {
                "description": "The agent key, for agent_key.",
                "type": "string",
                "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "examples": [
                  "key_01JB3Z4Q2V7XN3M9R6T1Y5W8ZA"
                ]
              },
              "user_id": {
                "description": "The person who confirmed.",
                "type": "string",
                "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "examples": [
                  "usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "client_id": {
                "description": "The OAuth client, such as a Client ID Metadata Document URL.",
                "type": "string"
              },
              "user_agent": {
                "description": "The calling client's User-Agent.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "mtls_certificate_fingerprint": {
                "description": "SHA-256 of the client certificate when one was presented (ChatGPT's mTLS).",
                "type": [
                  "string",
                  "null"
                ]
              },
              "web_bot_auth_signature_agent": {
                "description": "The Signature-Agent of a verified Web Bot Auth signature, when present.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "confirmed_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "method"
            ],
            "description": "Who approved the spend and from which client, recorded in the audit trail and on invoices."
          },
          "Licence": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "multi_use_12m",
                  "outright"
                ],
                "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
              },
              "reuse_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Order date plus 12 months; null for outright."
              },
              "resale_prohibited": {
                "type": "boolean"
              },
              "permitted_channels": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "email",
                    "telephone",
                    "post"
                  ]
                },
                "description": "email, telephone and post on standard terms."
              },
              "warranty_url": {
                "type": "string",
                "format": "uri"
              },
              "terms_version": {
                "type": "string",
                "description": "The version of the Data Licence and Sharing Agreement the licence is under, such as 1.0."
              },
              "terms_url": {
                "description": "Where that version of the Data Licence and Sharing Agreement is published.",
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "type",
              "reuse_until",
              "resale_prohibited",
              "permitted_channels",
              "warranty_url",
              "terms_version"
            ],
            "description": "Licence terms as data, on every quote, order, records page and receipt. Records stay usable, pushable and re-downloadable free until reuse_until."
          },
          "ValidationReportLinks": {
            "type": "object",
            "properties": {
              "pdf_url": {
                "type": "string",
                "format": "uri"
              },
              "json_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "pdf_url",
              "json_url"
            ],
            "description": "The per-order validation report: dataset version, status distribution, verification age, expected bounce band, TPS screen date, provider locations and the guarantee window."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_order",
      "title": "Get order status",
      "description": "Returns one order's status (queued, building, verifying, ready, failed or cancelled), counts, charges, licence and links to its records, download and receipt, or the recent orders when order_id is left out. Use it after create_order to wait for ready, or rely on the order.ready webhook. Free; it needs orders:read. Call fetch_order_records once the status is ready. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "order_id": {
            "description": "The order to return. Leave it out for the recent orders, newest first.",
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "building",
              "verifying",
              "ready",
              "failed",
              "cancelled"
            ],
            "description": "queued, building, verifying, ready; failed if processing failed; cancelled (only while queued)."
          },
          "limit": {
            "description": "Items per page, 1 to 100. Default 25.",
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "An opaque cursor from next_cursor. Pass it back unchanged."
          }
        },
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "anyOf": [
          {
            "$ref": "#/$defs/Order"
          },
          {
            "$ref": "#/$defs/OrderList"
          }
        ],
        "$defs": {
          "BuyerKit": {
            "type": "object",
            "properties": {
              "draft_lia_url": {
                "type": "string",
                "format": "uri"
              },
              "first_email_wording_url": {
                "type": "string",
                "format": "uri"
              },
              "article30_stub_url": {
                "type": "string",
                "format": "uri"
              },
              "due_diligence_file_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "draft_lia_url",
              "first_email_wording_url",
              "article30_stub_url",
              "due_diligence_file_url"
            ],
            "description": "Four signed documents that help the buyer use the list lawfully."
          },
          "ConfirmedBy": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "elicitation_form",
                  "approval_url",
                  "agent_key",
                  "app"
                ],
                "description": "elicitation_form (the MCP form), approval_url (the approval page's confirmation_token), agent_key (a pre-authorised agent key within its limits) or app (a person ordering in the app itself, a first-party session; third-party OAuth clients never count)."
              },
              "key_id": {
                "description": "The agent key, for agent_key.",
                "type": "string",
                "pattern": "^key_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "examples": [
                  "key_01JB3Z4Q2V7XN3M9R6T1Y5W8ZA"
                ]
              },
              "user_id": {
                "description": "The person who confirmed.",
                "type": "string",
                "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "examples": [
                  "usr_01JA0Q3V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "client_id": {
                "description": "The OAuth client, such as a Client ID Metadata Document URL.",
                "type": "string"
              },
              "user_agent": {
                "description": "The calling client's User-Agent.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "mtls_certificate_fingerprint": {
                "description": "SHA-256 of the client certificate when one was presented (ChatGPT's mTLS).",
                "type": [
                  "string",
                  "null"
                ]
              },
              "web_bot_auth_signature_agent": {
                "description": "The Signature-Agent of a verified Web Bot Auth signature, when present.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "confirmed_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "method"
            ],
            "description": "Who approved the spend and from which client, recorded in the audit trail and on invoices."
          },
          "Licence": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "multi_use_12m",
                  "outright"
                ],
                "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
              },
              "reuse_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Order date plus 12 months; null for outright."
              },
              "resale_prohibited": {
                "type": "boolean"
              },
              "permitted_channels": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "email",
                    "telephone",
                    "post"
                  ]
                },
                "description": "email, telephone and post on standard terms."
              },
              "warranty_url": {
                "type": "string",
                "format": "uri"
              },
              "terms_version": {
                "type": "string",
                "description": "The version of the Data Licence and Sharing Agreement the licence is under, such as 1.0."
              },
              "terms_url": {
                "description": "Where that version of the Data Licence and Sharing Agreement is published.",
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "type",
              "reuse_until",
              "resale_prohibited",
              "permitted_channels",
              "warranty_url",
              "terms_version"
            ],
            "description": "Licence terms as data, on every quote, order, records page and receipt. Records stay usable, pushable and re-downloadable free until reuse_until."
          },
          "Order": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
                "examples": [
                  "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "queued",
                  "building",
                  "verifying",
                  "ready",
                  "failed",
                  "cancelled"
                ],
                "description": "queued, building, verifying, ready; failed if processing failed; cancelled (only while queued)."
              },
              "name": {
                "type": "string"
              },
              "quote_id": {
                "type": "string",
                "pattern": "^qte_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The machine quote the order settled.",
                "examples": [
                  "qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3"
                ]
              },
              "count_id": {
                "type": "string",
                "pattern": "^cnt_[A-Z2-7]{20}$",
                "description": "The count the machine quote was priced from.",
                "examples": [
                  "cnt_7K2PQ4MAXN3R6TBY5WDZ"
                ]
              },
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "field_set": {
                "type": "string",
                "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
              },
              "delivery": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "api",
                    "csv",
                    "google_sheets"
                  ]
                }
              },
              "records": {
                "type": "integer",
                "minimum": 0
              },
              "credits_charged": {
                "type": "number",
                "minimum": 0,
                "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
              },
              "credits_remaining": {
                "type": "number",
                "minimum": 0,
                "description": "The balance right after this order was charged."
              },
              "cost_gbp": {
                "type": "number",
                "minimum": 0,
                "description": "The charge in GBP excluding VAT at your plan's rate."
              },
              "licence_expires_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When the licence ends; null for outright ownership."
              },
              "licence": {
                "$ref": "#/$defs/Licence"
              },
              "confirmed_by": {
                "$ref": "#/$defs/ConfirmedBy"
              },
              "verification": {
                "description": "The real-time check at delivery, such as 4,102 checked, 4,071 passed.",
                "type": "object",
                "properties": {
                  "checked": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "passed": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "replaced": {
                    "type": "integer",
                    "minimum": 0
                  }
                },
                "required": [
                  "checked",
                  "passed",
                  "replaced"
                ]
              },
              "records_url": {
                "type": "string",
                "pattern": "^\\/v1\\/[A-Za-z0-9_\\-./]+$",
                "format": "uri-reference",
                "description": "A path on https://mydatahub.emailmovers.com starting /v1/. Resolve it against the origin (RFC 3986), not by appending it to the server URL."
              },
              "download_url": {
                "description": "302 to a single-use signed URL that lives 5 minutes.",
                "type": "string",
                "pattern": "^\\/v1\\/[A-Za-z0-9_\\-./]+$",
                "format": "uri-reference"
              },
              "receipt_url": {
                "type": "string",
                "pattern": "^\\/v1\\/[A-Za-z0-9_\\-./]+$",
                "format": "uri-reference",
                "description": "A path on https://mydatahub.emailmovers.com starting /v1/. Resolve it against the origin (RFC 3986), not by appending it to the server URL."
              },
              "validation_report": {
                "description": "Present once the order is ready.",
                "$ref": "#/$defs/ValidationReportLinks"
              },
              "buyer_kit": {
                "$ref": "#/$defs/BuyerKit"
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "ready_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "failure": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "status",
              "quote_id",
              "count_id",
              "records",
              "credits_charged",
              "credits_remaining",
              "cost_gbp",
              "licence_expires_at",
              "licence",
              "confirmed_by",
              "records_url"
            ],
            "description": "The purchase and its delivery: status, records, charges, the licence, links to records, download, the validation report and the signed compliance receipt."
          },
          "OrderList": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/Order"
                }
              },
              "has_more": {
                "type": "boolean",
                "description": "Whether another page follows."
              },
              "next_cursor": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "An opaque cursor from next_cursor. Pass it back unchanged."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Pass as cursor to fetch the next page; null on the last page."
              }
            },
            "required": [
              "data",
              "has_more",
              "next_cursor"
            ],
            "description": "A page of orders, newest first."
          },
          "ValidationReportLinks": {
            "type": "object",
            "properties": {
              "pdf_url": {
                "type": "string",
                "format": "uri"
              },
              "json_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "pdf_url",
              "json_url"
            ],
            "description": "The per-order validation report: dataset version, status distribution, verification age, expected bounce band, TPS screen date, provider locations and the guarantee window."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "fetch_order_records",
      "title": "Fetch order records",
      "description": "Returns a page of an order's delivered records (50 by default, up to 100) with the licence block on every page, as JSON or, on request, as CSV. Pages stay under about 8,000 tokens, with approx_tokens on each; pass next_cursor to continue. Fetching again under licence costs 0 credits; it needs records:read. Call check_suppression before any send, and get_compliance_receipt for proof of screening. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The order whose records to fetch. It must be ready.",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          },
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "description": "An opaque cursor from next_cursor. Pass it back unchanged."
          },
          "limit": {
            "description": "Records per page, 1 to 100 over MCP so a result stays under about 8,000 tokens. Default 50.",
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "format": {
            "description": "json (default) or csv.",
            "default": "json",
            "type": "string",
            "enum": [
              "json",
              "csv"
            ]
          },
          "fields": {
            "description": "Columns to return; default the order's field set.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[a-z0-9_]+$"
            }
          }
        },
        "required": [
          "order_id"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "oneOf": [
          {
            "$ref": "#/$defs/RecordsPage"
          },
          {
            "$ref": "#/$defs/RecordsCsvPage"
          }
        ],
        "$defs": {
          "ComplianceObject": {
            "type": "object",
            "properties": {
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ],
                "description": "UK GDPR Article 6(1)(f) legitimate interests, with the LIA in lia_ref."
              },
              "lia_ref": {
                "type": "string",
                "description": "The published legitimate interests assessment."
              },
              "subscriber_class": {
                "type": "string",
                "enum": [
                  "ltd",
                  "plc",
                  "llp",
                  "scottish_partnership",
                  "public_body",
                  "charity_incorporated",
                  "sole_trader",
                  "ordinary_partnership",
                  "unknown"
                ],
                "description": "PECR subscriber class: ltd, plc, llp, scottish_partnership, public_body, charity_incorporated, sole_trader, ordinary_partnership, unknown."
              },
              "corporate_subscriber": {
                "type": "boolean",
                "description": "True for companies, LLPs, Scottish partnerships and public bodies, where the PECR regulation 22 consent rule does not apply."
              },
              "email_marketing_basis": {
                "type": "string",
                "enum": [
                  "pecr_corporate_subscriber",
                  "consent_required"
                ]
              },
              "subscriber_evidence": {
                "type": "object",
                "properties": {
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "company_type": {
                    "type": "string"
                  }
                },
                "required": [
                  "companies_house_number",
                  "company_type"
                ],
                "description": "The register entry behind subscriber_class."
              },
              "article14_status": {
                "type": "string",
                "enum": [
                  "notified",
                  "publicly_notified_disproportionate_effort",
                  "pending_within_window"
                ],
                "description": "Article 14 notice status: notified, publicly_notified_disproportionate_effort, pending_within_window."
              },
              "article14_notified_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "notice_version": {
                "type": "string",
                "description": "The privacy notice version sent."
              },
              "provenance": {
                "$ref": "#/$defs/Provenance"
              },
              "tps_ctps_status": {
                "type": "string",
                "enum": [
                  "clear",
                  "tps_registered",
                  "ctps_registered",
                  "tps_or_ctps_registered",
                  "not_screened"
                ],
                "description": "Telephone screen: clear, tps_registered, ctps_registered, tps_or_ctps_registered, not_screened. The result of the screen on tps_ctps_screened_at, valid until tps_ctps_valid_until. In a sample, an order's records (each time they are fetched, downloaded or pushed) and an enrichment, a clear number reads not_screened, with no dates, once that screen is more than 28 days before the day the record is served; a registered number stays registered."
              },
              "tps_ctps_screened_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The date of the screen the status is as of; null when not screened."
              },
              "tps_ctps_valid_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "28 days after tps_ctps_screened_at, when this screen stops being valid. Null when not screened. Screen the numbers you are supplied yourself before calling, and again every 28 days."
              },
              "suppression_status": {
                "type": "string",
                "enum": [
                  "none",
                  "objected_to_emailmovers",
                  "objected_to_licensee",
                  "deceased",
                  "left_company"
                ]
              },
              "record_age_days": {
                "type": "integer",
                "minimum": 0,
                "description": "Days since the record was compiled."
              },
              "attribution": {
                "description": "The OGL v3.0 attribution for Companies House company data. Officer names are personal data outside the OGL, so they carry article14_status instead.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "lawful_basis",
              "lia_ref",
              "subscriber_class",
              "corporate_subscriber",
              "email_marketing_basis",
              "subscriber_evidence",
              "article14_status",
              "article14_notified_at",
              "notice_version",
              "provenance",
              "tps_ctps_status",
              "tps_ctps_screened_at",
              "tps_ctps_valid_until",
              "suppression_status",
              "record_age_days",
              "attribution"
            ],
            "description": "Carried by every preview row, order record, lookup and enrichment, and repeated as CSV columns and as the MyDataHub property group on CRM push.",
            "examples": [
              {
                "lawful_basis": "legitimate_interests_art6_1_f",
                "lia_ref": "EM-LIA-2026-03",
                "subscriber_class": "ltd",
                "corporate_subscriber": true,
                "email_marketing_basis": "pecr_corporate_subscriber",
                "subscriber_evidence": {
                  "companies_house_number": "05046417",
                  "company_type": "ltd"
                },
                "article14_status": "notified",
                "article14_notified_at": "2026-06-14",
                "notice_version": "2026-02",
                "provenance": {
                  "company": {
                    "source": "companies_house",
                    "as_of": "2026-09-21"
                  },
                  "contact": {
                    "source": "emailmovers_research",
                    "compiled_at": "2026-05-02",
                    "last_verified_at": "2026-08-30",
                    "method": "telephone"
                  },
                  "email": {
                    "verified_at": "2026-09-10",
                    "result": "ok",
                    "provider_location": "EU"
                  }
                },
                "tps_ctps_status": "clear",
                "tps_ctps_screened_at": "2026-09-12",
                "tps_ctps_valid_until": "2026-10-10",
                "suppression_status": "none",
                "record_age_days": 147,
                "attribution": "Contains public sector information licensed under the Open Government Licence v3.0"
              }
            ]
          },
          "ContactRecord": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The record id, pushed to CRMs as mydatahub_record_id.",
                "examples": [
                  "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "contact": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "title_family": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "job_function": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "job_level_rank": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 13
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Rank on the 13-rank ladder, 1 (Owner) the most senior to 13 (Volunteer); null when the level is not known."
                  },
                  "job_level": {
                    "description": "The level, such as Director; null when the level is not known.",
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "first_name",
                  "last_name",
                  "title",
                  "title_family",
                  "job_function",
                  "job_level_rank",
                  "job_level"
                ]
              },
              "email": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "address": {
                        "type": "string",
                        "format": "email"
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "named",
                          "generic_local_part",
                          "generic_domain"
                        ]
                      },
                      "deliverability_score": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "verified_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "result": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "catch_all",
                          "unknown",
                          "invalid",
                          "disposable"
                        ]
                      }
                    },
                    "required": [
                      "address",
                      "type",
                      "deliverability_score",
                      "verified_at",
                      "result"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "phone": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "e164": {
                        "type": "string",
                        "pattern": "^\\+[1-9][0-9]{7,14}$"
                      },
                      "line_type": {
                        "type": "string",
                        "enum": [
                          "landline",
                          "mobile",
                          "voip",
                          "unknown"
                        ]
                      },
                      "tps_ctps_status": {
                        "type": "string",
                        "enum": [
                          "clear",
                          "tps_registered",
                          "ctps_registered",
                          "tps_or_ctps_registered",
                          "not_screened"
                        ]
                      },
                      "screened_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "e164",
                      "line_type",
                      "tps_ctps_status",
                      "screened_at"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Present when the field set includes telephone and a number is held."
              },
              "company": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string"
                  },
                  "type": {
                    "type": "string"
                  },
                  "subscriber_class": {
                    "type": "string",
                    "enum": [
                      "ltd",
                      "plc",
                      "llp",
                      "scottish_partnership",
                      "public_body",
                      "charity_incorporated",
                      "sole_trader",
                      "ordinary_partnership",
                      "unknown"
                    ]
                  },
                  "sic_2007": {
                    "type": "array",
                    "items": {
                      "$ref": "#/$defs/SicCode"
                    }
                  },
                  "employee_band": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "turnover_band": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "website_domain": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "name",
                  "companies_house_number",
                  "status",
                  "type",
                  "subscriber_class",
                  "sic_2007",
                  "employee_band",
                  "turnover_band",
                  "website_domain"
                ]
              },
              "site": {
                "type": "object",
                "properties": {
                  "address_lines": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "town": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "county": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "postcode": {
                    "type": "string"
                  },
                  "region": {
                    "type": "string"
                  }
                },
                "required": [
                  "address_lines",
                  "town",
                  "county",
                  "postcode",
                  "region"
                ]
              },
              "compliance": {
                "$ref": "#/$defs/ComplianceObject"
              },
              "licence_expires_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "dataset_version",
              "contact",
              "email",
              "phone",
              "company",
              "site",
              "compliance",
              "licence_expires_at"
            ],
            "description": "One complete UK record: named email, telephone where held, postal address and company fields with Companies House number and SIC, plus the compliance object."
          },
          "Licence": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "multi_use_12m",
                  "outright"
                ],
                "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
              },
              "reuse_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Order date plus 12 months; null for outright."
              },
              "resale_prohibited": {
                "type": "boolean"
              },
              "permitted_channels": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "email",
                    "telephone",
                    "post"
                  ]
                },
                "description": "email, telephone and post on standard terms."
              },
              "warranty_url": {
                "type": "string",
                "format": "uri"
              },
              "terms_version": {
                "type": "string",
                "description": "The version of the Data Licence and Sharing Agreement the licence is under, such as 1.0."
              },
              "terms_url": {
                "description": "Where that version of the Data Licence and Sharing Agreement is published.",
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "type",
              "reuse_until",
              "resale_prohibited",
              "permitted_channels",
              "warranty_url",
              "terms_version"
            ],
            "description": "Licence terms as data, on every quote, order, records page and receipt. Records stay usable, pushable and re-downloadable free until reuse_until."
          },
          "Provenance": {
            "type": "object",
            "properties": {
              "company": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": [
                      "emailmovers_research",
                      "companies_house",
                      "onspd",
                      "ukbizdirectory",
                      "partner_rampedup"
                    ]
                  },
                  "as_of": {
                    "type": "string",
                    "format": "date"
                  }
                },
                "required": [
                  "source",
                  "as_of"
                ],
                "description": "Where the company facts came from and the snapshot date."
              },
              "contact": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "source": {
                        "type": "string",
                        "enum": [
                          "emailmovers_research",
                          "companies_house",
                          "onspd",
                          "ukbizdirectory",
                          "partner_rampedup"
                        ]
                      },
                      "compiled_at": {
                        "type": "string",
                        "format": "date"
                      },
                      "last_verified_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "method": {
                        "type": "string",
                        "enum": [
                          "telephone",
                          "web",
                          "register"
                        ]
                      }
                    },
                    "required": [
                      "source",
                      "compiled_at",
                      "last_verified_at",
                      "method"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Who compiled the contact, when, and how it was last confirmed."
              },
              "email": {
                "description": "The latest email verification: date, provider result and location.",
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "verified_at": {
                        "type": "string",
                        "format": "date"
                      },
                      "result": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "catch_all",
                          "unknown",
                          "invalid",
                          "disposable"
                        ]
                      },
                      "provider_location": {
                        "type": "string",
                        "enum": [
                          "UK",
                          "EU",
                          "US"
                        ]
                      }
                    },
                    "required": [
                      "verified_at",
                      "result",
                      "provider_location"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "company",
              "contact"
            ],
            "description": "Source per entity, answering the ICO questions who compiled it and where from."
          },
          "RecordsCsvPage": {
            "type": "object",
            "properties": {
              "order_id": {
                "type": "string",
                "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
                "examples": [
                  "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
                ]
              },
              "format": {
                "type": "string",
                "const": "csv"
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
                },
                "description": "The columns, in the order of the header."
              },
              "rows": {
                "type": "integer",
                "minimum": 0,
                "description": "Records in this page, not counting the header."
              },
              "csv": {
                "type": "string",
                "description": "The page as CSV with a header row and compliance fields as columns: the text GET /v1/orders/{id}/records returns with format=csv."
              },
              "has_more": {
                "type": "boolean"
              },
              "next_cursor": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "An opaque cursor from next_cursor. Pass it back unchanged."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "remaining": {
                "type": "integer",
                "minimum": 0,
                "description": "Records after this page."
              },
              "approx_tokens": {
                "type": "integer",
                "minimum": 0
              },
              "licence": {
                "$ref": "#/$defs/Licence"
              }
            },
            "required": [
              "order_id",
              "format",
              "fields",
              "rows",
              "csv",
              "has_more",
              "next_cursor",
              "remaining",
              "licence"
            ],
            "description": "A page of delivered records as CSV text with the licence block, for fetch_order_records with format csv."
          },
          "RecordsPage": {
            "type": "object",
            "properties": {
              "order_id": {
                "type": "string",
                "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
                "examples": [
                  "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
                ]
              },
              "format": {
                "type": "string",
                "const": "json"
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[a-z0-9]+(_[a-z0-9]+)*$"
                },
                "description": "The field set's columns in this page."
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/ContactRecord"
                }
              },
              "has_more": {
                "type": "boolean"
              },
              "next_cursor": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "An opaque cursor from next_cursor. Pass it back unchanged."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "remaining": {
                "type": "integer",
                "minimum": 0,
                "description": "Records after this page."
              },
              "approx_tokens": {
                "description": "A rough token size of this page; pages stay under about 8,000 tokens.",
                "type": "integer",
                "minimum": 0
              },
              "licence": {
                "$ref": "#/$defs/Licence"
              }
            },
            "required": [
              "order_id",
              "format",
              "fields",
              "data",
              "has_more",
              "next_cursor",
              "remaining",
              "licence"
            ],
            "description": "A page of delivered records with the licence block. Re-fetching records under licence costs 0 credits."
          },
          "SicCode": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "label": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "label"
            ],
            "description": "A SIC 2007 code and its label, such as 25620 Machining."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "push_to_crm",
      "title": "Push an order to a CRM",
      "description": "Pushes an order's records to a connected CRM such as HubSpot or Salesforce, keyed on mydatahub_record_id, as record operations only: nothing is ever sent to the contacts. dry_run defaults to true and reports what would be created, updated or skipped; a live push needs the user's confirmation or an agent key allowed push_to_crm on that connection, or it returns confirmation-required. Free; it needs pushes:write and a connection made in the app. Show the dry run to the user before a live push. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The order whose records to push.",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          },
          "connection_id": {
            "type": "string",
            "pattern": "^conn_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a CRM connection id: conn_ followed by a 26 character ULID in upper case Crockford base32, such as conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G.",
            "examples": [
              "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G"
            ]
          },
          "dry_run": {
            "description": "Default true: report what would change without writing. A live push needs approval: a person's confirmation, or an agent key allowed push_to_crm on this connection.",
            "default": true,
            "type": "boolean"
          },
          "update_existing": {
            "description": "Update records already in the CRM, matched on mydatahub_record_id. Default true.",
            "default": true,
            "type": "boolean"
          },
          "confirmation_token": {
            "type": "string",
            "minLength": 16,
            "maxLength": 2000,
            "description": "The token the approval page on mydatahub.emailmovers.com returns once the signed-in person approves. It is bound to that person (their sub), this spend (the machine quote_id, or the enrichment or push) and an expiry no later than the quote's, and it is redeemable once."
          }
        },
        "required": [
          "order_id",
          "connection_id"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^psh_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a CRM push id: psh_ followed by a 26 character ULID in upper case Crockford base32, such as psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5.",
            "examples": [
              "psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5"
            ]
          },
          "order_id": {
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          },
          "connection_id": {
            "type": "string",
            "pattern": "^conn_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a CRM connection id: conn_ followed by a 26 character ULID in upper case Crockford base32, such as conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G.",
            "examples": [
              "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G"
            ]
          },
          "dry_run": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "completed",
              "partial",
              "failed"
            ]
          },
          "summary": {
            "type": "object",
            "properties": {
              "to_create": {
                "type": "integer",
                "minimum": 0
              },
              "to_update": {
                "type": "integer",
                "minimum": 0
              },
              "already_present": {
                "type": "integer",
                "minimum": 0
              },
              "skipped": {
                "type": "integer",
                "minimum": 0
              },
              "failed": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "to_create",
              "to_update",
              "already_present",
              "skipped",
              "failed"
            ]
          },
          "property_group": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "mydatahub_record_id",
                "licence_expires_at",
                "lawful_basis",
                "article14_status",
                "tps_ctps_screened_at",
                "subscriber_class",
                "suppression_status",
                "compliance_receipt_url"
              ]
            },
            "description": "The MyDataHub property group written on every record (CrmPropertyGroup)."
          },
          "sample": {
            "anyOf": [
              {
                "$ref": "#/$defs/CrmPropertyGroup"
              },
              {
                "type": "null"
              }
            ],
            "description": "On a dry run: the property group the first record would carry."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "record_id": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              },
              "required": [
                "record_id",
                "message"
              ]
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "order_id",
          "connection_id",
          "dry_run",
          "status",
          "summary",
          "property_group",
          "sample",
          "errors",
          "created_at",
          "completed_at"
        ],
        "description": "A CRM push or its dry run, such as 4,102 to create and 0 already in your HubSpot.",
        "$defs": {
          "CrmPropertyGroup": {
            "type": "object",
            "properties": {
              "mydatahub_record_id": {
                "type": "string",
                "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The record id: a Salesforce External ID, a HubSpot unique property, a Pipedrive custom field.",
                "examples": [
                  "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "licence_expires_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ]
              },
              "article14_status": {
                "type": "string",
                "enum": [
                  "notified",
                  "publicly_notified_disproportionate_effort",
                  "pending_within_window"
                ]
              },
              "tps_ctps_screened_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "subscriber_class": {
                "type": "string",
                "enum": [
                  "ltd",
                  "plc",
                  "llp",
                  "scottish_partnership",
                  "public_body",
                  "charity_incorporated",
                  "sole_trader",
                  "ordinary_partnership",
                  "unknown"
                ]
              },
              "suppression_status": {
                "type": "string",
                "enum": [
                  "none",
                  "objected_to_emailmovers",
                  "objected_to_licensee",
                  "deceased",
                  "left_company"
                ],
                "description": "Kept current: an objection reaching the record updates it in the CRM."
              },
              "compliance_receipt_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "mydatahub_record_id",
              "licence_expires_at",
              "lawful_basis",
              "article14_status",
              "tps_ctps_screened_at",
              "subscriber_class",
              "suppression_status",
              "compliance_receipt_url"
            ],
            "description": "The MyDataHub property group written on every pushed record, so licence expiry and suppression are enforced in the CRM by field flags."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "lookup_company",
      "title": "Look up a company",
      "description": "Looks up one company by Companies House number, domain or name and returns its Companies House fields and compliance facts, and for a signed-in caller the contacts held there by job level. It returns no contact details: use enrich_contact for one known person, or count_audience for everyone at the company. Free and needs no account, though the contacts held are a single company count that needs an account (null when signed out). Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "company_number": {
            "type": "string",
            "pattern": "^[A-Z0-9]{8}$",
            "description": "Eight characters in upper case, such as 05046417 or SC123456."
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200
          },
          "town": {
            "description": "Narrows a name search.",
            "type": "string",
            "maxLength": 100
          }
        },
        "additionalProperties": false,
        "description": "A company by exactly one of number, domain or name.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "company_number": true
            },
            "required": [
              "company_number"
            ]
          },
          {
            "type": "object",
            "properties": {
              "domain": true
            },
            "required": [
              "domain"
            ]
          },
          {
            "type": "object",
            "properties": {
              "name": true
            },
            "required": [
              "name"
            ]
          }
        ]
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "match_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "dataset_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
            "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
            "examples": [
              "2026-W39"
            ]
          },
          "company": {
            "type": "object",
            "properties": {
              "companies_house_number": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "subscriber_class": {
                "type": "string",
                "enum": [
                  "ltd",
                  "plc",
                  "llp",
                  "scottish_partnership",
                  "public_body",
                  "charity_incorporated",
                  "sole_trader",
                  "ordinary_partnership",
                  "unknown"
                ]
              },
              "incorporation_date": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "sic_2007": {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/SicCode"
                }
              },
              "employee_band": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "turnover_band": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "website_domain": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "registered_office": {
                "type": "object",
                "properties": {
                  "town": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "postcode": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "town",
                  "postcode"
                ]
              }
            },
            "required": [
              "companies_house_number",
              "name",
              "status",
              "type",
              "subscriber_class",
              "incorporation_date",
              "sic_2007",
              "employee_band",
              "turnover_band",
              "website_domain",
              "registered_office"
            ]
          },
          "contacts_held": {
            "anyOf": [
              {
                "$ref": "#/$defs/CellCount"
              },
              {
                "type": "null"
              }
            ],
            "description": "Contacts we hold at the company: a single-company count, so signed-in callers only (null otherwise) and logged. Trial callers see it rounded."
          },
          "contacts_by_level": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/LevelCount"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "The same count by job level, most senior first, with Level not known last; null when signed out."
          },
          "disclosure": {
            "$ref": "#/$defs/Disclosure"
          },
          "compliance": {
            "$ref": "#/$defs/CompanyCompliance"
          },
          "credits_charged": {
            "type": "number",
            "const": 0
          }
        },
        "required": [
          "match_confidence",
          "dataset_version",
          "company",
          "contacts_held",
          "contacts_by_level",
          "disclosure",
          "compliance",
          "credits_charged"
        ],
        "description": "Companies House fields for one company and, for signed-in callers, the contacts held there. No contact details.",
        "$defs": {
          "CellCount": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "const": "under 10"
              },
              {
                "type": "string",
                "const": "suppressed"
              }
            ],
            "description": "A whole number; \"under 10\" when disclosure control withholds a small cell; or \"suppressed\" when secondary suppression hides a cell of 10 or more in a cross-tab or breakdown, so totals cannot be differenced. Anonymous and trial callers see cells rounded to the nearest 5.",
            "examples": [
              4120,
              "under 10",
              "suppressed"
            ]
          },
          "CompanyCompliance": {
            "type": "object",
            "properties": {
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ]
              },
              "subscriber_class": {
                "type": "string",
                "enum": [
                  "ltd",
                  "plc",
                  "llp",
                  "scottish_partnership",
                  "public_body",
                  "charity_incorporated",
                  "sole_trader",
                  "ordinary_partnership",
                  "unknown"
                ]
              },
              "corporate_subscriber": {
                "type": "boolean"
              },
              "email_marketing_basis": {
                "type": "string",
                "enum": [
                  "pecr_corporate_subscriber",
                  "consent_required"
                ]
              },
              "subscriber_evidence": {
                "type": "object",
                "properties": {
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "company_type": {
                    "type": "string"
                  }
                },
                "required": [
                  "companies_house_number",
                  "company_type"
                ]
              },
              "provenance": {
                "type": "object",
                "properties": {
                  "company": {
                    "type": "object",
                    "properties": {
                      "source": {
                        "type": "string",
                        "enum": [
                          "emailmovers_research",
                          "companies_house",
                          "onspd",
                          "ukbizdirectory",
                          "partner_rampedup"
                        ]
                      },
                      "as_of": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "required": [
                      "source",
                      "as_of"
                    ]
                  }
                },
                "required": [
                  "company"
                ]
              },
              "attribution": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "lawful_basis",
              "subscriber_class",
              "corporate_subscriber",
              "email_marketing_basis",
              "subscriber_evidence",
              "provenance",
              "attribution"
            ],
            "description": "The company facts of the compliance object, for results with no contact."
          },
          "Disclosure": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string",
                "enum": [
                  "exact",
                  "rounded"
                ],
                "description": "exact for authenticated paid callers; rounded for anonymous and trial callers, whose counts under 100 and every cell are rounded to the nearest 5."
              },
              "rounded_to": {
                "anyOf": [
                  {
                    "type": "integer",
                    "exclusiveMinimum": 0
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "5 when numbers are rounded; null when they are exact."
              },
              "secondary_suppression": {
                "type": "boolean",
                "description": "True when cross-tab or breakdown cells of 10 or more were hidden as \"suppressed\" so totals cannot be differenced."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "level",
              "rounded_to",
              "secondary_suppression",
              "notes"
            ],
            "description": "Whether these numbers are exact or protected: \"under 10\" cells, rounding to 5 and secondary suppression for anonymous and trial callers."
          },
          "LevelCount": {
            "type": "object",
            "properties": {
              "level": {
                "type": "string"
              },
              "contacts": {
                "$ref": "#/$defs/CellCount"
              }
            },
            "required": [
              "level",
              "contacts"
            ],
            "description": "Contacts at one job level."
          },
          "SicCode": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "label": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "label"
            ],
            "description": "A SIC 2007 code and its label, such as 25620 Machining."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "enrich_contact",
      "title": "Enrich a contact (spends credits)",
      "description": "Returns the full record for one known person, matched by email or by name with a company name, number or domain. It spends 1 credit only on a confident match, and 0 on no match or when you already hold the record under licence, so a repeat never charges twice. Like create_order it needs the user's confirmation (a form, or the confirmation_token from an approval_url) or an agent key whose allowed_tools include enrich_contact within its per-order cap and monthly budget; otherwise nothing is charged and it returns confirmation-required or agent-budget-exceeded. It needs enrich:write; use it for a single named person, and the result gives credits_charged and the balance left. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "first_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "last_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "company_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "company_number": {
            "type": "string",
            "pattern": "^[A-Z0-9]{8}$",
            "description": "Eight characters in upper case, such as 05046417 or SC123456."
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "confirmation_token": {
            "type": "string",
            "minLength": 16,
            "maxLength": 2000,
            "description": "The token the approval page on mydatahub.emailmovers.com returns once the signed-in person approves. It is bound to that person (their sub), this spend (the machine quote_id, or the enrichment or push) and an expiry no later than the quote's, and it is redeemable once."
          }
        },
        "additionalProperties": false,
        "description": "One known person to match. Send email, or first_name and last_name with company_name, company_number or domain.",
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "email": true
            },
            "required": [
              "email"
            ]
          },
          {
            "type": "object",
            "properties": {
              "first_name": true,
              "last_name": true
            },
            "required": [
              "first_name",
              "last_name"
            ],
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "company_name": true
                },
                "required": [
                  "company_name"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "company_number": true
                },
                "required": [
                  "company_number"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "domain": true
                },
                "required": [
                  "domain"
                ]
              }
            ]
          }
        ]
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "matched": {
            "type": "boolean"
          },
          "match_confidence": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "already_licensed": {
            "type": "boolean",
            "description": "True when you already hold the record, so it costs 0."
          },
          "record": {
            "anyOf": [
              {
                "$ref": "#/$defs/ContactRecord"
              },
              {
                "type": "null"
              }
            ]
          },
          "credits_charged": {
            "type": "number",
            "minimum": 0,
            "description": "1 on a confident match, otherwise 0."
          },
          "credits_remaining": {
            "type": "number",
            "minimum": 0,
            "description": "Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed)."
          },
          "cost_gbp": {
            "type": "number",
            "minimum": 0,
            "description": "Pounds sterling excluding VAT, to two decimal places."
          },
          "licence_expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "matched",
          "match_confidence",
          "already_licensed",
          "record",
          "credits_charged",
          "credits_remaining",
          "cost_gbp",
          "licence_expires_at"
        ],
        "description": "The full record for a confident match, or no match at no charge.",
        "$defs": {
          "ComplianceObject": {
            "type": "object",
            "properties": {
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ],
                "description": "UK GDPR Article 6(1)(f) legitimate interests, with the LIA in lia_ref."
              },
              "lia_ref": {
                "type": "string",
                "description": "The published legitimate interests assessment."
              },
              "subscriber_class": {
                "type": "string",
                "enum": [
                  "ltd",
                  "plc",
                  "llp",
                  "scottish_partnership",
                  "public_body",
                  "charity_incorporated",
                  "sole_trader",
                  "ordinary_partnership",
                  "unknown"
                ],
                "description": "PECR subscriber class: ltd, plc, llp, scottish_partnership, public_body, charity_incorporated, sole_trader, ordinary_partnership, unknown."
              },
              "corporate_subscriber": {
                "type": "boolean",
                "description": "True for companies, LLPs, Scottish partnerships and public bodies, where the PECR regulation 22 consent rule does not apply."
              },
              "email_marketing_basis": {
                "type": "string",
                "enum": [
                  "pecr_corporate_subscriber",
                  "consent_required"
                ]
              },
              "subscriber_evidence": {
                "type": "object",
                "properties": {
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "company_type": {
                    "type": "string"
                  }
                },
                "required": [
                  "companies_house_number",
                  "company_type"
                ],
                "description": "The register entry behind subscriber_class."
              },
              "article14_status": {
                "type": "string",
                "enum": [
                  "notified",
                  "publicly_notified_disproportionate_effort",
                  "pending_within_window"
                ],
                "description": "Article 14 notice status: notified, publicly_notified_disproportionate_effort, pending_within_window."
              },
              "article14_notified_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "notice_version": {
                "type": "string",
                "description": "The privacy notice version sent."
              },
              "provenance": {
                "$ref": "#/$defs/Provenance"
              },
              "tps_ctps_status": {
                "type": "string",
                "enum": [
                  "clear",
                  "tps_registered",
                  "ctps_registered",
                  "tps_or_ctps_registered",
                  "not_screened"
                ],
                "description": "Telephone screen: clear, tps_registered, ctps_registered, tps_or_ctps_registered, not_screened. The result of the screen on tps_ctps_screened_at, valid until tps_ctps_valid_until. In a sample, an order's records (each time they are fetched, downloaded or pushed) and an enrichment, a clear number reads not_screened, with no dates, once that screen is more than 28 days before the day the record is served; a registered number stays registered."
              },
              "tps_ctps_screened_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The date of the screen the status is as of; null when not screened."
              },
              "tps_ctps_valid_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "28 days after tps_ctps_screened_at, when this screen stops being valid. Null when not screened. Screen the numbers you are supplied yourself before calling, and again every 28 days."
              },
              "suppression_status": {
                "type": "string",
                "enum": [
                  "none",
                  "objected_to_emailmovers",
                  "objected_to_licensee",
                  "deceased",
                  "left_company"
                ]
              },
              "record_age_days": {
                "type": "integer",
                "minimum": 0,
                "description": "Days since the record was compiled."
              },
              "attribution": {
                "description": "The OGL v3.0 attribution for Companies House company data. Officer names are personal data outside the OGL, so they carry article14_status instead.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "lawful_basis",
              "lia_ref",
              "subscriber_class",
              "corporate_subscriber",
              "email_marketing_basis",
              "subscriber_evidence",
              "article14_status",
              "article14_notified_at",
              "notice_version",
              "provenance",
              "tps_ctps_status",
              "tps_ctps_screened_at",
              "tps_ctps_valid_until",
              "suppression_status",
              "record_age_days",
              "attribution"
            ],
            "description": "Carried by every preview row, order record, lookup and enrichment, and repeated as CSV columns and as the MyDataHub property group on CRM push.",
            "examples": [
              {
                "lawful_basis": "legitimate_interests_art6_1_f",
                "lia_ref": "EM-LIA-2026-03",
                "subscriber_class": "ltd",
                "corporate_subscriber": true,
                "email_marketing_basis": "pecr_corporate_subscriber",
                "subscriber_evidence": {
                  "companies_house_number": "05046417",
                  "company_type": "ltd"
                },
                "article14_status": "notified",
                "article14_notified_at": "2026-06-14",
                "notice_version": "2026-02",
                "provenance": {
                  "company": {
                    "source": "companies_house",
                    "as_of": "2026-09-21"
                  },
                  "contact": {
                    "source": "emailmovers_research",
                    "compiled_at": "2026-05-02",
                    "last_verified_at": "2026-08-30",
                    "method": "telephone"
                  },
                  "email": {
                    "verified_at": "2026-09-10",
                    "result": "ok",
                    "provider_location": "EU"
                  }
                },
                "tps_ctps_status": "clear",
                "tps_ctps_screened_at": "2026-09-12",
                "tps_ctps_valid_until": "2026-10-10",
                "suppression_status": "none",
                "record_age_days": 147,
                "attribution": "Contains public sector information licensed under the Open Government Licence v3.0"
              }
            ]
          },
          "ContactRecord": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "The record id, pushed to CRMs as mydatahub_record_id.",
                "examples": [
                  "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "contact": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "title_family": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "job_function": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "job_level_rank": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 13
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Rank on the 13-rank ladder, 1 (Owner) the most senior to 13 (Volunteer); null when the level is not known."
                  },
                  "job_level": {
                    "description": "The level, such as Director; null when the level is not known.",
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "first_name",
                  "last_name",
                  "title",
                  "title_family",
                  "job_function",
                  "job_level_rank",
                  "job_level"
                ]
              },
              "email": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "address": {
                        "type": "string",
                        "format": "email"
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "named",
                          "generic_local_part",
                          "generic_domain"
                        ]
                      },
                      "deliverability_score": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100
                      },
                      "verified_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "result": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "catch_all",
                          "unknown",
                          "invalid",
                          "disposable"
                        ]
                      }
                    },
                    "required": [
                      "address",
                      "type",
                      "deliverability_score",
                      "verified_at",
                      "result"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "phone": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "e164": {
                        "type": "string",
                        "pattern": "^\\+[1-9][0-9]{7,14}$"
                      },
                      "line_type": {
                        "type": "string",
                        "enum": [
                          "landline",
                          "mobile",
                          "voip",
                          "unknown"
                        ]
                      },
                      "tps_ctps_status": {
                        "type": "string",
                        "enum": [
                          "clear",
                          "tps_registered",
                          "ctps_registered",
                          "tps_or_ctps_registered",
                          "not_screened"
                        ]
                      },
                      "screened_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "e164",
                      "line_type",
                      "tps_ctps_status",
                      "screened_at"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Present when the field set includes telephone and a number is held."
              },
              "company": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "companies_house_number": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string"
                  },
                  "type": {
                    "type": "string"
                  },
                  "subscriber_class": {
                    "type": "string",
                    "enum": [
                      "ltd",
                      "plc",
                      "llp",
                      "scottish_partnership",
                      "public_body",
                      "charity_incorporated",
                      "sole_trader",
                      "ordinary_partnership",
                      "unknown"
                    ]
                  },
                  "sic_2007": {
                    "type": "array",
                    "items": {
                      "$ref": "#/$defs/SicCode"
                    }
                  },
                  "employee_band": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "turnover_band": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "website_domain": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "name",
                  "companies_house_number",
                  "status",
                  "type",
                  "subscriber_class",
                  "sic_2007",
                  "employee_band",
                  "turnover_band",
                  "website_domain"
                ]
              },
              "site": {
                "type": "object",
                "properties": {
                  "address_lines": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "town": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "county": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "postcode": {
                    "type": "string"
                  },
                  "region": {
                    "type": "string"
                  }
                },
                "required": [
                  "address_lines",
                  "town",
                  "county",
                  "postcode",
                  "region"
                ]
              },
              "compliance": {
                "$ref": "#/$defs/ComplianceObject"
              },
              "licence_expires_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "dataset_version",
              "contact",
              "email",
              "phone",
              "company",
              "site",
              "compliance",
              "licence_expires_at"
            ],
            "description": "One complete UK record: named email, telephone where held, postal address and company fields with Companies House number and SIC, plus the compliance object."
          },
          "Provenance": {
            "type": "object",
            "properties": {
              "company": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": [
                      "emailmovers_research",
                      "companies_house",
                      "onspd",
                      "ukbizdirectory",
                      "partner_rampedup"
                    ]
                  },
                  "as_of": {
                    "type": "string",
                    "format": "date"
                  }
                },
                "required": [
                  "source",
                  "as_of"
                ],
                "description": "Where the company facts came from and the snapshot date."
              },
              "contact": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "source": {
                        "type": "string",
                        "enum": [
                          "emailmovers_research",
                          "companies_house",
                          "onspd",
                          "ukbizdirectory",
                          "partner_rampedup"
                        ]
                      },
                      "compiled_at": {
                        "type": "string",
                        "format": "date"
                      },
                      "last_verified_at": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "method": {
                        "type": "string",
                        "enum": [
                          "telephone",
                          "web",
                          "register"
                        ]
                      }
                    },
                    "required": [
                      "source",
                      "compiled_at",
                      "last_verified_at",
                      "method"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Who compiled the contact, when, and how it was last confirmed."
              },
              "email": {
                "description": "The latest email verification: date, provider result and location.",
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "verified_at": {
                        "type": "string",
                        "format": "date"
                      },
                      "result": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "catch_all",
                          "unknown",
                          "invalid",
                          "disposable"
                        ]
                      },
                      "provider_location": {
                        "type": "string",
                        "enum": [
                          "UK",
                          "EU",
                          "US"
                        ]
                      }
                    },
                    "required": [
                      "verified_at",
                      "result",
                      "provider_location"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "company",
              "contact"
            ],
            "description": "Source per entity, answering the ICO questions who compiled it and where from."
          },
          "SicCode": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "label": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "label"
            ],
            "description": "A SIC 2007 code and its label, such as 25620 Machining."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "check_suppression",
      "title": "Check suppression",
      "description": "Checks the suppression status of up to 1,000 delivered records by record id, as of now, and names the lists that suppress each. Use it before every send, because objections reach records after delivery. Free; it needs suppressions:read. Leave suppressed records out of the send, and call report_objection when someone objects. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "record_ids": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
              "description": "Format: a contact id: contact_ followed by a 26 character ULID in upper case Crockford base32, such as contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8.",
              "examples": [
                "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
              ]
            }
          }
        },
        "required": [
          "record_ids"
        ],
        "additionalProperties": false,
        "description": "Records to check before a send."
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "record_id": {
                  "type": "string",
                  "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                  "description": "Format: a contact id: contact_ followed by a 26 character ULID in upper case Crockford base32, such as contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8.",
                  "examples": [
                    "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
                  ]
                },
                "suppressed": {
                  "type": "boolean"
                },
                "suppression_status": {
                  "type": "string",
                  "enum": [
                    "none",
                    "objected_to_emailmovers",
                    "objected_to_licensee",
                    "deceased",
                    "left_company"
                  ]
                },
                "list_ids": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                    "description": "Format: a suppression list id: sup_ followed by a 26 character ULID in upper case Crockford base32, such as sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA.",
                    "examples": [
                      "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
                    ]
                  }
                }
              },
              "required": [
                "record_id",
                "suppressed",
                "suppression_status",
                "list_ids"
              ]
            }
          }
        },
        "required": [
          "checked_at",
          "results"
        ],
        "description": "Suppression status per record, as of now."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "report_objection",
      "title": "Report an objection",
      "description": "Records an objection to direct marketing for one record, by record id or email hash. Scope licensee suppresses it for your organisation at once; scope emailmovers suppresses it database-wide within one working day and tells every licensee holding it. Free; it needs suppressions:write, and repeating the same objection returns the same suppression. Call it whenever a contact objects, in any channel. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "record_id": {
            "type": "string",
            "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a contact id: contact_ followed by a 26 character ULID in upper case Crockford base32, such as contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8.",
            "examples": [
              "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
            ]
          },
          "email_sha256": {
            "description": "SHA-256 of the trimmed, lower cased address, when the record id is not known.",
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "channel": {
            "type": "string",
            "enum": [
              "email",
              "telephone",
              "post",
              "web_form",
              "other"
            ]
          },
          "received_at": {
            "type": "string",
            "format": "date-time",
            "description": "RFC 3339 date and time, with Z or an offset such as +01:00."
          },
          "scope": {
            "type": "string",
            "enum": [
              "licensee",
              "emailmovers"
            ],
            "description": "licensee suppresses the record for your organisation at once; emailmovers suppresses it database-wide within one working day."
          },
          "note": {
            "type": "string",
            "maxLength": 2000
          }
        },
        "required": [
          "channel",
          "received_at",
          "scope"
        ],
        "additionalProperties": false,
        "description": "An objection to direct marketing, to record and propagate: exactly one of record_id or email_sha256.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "record_id": true
            },
            "required": [
              "record_id"
            ]
          },
          {
            "type": "object",
            "properties": {
              "email_sha256": true
            },
            "required": [
              "email_sha256"
            ]
          }
        ]
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "suppression_id": {
            "type": "string",
            "pattern": "^sup_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The list the record now sits on.",
            "examples": [
              "sup_01JB4H7Q2V7XN3M9R6T1Y5W8ZA"
            ]
          },
          "record_id": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^contact_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a contact id: contact_ followed by a 26 character ULID in upper case Crockford base32, such as contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8.",
                "examples": [
                  "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "licensee",
              "emailmovers"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "suppressed",
              "pending"
            ],
            "description": "suppressed now, or pending until the database-wide overlay applies."
          },
          "suppressed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "effective_by": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "suppression_id",
          "record_id",
          "scope",
          "status",
          "suppressed_at",
          "effective_by"
        ],
        "description": "The suppression an objection created. Database-wide objections reach every licensee holding the record through the suppression.created webhook."
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_compliance_receipt",
      "title": "Get a compliance receipt",
      "description": "Returns an order's signed compliance receipt: an ES256 JWS with its decoded claims and a PDF link, covering records delivered, suppression removals, subscriber classes, TPS screening, Article 14 status, the licence and the file hash. Use it to prove to the user, a colleague or another agent that a list is licensed and screened; anyone can verify it with POST /v1/compliance/receipts/verify. Free; it needs orders:read. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "The order the receipt covers.",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          }
        },
        "required": [
          "order_id"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^rcpt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: a compliance receipt id: rcpt_ followed by a 26 character ULID in upper case Crockford base32, such as rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R.",
            "examples": [
              "rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R"
            ]
          },
          "order_id": {
            "type": "string",
            "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
            "examples": [
              "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
            ]
          },
          "jws": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$",
            "description": "The receipt as a compact JWS signed with ES256."
          },
          "alg": {
            "type": "string",
            "const": "ES256"
          },
          "kid": {
            "type": "string",
            "description": "The signing key id in jwks_url."
          },
          "jwks_url": {
            "type": "string",
            "format": "uri"
          },
          "pdf_url": {
            "type": "string",
            "format": "uri",
            "description": "The PDF twin at mydatahub.emailmovers.com/receipts/{id}."
          },
          "claims": {
            "$ref": "#/$defs/ReceiptClaims"
          }
        },
        "required": [
          "id",
          "order_id",
          "jws",
          "alg",
          "kid",
          "jwks_url",
          "pdf_url",
          "claims"
        ],
        "description": "A signed compliance receipt for an order, verifiable by anyone with POST /v1/compliance/receipts/verify.",
        "$defs": {
          "Licence": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "multi_use_12m",
                  "outright"
                ],
                "description": "multi_use_12m (12 month multi-use, every plan) or outright (1.8 credits a record, proposed)."
              },
              "reuse_until": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Order date plus 12 months; null for outright."
              },
              "resale_prohibited": {
                "type": "boolean"
              },
              "permitted_channels": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "email",
                    "telephone",
                    "post"
                  ]
                },
                "description": "email, telephone and post on standard terms."
              },
              "warranty_url": {
                "type": "string",
                "format": "uri"
              },
              "terms_version": {
                "type": "string",
                "description": "The version of the Data Licence and Sharing Agreement the licence is under, such as 1.0."
              },
              "terms_url": {
                "description": "Where that version of the Data Licence and Sharing Agreement is published.",
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "type",
              "reuse_until",
              "resale_prohibited",
              "permitted_channels",
              "warranty_url",
              "terms_version"
            ],
            "description": "Licence terms as data, on every quote, order, records page and receipt. Records stay usable, pushable and re-downloadable free until reuse_until."
          },
          "ReceiptClaims": {
            "type": "object",
            "properties": {
              "receipt_id": {
                "type": "string",
                "pattern": "^rcpt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: a compliance receipt id: rcpt_ followed by a 26 character ULID in upper case Crockford base32, such as rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R.",
                "examples": [
                  "rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R"
                ]
              },
              "order_id": {
                "type": "string",
                "pattern": "^ord_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
                "description": "Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E.",
                "examples": [
                  "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E"
                ]
              },
              "issued_at": {
                "type": "string",
                "format": "date-time"
              },
              "dataset_version": {
                "type": "string",
                "pattern": "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$",
                "description": "The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable.",
                "examples": [
                  "2026-W39"
                ]
              },
              "records_delivered": {
                "type": "integer",
                "minimum": 0
              },
              "removed_by_suppression": {
                "type": "integer",
                "minimum": 0
              },
              "counts": {
                "type": "object",
                "properties": {
                  "subscriber_class": {
                    "type": "object",
                    "properties": {
                      "ltd": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "plc": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "llp": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "scottish_partnership": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "public_body": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "charity_incorporated": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "sole_trader": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "ordinary_partnership": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "unknown": {
                        "type": "integer",
                        "minimum": 0
                      }
                    },
                    "required": [
                      "ltd",
                      "plc",
                      "llp",
                      "scottish_partnership",
                      "public_body",
                      "charity_incorporated",
                      "sole_trader",
                      "ordinary_partnership",
                      "unknown"
                    ]
                  },
                  "tps_ctps_status": {
                    "type": "object",
                    "properties": {
                      "clear": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "tps_registered": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "ctps_registered": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "tps_or_ctps_registered": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "not_screened": {
                        "type": "integer",
                        "minimum": 0
                      }
                    },
                    "required": [
                      "clear",
                      "tps_registered",
                      "ctps_registered",
                      "tps_or_ctps_registered",
                      "not_screened"
                    ]
                  },
                  "article14_status": {
                    "type": "object",
                    "properties": {
                      "notified": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "publicly_notified_disproportionate_effort": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "pending_within_window": {
                        "type": "integer",
                        "minimum": 0
                      }
                    },
                    "required": [
                      "notified",
                      "publicly_notified_disproportionate_effort",
                      "pending_within_window"
                    ]
                  }
                },
                "required": [
                  "subscriber_class",
                  "tps_ctps_status",
                  "article14_status"
                ]
              },
              "lawful_basis": {
                "type": "string",
                "enum": [
                  "legitimate_interests_art6_1_f"
                ]
              },
              "lia_ref": {
                "type": "string"
              },
              "licence": {
                "$ref": "#/$defs/Licence"
              },
              "residency_statement_version": {
                "type": "string"
              },
              "sub_processor_list_version": {
                "type": "string"
              },
              "verified_within_days": {
                "type": "object",
                "properties": {
                  "within_30_days": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "within_60_days": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "within_90_days": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  }
                },
                "required": [
                  "within_30_days",
                  "within_60_days",
                  "within_90_days"
                ],
                "description": "Share of delivered emails verified within 30, 60 and 90 days."
              },
              "content_sha256": {
                "type": "string",
                "pattern": "^[0-9a-f]{64}$",
                "description": "SHA-256 of the delivered file, lower case hex."
              }
            },
            "required": [
              "receipt_id",
              "order_id",
              "issued_at",
              "dataset_version",
              "records_delivered",
              "removed_by_suppression",
              "counts",
              "lawful_basis",
              "lia_ref",
              "licence",
              "residency_statement_version",
              "sub_processor_list_version",
              "verified_within_days",
              "content_sha256"
            ],
            "description": "The decoded payload of a compliance receipt."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "available_selection_categories",
      "title": "Deprecated: filter categories",
      "description": "Deprecated: lists the filter categories. Use list_filters instead. It returns every field by name, such as company.employee_band, with its type, operators and value count. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "available_selection_values",
      "title": "Deprecated: filter values",
      "description": "Deprecated: lists the values of one filter category by numeric id. Use search_filter_values instead. It takes the field name and search text and returns codes with contact and company counts. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "search_discrete_values",
      "title": "Deprecated: search filter values",
      "description": "Deprecated: searches the values of one filter category. Use search_filter_values instead. It returns codes with counts and did_you_mean for near misses. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_search",
      "title": "Deprecated: build a count",
      "description": "Deprecated: adds filters to a count held in the server session. Use compile_audience, then count_audience instead. count_audience takes the whole audience definition in one call, so there is no session state to build up, and compile_audience turns a brief into that definition. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "clear_search",
      "title": "Deprecated: clear the count",
      "description": "Deprecated: clears the filters held in the server session. Use count_audience instead. There is nothing to clear: every count_audience call carries its own audience. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_count",
      "title": "Deprecated: get the count",
      "description": "Deprecated: returns the count for the filters held in the server session. Use count_audience instead. It returns Total, New to you and Emailable with breakdowns, quality, the compliance summary, a price estimate and a count id. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "save_selections",
      "title": "Deprecated: save an audience",
      "description": "Deprecated: saves the filters held in the server session under a name. Use save_audience instead. It saves an audience definition shared across the organisation; saved lists carry over as audiences (aud_). It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_saved_selections",
      "title": "Deprecated: list saved audiences",
      "description": "Deprecated: lists the saved lists of the organisation. Use list_audiences instead. Saved lists carry over as audiences (aud_) in the same organisation, with their current counts. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_data_extract",
      "title": "Deprecated: create an order",
      "description": "Deprecated: spent credits on a saved list when the model set a confirmation flag, and no longer does. Use quote_order, then create_order instead. The flag is ignored, since a flag set by a model is never consent: the call makes a machine quote for the list, and the user confirms the spend in a form or on mydatahub.emailmovers.com, or an agent key covers it within its limits; otherwise nothing is charged and it returns the approval_url. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "get_credits",
      "title": "Deprecated: credit balance",
      "description": "Deprecated: returns the credit balance. Use get_account instead. It returns the balance by source, the plan, per-action prices, the rate limit and any agent key budget; balances carry over one for one. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_packs",
      "title": "Deprecated: list field sets",
      "description": "Deprecated: lists the field bundles an order can deliver. Use list_field_sets instead. The old bundles become named field sets with their exact columns; the five test bundles are removed. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_pack_details",
      "title": "Deprecated: field set columns",
      "description": "Deprecated: lists the columns of one field bundle. Use list_field_sets instead. list_field_sets returns every field set with its exact columns and credits per record. It stops working 12 months after the new tools launch, after three emailed notices; https://emailmovers.com/mydatahub/docs/migrate maps every call. Lawful basis is UK GDPR Article 6(1)(f) legitimate interests; email audiences include corporate subscribers only by default (PECR), so sole traders and ordinary partnerships are left out unless the toggle is changed.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The arguments of the old tool, unchanged during the deprecation window. The adapter maps them to the new tools; emailmovers.com/mydatahub/docs/migrate lists them."
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": {},
        "description": "The old tool's result, unchanged during the deprecation window."
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    }
  ],
  "ttlMs": 300000,
  "cacheScope": "public"
}
