Backup Schedules
The nine endpoints that set up backup schedules and manage the backups taken.
Overview
These nine endpoints handle two things. Five of them set up the schedules: what content, how often, to which target. The other four deal with the backups already taken.
A schedule is only an intent. What actually makes a backup is the scheduled job that picks the work up when its turn comes. Writing calls do not return a result straight away: the job queues, a record opens, and the status moves along over time.
Where backups go is a separate matter. Targets are set up through their own endpoints, and the storage_id here merely points at one of them.
Reference
Listing the Schedules
Returns the backup schedules defined.
hourly, daily, weekly, monthly.database, files, uploads.curl 'https://panel.example.com/api/v1/admin/settings/backup/schedules' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/settings/backup/schedules', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/schedules');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The next run time reads full on an OFF schedule too, so read the status as well.
$due = array_filter(
Api::Settings()->GetBackupSchedules()['data'],
fn ($s) => $s['status'] === 'enabled',
);Creating a Schedule
Sets up a new backup schedule.
database, files, uploads. At least one is needed.hourly, daily, weekly, monthly. Daily by default.curl -X POST 'https://panel.example.com/api/v1/admin/settings/backup/schedules' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"name":"Gecelik veritabani","frequency":"daily","run_time":"03:00","contents":["database"],"status":1}'const res = await fetch('https://panel.example.com/api/v1/admin/settings/backup/schedules', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Nightly database',
frequency: 'daily',
run_time: '03:00',
contents: ['database'],
status: 1,
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/schedules');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Nightly database',
'frequency' => 'daily',
'run_time' => '03:00',
'contents' => ['database'],
'status' => 1,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// LEAVE THE STATUS OUT and the schedule is born off, so no night ever runs it.
Api::Settings()->CreateBackupSchedule([
'name' => 'Nightly database',
'contents' => ['database'],
'status' => 1,
]);Reading One Schedule
Returns a single schedule.
hourly, daily, weekly, monthly.database, files, uploads.curl 'https://panel.example.com/api/v1/admin/settings/backup/schedules/4' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/settings/backup/schedules/${id}`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/schedules/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// When the day fields do not MATCH the frequency they read full and do nothing.
$s = Api::Settings()->GetBackupSchedule(['id' => $id])['data'];
$day = $s['frequency'] === 'weekly' ? $s['run_dow'] : null;Updating a Schedule
Changes a schedule, recomputing the next run when a timing field moves.
database, files, uploads. At least one is needed.hourly, daily, weekly, monthly. Daily by default.curl -X PATCH 'https://panel.example.com/api/v1/admin/settings/backup/schedules/4' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"run_time":"04:30","retention_count":14}'const res = await fetch(`https://panel.example.com/api/v1/admin/settings/backup/schedules/${id}`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ run_time: '04:30', retention_count: 14 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/schedules/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['run_time' => '04:30', 'retention_count' => 14]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// What you leave out is KEPT; moving the time shifts when the schedule next runs.
Api::Settings()->UpdateBackupSchedule([
'id' => $id,
'run_time' => '04:30',
]);Deleting a Schedule
Removes a schedule and unhooks the backups it made.
curl -X DELETE 'https://panel.example.com/api/v1/admin/settings/backup/schedules/4' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/settings/backup/schedules/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/schedules/' . $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);// The backups are NOT removed, only unhooked; their files stay where they are.
Api::Settings()->DeleteBackupSchedule(['id' => $id]);Listing the Backups
Returns the history of backups taken.
curl 'https://panel.example.com/api/v1/admin/settings/backup/backups' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/settings/backup/backups', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/backups');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A ready backup can STILL have lost its offsite copy, so read both statuses together.
$risky = array_filter(
Api::Settings()->GetBackups()['data'],
fn ($b) => $b['status'] === 'ready' && $b['upload_status'] === 'failed',
);Taking a Backup by Hand
Queues a backup job without waiting for a schedule.
database, files, uploads.curl -X POST 'https://panel.example.com/api/v1/admin/settings/backup/backups' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"contents":["database","files"],"storage_id":0}'const res = await fetch('https://panel.example.com/api/v1/admin/settings/backup/backups', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
contents: ['database', 'files'],
storage_id: 0,
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/backups');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'contents' => ['database', 'files'],
'storage_id' => 0,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Only ONE backup runs at a time: a request landing in the nightly window is refused.
$id = Api::Settings()->CreateManualBackup([
'contents' => ['database'],
])['data']['backup_id'];Retrying a Backup
Puts a failed backup back in the queue.
curl -X POST 'https://panel.example.com/api/v1/admin/settings/backup/backups/91/retry' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/settings/backup/backups/${id}/retry`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/backups/' . $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);// A backup whose upload failed while it stayed READY cannot be retried from here.
if ($backup['status'] === 'failed')
Api::Settings()->RetryBackup(['id' => $backup['id']]);Deleting a Backup
Removes a backup record, its queued job and its files.
curl -X DELETE 'https://panel.example.com/api/v1/admin/settings/backup/backups/91' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/settings/backup/backups/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/settings/backup/backups/' . $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);// A running backup cannot go; wait for it to end, as NO endpoint cancels one.
Api::Settings()->DeleteBackup(['id' => $id]);Pitfalls
Leave the status field out and the schedule is created switched off. It shows in the list, its next run time even reads full, and no night ever runs it. Believing it works and finding no backups months later starts here, so send the status along when you create it.
While a backup runs, the take-by-hand and retry calls are refused. A script that lands in the nightly window reads that as a failure. The answer describes a busy moment rather than a lasting problem, so try again a little later.
A backup's own status and its upload status are separate fields. One can read as ready while its offsite copy failed: the archive sits on the server and never reached the target. On the day you lose that server the second field is what matters, so read both together.
The retry endpoint refuses any backup whose status is not failed. One whose upload failed while it stayed ready cannot pass either, because what is missing there is the offsite copy rather than the backup. That case calls for taking a fresh backup.
When a schedule goes, the backups it made are unhooked and stay put. Their files remain and no retention count counts them for anyone any more. Freeing space means deleting those backups one by one, and deleting a backup cancels its queued job and removes its files.
Related Articles
Merci pour votre retour !
Notre équipe d'assistance est disponible 24h/24 pour tout ce que vous ne trouvez pas ci-dessus.