API

Backup destinations

Configure and verify storage for backups.

A backup destination is a reusable storage target — an S3-compatible bucket, an SFTP server, a local filesystem path, or another Openship server — that backup policies write their archives to. This API creates and manages those targets and runs a preflight that proves a destination is actually reachable (it writes, reads back, and deletes a probe object). Credentials are encrypted at rest; serialized destinations never return secret values, only hasX flags showing which are configured.

This module is available on both self-hosted and cloud instances. The local destination kind is self-hosted only — it is rejected in cloud mode and, on self-hosted, must be explicitly enabled (see below).

Create a destination

const result = await ship.backupDestinations.create({
  name: "prod-s3",
  kind: "s3_compatible",
  bucket: "my-backups",
  region: "us-east-1",
  accessKeyId: "AKIA...",
  secretAccessKey: "...",
});
console.log(result);
curl -X POST "$OPENSHIP_URL/api/backup-destinations" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"prod-s3","kind":"s3_compatible","bucket":"my-backups","region":"us-east-1","accessKeyId":"AKIA...","secretAccessKey":"..."}'

Prop

Type

Required fields depend on kind:

  • s3_compatible — bucket, accessKeyId, and secretAccessKey.
  • sftp — sshHost, sshUser, and one of sftpPassword / sftpPrivateKey.
  • openship_server — serverId (a server in your org).
  • local — endpoint (an absolute path inside BACKUP_LOCAL_ROOT).

Update a destination

Send only the fields you want to change. For credentials, undefined (omitted) leaves the stored value unchanged, null clears it, and a string replaces it. The kind cannot be changed after creation.

const result = await ship.backupDestinations.update("bkd_123", {
  pathPrefix: "nightly/",
  isDefault: true,
});
console.log(result);
curl -X PATCH "$OPENSHIP_URL/api/backup-destinations/bkd_123" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"pathPrefix":"nightly/","isDefault":true}'

Prop

Type

Preflight (verify connectivity)

Proves the destination works by writing, reading back, and deleting a small probe object. On success it stamps lastVerifiedAt; on failure it records the error in lastVerifyError.

const result = await ship.backupDestinations.preflight("bkd_123");
console.log(result);
curl -X POST "$OPENSHIP_URL/api/backup-destinations/bkd_123/preflight" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN"

A failed check is still a 200

Preflight returns 200 with {"ok": false, "reason": "..."} when the target is unreachable or misconfigured — the reason (bad credentials, DNS failure, permission denied) is in the body, not the HTTP status. A 404 here means the :id doesn't belong to your organization.

Errors

400 — validation failed

The body is missing a field required for its kind (e.g. an S3 destination without a bucket or credentials), the name is blank / over 80 chars or duplicates an existing destination, or you passed an unsupported kind. http_upload is defined but not yet supported.

400 — local destinations disabled

A local destination requires BACKUP_ALLOW_LOCAL_DESTINATION=true and a configured BACKUP_LOCAL_ROOT, and the endpoint must resolve to an absolute path inside that root. Both the root and the endpoint are symlink-resolved before the check, so a symlink that escapes the root is rejected. BACKUP_LOCAL_ROOT itself must be a dedicated directory — not /, /var, /var/lib, Openship's own state directory, or anything inside a system tree such as /etc or /var/lib/docker. Local destinations are always rejected in cloud mode.

404 on a per-destination route

The :id doesn't belong to your organization (or was deleted). List your destinations with GET /api/backup-destinations to get valid IDs.

Operations

OperationSDKREST API
List backup storage destinations.backupDestinations.list()GET /api/backup-destinations
backup_destination:list
Create a backup destination.backupDestinations.create(input)POST /api/backup-destinations
backup_destination:write
Test destination configuration before saving it.backupDestinations.preflightDraft(input)POST /api/backup-destinations/preflight
backup_destination:write
List backup history across storage destinations.backupDestinations.history(input?)GET /api/backup-destinations/history
backup_destination:list
List backup runs stored in one destination.backupDestinations.runs(id, input?)GET /api/backup-destinations/:id/runs
backup_destination:read
Read a destination with credentials protected.backupDestinations.get(id)GET /api/backup-destinations/:id
backup_destination:read
Read destination storage usage.backupDestinations.usage(id)GET /api/backup-destinations/:id/usage
backup_destination:read
Update destination settings.backupDestinations.update(id, input)PATCH /api/backup-destinations/:id
backup_destination:write
Remove an eligible destination.backupDestinations.remove(id)DELETE /api/backup-destinations/:id
backup_destination:admin
Test a saved destination and record its verification state.backupDestinations.preflight(id)POST /api/backup-destinations/:id/preflight
backup_destination:write

On this page