Bancos (referência)
GET /v1/projects/{p}/databases
Seção intitulada “GET /v1/projects/{p}/databases”Lista os bancos do projeto
Bancos do projeto, do mais antigo para o mais novo (size_mb do estado armazenado).
Escopo exigido: projects:read.
Escopo exigido: projects:read · operationId: listDatabases
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
cursor |
query | string | não | Cursor opaco devolvido em next_cursor da página anterior. |
limit |
query | integer | não | Itens por página (1 a 200). |
Resposta 200
Seção intitulada “Resposta 200”Página (mais novo/antigo primeiro conforme o recurso).
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
next_cursor |
string|null | sim | Passe em cursor para a próxima página; null ao fim. |
has_more |
boolean | sim | Há mais páginas. |
items |
array | sim | |
items[].id |
string | sim | Id do serviço kind=database. |
items[].project_id |
string | sim | |
items[].name |
string | sim | |
items[].kind |
enum(database) | sim | |
items[].engine |
enum(postgres, mariadb, sqlite) | sim | |
items[].status |
enum(provisioning, ready, read_only, error, deleting, running, idle, deploying, failed) | sim | Estado da instância. |
items[].size_mb |
integer | sim | |
items[].quota_mb |
integer | sim | |
items[].read_only |
boolean | sim | true quando o banco passou da cota. |
items[].host |
string | sim | Host público do motor do banco, com URL própria por motor no nó (PostgreSQL db01.pgsql.<domínio>, MariaDB db01.mariadb.<domínio>, sqlite <banco>.db01.sqlite.<domínio>); é o host das variáveis DATABASE_URL/PGHOST/MYSQL_HOST/LIBSQL_URL. |
items[].port |
integer | sim | |
items[].created_at |
string | sim |
{ "items": [ { "id": "01jb7k4a5q8r7t2v4w6x8y0a9z", "project_id": "01jb7k3m5q8r7t2v4w6x8y0a1b", "name": "db", "kind": "database", "engine": "postgres", "status": "ready", "size_mb": 42, "quota_mb": 1024, "read_only": false, "host": "db01.pgsql.nebularws.com", "port": 5432, "created_at": "2026-10-10T14:03:11Z" } ], "next_cursor": null, "has_more": false}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
POST /v1/projects/{p}/databases
Seção intitulada “POST /v1/projects/{p}/databases”Cria um banco gerenciado
Cria um serviço kind=database e provisiona a instância (postgres, mariadb ou sqlite). As credenciais não vêm na resposta: apps do projeto as recebem como variáveis ${{db.VAR}}; para vê-las use POST …/credentials.
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: createDatabase
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
Idempotency-Key |
header | string | não | Chave de idempotência (8 a 128 caracteres [A-Za-z0-9._:-]; use um UUID). Mesma chave + mesmo pedido em 24 h ⇒ a mesma resposta, com Idempotent-Replay: true; mesma chave + pedido diferente ⇒ 422 idempotency_conflict. Falhas nunca são gravadas, então a repetição executa de verdade. |
Corpo (application/json)
Seção intitulada “Corpo (application/json)”| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
name |
string | sim | |
engine |
enum(postgres, mariadb, sqlite) | sim | |
quota_mb |
integer | sim |
Resposta 201
Seção intitulada “Resposta 201”Banco criado.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
id |
string | sim | Id do serviço kind=database. |
project_id |
string | sim | |
name |
string | sim | |
kind |
enum(database) | sim | |
engine |
enum(postgres, mariadb, sqlite) | sim | |
status |
enum(provisioning, ready, read_only, error, deleting, running, idle, deploying, failed) | sim | Estado da instância. |
size_mb |
integer | sim | |
quota_mb |
integer | sim | |
read_only |
boolean | sim | true quando o banco passou da cota. |
host |
string | sim | Host público do motor do banco, com URL própria por motor no nó (PostgreSQL db01.pgsql.<domínio>, MariaDB db01.mariadb.<domínio>, sqlite <banco>.db01.sqlite.<domínio>); é o host das variáveis DATABASE_URL/PGHOST/MYSQL_HOST/LIBSQL_URL. |
port |
integer | sim | |
created_at |
string | sim |
{ "id": "01jb7k4a5q8r7t2v4w6x8y0a9z", "project_id": "01jb7k3m5q8r7t2v4w6x8y0a1b", "name": "db", "kind": "database", "engine": "postgres", "status": "ready", "size_mb": 42, "quota_mb": 1024, "read_only": false, "host": "db01.pgsql.nebularws.com", "port": 5432, "created_at": "2026-10-10T14:03:11Z"}Resposta 409
Seção intitulada “Resposta 409”name_taken.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
{ "error": "name_taken", "message": "Já existe um serviço com esse nome no projeto."}Resposta 422
Seção intitulada “Resposta 422”quota_exceeded ou idempotency_conflict.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
{ "error": "quota_exceeded", "message": "Limite de serviços do plano atingido."}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 413 Corpo JSON acima do limite da rota (too_large); 415 O corpo precisa ser application/json (unsupported_media_type); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
GET /v1/projects/{p}/databases/{s}
Seção intitulada “GET /v1/projects/{p}/databases/{s}”Consulta um banco
Estado, tamanho e cota.
Escopo exigido: projects:read.
Escopo exigido: projects:read · operationId: getDatabase
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Resposta 200
Seção intitulada “Resposta 200”Banco.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
id |
string | sim | Id do serviço kind=database. |
project_id |
string | sim | |
name |
string | sim | |
kind |
enum(database) | sim | |
engine |
enum(postgres, mariadb, sqlite) | sim | |
status |
enum(provisioning, ready, read_only, error, deleting, running, idle, deploying, failed) | sim | Estado da instância. |
size_mb |
integer | sim | |
quota_mb |
integer | sim | |
read_only |
boolean | sim | true quando o banco passou da cota. |
host |
string | sim | Host público do motor do banco, com URL própria por motor no nó (PostgreSQL db01.pgsql.<domínio>, MariaDB db01.mariadb.<domínio>, sqlite <banco>.db01.sqlite.<domínio>); é o host das variáveis DATABASE_URL/PGHOST/MYSQL_HOST/LIBSQL_URL. |
port |
integer | sim | |
created_at |
string | sim |
{ "id": "01jb7k4a5q8r7t2v4w6x8y0a9z", "project_id": "01jb7k3m5q8r7t2v4w6x8y0a1b", "name": "db", "kind": "database", "engine": "postgres", "status": "ready", "size_mb": 42, "quota_mb": 1024, "read_only": false, "host": "db01.pgsql.nebularws.com", "port": 5432, "created_at": "2026-10-10T14:03:11Z"}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
PATCH /v1/projects/{p}/databases/{s}
Seção intitulada “PATCH /v1/projects/{p}/databases/{s}”Altera a cota
Altera quota_mb.
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: updateDatabase
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Corpo (application/json)
Seção intitulada “Corpo (application/json)”| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
quota_mb |
integer | sim |
Resposta 200
Seção intitulada “Resposta 200”Banco atualizado.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
id |
string | sim | Id do serviço kind=database. |
project_id |
string | sim | |
name |
string | sim | |
kind |
enum(database) | sim | |
engine |
enum(postgres, mariadb, sqlite) | sim | |
status |
enum(provisioning, ready, read_only, error, deleting, running, idle, deploying, failed) | sim | Estado da instância. |
size_mb |
integer | sim | |
quota_mb |
integer | sim | |
read_only |
boolean | sim | true quando o banco passou da cota. |
host |
string | sim | Host público do motor do banco, com URL própria por motor no nó (PostgreSQL db01.pgsql.<domínio>, MariaDB db01.mariadb.<domínio>, sqlite <banco>.db01.sqlite.<domínio>); é o host das variáveis DATABASE_URL/PGHOST/MYSQL_HOST/LIBSQL_URL. |
port |
integer | sim | |
created_at |
string | sim |
{ "id": "01jb7k4a5q8r7t2v4w6x8y0a9z", "project_id": "01jb7k3m5q8r7t2v4w6x8y0a1b", "name": "db", "kind": "database", "engine": "postgres", "status": "ready", "size_mb": 42, "quota_mb": 1024, "read_only": false, "host": "db01.pgsql.nebularws.com", "port": 5432, "created_at": "2026-10-10T14:03:11Z"}Resposta 422
Seção intitulada “Resposta 422”quota_exceeded: a cota não comporta a operação.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
{ "error": "quota_exceeded", "message": "Limite de serviços do plano atingido."}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 413 Corpo JSON acima do limite da rota (too_large); 415 O corpo precisa ser application/json (unsupported_media_type); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
DELETE /v1/projects/{p}/databases/{s}
Seção intitulada “DELETE /v1/projects/{p}/databases/{s}”Apaga o banco
Apaga o banco. Corpo opcional {"final_backup": true|false} (padrão true: faz um backup antes). Idempotente: repetir para um banco que este time apagou pela API devolve 204.
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: deleteDatabase
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Corpo (application/json)
Seção intitulada “Corpo (application/json)”| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
final_backup |
boolean | não | Faz um backup antes de apagar (padrão true). |
Resposta 204
Seção intitulada “Resposta 204”Removido (ou já removido anteriormente: repetir é 204).
Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 413 Corpo JSON acima do limite da rota (too_large); 415 O corpo precisa ser application/json (unsupported_media_type); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
GET /v1/projects/{p}/databases/{s}/backups
Seção intitulada “GET /v1/projects/{p}/databases/{s}/backups”Lista os backups
Backups do mais novo para o mais antigo.
Escopo exigido: projects:read.
Escopo exigido: projects:read · operationId: listBackups
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
cursor |
query | string | não | Cursor opaco devolvido em next_cursor da página anterior. |
limit |
query | integer | não | Itens por página (1 a 200). |
Resposta 200
Seção intitulada “Resposta 200”Página (mais novo/antigo primeiro conforme o recurso).
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
next_cursor |
string|null | sim | Passe em cursor para a próxima página; null ao fim. |
has_more |
boolean | sim | Há mais páginas. |
items |
array | sim | |
items[].id |
string | sim | |
items[].at |
string | sim | |
items[].size |
integer | sim | Bytes. |
items[].status |
string | sim | Estado do backup (ex.: done). |
{ "items": [ { "id": "01jb7kb15q8r7t2v4w6x8y0a1j", "at": "2026-10-10T14:03:11Z", "size": 44040192, "status": "done" } ], "next_cursor": null, "has_more": false}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
POST /v1/projects/{p}/databases/{s}/backups
Seção intitulada “POST /v1/projects/{p}/databases/{s}/backups”Inicia um backup
Backup sob demanda, assíncrono: acompanhe em GET …/jobs/{job_id}.
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: createBackup
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Idempotency-Key |
header | string | não | Chave de idempotência (8 a 128 caracteres [A-Za-z0-9._:-]; use um UUID). Mesma chave + mesmo pedido em 24 h ⇒ a mesma resposta, com Idempotent-Replay: true; mesma chave + pedido diferente ⇒ 422 idempotency_conflict. Falhas nunca são gravadas, então a repetição executa de verdade. |
Resposta 202
Seção intitulada “Resposta 202”Backup iniciado.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
job_id |
string | sim | |
backup_id |
string | não | Só no backup. |
{ "job_id": "01jb7k8a5q8r7t2v4w6x8y0a6g", "backup_id": "01jb7kb15q8r7t2v4w6x8y0a1j"}Resposta 422
Seção intitulada “Resposta 422”idempotency_conflict.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
{ "error": "idempotency_conflict", "message": "Esta Idempotency-Key já foi usada com outro conteúdo. Gere uma chave nova."}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
POST /v1/projects/{p}/databases/{s}/credentials
Seção intitulada “POST /v1/projects/{p}/databases/{s}/credentials”Revela as credenciais de conexão
Devolve as credenciais em claro. Nunca em GET, nunca em cache, e a leitura é auditada. O token precisa do escopo env:reveal e ter sido criado com confirmação de identidade (step-up); sem isso, 403.
Escopo exigido: env:reveal.
Escopo exigido: env:reveal · operationId: revealDatabaseCredentials
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Resposta 200
Seção intitulada “Resposta 200”Credenciais.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
credentials |
array | sim | |
credentials[].name |
string | sim | |
credentials[].value |
string | sim |
{ "credentials": [ { "name": "DB_HOST", "value": "db" }, { "name": "DB_PASSWORD", "value": "valor-exibido-uma-vez" } ]}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
POST /v1/projects/{p}/databases/{s}/restore
Seção intitulada “POST /v1/projects/{p}/databases/{s}/restore”Restaura um backup
Inicia um restore. target=new (padrão) cria um banco ao lado do atual, sem substituí-lo: o serviço continua apontando para o banco de origem e o novo aparece em GET …/restores já com status: restoring. same sobrescreve os dados vivos (no painel exige step-up). Acompanhe em GET …/jobs/{job_id} ou em GET …/restores.
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: restoreDatabase
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Idempotency-Key |
header | string | não | Chave de idempotência (8 a 128 caracteres [A-Za-z0-9._:-]; use um UUID). Mesma chave + mesmo pedido em 24 h ⇒ a mesma resposta, com Idempotent-Replay: true; mesma chave + pedido diferente ⇒ 422 idempotency_conflict. Falhas nunca são gravadas, então a repetição executa de verdade. |
Corpo (application/json)
Seção intitulada “Corpo (application/json)”| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
backup_id |
string | sim | |
target |
enum(new, same) | não | new (padrão) cria ao lado, sem substituir o banco atual; same sobrescreve o banco vivo (no painel exige step-up). |
new_db_name |
string | não | Ignorado: o nome do banco restaurado é gerado pelo servidor (n_…) e vem em db_name de GET …/restores. |
Resposta 202
Seção intitulada “Resposta 202”Restore iniciado.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
job_id |
string | sim | |
backup_id |
string | não | Só no backup. |
{ "job_id": "01jb7kc15q8r7t2v4w6x8y0a2k"}Resposta 409
Seção intitulada “Resposta 409”backup_not_ready: o backup ainda não terminou.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
Resposta 422
Seção intitulada “Resposta 422”idempotency_conflict.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
{ "error": "idempotency_conflict", "message": "Esta Idempotency-Key já foi usada com outro conteúdo. Gere uma chave nova."}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 413 Corpo JSON acima do limite da rota (too_large); 415 O corpo precisa ser application/json (unsupported_media_type); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
GET /v1/projects/{p}/databases/{s}/restores
Seção intitulada “GET /v1/projects/{p}/databases/{s}/restores”Lista os bancos criados por restore
Bancos criados por restores target=new ao lado do banco, de qualquer motor, com o estado de cada um (restoring, ready ou failed, com error quando falhou). Postgres e MariaDB: o banco restaurado (db_name) fica na mesma instância, host e porta, e usa as mesmas credenciais do banco de origem. SQLite: nasce uma instância própria (url; gere um token novo com a rotação).
Escopo exigido: projects:read.
Escopo exigido: projects:read · operationId: listRestores
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
cursor |
query | string | não | Cursor opaco devolvido em next_cursor da página anterior. |
limit |
query | integer | não | Itens por página (1 a 200). |
Resposta 200
Seção intitulada “Resposta 200”Página (mais novo/antigo primeiro conforme o recurso).
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
next_cursor |
string|null | sim | Passe em cursor para a próxima página; null ao fim. |
has_more |
boolean | sim | Há mais páginas. |
items |
array | sim | |
items[].id |
string | sim | |
items[].job_id |
string | sim | |
items[].backup_id |
string | sim | |
items[].db_name |
string | sim | Nome do banco restaurado (postgres/mariadb: na mesma instância da origem; sqlite: o id da instância nova). |
items[].status |
enum(restoring, ready, failed) | sim | restoring enquanto o job roda; ready quando pronto para uso; failed com error. |
items[].error |
object | não | |
items[].error.code |
string | sim | Código estável da falha: deploy_failed (genérico), unresolved_reference, reference_cycle, image_requires_root, crashed_after_start e os do build: build_clone_failed, build_detect_failed, build_install_failed, build_script_failed, build_copy_failed, build_activate_failed, activate_readonly_write (o app tentou gravar sob /app, somente leitura: use um volume nessa pasta ou /tmp), activate_app_crashed (o app encerrou logo ao iniciar; a mensagem traz a primeira linha de erro do log), activate_oom (o app usou mais memória que o limite do serviço e foi encerrado), activate_no_http (o app estável e rodando não respondeu na porta esperada), team_app_limit (o time já roda o máximo de apps do plano; a mensagem traz N de M: pare ou remova um app, ou peça ao operador para ampliar o limite), build_volume_unavailable, build_oom, build_timeout, build_storage_error (falha interna de armazenamento da plataforma, não do repositório), build_disk_full (espaço de build cheio) e build_storage_unavailable (nenhum armazenamento de build utilizável na plataforma; não é falta de espaço). O código vem gravado com o deploy; message traz a causa em português (sem segredos nem caminhos do servidor). |
items[].error.message |
string | sim | |
items[].error.details |
any | não | Dados extras do erro (qualquer JSON). |
items[].host |
string | sim | |
items[].port |
integer | sim | |
items[].url |
string | não | Só sqlite. |
items[].created_at |
string | sim |
{ "items": [ { "id": "01jb7k9a5q8r7t2v4w6x8y0a7h", "job_id": "01jb7kc15q8r7t2v4w6x8y0a2k", "backup_id": "01jb7kb15q8r7t2v4w6x8y0a1j", "db_name": "n_k7p2m4q6r8t2v4w6", "status": "ready", "host": "db01.pgsql.example.com", "port": 5432, "created_at": "2026-10-10T14:03:11Z" } ], "next_cursor": null, "has_more": false}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 400 Entrada inválida (nome de arquivo fora das regras, cursor malformado, formulário sem file, nome de galeria vazio ou longo); 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
POST /v1/projects/{p}/databases/{s}/rotate
Seção intitulada “POST /v1/projects/{p}/databases/{s}/rotate”Rotaciona as credenciais
Gera novas credenciais e marca os serviços dependentes para novo deploy.
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: rotateDatabase
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
Resposta 200
Seção intitulada “Resposta 200”Banco.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
id |
string | sim | Id do serviço kind=database. |
project_id |
string | sim | |
name |
string | sim | |
kind |
enum(database) | sim | |
engine |
enum(postgres, mariadb, sqlite) | sim | |
status |
enum(provisioning, ready, read_only, error, deleting, running, idle, deploying, failed) | sim | Estado da instância. |
size_mb |
integer | sim | |
quota_mb |
integer | sim | |
read_only |
boolean | sim | true quando o banco passou da cota. |
host |
string | sim | Host público do motor do banco, com URL própria por motor no nó (PostgreSQL db01.pgsql.<domínio>, MariaDB db01.mariadb.<domínio>, sqlite <banco>.db01.sqlite.<domínio>); é o host das variáveis DATABASE_URL/PGHOST/MYSQL_HOST/LIBSQL_URL. |
port |
integer | sim | |
created_at |
string | sim |
{ "id": "01jb7k4a5q8r7t2v4w6x8y0a9z", "project_id": "01jb7k3m5q8r7t2v4w6x8y0a1b", "name": "db", "kind": "database", "engine": "postgres", "status": "ready", "size_mb": 42, "quota_mb": 1024, "read_only": false, "host": "db01.pgsql.nebularws.com", "port": 5432, "created_at": "2026-10-10T14:03:11Z"}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
GET /v1/projects/{p}/databases/{s}/jobs/{j}
Seção intitulada “GET /v1/projects/{p}/databases/{s}/jobs/{j}”Consulta um job de backup/restore (polling)
queued → running → done|failed. Em restore target=new, new_instance descreve o banco criado ao lado e seu estado (sem credencial). Em job com falha, error.code é estável (backup_failed, backup_tls_failed, restore_failed, …) e error.message está em português claro, sem segredos.
Escopo exigido: projects:read.
Escopo exigido: projects:read · operationId: getDatabaseJob
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
j |
path | string | sim | Id do job de backup/restore (job_id). |
Resposta 200
Seção intitulada “Resposta 200”Job.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
id |
string | sim | |
kind |
enum(backup, restore) | sim | |
status |
enum(queued, running, done, failed) | sim | |
error |
object | não | |
error.code |
string | sim | Código estável da falha: deploy_failed (genérico), unresolved_reference, reference_cycle, image_requires_root, crashed_after_start e os do build: build_clone_failed, build_detect_failed, build_install_failed, build_script_failed, build_copy_failed, build_activate_failed, activate_readonly_write (o app tentou gravar sob /app, somente leitura: use um volume nessa pasta ou /tmp), activate_app_crashed (o app encerrou logo ao iniciar; a mensagem traz a primeira linha de erro do log), activate_oom (o app usou mais memória que o limite do serviço e foi encerrado), activate_no_http (o app estável e rodando não respondeu na porta esperada), team_app_limit (o time já roda o máximo de apps do plano; a mensagem traz N de M: pare ou remova um app, ou peça ao operador para ampliar o limite), build_volume_unavailable, build_oom, build_timeout, build_storage_error (falha interna de armazenamento da plataforma, não do repositório), build_disk_full (espaço de build cheio) e build_storage_unavailable (nenhum armazenamento de build utilizável na plataforma; não é falta de espaço). O código vem gravado com o deploy; message traz a causa em português (sem segredos nem caminhos do servidor). |
error.message |
string | sim | |
error.details |
any | não | Dados extras do erro (qualquer JSON). |
result |
any | não | Resultado do job quando done (qualquer JSON). |
new_instance |
object | não | Banco criado por um restore target=new (qualquer motor). Nunca carrega credencial (postgres/mariadb usam as da origem). |
new_instance.id |
string | sim | |
new_instance.job_id |
string | sim | |
new_instance.backup_id |
string | sim | |
new_instance.db_name |
string | sim | Nome do banco restaurado (postgres/mariadb: na mesma instância da origem; sqlite: o id da instância nova). |
new_instance.status |
enum(restoring, ready, failed) | sim | restoring enquanto o job roda; ready quando pronto para uso; failed com error. |
new_instance.error |
object | não | |
new_instance.error.code |
string | sim | Código estável da falha: deploy_failed (genérico), unresolved_reference, reference_cycle, image_requires_root, crashed_after_start e os do build: build_clone_failed, build_detect_failed, build_install_failed, build_script_failed, build_copy_failed, build_activate_failed, activate_readonly_write (o app tentou gravar sob /app, somente leitura: use um volume nessa pasta ou /tmp), activate_app_crashed (o app encerrou logo ao iniciar; a mensagem traz a primeira linha de erro do log), activate_oom (o app usou mais memória que o limite do serviço e foi encerrado), activate_no_http (o app estável e rodando não respondeu na porta esperada), team_app_limit (o time já roda o máximo de apps do plano; a mensagem traz N de M: pare ou remova um app, ou peça ao operador para ampliar o limite), build_volume_unavailable, build_oom, build_timeout, build_storage_error (falha interna de armazenamento da plataforma, não do repositório), build_disk_full (espaço de build cheio) e build_storage_unavailable (nenhum armazenamento de build utilizável na plataforma; não é falta de espaço). O código vem gravado com o deploy; message traz a causa em português (sem segredos nem caminhos do servidor). |
new_instance.error.message |
string | sim | |
new_instance.error.details |
any | não | Dados extras do erro (qualquer JSON). |
new_instance.host |
string | sim | |
new_instance.port |
integer | sim | |
new_instance.url |
string | não | Só sqlite. |
new_instance.created_at |
string | sim |
{ "id": "01jb7k8a5q8r7t2v4w6x8y0a6g", "kind": "backup", "status": "done", "result": { "size": 44040192 }}Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.
DELETE /v1/projects/{p}/databases/{s}/restores/{r}
Seção intitulada “DELETE /v1/projects/{p}/databases/{s}/restores/{r}”Apaga um banco de restore
Idempotente (repetir ⇒ 204). Em postgres/mariadb o banco restaurado vive na instância da origem e só sai com ela: a resposta é 409 restore_not_removable, exceto para um restore failed (só o registro é removido).
Escopo exigido: databases:write.
Escopo exigido: databases:write · operationId: deleteRestore
| Parâmetro | Em | Tipo | Obrig. | Descrição |
|---|---|---|---|---|
p |
path | string | sim | Id (26 caracteres) ou slug do projeto. Projeto de outro time ou fora dos project_ids do token ⇒ 404. |
s |
path | string | sim | Id ou nome do serviço kind=database. Serviço que não é banco ⇒ 404. |
r |
path | string | sim | Id da instância criada por um restore target=new. |
Resposta 204
Seção intitulada “Resposta 204”Removido (ou já removido anteriormente: repetir é 204).
Resposta 409
Seção intitulada “Resposta 409”restore_not_removable: o banco restaurado divide a instância da origem e ainda não pode ser removido sozinho.
| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
error |
enum(unauthorized, forbidden, not_found, payload_too_large, quota_exceeded, unsupported_type, class_not_allowed, extension_mismatch, malware_detected, svg_unsafe, archive_encrypted, archive_bomb, archive_unsupported, rate_limited, unavailable, idempotency_conflict, invalid_request, unsupported_media_type, bad_json, too_large, authz_unavailable, database_unavailable, restore_not_removable, gallery_not_empty, bad_body, internal, name_taken, slug_taken, project_quota_exceeded, project_not_empty, deploy_in_progress, nothing_to_rollback, not_cancelable, sensitive_lowered, duplicate_variable, domain_taken, volume_exists, volume_in_use, volume_attached, backup_not_ready, unresolved_reference, reference_cycle, invalid_reference, reference_too_deep, value_too_large) | sim | Código estável para tratamento programático. A tabela completa está na descrição geral. |
message |
string | sim | Mensagem legível em pt-BR. |
details |
object | não | Presente em alguns 422 (ex.: unresolved_reference e reference_cycle trazem details.references). |
details.references |
array |
não | Referências problemáticas (só nomes, nunca valores). |
details.retry_after_seconds |
integer | não | Em 422 rate_limited (ex.: verificação manual de domínio): segundos até poder tentar de novo. |
Erros comuns
Seção intitulada “Erros comuns”Corpo {"error", "message", "details"?} (veja Autenticação e visão geral e a tabela de erros): 401 Token ausente, inválido, expirado ou revogado. A resposta é genérica de propósito; 403 O token não tem o escopo exigido pela operação; 404 Recurso inexistente ou pertencente a outro time (indistinguíveis de propósito); 429 Limite de requisições excedido. Espere Retry-After segundos; 500 Falha interna (internal). O detalhe fica só no log do servidor; repita depois, e informe o Idempotency-Key ao suporte se persistir; 503 Serviço (ex.: scanner ou borda) temporariamente indisponível. Tente de novo após Retry-After.