Visão Geral da API
URL Base e Versionamento
A API Ozzie é versionada via caminho de URL. A versão estável atual é v1.
https://api.ozzieapp.com/v1
Política de versionamento:
- O prefixo de versão (
/v1,/v2, etc.) é incrementado apenas para mudanças incompatíveis. - Mudanças aditivas (novos campos opcionais, novos endpoints) são feitas sem incremento de versão.
- Versões depreciadas são anunciadas com pelo menos 90 dias de antecedência e retornarão um header de resposta
Deprecationdurante o período de descontinuação. - Sempre fixe uma versão explícita na sua URL base. Nunca use
/latest.
Quando uma versão entra no período de depreciação, todas as respostas incluirão:
Deprecation: true
Sunset: Sat, 01 Nov 2025 00:00:00 GMT
Todos os Endpoints Disponíveis
| Método | Caminho | Descrição |
|---|---|---|
POST | /v1/users | Criar um novo usuário |
GET | /v1/users/{user_id} | Recuperar um usuário por ID Ozzie ou external_user_id |
PATCH | /v1/users/{user_id} | Atualizar campos do usuário (name, email, phone, language) |
POST | /v1/users/{user_id}/financial-intake | Enviar um snapshot financeiro mensal |
GET | /v1/users/{user_id}/financial-intake | Obter o intake financeiro mais recente |
GET | /v1/users/{user_id}/financial-intake/history | Obter todos os snapshots históricos de intake |
POST | /v1/users/{user_id}/plan/generate | Gerar um plano financeiro personalizado |
GET | /v1/users/{user_id}/plan | Obter o plano ativo atual |
POST | /v1/users/{user_id}/goals | Criar uma meta financeira |
GET | /v1/users/{user_id}/goals | Listar todas as metas |
GET | /v1/users/{user_id}/goals/{goal_id} | Obter uma meta específica |
PATCH | /v1/users/{user_id}/goals/{goal_id} | Atualizar uma meta |
DELETE | /v1/users/{user_id}/goals/{goal_id} | Excluir uma meta |
POST | /v1/users/{user_id}/transactions | Enviar transações (texto, imagem, PDF, planilha) |
GET | /v1/users/{user_id}/transactions | Listar transações com filtros |
GET | /v1/users/{user_id}/transactions/{transaction_id} | Obter uma transação específica |
DELETE | /v1/users/{user_id}/transactions/{transaction_id} | Excluir uma transação |
GET | /v1/users/{user_id}/money-moves | Obter recomendações de gastos personalizadas |
POST | /v1/users/{user_id}/chat | Enviar mensagem ao assistente financeiro do Ozzie |
GET | /v1/users/{user_id}/chat/history | Obter histórico de mensagens do chat |
Autenticação
Todas as requisições à API devem incluir um header Authorization usando autenticação HTTP Bearer. O token é a codificação Base64 do seu client_id e client_secret unidos por dois pontos.
Formato do token:
base64(client_id + ":" + client_secret)
Formato do header:
Authorization: Bearer <base64_encoded_credentials>
Gerando o token:
- Node.js
- Python
- curl
const token = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
// Use como: `Bearer ${token}`
import base64
token = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()
# Use como: f"Bearer {token}"
TOKEN=$(echo -n "seu_client_id:seu_client_secret" | base64)
curl -H "Authorization: Bearer $TOKEN" https://api.ozzieapp.com/v1/users
Nunca exponha seu client_secret em código client-side, aplicativos móveis ou repositórios públicos. Todas as chamadas à API devem originar do seu servidor backend.
Convenções de Requisição e Resposta
Headers de Requisição
| Header | Obrigatório | Valor |
|---|---|---|
Authorization | Sim | Bearer <token> |
Content-Type | Sim (para POST/PATCH) | application/json |
Accept | Não (recomendado) | application/json |
Idempotency-Key | Não | String UUID v4 para requisições POST idempotentes |
Envelope de Resposta
Todas as respostas bem-sucedidas seguem esta estrutura de envelope:
{
"object": "object_type_name",
"data": { ... }
}
Para endpoints de lista:
{
"object": "list",
"data": {
"items": [ ... ],
"has_more": true,
"next_cursor": "2025-04-30T12:00:00Z",
"total_count": 142
}
}
Códigos de Status HTTP
| Status | Significado |
|---|---|
200 OK | Requisição bem-sucedida |
201 Created | Recurso criado |
204 No Content | Recurso excluído |
400 Bad Request | JSON malformado ou erro de validação |
401 Unauthorized | Credenciais ausentes ou inválidas |
403 Forbidden | Credenciais válidas, mas permissões insuficientes |
404 Not Found | Recurso não existe |
409 Conflict | Recurso já existe (ex.: usuário duplicado) |
422 Unprocessable Entity | Erro de lógica de negócio (ex.: intake ausente) |
429 Too Many Requests | Limite de taxa excedido |
500 Internal Server Error | Erro no servidor Ozzie |
Paginação
Endpoints de lista usam paginação baseada em cursor com cursores datetime ISO. Esta abordagem é estável mesmo quando novos registros são inseridos entre páginas.
Parâmetros de Query
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
limit | integer | 50 | Número de registros por página (máx 200) |
cursor | string | — | String datetime ISO 8601 — retorna registros mais antigos que este timestamp |
from | string | — | Filtro: incluir registros a partir desta data (YYYY-MM-DD) |
to | string | — | Filtro: incluir registros até esta data (YYYY-MM-DD) |
Campos da Resposta Paginada
| Campo | Tipo | Descrição |
|---|---|---|
has_more | boolean | true se existem páginas adicionais |
next_cursor | string | null | Passe como cursor na próxima requisição para obter a próxima página |
total_count | integer | Número total de registros correspondentes (não apenas esta página) |
Exemplo de Paginação
async function fetchAllTransactions(userId) {
const allTransactions = [];
let cursor = null;
do {
const params = new URLSearchParams({ limit: '200' });
if (cursor) params.set('cursor', cursor);
const res = await fetch(
`https://api.ozzieapp.com/v1/users/${userId}/transactions?${params}`,
{ headers }
);
const json = await res.json();
allTransactions.push(...json.data.transactions);
cursor = json.data.has_more ? json.data.next_cursor : null;
} while (cursor);
return allTransactions;
}
Cursores são baseados em timestamps created_at. Registros criados após o início da paginação não aparecerão na sequência de páginas atual — inicie uma nova requisição para capturar novos registros.
Códigos de Erro
Todos os erros seguem este formato:
{
"error": {
"code": "ERROR_CODE",
"message": "Explicação legível do que deu errado."
}
}
| Código | Status HTTP | Descrição |
|---|---|---|
INVALID_JSON | 400 | O corpo da requisição não é JSON válido. Verifique vírgulas extras, aspas ausentes ou problemas de codificação. |
VALIDATION_ERROR | 400 | Um ou mais campos falharam na validação. O message identificará o campo e a restrição específicos. |
UNAUTHORIZED | 401 | O header Authorization está ausente, malformado ou as credenciais são inválidas. |
FORBIDDEN | 403 | As credenciais são válidas mas não têm permissão para acessar este recurso (ex.: acessar o usuário de outro cliente). |
NOT_FOUND | 404 | O recurso solicitado (usuário, transação, meta, etc.) não existe. |
CONFLICT | 409 | Um recurso com chave única conflitante já existe (ex.: external_user_id já em uso). |
INTAKE_REQUIRED | 422 | Um snapshot de intake financeiro deve ser enviado antes desta operação (ex.: geração de plano). |
PLAN_REQUIRED | 422 | Um plano financeiro deve ser gerado antes desta operação (ex.: money moves). |
PERSONALITY_REQUIRED | 422 | O perfil de personalidade do Ozzie para este usuário ainda não foi inicializado. Resolve automaticamente após a geração do plano. |
RATE_LIMIT_EXCEEDED | 429 | Você excedeu o limite de taxa de requisições. Veja o header Retry-After para quando tentar novamente. |
VERSION_MISMATCH | 400 | A versão da API que você está usando não é mais suportada. Atualize sua URL base para a versão atual. |
INTERNAL_ERROR | 500 | Ocorreu um erro inesperado nos servidores do Ozzie. Estes são registrados e investigados automaticamente. Tente novamente com backoff exponencial. |
Limite de Taxa
Limites de taxa são aplicados por client_id. Limites atuais:
| Tier | Requisições por minuto | Burst |
|---|---|---|
| Standard | 120 | 20 |
| Growth | 600 | 100 |
| Enterprise | Personalizado | Personalizado |
Quando o limite é excedido, a API retorna HTTP 429 com:
HTTP/1.1 429 Too Many Requests
Retry-After: 15
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1746460800
| Header de Resposta | Descrição |
|---|---|
Retry-After | Segundos a aguardar antes de tentar novamente |
X-RateLimit-Limit | Sua cota total de requisições por minuto |
X-RateLimit-Remaining | Requisições restantes na janela atual |
X-RateLimit-Reset | Timestamp Unix de quando a janela reinicia |
Sempre implemente backoff exponencial ao lidar com respostas 429. Um loop de retry simples sem delay piorará a pressão sobre o limite de taxa. Comece com 1 segundo de delay, dobrando até 32 segundos.
Idempotência
Requisições POST que criam recursos suportam idempotência via o header Idempotency-Key. Se você fornecer a mesma chave em uma requisição repetida (ex.: após um timeout de rede), o Ozzie retornará a resposta original em vez de criar um duplicado.
POST https://api.ozzieapp.com/v1/users
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{
"external_user_id": "usr_8821",
"name": "Maria Santos"
}
Regras:
- A chave deve ser um UUID v4.
- As chaves têm escopo para seu
client_ide expiram após 24 horas. - Se a requisição original ainda estiver em andamento, o retry receberá HTTP
409com códigoCONFLICTaté que o original seja concluído. - Suportado em:
POST /v1/users,POST /v1/users/{user_id}/financial-intake,POST /v1/users/{user_id}/transactions.
POST /v1/users/{user_id}/plan/generate e POST /v1/users/{user_id}/chat não são idempotentes por design — cada chamada intencionalmente gera um novo recurso.