Skip to content

Campaigns ​

APIs for managing email campaigns (drafts) in your Lindris account.

As a reminder, all requests must be authenticated and use the base URL: https://api.lindris.com

List campaigns ​

GET api/campaigns

Retrieve a paginated list of campaigns. Defaults to draft campaigns when no status filter is provided.

Query Parameters ​

  • status string optional - A single campaign status to filter by, or all for every status. Defaults to draft when omitted. Filtering by sending includes campaigns in the preparing sub-state. Example: sent
    • Must be one of:
      • draft
      • sent
      • scheduled
      • sending
      • paused
      • failed
      • all
  • page integer optional - Page number for pagination. Defaults to 1. Example: 2
  • perPage integer optional - Number of items per page. Defaults to 10, maximum 100. Example: 25
  • sort string optional - Field to sort by. Defaults to the backend's per-status order. Example: createdAt
    • Must be one of:
      • name
      • status
      • createdAt
  • order string optional - Sort direction (requires sort). Defaults to desc. Example: desc
    • Must be one of:
      • asc
      • desc

Request ​

bash
curl --request GET \
    --get "https://api.lindris.com/api/campaigns?status=sent&page=2&perPage=25&sort=createdAt&order=desc" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'query' => [
            'status' => 'sent',
            'page' => '2',
            'perPage' => '25',
            'sort' => 'createdAt',
            'order' => 'desc',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns"
);

const params = {
    "status": "sent",
    "page": "2",
    "perPage": "25",
    "sort": "createdAt",
    "order": "desc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Responses ​

json
{
   "data": [
      {
         "id": 123,
         "name": "My Newsletter",
         "status": "draft",
         "builderReviewed": false,
         "createdAt": "2024-01-19T08:30:00+00:00",
         "scheduledAt": null,
         "sentAt": null,
         "links": {
            "campaignUrl": "https://app.lindris.com/campaigns/123",
            "editorUrl": "https://app.lindris.com/emails/campaigns/123"
         }
      }
   ],
   "meta": {
      "currentPage": 1,
      "lastPage": 1,
      "from": 1,
      "to": 1,
      "total": 1,
      "perPage": 10,
      "path": "/api/campaigns"
   },
   "links": {
      "next": null,
      "prev": null,
      "first": "/api/campaigns?page=1",
      "last": "/api/campaigns?page=1"
   }
}
json
{
   "message": "Unauthenticated"
}

Create campaign draft ​

POST api/campaigns

Create a new campaign draft. You may optionally provide a templateId to pre-populate the email content from a saved template. To duplicate an existing campaign, use POST /campaigns/{id}/clone.

Request Body ​

  • name string required - The campaign name. Example: My Newsletter
  • templateId string optional - The ID of an email template to use as the starting content.

Request ​

bash
curl --request POST \
    "https://api.lindris.com/api/campaigns" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"My Newsletter\"
}"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'name' => 'My Newsletter',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "My Newsletter"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "id": 123,
      "name": "My Newsletter",
      "status": "draft",
      "subject": "Welcome to our newsletter",
      "previewText": "Read our latest updates inside",
      "sender": {
         "name": "Acme Corp",
         "email": "[email protected]"
      },
      "replyTo": {
         "name": "Acme Support",
         "email": "[email protected]"
      },
      "builderReviewed": false,
      "createdAt": "2024-01-19T08:30:00+00:00",
      "scheduledAt": null,
      "sentAt": null,
      "links": {
         "campaignUrl": "https://app.lindris.com/campaigns/123",
         "editorUrl": "https://app.lindris.com/emails/campaigns/123"
      }
   }
}
json
{
   "message": "Your account is not active. Resolve your billing status to perform this action.",
   "status_code": 403
}
json
{
   "message": "The name field is required.",
   "errors": {
      "name": [
         "The name field is required."
      ]
   }
}
json
{
   "message": "The selected template does not exist.",
   "errors": {
      "templateId": [
         "The selected template does not exist."
      ]
   }
}

Clone campaign ​

POST api/campaigns/{id}/clone

Duplicate an existing campaign into a new draft, copying its content and targeting. The copy starts with builderReviewed: false, even when the original was reviewed: sending it needs a review in the editor or force: true.

URL Parameters ​

  • id integer required - The ID of the campaign to duplicate. Example: 123

Request Body ​

  • name string optional - Name for the new campaign. Defaults to a "Copy of …" name when omitted. Example: My Newsletter (copy)

Request ​

bash
curl --request POST \
    "https://api.lindris.com/api/campaigns/123/clone" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"My Newsletter (copy)\"
}"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123/clone';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'name' => 'My Newsletter (copy)',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123/clone"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "My Newsletter (copy)"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "id": 123,
      "name": "My Newsletter",
      "status": "draft",
      "subject": "Welcome to our newsletter",
      "previewText": "Read our latest updates inside",
      "sender": {
         "name": "Acme Corp",
         "email": "[email protected]"
      },
      "replyTo": {
         "name": "Acme Support",
         "email": "[email protected]"
      },
      "builderReviewed": false,
      "createdAt": "2024-01-19T08:30:00+00:00",
      "scheduledAt": null,
      "sentAt": null,
      "links": {
         "campaignUrl": "https://app.lindris.com/campaigns/123",
         "editorUrl": "https://app.lindris.com/emails/campaigns/123"
      }
   }
}
json
{
   "message": "Your account is not active. Resolve your billing status to perform this action.",
   "status_code": 403
}
json
{
   "message": "Campaign not found"
}

Get campaign details ​

GET api/campaigns/{id}

Retrieve a single campaign by its ID, including its builder-reviewed status and current campaign status.

URL Parameters ​

  • id integer required - The campaign ID. Example: 123

Response Fields ​

  • data array
    • id integer optional - The unique identifier for the campaign. Example: 123
    • name string optional - The campaign name. Example: My Newsletter
    • status string optional - The current campaign status. Enum: draft,sent,scheduled,sending,preparing,paused,failed Example: draft
    • subject string optional - The email subject line. Example: Welcome to our newsletter
    • previewText string optional - The email preview text shown in inbox previews. Example: Read our latest updates
  • sender object optional - Sender details.
    • name string optional - The sender display name. Example: Acme Corp
    • email string optional - The sender email address. No-example
  • replyTo object optional - Reply-to details.
    • name string optional - The reply-to display name. Example: Acme Support
    • email string optional - The reply-to email address. No-example
    • builderReviewed boolean optional - Whether the email content has been reviewed in the email builder. Example: false
    • createdAt string optional - ISO 8601 datetime when the campaign was created. Example: 2024-01-19T08:30:00+00:00
    • scheduledAt string optional - ISO 8601 datetime when the campaign is scheduled to send (null if not scheduled). Example: 2024-02-01T10:00:00+00:00
    • sentAt string optional - ISO 8601 datetime when the campaign finished sending (null if not sent). Example: 2024-01-25T14:32:00+00:00
  • links object optional - UI handoff links for this campaign.

Request ​

bash
curl --request GET \
    --get "https://api.lindris.com/api/campaigns/123" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "id": 123,
      "name": "My Newsletter",
      "status": "draft",
      "subject": "Welcome to our newsletter",
      "previewText": "Read our latest updates inside",
      "sender": {
         "name": "Acme Corp",
         "email": "[email protected]"
      },
      "replyTo": {
         "name": "Acme Support",
         "email": "[email protected]"
      },
      "builderReviewed": false,
      "createdAt": "2024-01-19T08:30:00+00:00",
      "scheduledAt": null,
      "sentAt": null,
      "links": {
         "campaignUrl": "https://app.lindris.com/campaigns/123",
         "editorUrl": "https://app.lindris.com/emails/campaigns/123"
      }
   }
}
json
{
   "message": "Campaign not found"
}

Update campaign ​

PUT api/campaigns/{id}

Update one or more fields of an existing campaign. All fields are optional, but at least one must be provided.

URL Parameters ​

  • id integer required - The campaign ID. Example: 123

Request Body ​

  • name string optional - The campaign name.
    • Example: My Updated Newsletter
  • subject string optional - The email subject line.
    • Example: Big sale — don't miss out!
  • previewText string optional - The email preview text.
    • Example: Up to 50% off this weekend only
  • sender object optional - Sender configuration.

Example: []

* `name` <small class="prop-details"> string _optional_</small> - The sender display name.
  Example: `Acme Marketing`
* `email` <small class="prop-details"> string _optional_</small> - The sender email address.
  • replyTo object optional - Reply-to configuration.

Example: []

* `name` <small class="prop-details"> string _optional_</small> - The reply-to display name.
  Example: `Acme Support`
* `email` <small class="prop-details"> string _optional_</small> - The reply-to email address.

Request ​

bash
curl --request PUT \
    "https://api.lindris.com/api/campaigns/123" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"My Updated Newsletter\",
    \"subject\": \"Big sale — don\'t miss out!\",
    \"previewText\": \"Up to 50% off this weekend only\",
    \"sender\": {
        \"name\": \"Acme Marketing\"
    },
    \"replyTo\": {
        \"name\": \"Acme Support\"
    }
}"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'name' => 'My Updated Newsletter',
            'subject' => 'Big sale — don\'t miss out!',
            'previewText' => 'Up to 50% off this weekend only',
            'sender' => [
                'name' => 'Acme Marketing',
            ],
            'replyTo' => [
                'name' => 'Acme Support',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "My Updated Newsletter",
    "subject": "Big sale — don't miss out!",
    "previewText": "Up to 50% off this weekend only",
    "sender": {
        "name": "Acme Marketing"
    },
    "replyTo": {
        "name": "Acme Support"
    }
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "id": 123,
      "name": "My Newsletter",
      "status": "draft",
      "subject": "Welcome to our newsletter",
      "previewText": "Read our latest updates inside",
      "sender": {
         "name": "Acme Corp",
         "email": "[email protected]"
      },
      "replyTo": {
         "name": "Acme Support",
         "email": "[email protected]"
      },
      "builderReviewed": false,
      "createdAt": "2024-01-19T08:30:00+00:00",
      "scheduledAt": null,
      "sentAt": null,
      "links": {
         "campaignUrl": "https://app.lindris.com/campaigns/123",
         "editorUrl": "https://app.lindris.com/emails/campaigns/123"
      }
   }
}
json
{
   "message": "Your account is not active. Resolve your billing status to perform this action.",
   "status_code": 403
}
json
{
   "message": "Campaign not found"
}
json
{
   "message": "At least one field must be provided for update.",
   "errors": {
      "_body": [
         "At least one field must be provided for update."
      ]
   }
}
json
{
   "message": "Only draft campaigns can be updated.",
   "errors": {
      "status": [
         "Only draft campaigns can be updated."
      ]
   }
}

Delete campaign ​

DELETE api/campaigns/{id}

Permanently delete a campaign by its ID. Campaigns of any status can be deleted (draft, scheduled, paused, sent, failed) except one that is actively sending, which is rejected to avoid disrupting an in-progress send.

URL Parameters ​

  • id integer required - The campaign ID. Example: 123

Request ​

bash
curl --request DELETE \
    "https://api.lindris.com/api/campaigns/123" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Responses ​

text
(No response body)
json
{
   "message": "Campaign not found"
}
json
{
   "message": "Campaigns that are currently sending cannot be deleted.",
   "errors": {
      "status": [
         "Campaigns that are currently sending cannot be deleted."
      ]
   }
}

Send campaign ​

POST api/campaigns/{id}/send

Send a draft campaign immediately. Sending is validated against your account's sending limit, sender settings and branding. The campaign goes to your whole confirmed list — recipient targeting is not available in this version of the API.

Campaigns that have not been reviewed in the visual builder are refused with a 422 so you can review them first; pass force: true to send anyway.

URL Parameters ​

  • id integer required - The campaign ID. Example: 123

Request Body ​

  • force boolean optional - Send even if the campaign hasn't been reviewed in the builder. Use only if you're confident in the design — the content hasn't been reviewed. Defaults to false.

Request ​

bash
curl --request POST \
    "https://api.lindris.com/api/campaigns/123/send" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"force\": false
}"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123/send';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'force' => false,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123/send"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "force": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "id": 123,
      "name": "My Newsletter",
      "status": "preparing",
      "subject": "Welcome to our newsletter",
      "previewText": "Read our latest updates inside",
      "sender": {
         "name": "Acme Corp",
         "email": "[email protected]"
      },
      "replyTo": {
         "name": "Acme Support",
         "email": "[email protected]"
      },
      "builderReviewed": false,
      "createdAt": "2024-01-19T08:30:00+00:00",
      "scheduledAt": null,
      "sentAt": null,
      "links": {
         "campaignUrl": "https://app.lindris.com/campaigns/123",
         "editorUrl": "https://app.lindris.com/emails/campaigns/123"
      }
   }
}
json
{
   "message": "Your account is not active. Resolve your billing status to perform this action.",
   "status_code": 403
}
json
{
   "message": "This API key was issued to a WordPress site and can't send campaigns. Use a dashboard or CLI key.",
   "status_code": 403
}
json
{
   "message": "Campaign not found."
}
json
{
   "message": "This campaign hasn't been reviewed in the editor. Review it at <editorUrl>, or retry with \"force\": true to send it as-is.",
   "errors": {
      "review": [
         "This campaign hasn't been reviewed in the editor. ..."
      ]
   },
   "links": {
      "campaignUrl": "https://app.lindris.com/campaigns/123",
      "editorUrl": "https://app.lindris.com/emails/campaigns/123"
   },
   "status_code": 422
}
json
{
   "message": "Only draft campaigns can be sent.",
   "errors": {
      "status": [
         "Only draft campaigns can be sent."
      ]
   },
   "status_code": 422
}
json
{
   "message": "The campaign could not be sent. Please try again.",
   "errors": {
      "campaign": [
         "The campaign could not be sent. Please try again."
      ]
   },
   "status_code": 422
}
json
{
   "message": "This campaign has no email to send.",
   "errors": {
      "campaign": [
         "This campaign has no email to send."
      ]
   },
   "status_code": 422
}
json
{
   "message": "You have 0 of 2,000 sends remaining in this period (resets November 1, 2026).",
   "errors": {
      "send": [
         "You have 0 of 2,000 sends remaining in this period (resets November 1, 2026)."
      ]
   },
   "links": {
      "campaignUrl": "https://app.lindris.com/campaigns/123",
      "editorUrl": "https://app.lindris.com/emails/campaigns/123"
   },
   "status_code": 422
}
json
{
   "message": "Upgrade required to send this email campaign",
   "errors": {
      "send": [
         "Upgrade required to send this email campaign"
      ]
   },
   "links": {
      "campaignUrl": "https://app.lindris.com/campaigns/123",
      "editorUrl": "https://app.lindris.com/emails/campaigns/123"
   },
   "upgrade": {
      "level": "plus",
      "levelName": "Premium",
      "monthlyAmount": 49,
      "proratedAmount": 12.5
   },
   "status_code": 422
}
json
{
   "message": "We couldn't check whether this campaign can be sent. Please try again."
}

Schedule campaign ​

POST api/campaigns/{id}/schedule

Schedule a draft campaign to send at a future time. Provide scheduledAt as an ISO 8601 datetime with an explicit offset — Z or ±hh:mm; a value without one is refused. The time is stored in UTC, to the minute: seconds round up to the next minute. The same draft, sending-limit and review rules as the send endpoint apply.

URL Parameters ​

  • id integer required - The campaign ID. Example: 123

Request Body ​

  • scheduledAt string required - ISO 8601 datetime in the future with an explicit offset (Z or ±hh:mm), to send the campaign. Example: 2030-01-15T14:30:00Z
  • force boolean optional - Schedule even if the campaign hasn't been reviewed in the builder. Use only if you're confident in the design — the content hasn't been reviewed. Defaults to false.

Request ​

bash
curl --request POST \
    "https://api.lindris.com/api/campaigns/123/schedule" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"scheduledAt\": \"2030-01-15T14:30:00Z\",
    \"force\": false
}"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123/schedule';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'scheduledAt' => '2030-01-15T14:30:00Z',
            'force' => false,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123/schedule"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "scheduledAt": "2030-01-15T14:30:00Z",
    "force": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "id": 123,
      "name": "My Newsletter",
      "status": "scheduled",
      "subject": "Welcome to our newsletter",
      "previewText": "Read our latest updates inside",
      "sender": {
         "name": "Acme Corp",
         "email": "[email protected]"
      },
      "replyTo": {
         "name": "Acme Support",
         "email": "[email protected]"
      },
      "builderReviewed": false,
      "createdAt": "2024-01-19T08:30:00+00:00",
      "scheduledAt": "2024-02-01T10:00:00+00:00",
      "sentAt": null,
      "links": {
         "campaignUrl": "https://app.lindris.com/campaigns/123",
         "editorUrl": "https://app.lindris.com/emails/campaigns/123"
      }
   }
}
json
{
   "message": "Your account is not active. Resolve your billing status to perform this action.",
   "status_code": 403
}
json
{
   "message": "This API key was issued to a WordPress site and can't send campaigns. Use a dashboard or CLI key.",
   "status_code": 403
}
json
{
   "message": "Campaign not found."
}
json
{
   "message": "The scheduled at field must be a date after now.",
   "errors": {
      "scheduledAt": [
         "The scheduled at field must be a date after now."
      ]
   },
   "status_code": 422
}
json
{
   "message": "The scheduled at must be an ISO 8601 datetime with an explicit offset, e.g. 2030-01-15T14:30:00Z or 2030-01-15T14:30:00+05:00.",
   "errors": {
      "scheduledAt": [
         "The scheduled at must be an ISO 8601 datetime with an explicit offset, e.g. 2030-01-15T14:30:00Z or 2030-01-15T14:30:00+05:00."
      ]
   },
   "status_code": 422
}
json
{
   "message": "Only draft campaigns can be scheduled.",
   "errors": {
      "status": [
         "Only draft campaigns can be scheduled."
      ]
   },
   "status_code": 422
}
json
{
   "message": "The campaign could not be scheduled. Please try again.",
   "errors": {
      "campaign": [
         "The campaign could not be scheduled. Please try again."
      ]
   },
   "status_code": 422
}
json
{
   "message": "This campaign has no email to schedule.",
   "errors": {
      "campaign": [
         "This campaign has no email to schedule."
      ]
   },
   "status_code": 422
}
json
{
   "message": "You have 0 of 2,000 sends remaining in this period (resets November 1, 2026).",
   "errors": {
      "send": [
         "You have 0 of 2,000 sends remaining in this period (resets November 1, 2026)."
      ]
   },
   "links": {
      "campaignUrl": "https://app.lindris.com/campaigns/123",
      "editorUrl": "https://app.lindris.com/emails/campaigns/123"
   },
   "status_code": 422
}
json
{
   "message": "Upgrade required to send this email campaign",
   "errors": {
      "send": [
         "Upgrade required to send this email campaign"
      ]
   },
   "links": {
      "campaignUrl": "https://app.lindris.com/campaigns/123",
      "editorUrl": "https://app.lindris.com/emails/campaigns/123"
   },
   "upgrade": {
      "level": "plus",
      "levelName": "Premium",
      "monthlyAmount": 49,
      "proratedAmount": 12.5
   },
   "status_code": 422
}
json
{
   "message": "This campaign hasn't been reviewed in the editor. Review it at <editorUrl>, or retry with \"force\": true to schedule it as-is.",
   "errors": {
      "review": [
         "This campaign hasn't been reviewed in the editor. ..."
      ]
   },
   "links": {
      "campaignUrl": "https://app.lindris.com/campaigns/123",
      "editorUrl": "https://app.lindris.com/emails/campaigns/123"
   },
   "status_code": 422
}
json
{
   "message": "We couldn't check whether this campaign can be sent. Please try again."
}

Test-send campaign ​

POST api/campaigns/{id}/test-send

Send a preview ("test send") of the campaign's email to one or more recipients so you can inspect it before sending. This does not change the campaign and works on any campaign that has email content. Rate-limited per account.

URL Parameters ​

  • id integer required - The campaign ID. Example: 123

Request Body ​

  • recipients string[] required - One to ten unique recipient email addresses (each at most 254 characters) to send the preview to.

Request ​

bash
curl --request POST \
    "https://api.lindris.com/api/campaigns/123/test-send" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"recipients\": [
        \"[email protected]\"
    ]
}"
php
$client = new \GuzzleHttp\Client();
$url = 'https://api.lindris.com/api/campaigns/123/test-send';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'recipients' => [
                '[email protected]',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
javascript
const url = new URL(
    "https://api.lindris.com/api/campaigns/123/test-send"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "recipients": [
        "[email protected]"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Responses ​

json
{
   "data": {
      "recipients": [
         "[email protected]"
      ]
   }
}
json
{
   "message": "Your account is not active. Resolve your billing status to perform this action.",
   "status_code": 403
}
json
{
   "message": "This API key was issued to a WordPress site and can't send campaigns. Use a dashboard or CLI key.",
   "status_code": 403
}
json
{
   "message": "Campaign not found."
}
json
{
   "message": "The recipients field is required.",
   "errors": {
      "recipients": [
         "The recipients field is required."
      ]
   },
   "status_code": 422
}
json
{
   "message": "This campaign has no email content to test.",
   "errors": {
      "campaign": [
         "This campaign has no email content to test."
      ]
   },
   "status_code": 422
}
json
{
   "message": "The preview could not be sent. Please try again.",
   "errors": {
      "testSend": [
         "The preview could not be sent. Please try again."
      ]
   },
   "status_code": 422
}
json
{
   "message": "Test emails can only be sent to addresses on your verified sending domains or to addresses on your account. \"[email protected]\" is not an authorized recipient.",
   "errors": {
      "recipients": [
         "Test emails can only be sent to addresses on your verified sending domains or to addresses on your account. \"[email protected]\" is not an authorized recipient."
      ]
   },
   "status_code": 422
}
json
{
   "message": "The test-send limit per minute has been reached. Please try again shortly.",
   "status_code": 429
}