Automation Jobs
The ten endpoints that watch the jobs in three queues and handle them one by one or in bulk.
Overview
The automation carries three queues: the scheduled tasks, the module calls and the notices. In each, job rows wait, run, complete or fail, and these ten endpoints work with those rows.
The dashboard gives everything in one call: the worker's health, the queue counts, the task list, the recent jobs and the last twenty-four hours as a chart. Reach for it when writing monitoring rather than making five calls.
Four endpoints touch one job (retry, cancel, clear the lock, delete), and three reach the whole queue. Those last three move hundreds of jobs with one call and cannot be undone.
Reference
Reading the Dashboard
Returns the whole state of the automation in one call.
curl 'https://panel.example.com/api/v1/admin/automation/dashboard' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/automation/dashboard', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();
if (data.status.status !== 'ok') console.warn('worker', data.status.status);$ch = curl_init('https://panel.example.com/api/v1/admin/automation/dashboard');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// ONE call is enough for monitoring; the dashboard carries what five endpoints would.
$d = Api::Automation()->GetAutomationDashboard()['data'];
$healthy = $d['status']['status'] === 'ok';Listing the Jobs
Returns the queue feed, newest first.
curl 'https://panel.example.com/api/v1/admin/automation/jobs?limit=50' \
-H "Authorization: Bearer $API_KEY"const url = new URL('https://panel.example.com/api/v1/admin/automation/jobs');
url.searchParams.set('limit', '50');
const res = await fetch(url, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();
// Daha eskisi: url.searchParams.set('before_id', data.jobs.at(-1).id)$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs?' . http_build_query(['limit' => 50]));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The total and the restore mark come on the FIRST call alone; a cursor call carries neither.
$first = Api::Automation()->GetAutomationJobs()['data'];
$older = Api::Automation()->GetAutomationJobs([], [
'before_id' => end($first['jobs'])['id'],
]);Reading One Job
Returns a job's whole row with its payload and logs.
cron, module, notification.curl 'https://panel.example.com/api/v1/admin/automation/jobs/cron/9001' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/automation/jobs/cron/${id}`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The fields differ BY QUEUE; read past the common ones without assuming they are there.
$job = Api::Automation()->GetAutomationJob(['queue' => 'cron', 'id' => $id])['data'];
$logs = $job['process_logs'] ?? [];Retrying a Job
Puts a job back among the waiting.
curl -X POST 'https://panel.example.com/api/v1/admin/automation/jobs/cron/9001/retry' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/automation/jobs/cron/${id}/retry`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/' . $id . '/retry');
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);// The attempt counter is CLEARED: a job that fails again looks as though it started afresh.
Api::Automation()->RetryAutomationJob(['queue' => 'cron', 'id' => $id]);Cancelling a Job
Marks a job cancelled.
curl -X POST 'https://panel.example.com/api/v1/admin/automation/jobs/cron/9001/cancel' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/automation/jobs/cron/${id}/cancel`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/' . $id . '/cancel');
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);// Cancelling does not stop a job ALREADY RUNNING; it changes the queue row's status.
Api::Automation()->CancelAutomationJob(['queue' => 'cron', 'id' => $id]);Clearing a Stuck Lock
Clears the lock a crashed worker left on a job.
curl -X POST 'https://panel.example.com/api/v1/admin/automation/jobs/cron/9001/reclaim' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/automation/jobs/cron/${id}/reclaim`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/' . $id . '/reclaim');
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);// If the worker IS STILL ALIVE the job runs twice; check the longest wait first.
$d = Api::Automation()->GetAutomationDashboard()['data'];
if ($d['status']['status'] === 'dead')
Api::Automation()->ReclaimAutomationJob(['queue' => 'cron', 'id' => $id]);Deleting a Job
Removes a job row from the queue.
curl -X DELETE 'https://panel.example.com/api/v1/admin/automation/jobs/cron/9001' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/automation/jobs/cron/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/' . $id);
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);// Cancel rather than delete: the record stays and the job is never picked up again.
Api::Automation()->CancelAutomationJob(['queue' => 'cron', 'id' => $id]);Deleting Many Jobs
Removes the job ids you give in one call.
curl -X POST 'https://panel.example.com/api/v1/admin/automation/jobs/cron/bulk-delete' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"ids":[9001,9002,9003]}'const res = await fetch('https://panel.example.com/api/v1/admin/automation/jobs/cron/bulk-delete', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ids: [9001, 9002, 9003] }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/bulk-delete');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['ids' => [9001, 9002, 9003]]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The count can come back BELOW what you sent: ids from another queue are not removed.
$n = Api::Automation()->BulkDeleteAutomationJobs([
'queue' => 'cron', 'ids' => $ids,
])['data']['count'];Retrying Everything That Failed
Puts every failed job in a queue back among the waiting.
curl -X POST 'https://panel.example.com/api/v1/admin/automation/jobs/cron/retry-all-failed' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/automation/jobs/cron/retry-all-failed', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/retry-all-failed');
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);// Hundreds that failed FOR ONE REASON all run again at once and fail again.
// Read the reason from one job's detail first, then make this call.
Api::Automation()->RetryAllFailedAutomationJobs(['queue' => 'cron']);Cancelling Everything Waiting
Cancels every job waiting in a queue.
curl -X POST 'https://panel.example.com/api/v1/admin/automation/jobs/cron/cancel-all-pending' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/automation/jobs/cron/cancel-all-pending', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/automation/jobs/cron/cancel-all-pending');
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);// The waiting jobs are INVOICES, NOTICES and provider calls; they all drop at once.
Api::Automation()->CancelAllPendingAutomationJobs(['queue' => 'cron']);Pitfalls
Retrying everything failed and cancelling everything waiting move hundreds of jobs in one call, and neither says which. Cancelling the waiting drops invoices not yet issued, notices not yet sent and provider calls not yet made, all at once. Look at the feed first to see what is there.
The reclaim endpoint assumes the worker died. If it is still alive the job gets picked up a second time and the same invoice can be issued twice. Read the worker health on the dashboard before using it; on a live worker a job that looks stuck is usually only slow.
The cancel endpoint changes the queue row's status and does not kill a running process. Cancelling a job in flight does not cut it short; when it ends it writes its own result. When something truly has to stop, switching the cron off is the only way.
Retrying a job clears its attempt counter. A job that failed three times looks as though it is running for the first time, and failing again starts the count at one. A check that sifts troubled jobs by their attempt count will miss the difference.
A bulk delete looks only in the queue named in the path, and ids from another are passed over quietly. A count below what you sent is no error; those ids live elsewhere. When removing a mixed list, group the ids by queue and make separate calls.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.