---
name: nitrosend/onboarding
version: 2026.08.17
updated: 2026-08-17
description: Plan a first branded email send on Nitrosend through a prepared brand-subdomain sender or a verified customer domain, using the canonical delivery-capacity outcome from nitro_get_status.
---

# Nitrosend Onboarding

**TL;DR.** Nitrosend is an AI-native multi-channel (email + SMS) marketing
automation platform driven through an MCP server. This skill teaches an
agent the platform. Vocabulary, send modes, tool surface, response
envelope, lifecycle, safety. And turns one bounded first-email objective
into a deterministic plan along the campaign-first path. Two paths:
`prepared_sender_first_email` (fastest safe test) or
`live_campaign_readiness` (approval-ready live campaign).

**Who this file is for.** Primarily agents immediately after MCP connect.
Also developers evaluating the platform.

**Related artifacts.** `nitro://guide` (authoritative reference, live),
`nitro://schema` (section/trigger/filter specs), `https://nitrosend.com/llms-full.txt`
(full-platform context), `https://api.nitrosend.com/openapi.yaml` (REST API).
If those disagree with this file, they win. They come from runtime state.

## Before you start

The caller needs the Nitrosend MCP connected and a Nitrosend account signed
in. OAuth handles signup and auth in-flow. No API key, no dashboard visit
for standard clients.

**Choose the right surface.** For Claude Desktop, Claude.ai, Claude Cowork,
ChatGPT, Cursor, Gemini, VS Code, Windsurf, and Zed, use the remote MCP
connector. Do not recommend the Nitrosend CLI, `nitrosend login`, or the local
`@nitrosend/mcp` bridge for standard Claude Desktop setup. Those are terminal
and stdio fallback surfaces, not the chat-client onboarding path.

The Nitrosend CLI is for a user terminal, CI, and headless agent runners with
real shell and network access. If an agent's command sandbox cannot reach
`api.nitrosend.com`, verify Nitrosend through the connected MCP tools instead
of trying to install or authenticate the CLI inside that sandbox.

**Connect once.** Pick your client:

```bash
# Claude Code
claude mcp add --transport http nitrosend https://api.nitrosend.com/mcp

# Codex CLI
codex mcp add nitrosend --url https://api.nitrosend.com/mcp
```

For **Claude Desktop**, **ChatGPT** (Developer Mode), **Cursor**, **Gemini**,
**VS Code**, **Windsurf**, or **Zed**, add a remote HTTP MCP server with URL
`https://api.nitrosend.com/mcp` via the client's MCP settings UI. Per-client
guides: <https://docs.nitrosend.com/integrations/overview>.

Sign in when your client opens the browser prompt. If it does not prompt:

- Claude Code: `/mcp`
- Codex CLI: `codex mcp login nitrosend`

Headless or CI clients without an MCP client can authenticate with a
`nskey_live_*` Bearer token instead. The key can be minted entirely over
HTTP with no dashboard visit — see "Headless / coding-agent path" below.

**Verify connection.** After signing in, call `nitro_get_status`. A
healthy connection returns JSON with `account`, `brand`, `issues`, and
`recommendations` keys. Failure at this step is almost always an auth
problem. Re-run the login command above. Then read `nitro://guide` and
`nitro://account` to ground the session.

Once connected, call `nitro_get_status`. Its JSON response is the
`account_status_json` input to this skill.

## Headless / coding-agent path (no dashboard, no MCP client)

For coding agents and builder stacks that can call HTTP but have no MCP
client (Replit, Lovable, v0, Bolt, CI runners), the whole first-send loop
runs over REST with zero dashboard visits:

1. **Create an account.** `POST /v1/signup` with `{ "user": { "email", "password" } }`. Returns a 15-day JWT in the `Authorization` response header.
2. **Mint an API key.** `POST /v1/my/api_keys` with that JWT. Returns `nskey_live_...`; store it as a secret.
3. **Prepare the reserved sender.** `POST /v1/my/brands/{sid}/prepare_sending` creates DNS, DKIM, provider identity, and tenant resources for the reserved `<brand>.nitrosend.com` name. Poll `GET /v1/my/brands/{sid}` until `brand_subdomain.ready` is true, then explicitly select a From local part with `PATCH /v1/my/brands/{sid}` and `{ "sender_local_part": "hello" }`.
4. **Send once ready.** `POST /v1/my/messages` with `{ "channel": "email", "to", "subject", "html" }` plus an `Idempotency-Key` header. If an eligible first attempt starts preparation, it returns retryable `sender_identity_provisioning` and stores no message; retry the same key only after readiness and selection.
5. **Optional customer-domain or paid-plan path.** A customer-owned domain needs DNS verification. Paid checkout needs a card; `$0` plans activate without one.

Node/Python `fetch`/`requests` calls work as-is; only the bare `Python-urllib` user agent is WAF-blocked. Once a client can speak MCP, the `nitro_*` tools above are the richer surface.

## Core principles

Apply these before doing anything else:

1. **Campaign-first.** For "send an email" asks, default to a campaign
   (one design → audience, approval gate). Flows are for automation, not
   one-shots; transactional is for system messages, not marketing. This
   ordering matches how users think in a marketing context and keeps the
   delivery lifecycle explicit.
2. **Brand auto-applies.** Do not invent colors, fonts, or an unsubscribe
   footer. Read `nitro://brand-kit` before composing; pass `header`/`footer`
   sections with empty props.
3. **Never send live without explicit user confirmation.** Draft, review,
   test. But `nitro_control_delivery(action: "approve" | "schedule")`
   only after the user says go. If audience is `all_contacts`, also
   require `confirm_send_to_all: true`.
4. **Trust the snapshot.** Do not assume state. Inspect
   `nitro_get_status` and skip setup steps that are already complete
   (see "Partial-state handling" below).
5. **Read the response envelope.** Every tool response carries sidecar
   enrichers with guidance. Use them (see "Response envelope" below).

## Core vocabulary

Know these terms before planning anything:

- **contact**. A person in the audience. Has `email` and/or `phone`
  channels with separate subscribed state.
- **contact_list**. A named group of contacts (static membership).
- **segment**. A dynamic filter-based subset of contacts.
- **brand**. Visual identity: colors, fonts, logo, tone, physical address.
  Applied automatically to every email. Scrape from a URL or set explicitly.
- **brand subdomain**. The protected `<brand>.nitrosend.com` sender reserved
  at brand creation and provisioned only on demand. It must be ready and
  explicitly selected before sending.
- **customer domain**. A verified sending subdomain owned by the customer.
  It keeps reputation and capacity separate from the Nitrosend brand subdomain.
- **template**. An email design stored as JSON sections (not an HTML
  string). Every email. Campaign, flow step, or standalone. Is a template.
- **campaign**. A marketing broadcast to an audience (list, segment, or
  all contacts). Must be approved before it can send.
- **flow**. An automated sequence triggered by an event (e.g.
  `contact_add`, list join, custom event). Can contain email, SMS, delay,
  and branching steps.
- **message**. A per-send record. Transactional messages fire
  immediately; campaign and flow messages are created at send time.
- **sender capacity**. Rolling headroom for one exact sender. It grows only
  from mature, clean volume that Nitrosend actually dispatched for that sender.
  Payment, account/domain age, imports, and validation grant no headroom.
- **delivery status**. The canonical `nitro_get_status.delivery` projection of
  commercial capacity, sender capacity, brand-subdomain capacity, and pacing.
- **idempotency_key**. Per-send dedup key. Same key returns the original
  message instead of double-sending. Use for every transactional send.

## Pick the right send mode

```
Does the user want ONE recipient, right now, tied to app code?
  → Transactional  (POST /v1/my/messages or the Node SDK)

Does the user want ONE design sent to MANY recipients, once or scheduled?
  → Campaign       (nitro_compose_campaign → review → approve)

Does the user want a SEQUENCE triggered by an event (welcome series,
abandoned cart, re-engagement, winback)?
  → Flow           (nitro_compose_flow → review → activate)

Still unsure?
  → Ask the user. Do not guess.
```

### 1. Campaign: bulk broadcast

One design sent to an audience, once or scheduled.

- Draft via MCP: `nitro_compose_campaign(name, subject, sections, audience_type, ...)`. Creates campaign + template + backing flow atomically.
- Review: `nitro_review_delivery(target_type: "campaign", target_id)`. Share `editor_url` with the user.
- Test (optional): `nitro_send_test_message(target_type: "campaign", ...)`.
- Approve/launch: `nitro_control_delivery(target_type: "campaign", action: "approve" | "schedule", ...)`.
- Also available via REST: `POST /v1/my/campaigns`, `POST /v1/my/campaigns/{id}/send`. See <https://api.nitrosend.com/openapi.yaml>.

Default tool when the user says "draft/compose/send an email."

### 2. Flow: automated sequence

Event-triggered series of steps (email + SMS + delay + branching).
Typical triggers: `contact_add`, list join, custom event.

- Build: `nitro_compose_flow(name, mode: "create" | "replace" | "patch", trigger, steps, ...)`.
- Review: `nitro_review_delivery(target_type: "flow", target_id)`.
- Approve/activate: `nitro_control_delivery(target_type: "flow", action: "approve", ...)`.

Flows are **out of scope for this skill**, but recognize flow-shaped asks
(welcome series, abandoned cart, re-engagement) and route to
`nitro_compose_flow` instead of forcing a campaign.

### 3. Transactional: single-recipient immediate

One email or SMS to one recipient, right now. No audience, no approval,
no lifecycle. Use for receipts, password resets, OTPs, order
confirmations, system notifications.

**Via REST API**. For application backends and non-MCP contexts:

```bash
curl -X POST https://api.nitrosend.com/v1/my/messages \
  -H "Authorization: Bearer nskey_live_..." \
  -H "Idempotency-Key: order-42" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "to": "user@example.com",
    "subject": "Your receipt",
    "html": "<h1>Thanks!</h1><p>Your order is confirmed.</p>",
    "data": {"order_id": "..."}
  }'
```

Both paths are equivalent. Same message record, same pipeline, same
dedupe semantics. Prototype with the MCP tool, ship with the REST call.
Same-key retries dedupe via `Idempotency-Key` header or `idempotency_key`
field.

Transactional is **out of scope for this skill**. Route directly.

## MCP tool surface

All 25 tools are prefixed `nitro_`:

**Account + status**
- `nitro_get_status`. Current account, brand, sender, `brand_subdomain`, canonical `delivery` status, dashboard links, readiness, issues, and recommendations
- `nitro_select_account` / `nitro_select_brand`. Switch the active account/brand. OAuth-only: API-key connections are pinned to their key's brand.
- `nitro_configure_account`. Sender defaults (`from_name`, `from_email`, `reply_to`, test recipients)
- `nitro_configure_providers`. BYO email provider credentials + status
- `nitro_manage_billing`. Plan, checkout, checkout_status, list plans

**Brand + assets**
- `nitro_set_brand_kit`. Scrape from URL or set colors/fonts/logo/address directly
- `nitro_ingest`. Upload local/chat image; returns CDN URL for email fields

**Domains**
- `nitro_manage_domains`. `prepare_brand_subdomain`, `select_brand_subdomain`, add, verify, check_dns, list, and remove

**Audience**
- `nitro_import_contacts`. Inline records (<100) or reference a pre-uploaded CSV import
- `nitro_search_contacts`. Full-text find by email/name/phone
- `nitro_query`. Structured filters across any entity (contacts, campaigns, flows, templates, segments, lists, …). Pagination: pass `page` + `per_page`; read `X-Total-Count` etc.
- `nitro_manage_audience`. Contacts, subscriptions, lists, events, segments, tags
- `nitro_define_segment`. Filter-based contact subset (`preview_only: true` by default)

**Composing**
- `nitro_compose_campaign` - **default for drafting emails**. Campaign + template + flow
- `nitro_compose_flow`. Create/replace/patch an automation flow
- `nitro_manage_template`. Create/update/clone a reusable standalone template (not sendable on its own. Attach to a campaign first)

**Delivery**
- `nitro_review_delivery`. Read-only validation, preflight, spam score, SMS segment info, `editor_url`
- `nitro_send_test_message`. Real test send to the saved test recipient (no audience, no approval)
- `nitro_send_message`. Single transactional send (email/SMS) to one recipient, immediate. Same as `POST /v1/my/messages`.
- `nitro_control_delivery`. Approve, schedule, live, pause, cancel, archive (campaigns + flows)

**Intelligence**
- `nitro_get_insights`. Analytics, trends, benchmarks, recommendations
- `nitro_search_docs`. Search the Nitrosend docs / knowledge base for how-tos and reference.
- `nitro_set_memory`. Read/update/patch/append the AI memory document

**Support**
- `nitro_request_support`. Escalate to Nitrosend. Call only when the user asks explicitly or all other tools are exhausted.

### When to read each resource

- **Always at session start:** `nitro://guide` (authoritative platform
  reference. Vocabulary, workflows, constraints).
- **Before composing an email:** `nitro://brand-kit` (voice, colors,
  company), then `nitro://schema` (section prop specs).
- **When validating state:** `nitro://account` (live tier, counts,
  onboarding, Brand Kit status).
- **When stuck on error codes or provider quirks:** `nitro://providers`,
  `nitro://config`.
- **For reference payloads:** `nitro://examples/email`,
  `nitro://examples/flow`, `nitro://examples/campaign`.
- **For cross-session memory:** `nitro://memory` (see "Memory" below).
- **For marketing best-practice lookups:** `nitro://knowledge/index`,
  then `nitro://knowledge/{slug}` for a specific topic.

## Response envelope

Every tool response carries structured sidecars. Read them. They contain
the platform's best guidance for what to do next.

- **`feedback.knowledge`**. Relevant marketing best practice surfaced
  for the current action (populated on goal-driven + insights responses).
- **`feedback.quality`**. Quality/readability notes about the content
  you just created.
- **`flywheel_context`** - `{applied, data_maturity, contributions}` -
  how much the platform's learning model informed the response.
- **`memory_delta`**. Emitted when the call changed the AI memory
  document. Non-null means "the platform learned something from this."
- **`next_action`**. Plain-string recommendation. If present, surface
  it to the user unless you have a better one.
- **On error:** `how_to_fix` (remediation) and sometimes
  `suggested_tool_call` (exact next call to make).

### Error handling

Nitrosend errors are actionable. **Do not retry the same call on error.**
Read `how_to_fix` and follow it. If `suggested_tool_call` is present, call
that instead. If the error is ambiguous, ask the user for what
`how_to_fix` is missing, not for "what to do next." Common classes:

- **Validation (422)**. Missing required field or bad value. `how_to_fix`
  names the field.
- **Preflight block**. E.g. domain not verified, physical address
  missing, no subject. Fix the named blocker, then re-call.
- **Capacity / pacing deferral**. Read `delivery.reason_code`, `issues`, and
  `retry_at`; wait or reduce the audience as directed. Never calculate a
  private limit from the plan name.
- **Auth**. Re-run the client's login command.

## Composing emails

Emails are **structured sections**, not HTML strings. The brand theme
auto-applies. Do not override colors or fonts unless the user asks.

Minimum viable email = header + text + button + footer:

```json
[
  {"type": "header", "props": {}},
  {"type": "text",   "props": {"content": "<h1>Hello!</h1><p>Your message here.</p>"}},
  {"type": "button", "props": {"text": "Get Started", "href": "https://example.com"}},
  {"type": "footer", "props": {}}
]
```

`header` auto-fills the logo from brand. `footer` auto-fills company
name, physical address, and unsubscribe link. Pass `{"props": {}}` for
both.

Section types: `header`, `text`, `image`, `button`, `hero`, `columns`
(2-4; cannot nest), `product`, `social`, `divider`, `spacer`, `footer`.
Read `nitro://schema` for full prop specs.

Images: public URLs drop straight into `image.src`, `product.image_url`,
`hero.background_url`, `theme.logo_url`. For local or chat-attached
images, call `nitro_ingest` first and use the returned CDN URL.
Never persist `data:` URIs.

Always pass `name` + `subject` + `sections` together when composing a
campaign. A campaign with only a name fails review.

## Delivery lifecycle

Campaigns and flows both use an approval-based state machine:

```
draft → approve → live/scheduled ↔ pause → cancel → archive
```

Approval gates (all must pass for a live send):

- one ready, explicitly selected brand-subdomain sender or verified customer domain
- active subscription
- physical address set (CAN-SPAM)
- template has subject + content
- sender email configured (`from_email` matches a verified domain)

`nitro_control_delivery` drives every transition. `approve` makes a
campaign eligible; `schedule` requires `scheduled_at` (ISO 8601);
`reject` reverts to draft. Approval is not a capacity reservation. Before a
large send, inspect `nitro_get_status.delivery`; the single delivery authority
rechecks current capacity, pacing, health, provider, and circuit state when it
reserves and dispatches.

Test sends (`nitro_send_test_message`) do not approve a campaign, but they use
the same delivery authority and require an eligible ready sender. No provider
call bypasses current safety controls.

### Safety rules

- **Never approve a live send without explicit user confirmation.**
  Present the review + `editor_url` first and wait.
- **Audience `all_contacts` requires `confirm_send_to_all: true`.** Only
  set it after the user re-confirms with that audience named.
- **Schedule beats live.** If the user is unsure, propose a schedule;
  they can cancel before `scheduled_at`.

## Partial-state handling

Never assume a blank account. Inspect the snapshot and skip what is done:

| Snapshot signal | Skip |
|---|---|
| `brand.setup_complete: true` | `nitro_set_brand_kit` (unless user requests a change) |
| `brand_subdomain.ready: true` and `brand_subdomain.selected: true`, or a verified customer domain is selected | sender preparation and selection |
| `brand.contact_count > 0` AND objective is test-only | `nitro_import_contacts` |
| `config.from_email` matches a verified domain | `nitro_configure_account` |

Plan the shortest incomplete prefix of the path's tool order. Do not
reset progress. If unsure whether a step is needed, ask the user.

## Memory

`nitro_set_memory` maintains a per-brand markdown notepad that persists
across sessions. Use it for:

- Learned user preferences (brand voice, typical audience, send cadence).
- Goals and active initiatives (Q2 launch, winback campaign in flight).
- Corrections from the user ("don't use pink buttons", "always sign off
  from Jenna").

Operations: `read` (get current), `update` (replace entirely),
`patch` (replace a single `## section` by heading), `append` (add to
end). Soft cap 10KB, hard cap 15KB. Read `nitro://memory` any time to
see the current document.

Write to memory after the user corrects you, confirms a non-obvious
choice, or states a goal. Do not write ephemera (today's subject line).

## Pricing & tiers: quick reference

The Free plan includes 8,000 free emails up front, then 500 free emails every
month. Quote it exactly that way: the 8,000 up-front allowance is the part
summaries drop.

Read `nitro://account` for the current account's live caps. Defaults:

| Tier | Email/mo | AI/mo | Brands | Domains | Seats | Branding | Notable |
|---|---|---|---|---|---|---|---|
| Free | 8,000 then 500/mo | 20 | 3 | 1 | 1 | shown | 50 commercial recipients / rolling 24h |
| Pro | 20,000 | 1,000 | 5 | 3 | 3 | removable | 10,000 commercial recipients / rolling 24h |
| Ultra | 125,000 | 5,000 | 10 | 10 | 10 | removable | 62,500 commercial recipients / rolling 24h |
| Enterprise | 500k-4M+ | unlimited | unlimited | unlimited | unlimited | removable | SSO, dedicated IP add-on ($50/mo via SES) |

**Upgrade from inside the agent:** call
`nitro_manage_billing(operation: "checkout", params: {plan_slug: "pro"})`
and share the returned checkout URL with the user. Poll
`operation: "checkout_status"` until paid. No need to leave the chat.

## Observability after send

A send is not "done" when it goes live. Propose this follow-up to the
user:

- **T+1 hour:** `nitro_get_insights(scope: "campaign", campaign_id)` -
  first-hour open/click signal, bounce spikes, spam complaints.
- **T+24 hours:** second check for settled metrics, plus a
  recommendation summary if the insights envelope includes one.
- **On anomalies:** suggest concrete fixes (reschedule, suppress, rewrite,
  domain check) based on `feedback.knowledge` in the insights response.
  Use A/B testing for subject lines or content when the campaign needs a
  measured comparison.

## What this skill plans

Plans **one campaign-first first-email path** from one bounded objective
and a `nitro_get_status` snapshot. It does not plan flows, SMS campaigns,
or transactional sends. Route those to the tools documented above.

Output: one `onboarding_plan` object. Do not invent status or skip the
snapshot. If the snapshot is missing information needed to choose a safe
path, return `decision: "needs_input"` instead of guessing.

### Inputs

- `objective`. The bounded user goal
- `account_status_json`. JSON string from a recent `nitro_get_status`
- `operator_context`. Optional extra guardrails from the caller
- `client_surface`. Optional; usually `runx_skill_cli` or `mcp_direct`

### Output schema (`onboarding_plan`)

```yaml
decision: ready | needs_input | reject
chosen_path: prepared_sender_first_email | live_campaign_readiness | none
rationale: string                     # why this path, why not the other
execution_surface:
  primary:  runx_skill_cli | nitrosend_mcp
  fallback: nitrosend_mcp  | runx_skill_cli
ordered_tool_calls:
  - tool: nitro_*
    purpose: string                   # why this call, in this order
    requires_confirmation: boolean    # true only for nitro_control_delivery
human_actions: [string]               # DNS records, explicit approvals
blockers: [string]                    # preconditions still missing
needs_input: [string]                 # what to ask the user
unsupported_requirements: [string]    # asks outside this lane
rejection_reason: string              # only when decision=reject
success_checkpoint:
  milestone: string                   # e.g. test_email_received
  description: string
```

`ordered_tool_calls` must stay in canonical campaign-first order.
`nitro_control_delivery` must only appear with
`requires_confirmation: true`.

## Supported paths

### `prepared_sender_first_email`

Fastest inbox win. A branded test email through a ready, explicitly selected
sender, with no live audience send.

Tool order:

1. `nitro_set_brand_kit`. Skip if `brand.setup_complete` is true
2. `nitro_manage_domains`. Prepare and explicitly select the reserved
   brand-subdomain sender unless another eligible sender is already selected
3. `nitro_compose_campaign`
4. `nitro_review_delivery`. Share `editor_url` with the user
5. `nitro_send_test_message`

Do not require contact import or live approval. Do require a current eligible
sender; a test send is not a gate bypass.

### `live_campaign_readiness`

Real audience send or approval-ready live campaign.

Tool order:

1. `nitro_set_brand_kit`. Skip if `brand.setup_complete`
2. `nitro_manage_domains`. Skip only if an eligible sender is ready and explicitly selected
3. `nitro_import_contacts`. Skip if `account.contact_count > 0` and the user is not importing new
4. `nitro_configure_account`. Skip if `from_email` already matches a verified domain
5. `nitro_compose_campaign`
6. `nitro_review_delivery`
7. `nitro_send_test_message`
8. `nitro_control_delivery` - `requires_confirmation: true`

`nitro_control_delivery` is only for post-confirmation planning. Never
present it as automatic or immediate.

## Worked example

**Input**

```yaml
objective: Get a first branded test email into my inbox today.
operator_context: Keep this on the fastest safe campaign-first path.
account_status_json: |
  {
    "status": "needs_attention",
    "account": {"tier": "free"},
    "brand":   {"setup_complete": false, "company_name": "Acme Co",
                "can_send": false, "contact_count": 0, "campaign_count": 0},
    "brand_subdomain": {"status":"not_prepared", "ready":false,
                        "selected":false, "preparation_required":true,
                        "fqdn":"acme-co.nitrosend.com"},
    "delivery": {"assessment_scope":"sender_capacity",
                 "admission_status":"denied",
                 "blocking_control":"sender_identity",
                 "reason_code":"sender_not_ready"},
    "issues":  [{"area":"brand_kit","severity":"warning",
                 "message":"Physical address not set",
                 "how_to_fix":"Use nitro_set_brand_kit to set physical_address"}],
    "recommendations": [
      {"action":"Set physical address","tool":"nitro_set_brand_kit"},
      {"action":"Prepare or verify a sending identity","tool":"nitro_manage_domains"}
    ]
  }
```

**Output**

```yaml
onboarding_plan:
  decision: ready
  chosen_path: prepared_sender_first_email
  rationale: >
    The caller wants the fastest inbox win. The reserved brand-subdomain sender
    must be prepared and explicitly selected before the test can dispatch.
  execution_surface:
    primary: runx_skill_cli
    fallback: nitrosend_mcp
  ordered_tool_calls:
    - tool: nitro_set_brand_kit
      purpose: Set Brand Kit identity and physical address before composing.
      requires_confirmation: false
    - tool: nitro_manage_domains
      purpose: Prepare the reserved brand-subdomain sender, poll readiness, and explicitly select its From address.
      requires_confirmation: false
    - tool: nitro_compose_campaign
      purpose: Create the campaign draft for the first branded email.
      requires_confirmation: false
    - tool: nitro_review_delivery
      purpose: Review validation, preflight, and editor URL before any inbox check.
      requires_confirmation: false
    - tool: nitro_send_test_message
      purpose: Send a real test message to the operator inbox.
      requires_confirmation: false
  human_actions:
    - Review the editor preview before the test send.
  blockers: []
  needs_input: []
  unsupported_requirements: []
  success_checkpoint:
    milestone: test_email_received
    description: A branded campaign draft has been reviewed and a test email lands in the inbox.
```

Two more worked examples (live readiness + rejected multi-lane ask) live
in the harness at `/X.yaml` on the same origin.

## After the first send

- **Want an automation, not a one-shot?** `nitro_compose_flow`. Welcome
  series, abandoned cart, re-engagement, re-permission.
- **Transactional integration (receipts, OTPs, order confirmations)?**
  Use `POST /v1/my/messages` or the Node SDK from application code. Spec:
  <https://api.nitrosend.com/openapi.yaml>.
- **Close the observability loop.** Schedule T+1h and T+24h
  `nitro_get_insights` checks (see "Observability after send").
- **Hit the Free cap or want higher volume?** Upgrade inline with
  `nitro_manage_billing(operation: "checkout", ...)` or see
  <https://nitrosend.com/pricing>.
- **Verify a sending domain, invite teammates, or connect BYO provider
  keys?** <https://docs.nitrosend.com>.

## Reject instead of guessing

This skill plans a first email send. One campaign, one Brand Kit-driven design,
one test or live broadcast. Reject asks outside that lane and route to
the appropriate tool:

- flow-first onboarding → `nitro_compose_flow`
- SMS-first onboarding → `nitro_compose_campaign(channel: "sms", ...)`
- transactional-only sends → `POST /v1/my/messages` or the Node SDK
- cross-lane "set everything up" asks → call `nitro_get_status`, then
  ask the user to narrow the goal
- combined flow + campaign + SMS orchestration → split into bounded
  asks, one tool per bounded goal

Use `decision: "needs_input"` when the ask is within this skill's lane
but too vague to choose between quickstart and live readiness.

## Current operating notes

- **Structured email editor**. Every email is JSON sections. Paste HTML
  only inside a `text` section's `content` prop.
- **A/B testing**. Use campaign variants for measured subject or content
  comparisons.
- **SMS tiers**. SMS requires a paid tier and a Twilio integration.
- **Column structure**. Keep column sections one level deep and compose
  more complex layouts as sibling sections.
- **HTML content**. Put arbitrary HTML in a `text` section's `content`
  prop.
