---
title: "Resend campaign to non-openers"
method: POST
path: "/campaigns/{campaignId}/resend-to-non-openers"
tags: ["Campaigns"]
---

# Resend campaign to non-openers

`POST /campaigns/{campaignId}/resend-to-non-openers`

## Request

- Base URL: `https://api.sequenzy.com/api/v1`
- URL: `https://api.sequenzy.com/api/v1/campaigns/{campaignId}/resend-to-non-openers`
- Auth: HTTP bearer

Creates a draft that resends a sent campaign to everyone in the same audience who didn't open it. Reuses the original audience plus a "didn't open this campaign" rule. Only available 6 hours after the campaign finishes sending, and never for imported already-sent campaigns, which have no opens in Sequenzy. The draft must be scheduled or sent separately. Every audience format stores excludedCampaignOpenerIds that manual additions cannot override, preserving inherited exclusions on repeated resends. Audience membership is evaluated live. Recreate older drafts missing this metadata from the original campaign and review before scheduling.

## Path parameters

- `campaignId` string, required

## Response `200`

Non-opener resend draft created

- object
  - `success` boolean
  - `campaign` object
    - `id` string
    - `name` string
    - `type` 'email' | 'sms' | 'push': Delivery channel. SMS campaigns are created and managed from the dashboard, and push campaigns through the /push/campaigns endpoints: they carry no email, so `subject` and `blocks` come back empty, and the email-only endpoints (update, schedule, pause, resume, duplicate, resend to non-openers) reject them. Campaign stats and campaign events reject them too, since both read email engagement. Cancelling a push campaign through POST /campaigns/{campaignId}/cancel uses the push lifecycle.
    - `subject` string
    - `emailId` string, nullable: ID of the new resend email.
    - `emailPreset` 'branded' | 'minimal' | 'null', nullable: Per-email Style > Format, derived from the stored blocks. `branded` renders the company logo and the full footer; `minimal` renders no logo and the simple footer. Null when the entire email is a single raw HTML block, which has no Sequenzy format. Sequence steps, campaigns, transactional templates, and saved templates all report this field, so chrome can be compared across emails without rendering them.
    - `hasAudience` boolean: Whether an explicit audience is configured. False for unset or empty selections. This does not validate resource existence or count eligible recipients. Draft rows can use this for an Audience set indicator.
    - `status` 'draft' | 'scheduled' | 'waiting_approval' | 'rejected' | 'sending' | 'paused' | 'sent' | 'cancelled': Campaign status. `waiting_approval` means the campaign is held for safety review and is not sending; this is most common on new accounts and recently registered sending domains. See https://docs.sequenzy.com/concepts/campaigns#safety-review
    - `rejectionComment` string, nullable: Reviewer feedback when the campaign status is rejected. Stays null while a campaign is still in waiting_approval.
    - `trackingCode` string, nullable: Campaign tracking code available to UTM templates as `{{campaign.trackingCode}}`.
    - `labels` string[]: Label names assigned to this campaign.
    - `scheduledAt` string, date-time, nullable
    - `sentAt` string, date-time, nullable: For native sends, when the send finished. It is stamped after the last recipient is handed off, so for a spread or optimal-time send this is the end of the delivery window rather than when sending started. Imported campaigns retain the source provider's timestamp.
    - `createdAt` string, date-time
    - `spreadOverHours` integer, nullable: Hours the send was (or will be) spread over. Null means there is no fixed spread; inspect sendTimeOptimization to distinguish an optimal-time send from a campaign with no recorded pacing. Imported campaigns may not include source-provider pacing data.
    - `sendTimeOptimization` boolean: Whether each recipient is sent at their best predicted open time. Campaign-only: there is no company or sequence STO setting. Sequences use sendingWindow instead. Always false when spreadOverHours is set: setting a spread clears send time optimization.
    - `sendTimeWindowHours` integer, nullable: Window send time optimization may deliver within, in hours from scheduledAt. Defaults to 12 and only applies when sendTimeOptimization is true.
    - `sendInRecipientTimezone` boolean: Whether the campaign is delivered at the scheduled wall-clock time in each recipient's timezone.
    - `scheduledTimezone` string, nullable: Stored IANA timezone that anchors the campaign's scheduled wall-clock time. Use sendInRecipientTimezone to determine whether recipient-timezone delivery is enabled; this value may remain set when that mode is disabled.
    - `maxRecipients` integer, nullable: Recipient cap applied when the audience is resolved at send time. The first N matching subscribers (by subscriber id) receive the campaign after every audience and suppression rule; recipients already reached count against the cap when a paused send resumes. Null means the whole audience is targeted.
    - `preheader` string
    - `preheaderText` string: Compatibility alias for preheader.
    - `blocks` EmailBlock[]
      - `id` string
      - `type` 'text' | 'html' | 'heading' | 'list' | 'button' | 'spacer' | 'divider' | 'image' | 'columns' | 'group' | 'conditional-group' | 'repeat' | 'card' | 'cta' | 'social' | 'logo' | 'header' | 'footer' | 'video' | 'product' | 'discount-code' | 'code' | 'countdown' | 'hero' | 'testimonial' | 'gallery' | 'badge' | 'table' | 'features' | 'image-card' | 'pricing' | 'author' | 'article' | 'rating' | 'stats' | 'steps' | 'product-grid' | 'poll', required
      - `content` string: Content for text, html, and heading-like blocks.
      - `label` string: Editor label for a structural group block.
      - `layout` 'stack' | 'row' | 'grid' | 'overlay': Direct-child layout for a structural group block.
      - `columns` integer: Number of columns used by a group with grid layout.
      - `gap` integer: Gap in pixels between direct group children.
      - `stackOnMobile` boolean: Columns block only. Multi-column rows stack into a single column on screens 480px wide or narrower. Set to false to keep the columns side by side on mobile. Omit or set to true for the default stacking.
      - `padding` integer: Uniform group padding in pixels; per-side styles.padding* fields override it.
      - `overlayColor` string: Opaque fallback and shade color for an overlay group.
      - `overlayShade` integer: Overlay shade intensity as a percentage.
      - `overlayPosition` 'top' | 'center' | 'bottom': Vertical position of overlay foreground content.
      - `children` EmailBlock[]: Recursive child blocks for group and repeat containers.
      - `styles` object: Per-block visual styles. For compatibility, style fields such as backgroundColor, backgroundOpacity, borderColor, borderWidth, and borderRadius can also be supplied at the block top level and are normalized into this object.
        - `paddingTop` number
        - `paddingBottom` number
        - `paddingLeft` number
        - `paddingRight` number
        - `backgroundColor` string
        - `backgroundOpacity` number: Background opacity percentage from 0 to 100.
        - `textColor` string
        - `textAlign` 'left' | 'center' | 'right'
        - `keepAlign` boolean: Keep a centered button, logo or footer centered when the email is left-aligned (layout.contentAlign left). Without it a left email moves these blocks left; right always stays.
        - `borderRadius` number
        - `borderColor` string
        - `borderWidth` number
        - `bleed` boolean: Stretch the block edge-to-edge across the email container. Top-level blocks only.
      - `conditions` object[]: Optional per-block display rules. The block renders only when every rule matches. The same shape is used for a conditional-group block's top-level `conditions`.
        - `id` string, required
        - `field` 'variable' | 'attribute' | 'email' | 'firstName' | 'lastName', required: `variable` resolves a merge-tag path from the transactional send `variables` or an automation `event` payload (nested paths like `order.total` or `event.plan` work). `attribute` reads a stored subscriber attribute. `email`, `firstName`, and `lastName` read core subscriber fields.
        - `operator` 'is' | 'is_not' | 'contains' | 'not_contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_empty' | 'is_not_empty', required
        - `value` string, required: For `variable` and `attribute`, use `name:value` - the part before the colon is the variable path or attribute name, and the part after it is the comparison value. For `email`, `firstName`, and `lastName`, provide the plain comparison string.
    - `campaignData` object, nullable
    - `computedLists` object[]
    - `targetLists` object, nullable: Saved campaign audience, or null when targeting is still unset and scheduling will fall back to all active subscribers.
    - `senderProfileId` string
    - `fromName` string, nullable
    - `fromEmail` string, email, nullable
    - `replyProfileId` string, nullable
    - `replyToName` string, nullable
    - `replyToEmail` string, email, nullable
    - `ccEmails` string[], nullable: Addresses CC'd on every recipient's email for this campaign.
    - `bccEmails` string[], nullable: Addresses BCC'd on every recipient's email for this campaign.
    - `shareUrl` string, nullable: Public anonymized view-in-browser link, or null until one is minted via POST /campaigns/{campaignId}/share-link.
  - `estimatedNonOpenerCount` integer: Estimated number of subscribers who haven't opened the original campaign.

## Other responses

- `400`: Campaign hasn't been sent, it's been less than 6 hours since it finished sending, or it is an imported already-sent campaign
- `401`: Unauthorized
- `404`: Campaign or campaign email not found
- `500`: Resend draft could not be created

## Changes

- **2026-10-26** `e2e7d27d7804`: 1 info
  - added the optional property `campaign/allOf[#/components/schemas/CampaignDetail]/allOf[subschema #2]/blocks/items/styles/keepAlign` to the response with the `200` status
- **2026-10-16** `db3873ca3d4d`: 1 warning, 5 info
  - added the new `push` enum value to the `campaign/allOf[#/components/schemas/CampaignDetail]/allOf[#/components/schemas/CampaignSummary]/type` response property for the response status `200`
  - added the optional property `campaign/allOf[#/components/schemas/CampaignDetail]/allOf[subschema #2]/blocks/items/stackOnMobile` to the response with the `200` status
  - added the optional property `issues` to the response with the `400` status
  - added the optional property `issues` to the response with the `401` status
  - …2 more
- **2026-09-17** `e93563b0d37e`: 1 info
  - added the optional property `campaign/allOf[#/components/schemas/CampaignDetail]/allOf[#/components/schemas/CampaignSummary]/maxRecipients` to the response with the `200` status
- **2026-09-11** `1938006077ff`: 1 info
  - added the optional property `campaign/allOf[#/components/schemas/CampaignDetail]/allOf[#/components/schemas/CampaignSummary]/hasAudience` to the response with the `200` status
- …earlier changes not shown

[Operation history](https://skmtc.dev/sequenzy/apis/sequenzy-api/changes/campaigns/:campaignId/resend-to-non-openers/post.md)

---

[API](https://skmtc.dev/sequenzy/apis/sequenzy-api.md) - [All operations](https://skmtc.dev/sequenzy/apis/sequenzy-api/llms.txt) - [OpenAPI document](https://skmtc.dev/sequenzy/apis/sequenzy-api/revisions/8156dc12d8b4?raw)
