{
  "description": "Motorical Agent Hub machine twin. Generated from docs-site/data/journeys.yaml plus the live scope catalog — do not hand-edit. Human-readable version: https://docs.motorical.com/agents",
  "coreDefinition": "The email API for developers with multiple projects: one isolated sending stream (a Motor Block) per project.",
  "connect": {
    "page": "https://docs.motorical.com/connect-your-agent",
    "server": "https://mcp.motorical.com/v1/motorical/mcp",
    "permissionNeeded": "Approve the permission when it is asked for (or add it in the Motorical dashboard under Settings, API, Connected AI Agents), then start a new chat or reconnect the connector if the tools still do not appear."
  },
  "motorBlock": {
    "canonicalTerm": "Motor Block",
    "definition": "A Motor Block is Motorical's SMTP sending block: one isolated sending stream per project, with its own domain, credentials, limits, logs, webhooks and analytics.",
    "aliases": [
      "SMTP sending block",
      "sending stream",
      "per-project sending stream",
      "email sending project"
    ],
    "nearestEquivalentsAtOtherProviders": [
      "Postmark Servers",
      "SendGrid subusers",
      "Mailgun subaccounts"
    ]
  },
  "scopes": {
    "send:transactional": {
      "resource": "transactional",
      "level": "manage",
      "agentDescription": "Send transactional email through the caller's Motor Block(s)."
    },
    "read:analytics": {
      "resource": "analytics",
      "level": "read",
      "agentDescription": "Read delivery logs, analytics, and usage for the caller's Motor Block(s). Never includes unmasked recipient PII (logs.pii) regardless of what is requested."
    },
    "manage:domains": {
      "resource": "domains",
      "level": "manage",
      "agentDescription": "Add, verify, and read sending domains and their DNS health. Includes everything read:domains grants."
    },
    "manage:motor-blocks": {
      "resource": "motor-blocks",
      "level": "manage",
      "agentDescription": "List and manage the ordinary lifecycle of production Motor Blocks: create, rename, change type, assign domain, deactivate, reactivate, and delete. Includes no credential values and cannot change the active auth method."
    },
    "manage:sandbox": {
      "resource": "sandbox",
      "level": "manage",
      "agentDescription": "Check, provision, and convert the developer sandbox. Allowlisting by 6-digit code is dashboard-only and not available over OAuth; to allow recipients over OAuth use the manage:recipients scope."
    },
    "manage:recipients": {
      "resource": "recipients",
      "level": "manage",
      "agentDescription": "Request permission to send test email to an address you name, and see which addresses have confirmed or stopped. The recipient confirms by clicking an emailed link; an agent can never confirm on their behalf."
    },
    "manage:webhooks": {
      "resource": "webhooks",
      "level": "manage",
      "agentDescription": "Create, update, delete, and test webhook endpoints on the caller's Motor Block(s). Includes everything read:webhooks grants."
    },
    "read:webhooks": {
      "resource": "webhooks",
      "level": "read",
      "agentDescription": "List webhook endpoints and read their delivery history and stats, without creating, updating, deleting, or testing any."
    },
    "read:domains": {
      "resource": "domains",
      "level": "read",
      "agentDescription": "List and read sending domains, their DNS records and email-authentication health, and read a Motor Block's configuration, without adding or verifying any domain."
    },
    "read:comms": {
      "resource": "comms",
      "level": "read",
      "agentDescription": "Read Communications data for the workspaces the person chose: lists and contacts, templates, campaigns, reports and events, the workspace map and readiness, and run read-only checks (template preview, lint, link check, starter render). Never changes anything."
    },
    "write:comms.audience": {
      "resource": "comms",
      "level": "manage",
      "agentDescription": "Create and change lists and contacts, add contacts (with a dry run), derive lists from lists, import, and add or remove suppressions. Includes everything read:comms grants. Cannot delete anything permanently."
    },
    "write:comms.content": {
      "resource": "comms",
      "level": "manage",
      "agentDescription": "Create and change templates, the brand kit and campaign drafts, duplicate and compile campaigns, and send a test email to the account owner only. Includes everything read:comms grants. Does not send to your contacts."
    },
    "send:comms.campaign": {
      "resource": "comms-sending",
      "level": "manage",
      "agentDescription": "Schedule a campaign (which sends it to the audience) and cancel a scheduled or sending one. Cancelling is final. Includes everything read:comms grants."
    },
    "manage:comms.workspace": {
      "resource": "comms-workspace",
      "level": "manage",
      "agentDescription": "Change workspace settings (consent, open tracking, unsubscribe page) and which marketing Motor Blocks a workspace uses. Includes everything read:comms grants."
    },
    "manage:comms.webhooks": {
      "resource": "comms-webhooks",
      "level": "manage",
      "agentDescription": "Create, update, delete and test campaign event webhooks of the workspaces the person chose. Includes everything read:comms grants."
    },
    "manage:comms.audience": {
      "resource": "comms-audience",
      "level": "manage",
      "agentDescription": "Delete lists and contacts (a contact is erased for good), clean up contacts that are on no list, and opt a contact back in. Includes everything read:comms grants, not the permission to edit lists. People who unsubscribed, bounced or are suppressed are never erased by a list delete or a clean-up."
    }
  },
  "journeys": [
    {
      "key": "A",
      "audience": "Coding assistant adding email to an app",
      "status": "real",
      "route": "Local server (API keys) or the HTTP API directly",
      "steps": [
        {
          "id": "A1",
          "description": "Get a Motor Block API key (mk_live_...) from the dashboard, or use the developer sandbox for a zero-credential start (see Journey C).",
          "humanRequired": true,
          "sayToHuman": "I need a Motor Block API key from your Motorical dashboard (or we can start with the free sandbox — no account needed yet)."
        },
        {
          "id": "A2",
          "description": "Dry-run the send payload before sending anything real.",
          "tool": "motorical_send_email",
          "endpoint": "POST /v1/send (dryRun: true)",
          "humanRequired": false
        },
        {
          "id": "A3",
          "description": "Remove dryRun (or set it false) to send for real.",
          "tool": "motorical_send_email",
          "endpoint": "POST /v1/send",
          "humanRequired": false
        },
        {
          "id": "A4",
          "description": "Check delivery status/events for a sent message, or wait for a terminal outcome rather than treating a 202 as delivered.",
          "tools": [
            "motorical_get_send_status",
            "motorical_get_message",
            "motorical_get_message_events",
            "motorical_wait_for_outcome"
          ],
          "humanRequired": false
        },
        {
          "id": "A5",
          "description": "Optional: register a webhook so the app learns about deliveries, bounces, and complaints without polling.",
          "tool": "motorical_webhook_create",
          "humanRequired": false,
          "note": "Available on both the local server and hosted OAuth's dedicated webhooks server (read:webhooks/manage:webhooks scopes) — not local-only."
        }
      ]
    },
    {
      "key": "B",
      "audience": "Operator agent running a customer's account over MCP",
      "status": "real",
      "route": "Hosted MCP over OAuth (a person present for consent)",
      "steps": [
        {
          "id": "B1",
          "description": "Connect to the hosted MCP server (main, for a full setup on one consent, or a narrow scoped server for least privilege).",
          "humanRequired": true,
          "sayToHuman": "I'll connect to Motorical over OAuth — you'll see a browser consent screen asking which scopes to grant."
        },
        {
          "id": "B2",
          "description": "Read live account state before acting.",
          "tools": [
            "motorical_get_onboarding_state",
            "motorical_list_motor_blocks"
          ],
          "humanRequired": false
        },
        {
          "id": "B3",
          "description": "Operate within the granted scope — send email, read analytics, manage domains, manage Motor Blocks, or manage webhooks, depending on which scopes were granted.",
          "tools": [
            "motorical_send_email",
            "motorical_get_overview",
            "motorical_get_deliverability",
            "motorical_motor_block_list",
            "motorical_motor_block_create"
          ],
          "humanRequired": false
        },
        {
          "id": "B4",
          "description": "A consequential operation (type change, domain assignment, deactivate, delete) asks for confirmation bound to the exact arguments shown — never assume consent carries to different arguments.",
          "tools": [
            "motorical_motor_block_change_type",
            "motorical_motor_block_assign_domain",
            "motorical_motor_block_deactivate",
            "motorical_motor_block_delete"
          ],
          "humanRequired": true,
          "sayToHuman": "This is a consequential change (e.g. permanently deleting a Motor Block) — confirming means exactly this action, nothing broader.",
          "stopCondition": "Deactivate is reversible; delete is not. Never treat them as interchangeable, and never skip the confirmation step."
        }
      ]
    },
    {
      "key": "C",
      "audience": "Agent in a chat client (Claude Code, Claude Desktop, another MCP client) whose human has no account",
      "status": "real",
      "route": "Connect the main motorical server and authenticate it; the person creates the account in the browser. Then Journey B.",
      "steps": [
        {
          "id": "C1",
          "description": "Connect the main hosted server (https://mcp.motorical.com/v1/motorical/mcp) in the client and run the client's authenticate step (for Claude Code: claude mcp add --transport http motorical https://mcp.motorical.com/v1/motorical/mcp in a terminal, then /mcp in the session, pick motorical, Authenticate). Do not use the signup server: it is for apps that implement an OAuth client (Journey D) and needs OAuth client values a chat agent cannot supply.",
          "humanRequired": false
        },
        {
          "id": "C2",
          "description": "The browser opens the Motorical sign-in page. The person creates the account there (onboarding), sets up MFA, which is required and cannot be skipped, and presses Allow on the consent screen. Consent resumes by itself; nobody runs authenticate a second time. No credential of any kind is returned to the agent.",
          "humanRequired": true,
          "sayToHuman": "A browser window opened. Create your Motorical account there, set up two-factor authentication (required for this connection), then press Allow. I never see or hold your credentials."
        },
        {
          "id": "C3",
          "description": "Continue as Journey B: the OAuth grant from consent is usable immediately, no separate step needed. The account starts on the unpaid developer sandbox (outbound-locked to an allowlist).",
          "humanRequired": false
        },
        {
          "id": "C4",
          "description": "To send in production, convert the sandbox Motor Block onto a domain the human owns. motorical_sandbox_convert requires an active Motorical plan — it throws subscription_required with err.data.upgradeUrl if none exists yet; retry the same call once the human has subscribed.",
          "tool": "motorical_sandbox_convert",
          "humanRequired": true,
          "sayToHuman": "To move off the sandbox onto your own domain, you'll need an active Motorical plan — here's the link to subscribe.",
          "stopCondition": "motorical_sandbox_convert fails closed with subscription_required until the human subscribes; there is no agent-side workaround."
        },
        {
          "id": "C5",
          "description": "Add the domain and complete DNS verification before any production send is possible.",
          "tools": [
            "motorical_domain_add",
            "motorical_domain_verify",
            "motorical_domain_check_dns"
          ],
          "humanRequired": true,
          "sayToHuman": "Add these DNS records at your domain registrar, then let me know once they're live so I can verify them.",
          "stopCondition": "A domain is not sendReady until DKIM and SPF are both configured — the human must publish the DNS records before send works."
        }
      ]
    },
    {
      "key": "sandbox_then_convert",
      "title": "Journey: sandbox then convert",
      "audience": "Agent that is only trying things, or whose person has no domain yet or is not at the keyboard (Path 1)",
      "status": "real",
      "route": "Hosted MCP over OAuth (main or sandbox server). Decision step in docs.motorical.com/ai, section \"Two ways to start\".",
      "steps": [
        {
          "id": "S1",
          "description": "Read live account state. For an account with no plan and no domain it lists the two onboarding options and a choose rule; state the choice and the reason, the person may override.",
          "tool": "motorical_get_onboarding_state",
          "humanRequired": false
        },
        {
          "id": "S2",
          "description": "Provision the sandbox on a Motorical-owned .sandbox domain. It is instant and needs no DNS. The Motor Block is outbound-locked and added to the live authorization.",
          "tool": "motorical_sandbox_provision",
          "humanRequired": false
        },
        {
          "id": "S3",
          "description": "Check motorical_sandbox_status. domain.sandbox true means the Motorical-owned sandbox domain. allowlist is the effective list of recipients a real send may reach.",
          "tool": "motorical_sandbox_status",
          "humanRequired": false
        },
        {
          "id": "S4",
          "description": "To send to anyone besides the account address, ask each recipient to confirm by emailed link. An authorization granted before the manage:recipients scope existed must be re-approved to include it.",
          "tool": "motorical_free_recipient_add",
          "humanRequired": true,
          "sayToHuman": "I have asked this person to allow test email from your account. They need to open the message and click the confirm button.",
          "stopCondition": "This tool never confirms for the recipient. Until they click, sends to that address are refused (sandbox_outbound_locked while locked, the default; sandbox_recipient_denied after an explicit unlock)."
        },
        {
          "id": "S5",
          "description": "Dry-run the send, then send for real to the account address or a confirmed recipient. The tool defaults to dryRun true and a real send needs confirmRealSend true; always set dryRun explicitly.",
          "tool": "motorical_send_email",
          "humanRequired": false
        },
        {
          "id": "S6",
          "description": "Wait for a terminal outcome instead of treating 202 as delivered. Pass the taskId from the send response's nextAction (it is not the message id). Without MCP, mint a read token with POST /api/public/token (scope logs.read) and call GET /api/public/v1/messages/{id}; the sandbox send key cannot read message status.",
          "tool": "motorical_wait_for_outcome",
          "humanRequired": false
        },
        {
          "id": "S7",
          "description": "To leave the sandbox, the person subscribes to a plan, then convert the sandbox Motor Block onto a verified domain they own. Without a plan the call fails closed with subscription_required and an upgradeUrl.",
          "tool": "motorical_sandbox_convert",
          "humanRequired": true,
          "sayToHuman": "To move off the sandbox onto your own domain you will need an active Motorical plan. Here is the link to subscribe."
        }
      ]
    },
    {
      "key": "free_own_domain",
      "title": "Journey: Free account with your own domain",
      "audience": "Agent whose person has a domain whose DNS they control and want to keep (Path 2)",
      "status": "real",
      "route": "Hosted MCP over OAuth (main server, or domains plus sandbox). Decision step in docs.motorical.com/ai, section \"Two ways to start\".",
      "steps": [
        {
          "id": "O1",
          "description": "Read live account state and state which path you chose and why.",
          "tool": "motorical_get_onboarding_state",
          "humanRequired": false
        },
        {
          "id": "O2",
          "description": "Add the domain. A Free account may have one domain; adding another returns free_domain_limit with a nextAction.",
          "tool": "motorical_domain_add",
          "humanRequired": false
        },
        {
          "id": "O3",
          "description": "Publish the DNS records exactly as returned, then re-check until DKIM and SPF pass.",
          "tools": [
            "motorical_domain_verify",
            "motorical_domain_check_dns"
          ],
          "humanRequired": true,
          "sayToHuman": "Add these DNS records at your domain registrar, then tell me once they are live so I can verify them.",
          "stopCondition": "The domain is not send-ready until DKIM and SPF are both configured; the person must publish the records."
        },
        {
          "id": "O4",
          "description": "Once DKIM and SPF pass, on a Free account when automatic provisioning is enabled and the domain is fully verified, a sandbox Motor Block is created on the domain automatically (no provisioning call). Check motorical_sandbox_status: domain.sandbox false means your own domain. If no block appeared (automatic provisioning off, or the account is not a Free account), motorical_sandbox_provision uses the Motorical-owned domain instead.",
          "tool": "motorical_sandbox_status",
          "humanRequired": false
        },
        {
          "id": "O5",
          "description": "If the account state reports grant_missing_sandbox, the current authorization predates the new Motor Block: the person must reconnect (re-authorize) the client.",
          "tool": "motorical_get_onboarding_state",
          "humanRequired": true,
          "sayToHuman": "Please reconnect this client in your connector settings so it can use the new sandbox Motor Block."
        },
        {
          "id": "O6",
          "description": "Ask each recipient to confirm by emailed link. An authorization granted before the manage:recipients scope existed must be re-approved to include it.",
          "tool": "motorical_free_recipient_add",
          "humanRequired": true,
          "sayToHuman": "I have asked this person to allow test email from your account. They need to open the message and click the confirm button."
        },
        {
          "id": "O7",
          "description": "Dry-run, send for real, and wait for a terminal outcome.",
          "tools": [
            "motorical_send_email",
            "motorical_wait_for_outcome"
          ],
          "humanRequired": false
        },
        {
          "id": "O8",
          "description": "To lift the sandbox, the person subscribes to a plan, then convert the sandbox Motor Block (confirm required).",
          "tool": "motorical_sandbox_convert",
          "humanRequired": true,
          "sayToHuman": "To lift the sandbox limits you will need an active Motorical plan. Here is the link to subscribe."
        }
      ]
    },
    {
      "key": "F",
      "audience": "Agent operating and reporting on an account that already sends",
      "status": "real",
      "route": "Hosted MCP over OAuth, read-only tools (read:analytics, read:domains)",
      "steps": [
        {
          "id": "F1",
          "description": "Read who the connection acts for and which scopes the grant holds (grant.scopes), instead of inferring scopes from the tool list.",
          "tool": "motorical_whoami",
          "humanRequired": false
        },
        {
          "id": "F2",
          "description": "List the Motor Blocks and keep their ids.",
          "tool": "motorical_list_motor_blocks",
          "humanRequired": false
        },
        {
          "id": "F3",
          "description": "Read results for a window. A date-only `to` means that whole day (up to 23:59:59 UTC); a full timestamp is exact; omit `to` for up to now.",
          "tools": [
            "motorical_get_overview",
            "motorical_get_daily_summary"
          ],
          "humanRequired": false,
          "note": "Days with no sends are absent from the daily summary; it is not zero-filled. See https://docs.motorical.com/ai-mcp-live-account."
        },
        {
          "id": "F4",
          "description": "Explain failures by cause, then list the messages behind a code.",
          "tools": [
            "motorical_get_error_codes",
            "motorical_get_logs"
          ],
          "humanRequired": false
        },
        {
          "id": "F5",
          "description": "Judge health and the sending domains.",
          "tools": [
            "motorical_get_deliverability",
            "motorical_get_reputation",
            "motorical_get_anomalies",
            "motorical_domain_health"
          ],
          "humanRequired": false
        },
        {
          "id": "F6",
          "description": "Report the window, the Motor Blocks and anything hidden by a missing scope. Do not call a write tool while reporting.",
          "humanRequired": false,
          "stopCondition": "Reporting never needs a write tool. A change is a separate, confirmed action (Journey B)."
        }
      ]
    },
    {
      "key": "E",
      "audience": "Agent running marketing campaigns (Communications Block)",
      "status": "real",
      "route": "Hosted MCP over OAuth, the main server (it carries every Communications tool) or the narrow communications server (a person present for consent)",
      "steps": [
        {
          "id": "E1",
          "description": "Check the plan first: marketing email needs a plan that includes it (read motorical://docs/plans, never quote from memory), a sending domain must be verified and a marketing Motor Block assigned to the workspace. Then connect. On the communications server the first approval covers reading, editing lists, contacts, templates and campaign drafts, and sending a test to the owner; on the main server the first marketing approval is read-only and editing is added on request. Either way scheduling or cancelling, managing workspaces, managing webhooks and deleting lists, contacts, templates or campaigns each ask for their own permission the first time they are needed. Tell the person before each.",
          "humanRequired": true,
          "sayToHuman": "I'll connect to Motorical's marketing server over OAuth. You'll see a consent screen; later, scheduling a campaign will ask you for one more permission, and I'll tell you before it does."
        },
        {
          "id": "E2",
          "description": "Look before acting: who the connection acts for, what is still missing before a campaign can go out, and the workspaces, lists, templates and campaigns at a glance. Say the first missing thing, not the whole manual. Then read the three workspace settings with their explanations (does a click count as consent, are opens tracked, where do people go after unsubscribing) and go through them with the person once, in plain words: what each does, what their recipients will experience, and that the choice is theirs. They apply to every campaign in the workspace and a campaign cannot override them. Never switch one on or off yourself; change one only after the person says yes to the dry run, and preflight again afterwards.",
          "tools": [
            "motorical_whoami",
            "comms_get_readiness",
            "comms_get_map",
            "comms_get_workspace_settings",
            "comms_update_workspace_settings"
          ],
          "humanRequired": true,
          "sayToHuman": "Three settings shape what your recipients experience. Counting a click as consent is off unless you turn it on. Open tracking adds an invisible image so opens can be counted, and mail apps can inflate the numbers. After someone unsubscribes they see Motorical's page unless you give your own. Do you want any of these changed?"
        },
        {
          "id": "E3",
          "description": "Check which sender the mail will come from. The From address must be on a verified domain; a domain that is not verified yet needs DNS records, which only the person can add. The domain tools are on the main server and on the separate domains server (https://mcp.motorical.com/v1/motorical_domains/mcp), not on the communications server.",
          "tools": [
            "comms_list_marketing_blocks",
            "motorical_domain_dns_records",
            "motorical_domain_check_dns"
          ],
          "humanRequired": true,
          "sayToHuman": "Mail has to come from an address on your verified domain. Your domain needs one more DNS record: here it is. Tell me when you've added it and I'll check."
        },
        {
          "id": "E4",
          "description": "Bring the audience in: a dry run first, then ask for the consent basis of each source, then write what the list is and where it came from into its description. Never add back someone who unsubscribed; add opt-outs from a previous tool as suppressions before importing. Read the audience afterwards (counts by status, consent and domain, who is suppressed) before choosing the list.",
          "tools": [
            "comms_import_contacts",
            "comms_create_list",
            "comms_get_list",
            "comms_audience_summary",
            "comms_search_audience",
            "comms_suppression_info"
          ],
          "humanRequired": true,
          "sayToHuman": "Nothing has been imported yet. Were these people told they would get your marketing email? Then I'll import them."
        },
        {
          "id": "E5",
          "description": "Set the brand kit from facts the person gives (sender name, postal address, language and the footer reason line in their own words); never invent any of it, show a dry run, then write. Then make the template: use a starter when one fits instead of designing from scratch, and ask for the footer reason before saving, because the footer states why the person is getting the email and only the person can say that. If the person has not given a reason, the template still saves, with a neutral \"sent by\" line and a footer_reason_default warning: say plainly that the footer then does not tell people why they are receiving the email, and offer to add the reason. Read the rulebook, lint it, explain each finding in plain words, apply a fix only with a yes, write the text version on purpose, and preview what a recipient sees.",
          "tools": [
            "comms_get_brand_kit",
            "comms_set_brand_kit",
            "comms_list_starters",
            "comms_create_template_from_starter",
            "comms_get_template_rules",
            "comms_create_template",
            "comms_lint_template",
            "comms_preview_template",
            "comms_check_links",
            "comms_suggest_template_fixes",
            "comms_apply_template_fixes"
          ],
          "humanRequired": true,
          "sayToHuman": "What name and postal address should appear in the footer, and in your own words, why are these people getting this email? I will not make that up."
        },
        {
          "id": "E6",
          "description": "Draft the campaign, then run the preflight and show its numbers exactly as returned, warnings first: who will get it, who was left out and why, the forecast and the sender.",
          "tools": [
            "comms_create_campaign",
            "comms_preflight_campaign"
          ],
          "humanRequired": false
        },
        {
          "id": "E7",
          "description": "Send a test to the account owner (the only address a test can go to), from the campaign or straight from a template, and wait for them to look at it. Links in a test copy are placeholders; the result says so. Do not ask the person to click the unsubscribe link in the copy: it is a placeholder in a test. Check the real links with comms_check_links on the template; for a test of the real path (including a working unsubscribe link), a real campaign to a list holding one test address is the alternative.",
          "tools": [
            "comms_send_test",
            "comms_send_template_test",
            "comms_check_links"
          ],
          "humanRequired": true,
          "sayToHuman": "I've sent a test to your own address, marked as a test. Have a look, and tell me when you're happy with it."
        },
        {
          "id": "E8",
          "description": "Confirm the timezone out loud, read back one sentence naming the campaign, the subject, the sender, exactly how many people, and the time with its timezone, and schedule only on a clear yes to that sentence. A send is always scheduled at an explicit time, never \"now\": there is a minimum lead time (so there is time to cancel), a maximum, and a cap on schedules a day; read them from the limits-and-pacing resource (motorical://comms/limits-and-pacing), never from memory.",
          "tool": "comms_schedule_campaign",
          "humanRequired": true,
          "sayToHuman": "To confirm: send this campaign to that many people at that time in that timezone, from that sender. After that I can't recall it, only cancel it before it starts. Shall I schedule it?"
        },
        {
          "id": "E9",
          "description": "If the person says stop, cancel at once and say that cancelling is final.",
          "tool": "comms_cancel_campaign",
          "humanRequired": false,
          "stopCondition": "Cancelling a campaign that has started cannot take back what was already sent, and a cancelled campaign cannot be restarted."
        },
        {
          "id": "E10",
          "description": "Report how it did from the campaign's own report: every count with what it is out of, opens as estimates, and delivery outcomes allowed to lag the hand-off. A campaign held by a sending limit is waiting, not failing.",
          "tools": [
            "comms_get_campaign",
            "comms_get_campaign_report",
            "comms_get_campaign_timeline"
          ],
          "humanRequired": false
        }
      ],
      "note": "Clean up after testing: test objects stay until removed. With the delete permission an agent can delete a template or a campaign (a campaign goes to the recycle bin; dry run first; a template stays locked while any campaign uses it, even one in the recycle bin), otherwise the person removes them in the dashboard. The communications server and the main server also offer six prompts that run parts of this journey (motorical_run_campaign, motorical_import_audience, motorical_write_template, motorical_fix_template, motorical_set_up_brand, motorical_diagnose_campaign) and four reference resources under motorical://comms/. Limits and times are never quoted from memory: read them from the tools or from the limits-and-pacing resource."
    }
  ]
}
