Preflight a campaign

POST/api/v1/campaigns/{campaign}/preflight
Requires anorganization API keywith the scopecampaigns:read

Checks a campaign for the problems that would stop it — unverified domain, missing unsubscribe, empty audience, insufficient allowance — without sending anything.

Once Bounce protection is on for your account it also says how many recipients were never checked (unchecked_count, and about what share looks bad, likely_bad_percent) and how many the send will skip because their inbox is full (inbox_full_count, with the latest end of those holds in inbox_full_until). Skipped recipients are still in recipient_count; their recipient status reads skipped_inbox_full.

If your marketing is stopped because too many emails bounced, the blocker bounce_stop says so, and its message says how to start again.

This endpoint takes no request body.

Parameters

NameInTypeDescription
campaignrequiredpathstringThe campaign identifier.

Request

POST/api/v1/campaigns/{campaign}/preflight
curl -X POST 'https://app.mailyte.com/api/v1/campaigns/01JBT8XQ2M9WYC3K4F6R7S8T9V/preflight' \
  -H 'Authorization: Bearer mk_live_YOUR_API_KEY'
The key names its own organization, so no X-Organization-ID header is needed.

Response

Success.

  • dataobject

    Whether the campaign can go out now, and what is stopping it. Readiness depends on your account, the sender, the audience and today's limits, so check it just before sending. Only drafts are checked.

    • objectstringcampaign_preflight
    • campaign_idstring
    • statestringdraft | scheduled | sending | paused | sent | canceled | unknown

      The campaign's lifecycle state, from the same map campaign.state uses.

    • sendableboolean

      The verdict. Exactly blockers === [], computed in the same expression, and kept because "is there anything in this array" is a worse thing to have to write.

    • blockersarray<object>

      Everything stopping this campaign. Empty means it can be sent. Branch on code: POST /send and POST /schedule give only the message.

      • codestringnot_draft | marketing_review_pending | sender_unverified | no_content | no_unsubscribe | no_audience | warmup_exceeded | marketing_allowance | scheduled_sends | bounce_stop | sample_content

        Why the campaign cannot go out. - not_draft: only a draft can be scheduled. - marketing_review_pending: your account's marketing application is not approved yet. - sender_unverified: the sender is not verified. - no_content: no subject and HTML body, and no template. - no_unsubscribe: the HTML has no unsubscribe link. - no_audience: no list or segment chosen. - warmup_exceeded: more recipients than today's warm-up limit allows. - marketing_allowance: more recipients than your marketing emails left this month. Scheduling answers 402 and names the plan that covers it. - scheduled_sends: a send time on a plan without scheduling. - bounce_stop: your marketing is stopped because too many emails bounced; message says how to start again. - sample_content: the email still has a gallery design's sample text, or a link or image to a placeholder address such as example.com; message names what to change.

      • fieldstring

        Which part of the campaign the code is about.

      • messagestring

        Human-readable prose. Not stable — branch on code.

    • warningsarray<object>

      Worth knowing, does not stop the send.

      • codestringinsufficient_credits

        insufficient_credits: your balance is below the number of recipients. A warning, not a blocker: scheduling still works.

      • fieldstring

        Which part of the campaign the code is about.

      • messagestring

        Human-readable prose. Not stable — branch on code.

    • recipient_countinteger

      How many contacts the campaign would go to now, counting each person once and leaving out those who cannot be emailed.

    • credit_balanceinteger

      Whole sends, not money: one credit is one recipient. The organization's balance in currency belongs to billing.

    • personalizationobject
      • variablesarray<object>

        Which template variables the content uses. Called variables, not tags, because this API already uses tags for the send-time correlation labels stamped on every message.

        • namestring

          The variable's name, without braces.

        • systemboolean

          True for variables that always have a value when sending: email, sender_name, sender_email, organization_name and unsubscribe_url. Their missing is always 0. name is not one of them, because a contact may have no name.

        • missinginteger

          Recipients in the audience with no value for it. A count, not a rate — recipient_count is the denominator if you want one.

        • defaultstring

          The organization's contact-field default, which fills a blank at send time. A variable with a default is never actually empty, so a non-zero missing beside a non-null default is informational rather than a problem.

      • has_unsubscribeboolean

        Whether the content satisfies the compliance gate that no_unsubscribe enforces. The blocker is the refusal; this is the observation, and both read the same check.

    • warmupobject

      Today's warm-up limit for the sending address. Null when your account is not warming up a dedicated IP (most accounts), or when the limit could not be read.

      • dayinteger

        Which day of the warm-up curve this is. Never null when the enclosing warmup object is present — the snapshot that builds it either has every figure or is itself null.

      • ceilinginteger

        How many recipients today's warm-up allows.

      • sent_todayinteger

        Recipients already sent from this address today.

      • remaininginteger

        How many more recipients today's warm-up allows: ceiling minus sent_today, never below 0.

      • recipientsinteger

        What THIS campaign would add — the same projection as the top-level recipient_count. Never null when the enclosing warmup object is present.

      • completes_onstring

        The date warm-up finishes. Null when it cannot be worked out.

    • unchecked_countinteger

      Recipients whose address was never checked, counted once each, out of recipient_count. POST /campaigns/{id}/check-recipients checks them, one check each. Always 0 while Bounce protection is off.

    • likely_bad_percentinteger

      Roughly what percent of recipient_count looks bad among the unchecked recipients, from a free estimate. Null when there are too few to estimate (under 10), while the estimate is being made, when it cannot be made, or while Bounce protection is off.

    • inbox_full_countinteger

      Recipients whose inbox was full when last checked. Marketing to them is held for 7 days, so the send skips them and uses no credit for them. Counted as of the send time. recipient_count still includes them. Always 0 while Bounce protection is off.

    • inbox_full_untilstring

      The latest time any of the inbox_full_count holds ends. null when inbox_full_count is 0.

Returned inside the standard envelope.

Errors

StatusWhen
401The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist.
403The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys.
404No such resource in this organization.
422The request was understood but the values were not acceptable.
429Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait.

Every status, with what causes it and what to do, is on the error reference.