Backup e restore
Escopo: databases:write. Substitua $P (projeto) e $DB (serviço-banco) pelos ids.
Política
Seção intitulada “Política”- Backup diário automático: retenção de 7 diários + 4 semanais.
- Backup sob demanda quando quiser (antes de uma migration arriscada, por exemplo).
- Apagar o banco faz um backup final por padrão.
Criar um backup
Seção intitulada “Criar um backup”SUF=$(date +%s)-$RANDOMH="Authorization: Bearer $NEBULAR_TOKEN"P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" -H "$H" -H "Content-Type: application/json" \ -d "{\"name\": \"bk-$SUF\"}" | jq -r .id)DB=$(curl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases" -H "$H" -H "Content-Type: application/json" \ -d '{"name": "db", "engine": "postgres", "quota_mb": 1024}' | jq -r .id)# o banco nasce em provisioning: espere ficar ready antes de pedir backupfor i in $(seq 1 40); do [ "$(curl -sS "$NEBULAR_API/v1/projects/$P/databases/$DB" -H "$H" | jq -r .status)" = ready ] && break sleep 2done
curl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases/$DB/backups" \ -H "$H" \ -H "Idempotency-Key: backup-$DB-$(date +%Y%m%d%H%M)-$RANDOM"{"backup_id": "b_01J9ZK5Q", "job_id": "j_01J9ZK5R"}A resposta é 202: o backup é assíncrono. Guarde backup_id.
Listar backups
Seção intitulada “Listar backups”Paginação por cursor (next_cursor / has_more). Cada item tem id, at, size, status.
SUF=$(date +%s)-$RANDOMH="Authorization: Bearer $NEBULAR_TOKEN"P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" -H "$H" -H "Content-Type: application/json" \ -d "{\"name\": \"bk-$SUF\"}" | jq -r .id)DB=$(curl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases" -H "$H" -H "Content-Type: application/json" \ -d '{"name": "db", "engine": "postgres", "quota_mb": 1024}' | jq -r .id)# o banco nasce em provisioning: espere ficar ready antes de pedir backupfor i in $(seq 1 40); do [ "$(curl -sS "$NEBULAR_API/v1/projects/$P/databases/$DB" -H "$H" | jq -r .status)" = ready ] && break sleep 2donecurl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases/$DB/backups" -H "$H" >/dev/null
curl -sS "$NEBULAR_API/v1/projects/$P/databases/$DB/backups" \ -H "$H"{"items": [{"id": "b_01J9ZK5Q", "at": "2026-10-10T03:00:00Z", "size": 1048576, "status": "running"}], "next_cursor": null, "has_more": false}O item nasce running e vira done. Espere o backup concluir antes de usá-lo (restaurar um backup que ainda roda responde 409 backup_not_ready): consulte o job com GET /v1/projects/{p}/databases/{s}/jobs/{job_id} (status: queued, running, done, failed; no failed vem error com code e message), com backoff de 2 s dobrando até 30 s, teto de uns 10 min.
Restore
Seção intitulada “Restore”target:
"new"(padrão): restaura para um banco novo; informenew_db_name. Seguro, não toca nos dados atuais."same": sobrescreve o banco atual. Destrutivo para os dados atuais: no painel exige step-up (confirmação recente de identidade); pela API de token vale o escopodatabases:write, então só use com autorização explícita de uma pessoa.
SUF=$(date +%s)-$RANDOMH="Authorization: Bearer $NEBULAR_TOKEN"P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" -H "$H" -H "Content-Type: application/json" \ -d "{\"name\": \"bk-$SUF\"}" | jq -r .id)DB=$(curl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases" -H "$H" -H "Content-Type: application/json" \ -d '{"name": "db", "engine": "postgres", "quota_mb": 1024}' | jq -r .id)# o banco nasce em provisioning: espere ficar ready antes de pedir backupfor i in $(seq 1 40); do [ "$(curl -sS "$NEBULAR_API/v1/projects/$P/databases/$DB" -H "$H" | jq -r .status)" = ready ] && break sleep 2doneR=$(curl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases/$DB/backups" -H "$H")B=$(echo "$R" | jq -r .backup_id); J=$(echo "$R" | jq -r .job_id)
# espera o job do backup concluir (backoff 2 s, dobrando até 30 s)delay=2for i in $(seq 1 40); do st=$(curl -sS "$NEBULAR_API/v1/projects/$P/databases/$DB/jobs/$J" -H "$H" | jq -r .status) echo "tentativa $i: $st" [ "$st" = done ] && break case "$st" in failed) exit 1 ;; esac sleep "$delay"; delay=$(( delay * 2 > 30 ? 30 : delay * 2 ))done[ "$st" = done ]
curl -sS -X POST "$NEBULAR_API/v1/projects/$P/databases/$DB/restore" \ -H "$H" -H "Content-Type: application/json" \ -H "Idempotency-Key: restore-$DB-$B" \ -d "{\"backup_id\": \"$B\", \"target\": \"new\", \"new_db_name\": \"n_restaurado\"}"{"job_id": "j_01J9ZK5S"}Resposta 202. O restore é assíncrono: consulte o resultado com backoff até concluir.
O que muda em cada motor
Seção intitulada “O que muda em cada motor”| Motor | Efeito do restore |
|---|---|
PostgreSQL / MariaDB, new |
cria um banco extra na mesma instância; a plataforma monta a DATABASE_URL do banco novo (mesmo papel e senha, outro nome de banco). Aponte o app para ele quando validar. |
PostgreSQL / MariaDB, same |
sobrescreve o banco atual; as variáveis não mudam. |
SQLite, new ou same |
a URL e o token MUDAM em todo restore (o namespace antigo é removido no same). A plataforma sela o token novo, atualiza LIBSQL_URL/LIBSQL_AUTH_TOKEN e marca os dependentes para redeploy: faça deploy deles. |
Se algo falhar
Seção intitulada “Se algo falhar”| Resposta | O que fazer |
|---|---|
401 / 403 |
Falta databases:write. Pare e peça a uma pessoa. |
409 backup_not_ready |
O backup ainda não terminou (job running): espere o job e repita. |
404 not_found |
Banco ou backup_id inexistente ou de outro time. Liste os backups de novo. |
409 |
Há outra operação em andamento no banco, ou new_db_name já existe. Espere ou troque o nome. |
422 quota_exceeded |
O restore não cabe na cota. Aumente a cota ou apague dados. |
503 unavailable |
Repita com backoff e a mesma Idempotency-Key; persistindo, pare e avise. |
429 rate_limited |
Espere Retry-After. |
Veja Erros e Rate limit e retry.