Send a test

POST/api/v1/campaigns/{campaign}/test-send
Requires anorganization API keywith the scopecampaigns:write

Sends the campaign to addresses you name, so you can see it as a recipient would. Does not touch the audience and does not count against the campaign report.

Parameters

NameInTypeDescription
campaignrequiredpathstringThe campaign identifier.

Request

POST/api/v1/campaigns/{campaign}/test-send
curl -X POST 'https://app.mailyte.com/api/v1/campaigns/01JBT8XQ2M9WYC3K4F6R7S8T9V/test-send' \
  -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

    A TEST SEND IS NOT A SEND. It goes through the per-message path, not the fan-out: the campaign's state, its recipient ledger and its stats are all untouched, and the subject is prefixed so nobody mistakes it for the real thing. It is also the one campaign action that does not re-assert the marketing-review gate — you can test a campaign you cannot yet send.

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

      The campaign's lifecycle state, unchanged by the test send — identical before and after, which is the point of publishing it here.

    • sentinteger

      Results with status `sent`. Derivable, and kept: it is the headline, and it is computed in the same pass as `results` so the two cannot disagree.

    • requestedinteger

      Addresses attempted — at most five.

    • resultsarray<object>

      One row per address, in the order given.

      • emailstring

        The address this row is about. In practice NEVER null — a row exists only because an address was attempted, and the addresses are validated before any of this runs. The marker is defensive, not a case you have to handle.

      • statusstringsent | suppressed | rate_limited | failed | unknown

        `sent` was handed to the mail server; `suppressed` is on the organization's suppression list; `rate_limited` hit the organization's send rate limit; `failed` threw, see `error`. `unknown` means we did not recognise the value and should never be seen.

      • errorstring

        The raw exception message, PHP function names and all. Unstructured and not a closed set — do not parse it. Same wart as `campaign_recipient.error`, kept for the same reason. `null` means NONE — nothing went wrong on this row — and it is null exactly when `status` is `sent`: `suppressed` and `rate_limited` both carry a written explanation here rather than an exception, so a non-null `error` does not on its own mean the send threw.

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.