{
  "server": "sendraven",
  "url": "https://mcp.sendraven.ai/mcp",
  "date": "2026-09-07",
  "protocolVersion": "2025-11-25",
  "serverInfo": {
    "name": "sendraven",
    "title": "SendRaven",
    "version": "0.1.0"
  },
  "listChangedDeclared": true,
  "toolCount": 50,
  "outputSchemaCoveragePct": 0,
  "tools": [
    {
      "description": "Add someone to an audience. A contact exists once per workspace and can be on any number of audiences, so adding an address that already exists joins them to this list rather than creating a second copy. Pass status when the person has opted out elsewhere — it writes the suppression as well as the flag, and an add never resubscribes someone who opted out here. Safe to retry. For more than a handful of people use import_contacts.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "attributes": {
            "additionalProperties": {
              "type": [
                "string",
                "number",
                "boolean"
              ]
            },
            "description": "Custom properties by key. An unknown key creates a string property.",
            "type": "object"
          },
          "audience_id": {
            "type": "string"
          },
          "email": {
            "format": "email",
            "type": "string"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "status": {
            "description": "Standing with the previous sender. unsubscribed suppresses for marketing; bounced and complained suppress for everything. Defaults to subscribed.",
            "enum": [
              "subscribed",
              "unsubscribed",
              "bounced",
              "complained"
            ],
            "type": "string"
          },
          "tags": {
            "description": "Flat labels; lower-cased, spaces become hyphens",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "audience_id",
          "email"
        ],
        "type": "object"
      },
      "name": "add_contact"
    },
    {
      "description": "Register a sending domain and get back the DNS records to publish. Give the domain you send from — mail.\u003cdomain\u003e and news.\u003cdomain\u003e are provisioned beneath it and the right one is chosen per message, so a marketing complaint spike can never affect password reset delivery. Pass risk_class only to provision one of the two on its own.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "domain": {
            "description": "The domain you send from, e.g. example.com",
            "type": "string"
          },
          "risk_class": {
            "description": "Omit to provision both, which is almost always what you want",
            "enum": [
              "transactional",
              "marketing"
            ],
            "type": "string"
          }
        },
        "required": [
          "domain"
        ],
        "type": "object"
      },
      "name": "add_sending_domain"
    },
    {
      "description": "Stop sending to an address. Scope 'marketing' leaves transactional mail working.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "reason": {
            "enum": [
              "manual",
              "list_hygiene",
              "unsubscribe"
            ],
            "type": "string"
          },
          "scope": {
            "enum": [
              "all",
              "transactional",
              "marketing"
            ],
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "type": "object"
      },
      "name": "add_suppression"
    },
    {
      "description": "Cancel a scheduled email before it sends. Only works while status is 'scheduled'.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "cancel_scheduled_email"
    },
    {
      "description": "How many contacts a segment currently matches. Run this before building a campaign around it — a filter that matches nobody is easier to spot here than after a send.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "count_segment"
    },
    {
      "description": "Create a campaign as a draft. Nothing is sent: follow with preview_broadcast, then send_broadcast. identity_id must be a marketing sending domain (see list_sending_domains; risk_class 'marketing'). To A/B test, pass 2 to 10 'variants' that differ in subject, from_name or send_at, and optionally 'ab_test'. A subject or from-name test sends sample_share of the audience (default 0.2) split evenly across the variants, waits decide_after_minutes (default 240) after the sample is out, picks the variant with the best unique open rate (or click rate with metric 'click'), and sends the rest to it. Each variant needs at least 100 recipients in the sample or the send is refused — preview_broadcast shows the number. Metric 'click' only works once the domain has click tracking; until then every variant shows zero clicks and the first variant wins by default.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "ab_test": {
            "additionalProperties": false,
            "properties": {
              "decide_after_minutes": {
                "description": "How long after the sample is fully sent to decide; 15 to 10080, default 240",
                "type": "integer"
              },
              "metric": {
                "description": "What decides the winner; default 'open'",
                "enum": [
                  "open",
                  "click"
                ],
                "type": "string"
              },
              "sample_share": {
                "description": "Share of the audience in the test, 0.05 to 1; default 0.2. Ignored for a send-time test",
                "type": "number"
              }
            },
            "type": "object"
          },
          "audience_id": {
            "type": "string"
          },
          "from_name": {
            "description": "From display name, e.g. 'Ana at Example'",
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "identity_id": {
            "description": "A marketing sending domain's id",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "segment": {
            "additionalProperties": false,
            "properties": {
              "clicked_within_days": {
                "type": "integer"
              },
              "exclude_unengaged_days": {
                "type": "integer"
              },
              "opened_within_days": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "segment_id": {
            "description": "A saved segment to narrow the audience",
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "topic_key": {
            "description": "Lets recipients opt out of this kind of mail only",
            "type": "string"
          },
          "variants": {
            "items": {
              "additionalProperties": false,
              "properties": {
                "from_name": {
                  "description": "From display name for this variant; omit to use the campaign's",
                  "type": "string"
                },
                "key": {
                  "description": "Your name for this variant, lowercase letters, digits, - or _: 'urgent', 'question'",
                  "type": "string"
                },
                "send_at": {
                  "description": "ISO 8601 send time, for a send-time test only. Set it on every variant or on none; a send-time test mails the whole audience, each variant at its own time, with nothing held back",
                  "type": "string"
                },
                "subject": {
                  "description": "Subject for this variant; omit to use the campaign's",
                  "type": "string"
                }
              },
              "required": [
                "key"
              ],
              "type": "object"
            },
            "maxItems": 10,
            "minItems": 2,
            "type": "array"
          }
        },
        "required": [
          "audience_id",
          "identity_id",
          "name",
          "subject",
          "html"
        ],
        "type": "object"
      },
      "name": "create_broadcast"
    },
    {
      "description": "Approve or reject a held message. Approving sends it immediately. Only use this when a human has explicitly told you which decision to make — the hold exists precisely so that an agent is not the one deciding.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "decided_by": {
            "description": "Who authorised this decision",
            "type": "string"
          },
          "decision": {
            "enum": [
              "approve",
              "reject"
            ],
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "decision",
          "decided_by"
        ],
        "type": "object"
      },
      "name": "decide_approval"
    },
    {
      "description": "Remove a person from the workspace entirely, along with every audience membership. Their suppression and topic preferences are kept on purpose — an opt-out has to outlive the contact record, or the next import silently puts them back on the list. To take someone off a single audience use remove_from_audience instead.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "contact_id": {
            "type": "string"
          }
        },
        "required": [
          "contact_id"
        ],
        "type": "object"
      },
      "name": "delete_contact"
    },
    {
      "description": "Emit a named event, starting every automation that waits on it — for example 'trial_started' or 'invoice_overdue'. Use this when you want the configured sequences to decide what happens, rather than naming an automation yourself.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "name": {
            "description": "Event name, e.g. trial_started",
            "type": "string"
          },
          "variables": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          }
        },
        "required": [
          "name",
          "email"
        ],
        "type": "object"
      },
      "name": "emit_event"
    },
    {
      "description": "Put someone into a multi-step sequence. Prefer this over scheduling several emails yourself: the sequence stops on its own if they unsubscribe, reply, or hard bounce, which you would otherwise have to track and cancel by hand. Enrolling the same person twice is a no-op, so it is safe to retry a call you are unsure about.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "automation_id": {
            "type": "string"
          },
          "email": {
            "format": "email",
            "type": "string"
          },
          "variables": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Values for any templated steps in the sequence",
            "type": "object"
          }
        },
        "required": [
          "automation_id",
          "email"
        ],
        "type": "object"
      },
      "name": "enroll_in_automation"
    },
    {
      "description": "Find a contact by address across every audience, without knowing which list they are on. Use email for an exact match, or q for a prefix. Returns each audience membership separately — the same address on three lists is three rows — and whether each is unsubscribed.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "cursor": {
            "description": "An address, from a previous call's next_cursor",
            "type": "string"
          },
          "email": {
            "description": "Exact address",
            "type": "string"
          },
          "limit": {
            "type": "number"
          },
          "q": {
            "description": "Address prefix, for a partial match",
            "type": "string"
          },
          "unsubscribed": {
            "description": "Filter to only opted-in or only opted-out",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "name": "find_contact"
    },
    {
      "description": "One campaign, with a 'progress' object while it is sending, paused or testing: how many addresses are still pending, sent, failed, or skipped because the person opted out after the campaign started. This is how you tell a paused campaign that is still making progress from one waiting on quota. An A/B test carries 'ab_test' with live per-variant results — sent, unique opens, unique clicks and their rates — plus 'decide_at' and, once decided, 'winner' and 'decided_by'. Status 'testing' means the sample is out and the rest of the audience is waiting on the decision.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "get_broadcast"
    },
    {
      "description": "Fetch one contact by id, with their audience memberships, custom properties and engagement dates.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "get_contact"
    },
    {
      "description": "Fetch one message with its full event timeline (send, delivery, bounce, complaint, open, click). This is the tool to reach for when asked why an email didn't arrive.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "description": "Message id",
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "get_email"
    },
    {
      "description": "Delivery and engagement over a window. Open and click rates are over delivered, not sent — a low open rate with a high bounce rate is a deliverability problem, not an engagement one.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "days": {
            "description": "Defaults to 30",
            "maximum": 365,
            "minimum": 1,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "name": "get_email_metrics"
    },
    {
      "description": "What one person has chosen to receive. Check this before asking a human why someone isn't getting a particular kind of email — an opt-out looks identical to a delivery failure from the outside.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "type": "object"
      },
      "name": "get_email_preferences"
    },
    {
      "description": "Read a conversation as a chronological transcript of outbound and inbound messages. Inbound text already has quoted history and signatures stripped, so read `text`; `raw_text` holds the untrimmed body if the stripped version looks wrong. Check spf_verdict and dkim_verdict before trusting a reply's claimed sender.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "description": "Thread id",
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "get_thread"
    },
    {
      "description": "This workspace's plan, how many emails it has sent this month, and how many are left. Check before a large batch: a send that would cross the included allowance on a plan without overage is refused whole, so it is better to know first than to discover it halfway through a campaign.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "get_usage"
    },
    {
      "description": "Import up to 5,000 contacts into an audience in one call, with names, tags, custom properties and subscription status. This is the migration tool: send the previous provider's unsubscribed, bounced and complained lists with the matching status *before* the first campaign, or the new domain mails people who opted out and loses its reputation in a day. Existing contacts are updated rather than duplicated, and nobody who opted out here is resubscribed, so re-running an import is safe. Returns counts: inserted, updated, skipped, unsubscribed, bounced, complained, suppressed, properties_created.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "audience_id": {
            "type": "string"
          },
          "contacts": {
            "items": {
              "additionalProperties": false,
              "properties": {
                "attributes": {
                  "additionalProperties": {
                    "type": [
                      "string",
                      "number",
                      "boolean"
                    ]
                  },
                  "description": "Custom properties by key. An unknown key creates a string property.",
                  "type": "object"
                },
                "email": {
                  "format": "email",
                  "type": "string"
                },
                "first_name": {
                  "type": "string"
                },
                "last_name": {
                  "type": "string"
                },
                "status": {
                  "description": "Standing with the previous sender. unsubscribed suppresses for marketing; bounced and complained suppress for everything. Defaults to subscribed.",
                  "enum": [
                    "subscribed",
                    "unsubscribed",
                    "bounced",
                    "complained"
                  ],
                  "type": "string"
                },
                "tags": {
                  "description": "Flat labels; lower-cased, spaces become hyphens",
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                }
              },
              "required": [
                "email"
              ],
              "type": "object"
            },
            "maxItems": 5000,
            "minItems": 1,
            "type": "array"
          },
          "source": {
            "description": "Where the list came from, e.g. \"Mailchimp\" — recorded on each suppression",
            "type": "string"
          }
        },
        "required": [
          "audience_id",
          "contacts"
        ],
        "type": "object"
      },
      "name": "import_contacts"
    },
    {
      "description": "List this workspace's API keys with their scopes and limits. Never returns key values.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_api_keys"
    },
    {
      "description": "List contact lists and how many contacts each holds.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_audiences"
    },
    {
      "description": "List multi-step email sequences and how many people are currently in each. Use this to find the right automation before enrolling someone.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_automations"
    },
    {
      "description": "Who a campaign reached and what happened to each message.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          },
          "limit": {
            "maximum": 1000,
            "minimum": 1,
            "type": "integer"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "list_broadcast_recipients"
    },
    {
      "description": "List campaigns with their status and send progress. A campaign showing 'paused' is not broken: it ran out of the day's sending quota part way and is waiting to continue. One showing 'testing' is an A/B test whose sample has gone out and whose winner is not yet decided. Use get_broadcast to see how much is left or how each variant is doing, and resume_broadcast to continue a paused one now.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_broadcasts"
    },
    {
      "description": "List recent messages with their delivery status. Filter by status (queued, scheduled, sent, delivered, bounced, complained, rejected) or recipient.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "limit": {
            "maximum": 200,
            "minimum": 1,
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "to": {
            "description": "Filter to one recipient address",
            "type": "string"
          }
        },
        "type": "object"
      },
      "name": "list_emails"
    },
    {
      "description": "List messages held for human approval, with their full content. A key configured to require approval drafts rather than sends; a person releases it. If your send returned status 'pending_approval', it is waiting here — do not retry the send.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_pending_approvals"
    },
    {
      "description": "Messages queued to send later but not yet sent. Cancel one with cancel_scheduled_email.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "limit": {
            "maximum": 200,
            "minimum": 1,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "name": "list_scheduled_emails"
    },
    {
      "description": "List saved audience filters. Use a segment id when creating a campaign rather than describing the filter inline, so the same definition can be reused and counted.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_segments"
    },
    {
      "description": "List sending domains with their verification status and the DNS records each one needs. Each record shows what is currently published, so this diagnoses a stuck verification.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_sending_domains"
    },
    {
      "description": "List addresses we refuse to mail and why (hard_bounce, complaint, unsubscribe, manual). Check here first when someone reports not receiving email.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "limit": {
            "maximum": 500,
            "minimum": 1,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "name": "list_suppressions"
    },
    {
      "description": "Every tag in use in the workspace, with how many contacts carry each. Tags are free-form, so this is the only way to know what exists before applying one.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_tags"
    },
    {
      "description": "List stored email templates and the variables each one needs. Prefer sending via a template over composing HTML yourself — templates carry the brand styling and the unsubscribe footer.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_templates"
    },
    {
      "description": "List email conversations. Pass awaiting_reply=true to get only the threads where someone has written to you and you haven't answered — this is the tool to poll when deciding what needs a response.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "awaiting_reply": {
            "type": "boolean"
          },
          "limit": {
            "maximum": 200,
            "minimum": 1,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "name": "list_threads"
    },
    {
      "description": "List subscription topics — the categories a person can opt out of individually. Pass a topic when sending marketing mail so recipients can unsubscribe from that kind alone rather than from everything.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {},
        "type": "object"
      },
      "name": "list_topics"
    },
    {
      "description": "Recent delivery attempts for a webhook endpoint, with status codes and errors. This is how to tell 'we never sent it' from 'your endpoint returned 500'.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "endpoint_id": {
            "type": "string"
          },
          "limit": {
            "maximum": 200,
            "minimum": 1,
            "type": "integer"
          }
        },
        "required": [
          "endpoint_id"
        ],
        "type": "object"
      },
      "name": "list_webhook_deliveries"
    },
    {
      "description": "Decide an A/B test now instead of waiting for decide_at. Pass 'variant' to choose a key yourself, or omit it to have the metric decide on the figures so far. The rest of the audience is then sent to the winner and cannot be redirected. Only a campaign in status 'testing' can be decided; anything else answers 409. Read get_broadcast first — a variant with a handful of opens more is not a result, and the worker decides on its own at decide_at.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          },
          "variant": {
            "description": "Variant key to send the remainder to; omit to let the metric decide",
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "pick_broadcast_winner"
    },
    {
      "description": "How many contacts a campaign would reach, and whether the reputation gate would allow it. Always run this before sending — it is the only way to see the size of a campaign without starting it. For an A/B test it also reports the sample size and per-variant count against the 100-per-variant floor; a send below the floor is refused.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "preview_broadcast"
    },
    {
      "description": "Take a contact off one audience. They stay in the workspace and keep every other audience, their suppression and their engagement history. To remove the person entirely use delete_contact — leaving a list and being forgotten are different things.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "audience_id": {
            "type": "string"
          },
          "contact_id": {
            "type": "string"
          }
        },
        "required": [
          "audience_id",
          "contact_id"
        ],
        "type": "object"
      },
      "name": "remove_from_audience"
    },
    {
      "description": "Remove a suppression so the address can be mailed again. Be careful with hard bounces — the address was rejected by the receiving server, and re-sending raises the bounce rate that AWS enforces on.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "scope": {
            "enum": [
              "all",
              "transactional",
              "marketing"
            ],
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "type": "object"
      },
      "name": "remove_suppression"
    },
    {
      "description": "Render a template with values, without sending. Use this to check your copy reads correctly before mailing a real person. Returns an error listing any missing variables.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "slug": {
            "type": "string"
          },
          "variables": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          }
        },
        "required": [
          "slug",
          "variables"
        ],
        "type": "object"
      },
      "name": "render_template"
    },
    {
      "description": "Reply to a message, keeping it on the same conversation. Sets the threading headers so the recipient's mail client shows it as part of the existing exchange rather than a new one. Prefer this over send_email whenever you are answering something.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "from": {
            "description": "Sender address on a verified domain",
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "reply_to_message_id": {
            "description": "Id of the message being replied to",
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "to": {
            "format": "email",
            "type": "string"
          }
        },
        "required": [
          "reply_to_message_id",
          "from",
          "to",
          "subject"
        ],
        "type": "object"
      },
      "name": "reply_to_message"
    },
    {
      "description": "Continue a campaign left 'paused' by the daily sending quota. It mails only the addresses still pending — the audience was frozen when the campaign started and everyone already reached is marked — so calling this twice cannot double-send. Only works on a paused campaign; anything else answers 409. A background worker also resumes paused campaigns on its own once quota frees up, so use this only when waiting is not acceptable. An A/B test paused mid-sample resumes the sample; one paused after the decision resumes the winner.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "resume_broadcast"
    },
    {
      "description": "Send a campaign now, or schedule it with scheduled_at. This mails every contact in the segment and cannot be undone once started — run preview_broadcast first. A campaign bigger than the day's remaining quota is not rejected: it sends what it can and stops as 'paused', then continues later. That is expected, not an error to retry. An A/B test sends its sample, goes to 'testing', and sends the rest to the winner after decide_after_minutes or when pick_broadcast_winner is called. A send-time test is scheduled by its variants' send_at and does not accept scheduled_at.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          },
          "scheduled_at": {
            "description": "ISO 8601 timestamp; omit to send now",
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "send_broadcast"
    },
    {
      "description": "Send a transactional email, immediately or scheduled. Use scheduled_at with a relative phrase like 'in 3 days' or an ISO timestamp. The From domain must already be verified.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "from": {
            "description": "Sender address on a verified domain, e.g. 'Team \u003cteam@mail.example.com\u003e'",
            "type": "string"
          },
          "html": {
            "description": "HTML body; provide html, text, or both",
            "type": "string"
          },
          "scheduled_at": {
            "description": "'in 3 days' or an ISO 8601 timestamp",
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "to": {
            "description": "Recipient address",
            "format": "email",
            "type": "string"
          }
        },
        "required": [
          "from",
          "to",
          "subject"
        ],
        "type": "object"
      },
      "name": "send_email"
    },
    {
      "description": "Send an email built from a stored template. Variable values are HTML-escaped on substitution, so they are safe to fill from user-supplied text.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "from": {
            "type": "string"
          },
          "scheduled_at": {
            "type": "string"
          },
          "subject": {
            "description": "Overrides the template's subject",
            "type": "string"
          },
          "template": {
            "description": "Template slug",
            "type": "string"
          },
          "to": {
            "format": "email",
            "type": "string"
          },
          "variables": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          }
        },
        "required": [
          "template",
          "variables",
          "from",
          "to"
        ],
        "type": "object"
      },
      "name": "send_template_email"
    },
    {
      "description": "Set which topics a person receives. Only do this when they have actually asked — silently re-subscribing someone who opted out is what generates spam complaints.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "topics": {
            "additionalProperties": {
              "type": "boolean"
            },
            "description": "Topic key to subscribed, e.g. {\"newsletter\": false}",
            "type": "object"
          }
        },
        "required": [
          "email",
          "topics"
        ],
        "type": "object"
      },
      "name": "set_email_preferences"
    },
    {
      "description": "Stop sending to many addresses at once — the path for importing another provider's unsubscribe list before a first campaign. Without it, everyone who already opted out there gets mailed again here.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "emails": {
            "items": {
              "format": "email",
              "type": "string"
            },
            "maxItems": 10000,
            "type": "array"
          },
          "reason": {
            "enum": [
              "manual",
              "list_hygiene",
              "unsubscribe"
            ],
            "type": "string"
          },
          "scope": {
            "enum": [
              "all",
              "transactional",
              "marketing"
            ],
            "type": "string"
          }
        },
        "required": [
          "emails"
        ],
        "type": "object"
      },
      "name": "suppress_many"
    },
    {
      "description": "Add or remove tags on a contact. Tags are flat labels — vip, beta, churned — as opposed to custom properties, which are declared fields with a value. They are lower-cased and spaces become hyphens, so VIP and vip are the same tag. Tagging reaches the person across every audience they are on. Call list_tags first to see what the workspace already uses, rather than inventing a synonym for an existing tag.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "add": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "contact_id": {
            "type": "string"
          },
          "remove": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "contact_id"
        ],
        "type": "object"
      },
      "name": "tag_contact"
    },
    {
      "description": "Update a contact. Attributes are merged, so sending one field does not clear the rest.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "attributes": {
            "additionalProperties": {
              "type": [
                "string",
                "number",
                "boolean"
              ]
            },
            "type": "object"
          },
          "first_name": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "update_contact"
    },
    {
      "description": "Re-check a domain's DNS records now instead of waiting for the background monitor.",
      "inputSchema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "name": "verify_sending_domain"
    }
  ]
}
