Scheduled Bulk Tasks
The six endpoints that send saved campaigns by themselves at a set time.
Overview
A scheduled task sends a saved campaign by itself at the time you set. The task holds the schedule, not the message: the text and the audience live on the template.
There are two patterns. A one-off task runs on a date and is done. A repeating one is built from a month, a day and a time. Leaving a part out means "every", so day one with no month is the first of every month.
Reference
Listing the Tasks
Returns the plan for the bulk notifications that send themselves.
mail or sms.active is running, paused is stopped.onetime fires once, recurring repeats.curl 'https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// An empty last-run time says the task has NEVER run; it may be paused.
$tasks = Api::Tools()->GetBulkScheduledTasks()['data'];
$never = array_filter($tasks, fn (array $t): bool => $t['last_exec'] === null);Creating a Task
Opens a task that sends an existing campaign by itself at the time you set.
onetime or recurring. It defaults to one-off.mail or sms.active is running, paused is stopped.onetime fires once, recurring repeats.curl -X POST 'https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"template_id":5,"schedule_period":"onetime","sending_time":"2026-02-15 10:00:00"}'const res = await fetch('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
template_id: 5,
schedule_period: 'onetime',
sending_time: '2026-02-15 10:00:00',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'template_id' => 5,
'schedule_period' => 'onetime',
'sending_time' => '2026-02-15 10:00:00',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The first of every month at 08:00: day 1, month left out (every month).
Api::Tools()->CreateBulkScheduledTask([
'template_id' => 5,
'schedule_period' => 'recurring',
'period_day' => 1,
'period_time' => '08:00',
]);Changing the Schedule
Changes when the task runs. The campaign itself is untouched.
onetime or recurring. It defaults to one-off.mail or sms.active is running, paused is stopped.onetime fires once, recurring repeats.curl -X PATCH 'https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"schedule_period":"recurring","period_day":1,"period_time":"08:00"}'const res = await fetch('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
schedule_period: 'recurring',
period_day: 1,
period_time: '08:00',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'schedule_period' => 'recurring',
'period_day' => 1,
'period_time' => '08:00',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// To change the message use the template update endpoint, NOT this one.
Api::Tools()->UpdateBulkTemplate(['id' => 5, 'subject' => 'Updated']);
Api::Tools()->UpdateBulkScheduledTask(['id' => 3, 'period_time' => '09:00']);Pausing a Task
Stops the task. The plan stops but is not deleted.
mail or sms.active is running, paused is stopped.onetime fires once, recurring repeats.curl -X POST 'https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3/pause' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3/pause', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3/pause');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Pausing does not stop notices already IN THE QUEUE: if the send started, delete them from the queue.
Api::Tools()->PauseBulkScheduledTask(['id' => 3]);Resuming a Task
Puts a paused task back into service.
mail or sms.active is running, paused is stopped.onetime fires once, recurring repeats.curl -X POST 'https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3/resume' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3/resume', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3/resume');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A one-off whose time has passed does not run on resume: move the schedule forward first.
$task = Api::Tools()->ResumeBulkScheduledTask(['id' => 3])['data'];
if ($task['period'] === 'onetime' && $task['period_datetime'] < $now) {
Api::Tools()->UpdateBulkScheduledTask([
'id' => 3,
'sending_time' => $tomorrow,
]);
}Deleting a Task
Deletes the scheduled task and its run records. The campaign stays.
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3', {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/bulk/scheduled-tasks/3');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Deleting the task does not delete the CAMPAIGN: the template stays and can still be sent by hand.
Api::Tools()->DeleteBulkScheduledTask(['id' => 3]);Pitfalls
Pause a one-off task, resume it after its send time has passed, and it never runs. A past time does not come round again, and nothing tells you. Move the time forward first.
These endpoints change the schedule and nothing else. Correcting the text, the subject or the audience means going to the template endpoints. A change there takes effect on the next run.
Pausing stops the next runs only. After a run the notices are already in the queue and keep going out. Stopping them means deleting the pending rows in the notification queue.
Creating a task requires that the source campaign is not already marked for automatic sending. Otherwise the same announcement can go out by two routes at once. The campaign's state for this is on the template detail.
On a repeating task, a month or a day left out counts as every value. Giving only a time and forgetting the day sends the announcement daily. Read the task back from the list and check the pattern after creating it.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.