Pular para o conteúdo
🔌 API REFERENCE

Groups — Referência API.

Todos os endpoints para criar, gerenciar e provisionar tenants via REST.

Autenticação

A API Groups usa dois tipos de autenticação dependendo do recurso:

  • Platform Admin JWT — para gerenciar Groups via /platform/v1/groups/*. Obtenha em admin.superdb.com.br.
  • Group API Key — para provisionar e gerenciar tenants via /groups/v1/*. Gerada em /groups no painel, na página do seu group — o texto claro aparece apenas uma vez.
⚠️

Group API Key é secreta. Nunca exponha no frontend. Guarde no .env do seu backend e jamais comite no git.

Todos os endpoints retornam JSON e aceitam Content-Type: application/json.


Endpoints de Platform Admin

Requerem o token de sessão do painel (Authorization: Bearer <token>). Você só enxerga e altera os groups que são seus — desde 04/08/2026 estas rotas deixaram de exigir cargo de admin e passaram a checar posse.

POST /platform/v1/groups

Cria um novo Group associado a um projeto template.

Request
POST https://auth.superdb.com.br/platform/v1/groups
Authorization: Bearer <platform_admin_jwt>
Content-Type: application/json

{
  "name": "ERP Clínicas",
  "description": "Template para sistemas de gestão de clínicas médicas",
  "template_project_id": "proj_erp_clinica_template"
}
Response 201
{
  "id": "grp_a1b2c3d4e5f6",
  "name": "ERP Clínicas",
  "description": "Template para sistemas de gestão de clínicas médicas",
  "template_project_id": "proj_erp_clinica_template",
  "tenant_count": 0,
  "created_at": "2026-05-14T10:30:00Z"
}
TypeScript
const resp = await fetch('https://auth.superdb.com.br/platform/v1/groups', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${platformAdminJwt}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'ERP Clínicas',
    template_project_id: 'proj_erp_clinica_template',
  }),
})
const group = await resp.json()

GET /platform/v1/groups

Lista todos os Groups da plataforma.

curl
curl https://auth.superdb.com.br/platform/v1/groups \
  -H "Authorization: Bearer $PLATFORM_ADMIN_JWT"
Response 200
[
  {
    "id": "grp_a1b2c3d4e5f6",
    "name": "ERP Clínicas",
    "tenant_count": 12,
    "created_at": "2026-05-14T10:30:00Z"
  },
  {
    "id": "grp_x9y8z7w6v5u4",
    "name": "Gestão Escolar",
    "tenant_count": 4,
    "created_at": "2026-05-10T08:15:00Z"
  }
]

GET /platform/v1/groups/:id

Retorna detalhes de um Group específico.

curl
curl https://auth.superdb.com.br/platform/v1/groups/grp_a1b2c3d4e5f6 \
  -H "Authorization: Bearer $PLATFORM_ADMIN_JWT"

DELETE /platform/v1/groups/:id

Deleta um Group. Retorna 409 Conflict se o Group ainda tiver tenants ativos.

curl
curl -X DELETE https://auth.superdb.com.br/platform/v1/groups/grp_a1b2c3d4e5f6 \
  -H "Authorization: Bearer $PLATFORM_ADMIN_JWT"

# Response: 204 No Content (sucesso)
# Response: 409 Conflict (group tem tenants ativos)

Endpoints de Group API (tenants)

Requerem Authorization: Bearer <group_api_key>. Use no backend do seu SaaS para provisionar clientes.

POST /groups/v1/:group_id/tenants

Provisiona um novo tenant para o Group. Esta é a operação mais importante — chame quando um novo cliente se cadastrar no seu SaaS.

O SuperDB clona o schema template, cria as tabelas de auth, gera o role Postgres dedicado e retorna as keys em ~1-2 segundos.

Request
POST https://auth.superdb.com.br/groups/v1/grp_a1b2c3d4e5f6/tenants
Authorization: Bearer <group_api_key>
Content-Type: application/json

{
  "slug": "clinica_sao_lucas",
  "external_id": "company_789",
  "metadata": {
    "cnpj": "12.345.678/0001-99",
    "plan": "professional",
    "admin_email": "dr.pedro@saolucas.com.br"
  }
}
Campo Tipo Obrigatório Descrição
slug string Sim Identificador único. Só letras minúsculas, números e underscore.
external_id string Não ID do cliente no seu banco de dados.
metadata object Não JSON livre. Armazenado mas não indexado.
Response 201 — salve as keys agora
{
  "tenant": {
    "id": "ten_f7e8d9c0b1a2",
    "slug": "clinica_sao_lucas",
    "schema_name": "proj_clinica_sao_lucas",
    "external_id": "company_789",
    "group_id": "grp_a1b2c3d4e5f6",
    "metadata": { "cnpj": "12.345.678/0001-99", "plan": "professional" },
    "created_at": "2026-05-14T11:45:00Z"
  },
  "anon_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsInRlbmFudCI6ImNsaW5pY2Ffc2FvX2x1Y2FzIn0.XXXX",
  "service_role_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIn0.YYYY"
}
⚠️

Salve as keys imediatamente. O service_role_key não é armazenado no SuperDB após a criação — por segurança. Se perder, precisará revogar e gerar novas keys.

TypeScript — exemplo completo
interface ProvisionResult {
  tenant: {
    id: string
    slug: string
    schema_name: string
    external_id?: string
    created_at: string
  }
  anon_key: string
  service_role_key: string
}

export async function provisionTenant(params: {
  slug: string
  externalId?: string
  metadata?: Record<string, unknown>
}): Promise<ProvisionResult> {
  const url = `${process.env.SUPERDB_BASE_URL}/groups/v1/${process.env.SUPERDB_GROUP_ID}/tenants`

  const resp = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SUPERDB_GROUP_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      slug: params.slug,
      external_id: params.externalId,
      metadata: params.metadata,
    }),
  })

  if (!resp.ok) {
    const error = await resp.text()
    throw new Error(`Provisioning falhou (${resp.status}): ${error}`)
  }

  return resp.json() as Promise<ProvisionResult>
}

GET /groups/v1/:group_id/tenants

Lista todos os tenants de um Group.

curl
curl "https://auth.superdb.com.br/groups/v1/grp_a1b2c3d4e5f6/tenants?limit=20&offset=0" \
  -H "Authorization: Bearer $SUPERDB_GROUP_API_KEY"
Response 200
{
  "tenants": [
    {
      "id": "ten_f7e8d9c0b1a2",
      "slug": "clinica_sao_lucas",
      "external_id": "company_789",
      "created_at": "2026-05-14T11:45:00Z"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

GET /groups/v1/:group_id/tenants/:id

Retorna detalhes de um tenant específico. Não retorna as keys (por segurança).

curl
curl "https://auth.superdb.com.br/groups/v1/grp_a1b2c3d4e5f6/tenants/ten_f7e8d9c0b1a2" \
  -H "Authorization: Bearer $SUPERDB_GROUP_API_KEY"

DELETE /groups/v1/:group_id/tenants/:id

Deleta um tenant e apaga o schema Postgres — operação irreversível. Todos os dados do tenant são removidos.

⚠️

IRREVERSÍVEL. Esta operação executa DROP SCHEMA tenant_xyz CASCADE. Faça backup antes. Confirme o slug do tenant antes de chamar.

curl
curl -X DELETE \
  "https://auth.superdb.com.br/groups/v1/grp_a1b2c3d4e5f6/tenants/ten_f7e8d9c0b1a2" \
  -H "Authorization: Bearer $SUPERDB_GROUP_API_KEY"

# Response: 204 No Content
TypeScript
export async function deleteTenant(tenantId: string): Promise<void> {
  const url = `${process.env.SUPERDB_BASE_URL}/groups/v1/${process.env.SUPERDB_GROUP_ID}/tenants/${tenantId}`

  const resp = await fetch(url, {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${process.env.SUPERDB_GROUP_API_KEY}`,
    },
  })

  if (!resp.ok && resp.status !== 204) {
    throw new Error(`Deleção falhou: ${resp.status}`)
  }
}

Códigos de erro

Status Código Descrição
400 invalid_slug Slug contém caracteres inválidos ou está vazio.
401 unauthorized Token ausente, expirado ou inválido.
403 forbidden API Key não tem permissão para este Group.
409 slug_conflict Slug já existe neste Group.
422 provisioning_failed Erro interno ao clonar o schema. Tente novamente.
402 tenant_limit_reached O grupo chegou a 100 tenants ativos — é o teto por grupo, e não há limite por minuto: este é o único freio quantitativo.

Publicar uma versão do template

POST /groups/v1/{groupId}/template/publish — autenticado com a Group API Key.

Congela o schema atual do projeto de origem num template novo (<fonte>_v2, _v3…) e aponta o group para ele. A partir daí, todo cliente provisionado nasce com essa estrutura. Use como passo do seu deploy, depois de rodar as migrations.

curl -X POST https://auth.superdb.com.br/groups/v1/{groupId}/template/publish \
  -H "Authorization: Bearer sdb_gk_..."

Resposta 201:

{
  "template": { "id": "...", "slug": "idepot_erp_v2", "name": "..." },
  "source_project_slug": "idepot_erp",
  "tables_copied": 46,
  "foreign_keys": 87,
  "tenants_na_versao_anterior": 12,
  "aviso": "12 tenant(s) continuam com a estrutura anterior — publicar não retroage."
}

Não retroage. Tenant que já existe continua com a estrutura anterior — por isso a resposta devolve tenants_na_versao_anterior. Para migrar os que já estão no ar, rode a migration em cada um via /db/exec, com a management key do tenant. Trocar o template e deixar você achar que os antigos acompanharam seria pior do que não ter a rota.

foreign_keys em null significa que o fechamento do clone falhou e o template ficou sem integridade referencial: não trate como sucesso.

Próximos passos

Essa página ajudou?