Recipients a campaign

GET/api/v1/campaigns/{campaign}/recipients
Requires anorganization API keywith the scopecampaigns:read

Parameters

NameInTypeDescription
campaignrequiredpathstringThe campaign identifier.

Request

GET/api/v1/campaigns/{campaign}/recipients
curl -X GET 'https://app.mailyte.com/api/v1/campaigns/01JBT8XQ2M9WYC3K4F6R7S8T9V/recipients' \
  -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
    • dataarray<object>
      • objectstringcampaign_recipient
      • idstring

        Unique identifier for the recipient row.

      • emailstring
      • contact_idstring

        Null for an address that reached the campaign without a contact row behind it.

      • statusstringpending | sent | failed | skipped_suppressed | skipped_unsubscribed | unknown

        `pending` is materialised but not yet attempted; `sent` was handed to the mail server; `failed` threw, see `error`; `skipped_suppressed` is on the organization's suppression list; `skipped_unsubscribed` opted out. `unknown` means we did not recognise the stored value and should never be seen.

      • errorstring

        The failure reason, VERBATIM from the send attempt — today that is whatever the transport threw, PHP function names included. Do not parse it or branch on it: it is unstructured, it is not a closed set, and it will change. It is published because `status: "failed"` on its own leaves you unable to tell a bad address from a broken TLS handshake. `null` means NONE — nothing went wrong on this row — and it is cleared back to null when a resend resets the recipient to `pending`. It is never "we did not look": `status` is the field that tells you whether to expect one.

      • sent_atstring

        When the message was submitted to the mail server. NOT a delivery confirmation — that is `engagement.delivered` on the campaign's stats. Stamped only on `status: "sent"`, so `null` means NONE — nothing was submitted for this row — which covers `pending`, `failed` and both `skipped_*` statuses. It is never "we did not look". One wrinkle: a resend resets the row to `pending` and clears `error` but LEAVES this timestamp, so a `pending` row on a resent campaign can carry the previous attempt's time. Read `status` first.

      • opened_atstring

        FIRST correlated open — a recipient who opens five times has one `opened_at`. Not a stored column: it is correlated from the delivery-event ledger and exists only on this endpoint. Null means none was observed, which for a campaign that has not started means nothing has been measured at all.

      • clicked_atstring

        First correlated click, on the same terms as `opened_at`: not a stored column, correlated from the delivery-event ledger, and available only on this endpoint. `null` means NONE was observed — no click has been correlated to this recipient — which for a campaign that has not started means nothing has been measured at all. It is correlated from `tracking.click` events, so it also reads null for a message whose links the tracking pipeline never produced an event for.

    • pagination_metaany

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.