Integração com ID Externo
A API do Ozzie suporta dois padrões de integração distintos. Você pode escolher o que melhor se adapta à sua arquitetura — ou misturar os dois na mesma conta de cliente.
Dois Padrões de Integração
Fluxo A — Criação explícita de usuário
Você cria um registro de usuário primeiro chamando POST /v1/users, recebe um UUID do Ozzie (ozz_usr_...) e usa esse UUID em todas as requisições seguintes.
POST /v1/users → retorna id: "ozz_usr_abc123"
POST /v1/users/ozz_usr_abc123/financial-intake → usa UUID do Ozzie
POST /v1/users/ozz_usr_abc123/plan/generate → usa UUID do Ozzie
POST /v1/users/ozz_usr_abc123/chat/messages → usa UUID do Ozzie
Indicado para: integrações onde você quer controle total sobre a criação de usuários, ou onde precisa armazenar o UUID do Ozzie no seu próprio banco de dados.
Fluxo B — Auto-provisionamento com ID externo
Você pula a criação de usuário completamente. Use o formato external:{seu_id} como o parâmetro de caminho {user_id} em qualquer endpoint. Na primeira chamada, o Ozzie cria o usuário automaticamente em segundo plano e continua processando a requisição.
POST /v1/users/external:usr_8821/financial-intake → usuário criado automaticamente na 1ª chamada
POST /v1/users/external:usr_8821/plan/generate → mesmo usuário, sem etapa de criação
POST /v1/users/external:usr_8821/chat/messages → mesmo usuário
Indicado para: integrações onde você não quer gerenciar uma etapa separada de criação de usuário, ou onde está conectando uma base de usuários existente sem migrar IDs.
Nenhuma configuração ou flag é necessária para usar o Fluxo B. Qualquer valor não-UUID prefixado com external: é automaticamente tratado como uma busca por ID externo. Se o usuário ainda não existir, ele é criado silenciosamente.
Como o external:{id} funciona
Quando o Ozzie recebe uma requisição com external:{seu_id} como parâmetro user_id, ele:
- Remove o prefixo
external:e extrai seu ID - Busca o usuário por
(api_client_id, external_user_id) - Se encontrado → processa a requisição usando o usuário encontrado
- Se não encontrado → auto-cria um novo usuário com
external_user_id = seu_idecreated_via = "api_external", depois continua processando a requisição
O usuário criado automaticamente começa com onboarding_stage: "financial_intake". O Ozzie avança o estágio automaticamente após o intake financeiro e a geração do plano, assim como com usuários criados via POST /v1/users.
Escolhendo entre os dois fluxos
| Situação | Padrão recomendado |
|---|---|
| Você quer cadastrar usuários com nome, e-mail e telefone antes de qualquer interação | Fluxo A — POST /v1/users |
| Você tem uma base de usuários existente e quer zero fricção na migração | Fluxo B — external:{id} em qualquer endpoint |
| Você está construindo um bot de WhatsApp ou interface conversacional | Fluxo A — defina phone na criação para correspondência de número |
| Você é uma fintech que faz proxy de requisições para seus próprios usuários | Fluxo B — use o ID do seu banco de dados como ID externo |
| Você precisa dos dois padrões na mesma integração | Misture livremente — cada usuário pode ser criado de qualquer forma |
Fluxo B — Exemplo completo
Este exemplo envia o intake financeiro, gera um plano e inicia um chat — tudo sem nenhuma chamada a POST /v1/users:
- curl
- Node.js
- Python
# Passo 1 — Enviar intake financeiro (usuário é criado automaticamente nesta chamada)
curl -X POST https://api.ozzieapp.com/v1/users/external:usr_8821/financial-intake \
-H "Authorization: Bearer SEU_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"monthly_income": 5000,
"monthly_expenses": 3200,
"financial_goal": "savings"
}'
# Passo 2 — Gerar plano
curl -X POST https://api.ozzieapp.com/v1/users/external:usr_8821/plan/generate \
-H "Authorization: Bearer SEU_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
# Passo 3 — Chat
curl -X POST https://api.ozzieapp.com/v1/users/external:usr_8821/chat/messages \
-H "Authorization: Bearer SEU_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "Quanto devo economizar este mês?"}'
import fetch from 'node-fetch';
const BASE_URL = 'https://api.ozzieapp.com/v1';
const USER_REF = 'external:usr_8821'; // seu ID de usuário, prefixado com "external:"
const TOKEN = Buffer.from('seu_client_id:seu_client_secret').toString('base64');
const headers = {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
};
async function post(path, body) {
const res = await fetch(`${BASE_URL}${path}`, {
method: 'POST', headers, body: JSON.stringify(body),
});
const json = await res.json();
if (!res.ok) throw new Error(`[${json.error?.code}] ${json.error?.message}`);
return json.data;
}
// Passo 1 — Intake financeiro (usuário é criado aqui se for novo)
const intake = await post(`/users/${USER_REF}/financial-intake`, {
monthly_income: 5000,
monthly_expenses: 3200,
financial_goal: 'savings',
});
console.log('Intake registrado. Saldo disponível:', intake.monthly_surplus);
// Passo 2 — Gerar plano
const plan = await post(`/users/${USER_REF}/plan/generate`, {});
console.log('Nível do plano:', plan.plan_tier);
// Passo 3 — Chat
const reply = await post(`/users/${USER_REF}/chat/messages`, {
message: 'Quanto devo economizar este mês?',
});
console.log('Ozzie:', reply.message);
import httpx, base64
BASE_URL = "https://api.ozzieapp.com/v1"
USER_REF = "external:usr_8821" # seu ID de usuário, prefixado com "external:"
TOKEN = base64.b64encode(b"seu_client_id:seu_client_secret").decode()
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
}
# Passo 1 — Intake financeiro (usuário é criado aqui se for novo)
resp = httpx.post(
f"{BASE_URL}/users/{USER_REF}/financial-intake",
headers=headers,
json={"monthly_income": 5000, "monthly_expenses": 3200, "financial_goal": "savings"},
)
resp.raise_for_status()
print("Saldo disponível:", resp.json()["data"]["monthly_surplus"])
# Passo 2 — Gerar plano
resp = httpx.post(f"{BASE_URL}/users/{USER_REF}/plan/generate", headers=headers, json={})
resp.raise_for_status()
print("Nível do plano:", resp.json()["data"]["plan_tier"])
# Passo 3 — Chat
resp = httpx.post(
f"{BASE_URL}/users/{USER_REF}/chat/messages",
headers=headers,
json={"message": "Quanto devo economizar este mês?"},
)
resp.raise_for_status()
print("Ozzie:", resp.json()["data"]["message"])
Recuperando um usuário auto-provisionado
Usuários criados via Fluxo B podem ser recuperados a qualquer momento usando GET /v1/users/external:{id} ou pelo UUID do Ozzie, uma vez que você o conheça:
curl https://api.ozzieapp.com/v1/users/external:usr_8821 \
-H "Authorization: Bearer SEU_BEARER_TOKEN"
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": null,
"email": null,
"phone": null,
"language": "en",
"onboarding_stage": "active",
"created_at": "2026-05-06T10:00:00Z"
}
}
Usuários auto-provisionados começam com name, email e phone como null. Você pode enriquecer o registro depois — entre em contato com commercial@ozzieapp.com se precisar de um endpoint de atualização de usuário.
Misturando os dois fluxos
Ambos os padrões são totalmente compatíveis na mesma conta de cliente da API. Alguns usuários podem ser criados explicitamente via POST /v1/users (ex: usuários que se cadastram com nome e e-mail), enquanto outros são auto-provisionados via external:{id} (ex: usuários anônimos ou importados de um sistema existente).
A única restrição é que external_user_id deve ser único por cliente da API. Um POST /v1/users explícito com o mesmo external_user_id de um usuário já auto-provisionado retornará 409 CONFLICT.
Considerações de segurança
- O prefixo
external:é resolvido após a autenticação. Requisições não autenticadas não podem usá-lo. - Usuários auto-provisionados via Fluxo B estão vinculados ao seu cliente da API. Outro cliente não pode acessá-los mesmo que conheça o
external_user_id. - Os limites de taxa aplicam-se igualmente aos dois fluxos. O auto-provisionamento de um novo usuário não consome uma chamada de API extra — faz parte da mesma requisição.