# Rebun > Backend-as-a-service para devs brasileiros: banco de dados Postgres, autenticação de usuários e arquivos por uma API REST e um SDK TypeScript, com API em São Paulo e cobrança em reais. Rebun está em beta: a API já é estável para uso, mas recursos e preços ainda podem mudar. ## Conceitos - project: projeto isolado, com tabelas, buckets, usuários, chaves de API e membros próprios. - table: tabela Postgres com colunas tipadas (`text`, `integer`, `numeric`, `boolean`, `timestamptz`, `date`, `uuid`, `jsonb`). Toda tabela ganha `id`, `created_at`, `updated_at`, `owner_id`. Os valores dos registros vão e voltam como `string | null`; colunas array (lista, definidas no painel) usam JSON array (`["a", "b"]`), e na leitura os itens vêm como string; colunas `jsonb` vão e voltam como JSON, e uma string enviada a elas é lida como texto JSON. - bucket: pasta de arquivos do project, pública ou privada, com `maxFileSize` e `allowedMimeTypes` opcionais. - usuário: usuário final do seu app, autenticado por `/auth` (OTP por e-mail, Google ou GitHub). - chave de API: credencial do project, mostrada uma vez na criação. ## API Base URL: https://api.rebun.dev/v1 Autenticação: header `x-api-key: `. Erros vêm como `{ error, message }`. Permissões da chave: `record:read`, `record:create`, `record:update`, `record:delete`, `file:read`, `file:create`, `file:delete`, `bucket:read`, `bucket:create`, `bucket:update`, `bucket:delete`, `auth:login`, `auth:signup`, `function:invoke`. Sem a permissão da rota, `MISSING_PERMISSION` (403). Chaves são de servidor por padrão: requisição com header `Origin` (navegador) é recusada com `CLIENT_NOT_ALLOWED` (403). Só chaves criadas para uso no navegador aceitam `Origin`, que precisa ser de um domínio autorizado do project, e elas só podem ter: `record:read`, `record:create`, `record:update`, `record:delete`, `file:read`, `bucket:read`, `auth:login`, `auth:signup`, `function:invoke`. Cada operação da tabela (read, create, update, delete) segue uma regra de acesso definida no painel: `nobody`, `public`, `authenticated`, `owner` (padrão `nobody`). `owner` usa o usuário do header `Authorization: Bearer `. ### Registros Tabelas e colunas são criadas e editadas só no painel; a API trabalha com os registros. - GET /tables/:name/records — lista. Query: `select` (JSON com nomes de coluna, padrão todas; `.` embute o registro referenciado como objeto, ou `null` sem referência ou sem acesso, um nível, até 5 FKs), `where` (JSON: `["coluna", op, valor]` ou `{ "and" | "or": [...] }` aninhável, até 5 grupos e 50 condições; op: `==`, `!=`, `>`, `>=`, `<`, `<=`, `in`/`not in` com lista de até 100, `like`/`ilike` só em `text`; `null` só com `==`/`!=`), `order` (JSON com até 5 `["coluna", "asc" | "desc"]`; padrão `created_at desc`), `skip` (padrão 0), `take` (padrão 20, máximo 100). Devolve o array de registros e o total no header `X-Total-Count`; consulta inválida, `INVALID_QUERY` (422) (`record:read`) - GET /tables/:name/records/:id — busca um registro (`record:read`) - POST /tables/:name/records — cria. Body: `{ "values": { "coluna": "valor" } }`; 201, ou `RECORD_EXISTS` (409, `message` é a coluna única repetida), ou `INVALID_REFERENCE` (422, `message` é a coluna cuja referência não existe) (`record:create`) - PATCH /tables/:name/records/:id — atualiza. Body: `{ "values": { ... } }`; `RECORD_EXISTS` (409) e `INVALID_REFERENCE` (422) como no POST (`record:update`) - DELETE /tables/:name/records/:id — remove; 204, ou `RECORD_REFERENCED` (409) se outro registro aponta para ele (`record:delete`) ### Buckets e arquivos - GET /buckets, GET /buckets/:name (`bucket:read`) - POST /buckets — cria. Body: `{ "name", "public"?, "maxFileSize"?, "allowedMimeTypes"? }`; 201, ou `BUCKET_EXISTS` (409) (`bucket:create`) - PATCH /buckets/:name — atualiza só os campos enviados (os mesmos do POST, todos opcionais; os omitidos ficam como estão, e `maxFileSize: null` e `allowedMimeTypes: []` limpam). Body vazio, `INVALID_BODY` (422) (`bucket:update`) - DELETE /buckets/:name — remove o bucket e os arquivos; 204 (`bucket:delete`) - GET /buckets/:name/files — lista. Query: `search`, `skip`, `take` (máximo 100). Devolve o array de arquivos e o total no header `X-Total-Count` (`file:read`) - POST /buckets/:name/files/upload-url — Body: `{ "path", "size", "mimeType" }`. Devolve `{ url }`: faça PUT dos bytes nela com `content-type` igual ao `mimeType`. Fora das regras do bucket, `FILE_TOO_LARGE` (413) ou `FILE_TYPE_NOT_ALLOWED` (415) (`file:create`) - POST /buckets/:name/files — confirma o envio. Body: `{ "path" }`; 201 com `{ id, path, size, mimeType, createdAt }`, ou `UPLOAD_MISSING` (422) (`file:create`) - GET /buckets/:name/files/:path — devolve `{ url }` assinada para download (`file:read`) - DELETE /buckets/:name/files/:path — remove; 204 (`file:delete`) ### Auth de usuários finais (`auth:login`) O login usa PKCE (`codeChallengeMethod: "S256"`) e devolve um code que é trocado por um access token. `redirectUri` precisa ser de um domínio autorizado do project. `auth:login` só entra com usuários que já existem; criar um usuário novo (primeiro login por OTP, magic link, Google ou GitHub, e o cadastro por senha) exige também `auth:signup`. Sem ela, um e-mail novo recebe `SIGNUP_NOT_ALLOWED` (403), ou `?error=SIGNUP_NOT_ALLOWED` no redirect. - POST /auth/otp/start — Body: `{ "email", "redirectUri", "codeChallenge", "codeChallengeMethod", "state"? }`. Envia um código de 6 dígitos e um magic link por e-mail, pelo provider (Resend ou SMTP) e o remetente da aba E-mail do projeto; 204. Falha no envio (ou projeto sem e-mail configurado), `EMAIL_SEND_FAILED` (502) - POST /auth/otp/verify — Body: `{ "email", "code" }`. Devolve `{ code, state }`; código errado ou expirado, `INVALID_OR_EXPIRED_CODE` (401) - POST /auth/:provider/start — `google` ou `github`. Body: `{ "redirectUri", "codeChallenge", "codeChallengeMethod", "state"? }`. Devolve `{ url }`; o retorno chega em `redirectUri?code&state`. Provider desligado, `PROVIDER_DISABLED` (403) - POST /oauth/token — Body: `{ "grantType": "authorization_code", "code", "codeVerifier", "redirectUri" }`. Devolve `{ accessToken, tokenType, expiresIn, user }`; code inválido, `INVALID_GRANT` (400) - GET /auth/me — header `Authorization: Bearer `. Devolve `{ user }`, ou `INVALID_TOKEN` (401) - POST /oauth/revoke — header `Authorization: Bearer `. Encerra a sessão; 204 ## SDK `npm install rebun-sdk` ```ts import { createClient } from "rebun-sdk" const rebun = createClient({ apiKey: process.env.REBUN_API_KEY }) const { data, error } = await rebun.db .from("posts") .select(["title"]) .where("views", ">=", "100") .orderBy("views", "desc") .take(10) ``` O SDK cobre `db.from(table)`, `storage.bucket` e `auth` (com PKCE automático). Por padrão, nenhum método lança: todos resolvem `{ data, error }`; as listagens trazem também o `total`. Com `throwOnError: true` no `createClient`, resolvem `{ data }` e rejeitam com `RebunError`. Sessão: no navegador, um único cliente no app inteiro. No servidor, o cliente nunca guarda sessão em memória (login e `setToken` sem `cookies` lançam `Error`): no Next, um cliente global com `cookies: async () => adaptador de await cookies()`, chamado a cada método; sem requisição implícita (Express), um cliente por requisição com `cookies: { get, set }`; com token em mãos, `rebun.withToken(token)`. O token vai no cookie httpOnly `rebun-token`. ## Cotas por plano - Free: banco 500 MB, storage 5 GB, compute 20 UC-h/mês, usuários e banda de saída ilimitados, 1 membro(s) - Pro: banco 5 GB, storage 50 GB, compute 100 UC-h/mês, usuários e banda de saída ilimitados, 5 membro(s) - Team: banco 5 GB, storage 50 GB, compute 100 UC-h/mês, usuários e banda de saída ilimitados, 20 membro(s) Estourar a cota do plano responde `PLAN_LIMIT_REACHED` (402). ## Rate limit Por minuto: 120 requisições por API key e 3 por IP em `/auth/otp/start` e `/auth/otp/verify`. Estourar responde `RATE_LIMITED` (429) com `Retry-After` em segundos. ## Páginas - [Início](https://rebun.dev/): visão geral do produto, preços e como funciona - [Manifesto](https://rebun.dev/manifesto) - [Marca](https://rebun.dev/brand): guia da marca, com logo, o mascote Goma, cores, tipografia e voz - [Showcase](https://rebun.dev/showcase) - [Termos de Uso](https://rebun.dev/terms-of-use) - [Política de Privacidade](https://rebun.dev/privacy-policy) - [Introdução](https://rebun.dev/docs/introducao): O que é o Rebun e como os projetos, tabelas, buckets e usuários se encaixam. - [API](https://rebun.dev/docs/api): Endpoints REST para registros, buckets, arquivos e autenticação de usuários. - [MCP](https://rebun.dev/docs/mcp): Conecte seu assistente de IA aos seus projetos pelo servidor MCP do Rebun. - [SDK](https://rebun.dev/docs/sdk): Cliente TypeScript tipado para registros, storage e autenticação de usuários.