Saltar al contenido principal

Autenticación

La API de Ozzie utiliza autenticación HTTP Bearer. Cada solicitud debe incluir un encabezado Authorization con un token codificado en base64 derivado de tu client_id y client_secret.


Cómo obtener tus credenciales

Para obtener credenciales de API, ya sea:

  • Contacta al equipo de Ozzie en commercial@ozzieapp.com para discutir tu caso de uso y obtener acceso
  • Inicia sesión en el panel de Ozzie y navega a Configuración → Claves de API para generar un par client_id y client_secret

Recibirás dos valores:

ValorEjemploDescripción
client_idozz_client_a1b2c3d4Un identificador estable para tu cliente de API. Seguro para registrar.
client_secretsk_live_xK9mP2qR7tL...Una clave secreta. Trátala como una contraseña. Nunca la expongas.
aviso

Tu client_secret se muestra solo una vez al momento de su generación. Guárdalo de forma segura inmediatamente — si lo pierdes, necesitarás rotar tus credenciales.


Cómo funciona la autenticación

Ozzie usa HTTP Basic Auth codificado como token Bearer. El token es la codificación base64 del string client_id:client_secret (separados por dos puntos, sin espacios).

token = base64("ozz_client_a1b2c3d4:sk_live_xK9mP2qR7tL...")
Authorization: Bearer <token>

Este es un token estático y único que generas una vez y reutilizas en todas las solicitudes. No necesitas intercambiarlo por un token de sesión ni actualizarlo según un horario — es válido hasta que rotas tus credenciales.


Codificando tu token

# Encode your credentials
CLIENT_ID="ozz_client_a1b2c3d4"
CLIENT_SECRET="sk_live_xK9mP2qR7tL..."

TOKEN=$(echo -n "$CLIENT_ID:$CLIENT_SECRET" | base64)
echo $TOKEN
# ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu...

Realizando solicitudes autenticadas

Una vez que tienes el token, adjúntalo a cada solicitud en el encabezado Authorization:

curl https://api.ozzieapp.com/v1/api/v1/users \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu..." \
-H "Content-Type: application/json" \
-d '{
"external_user_id": "user_123",
"name": "Alex Johnson",
"language": "en"
}'
tip

Construye el token una vez al inicio de la aplicación y reutilízalo en todas las solicitudes. No tiene vencimiento — no necesitas regenerarlo por cada solicitud.


Límite de tasa

Cada respuesta de la API incluye encabezados de límite de tasa para que puedas monitorear tu uso:

EncabezadoDescripción
X-RateLimit-LimitEl número máximo de solicitudes permitidas en la ventana actual
X-RateLimit-RemainingCuántas solicitudes te quedan en la ventana actual
X-RateLimit-ResetTimestamp Unix (segundos) cuando se reinicia la ventana y tu límite se repone

Ejemplo de encabezados de respuesta:

HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1746489600

Cuando alcanzas el límite de tasa, la API devuelve un estado 429. Espera y reintenta después del timestamp en X-RateLimit-Reset.

{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "You have exceeded the rate limit for this window. Please retry after the reset time.",
"details": [
{
"reset_at": 1746489600,
"limit": 1000,
"window": "1 minute"
}
]
}
}
info

Los límites de tasa varían según el tier. Los clientes del tier gratuito tienen límites más bajos que los clientes Pro o Enterprise. Contacta commercial@ozzieapp.com si necesitas mayor capacidad.


Códigos de error de autenticación

Estado HTTPCódigo de errorCuándo ocurre
401 UnauthorizedUNAUTHORIZEDEl encabezado Authorization está ausente, malformado o contiene credenciales inválidas
429 Too Many RequestsRATE_LIMIT_EXCEEDEDTu cliente ha enviado más solicitudes de las permitidas en la ventana actual

Ejemplo de respuesta 401:

{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing authorization credentials.",
"details": []
}
}

Causas comunes de un error 401:

  • Olvidaste incluir el encabezado Authorization
  • Codificaste client_id:client_secret con espacios o caracteres adicionales
  • Usas un client_secret que fue rotado o revocado
  • Enviaste el string client_id:client_secret sin codificar en base64

Autenticación del usuario final (OTP)

Las aplicaciones de consumo autentican a sus usuarios finales mediante un código OTP de 6 dígitos entregado por WhatsApp o correo electrónico. Este flujo es manejado completamente por la Channel API — tu servidor llama a channel.ozzieapp.com en nombre del usuario.

info

El flujo OTP es independiente de la autenticación del cliente de API. Tu client_id / client_secret son credenciales de servidor a servidor. El OTP sirve para autenticar al usuario final humano dentro de tu aplicación.

El flujo OTP completo

1. Registrar al usuario (una sola vez)


POST /v1/users → recibe el user_id de Ozzie


2. Solicitar un código OTP


POST /v1/auth/otp/request → código enviado al usuario por WhatsApp o correo


3. El usuario ingresa el código en tu UI


POST /v1/auth/otp/verify → devuelve user_id + onboarding_stage


4. Tu aplicación crea una sesión para el usuario
(SESSION_SECRET y la gestión de sesiones son responsabilidad de tu aplicación)

Detalles del OTP

PropiedadValor
Longitud del código6 dígitos
TTL10 minutos
Uso únicoSí — el código se invalida al primer verificado exitoso
AlmacenamientoHasheado con bcrypt en la base de datos
identifierTeléfono en formato E.164 (ej. +5511999990000) o dirección de correo electrónico
channel"whatsapp" o "email" — detectado automáticamente desde identifier si se omite

Ejemplo en TypeScript

const BASE = 'https://channel.ozzieapp.com/v1';
const token = Buffer.from(
`${process.env.OZZIE_CLIENT_ID}:${process.env.OZZIE_CLIENT_SECRET}`
).toString('base64');

const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
};

// Step 1 — Register the user (skip if already registered; handle 409 gracefully)
const registerRes = await fetch(`${BASE}/users`, {
method: 'POST',
headers,
body: JSON.stringify({
external_user_id: 'usr_8821', // your own user ID — do NOT include "external:" prefix
name: 'Maria Santos',
phone: '+5511999990000', // E.164 format
language: 'pt',
}),
});
if (!registerRes.ok && registerRes.status !== 409) {
throw new Error('User registration failed');
}

// Step 2 — Request OTP
const otpRes = await fetch(`${BASE}/auth/otp/request`, {
method: 'POST',
headers,
body: JSON.stringify({
identifier: '+5511999990000',
language: 'pt',
// channel: 'whatsapp' // optional — auto-detected from E.164 phone
}),
});
const { data: otpData } = await otpRes.json();
// otpData = { channel: "whatsapp", masked: "+55119****0000", expires_at: "2026-05-16T..." }

// Step 3 — Verify OTP (called after the user submits the code in your UI)
async function verifyOtp(code: string) {
const verifyRes = await fetch(`${BASE}/auth/otp/verify`, {
method: 'POST',
headers,
body: JSON.stringify({
identifier: '+5511999990000',
code,
}),
});

if (!verifyRes.ok) {
const { error } = await verifyRes.json();
// error.code === 'INVALID_CODE' or 'CODE_EXPIRED'
throw new Error(error.code);
}

const { data } = await verifyRes.json();
// data = { user_id: "external:usr_8821", core_user_id: "uuid", onboarding_stage: "financial_intake" }

// Step 4 — Create a session (SESSION_SECRET is your app's own concern, not Ozzie's)
return data;
}
tip

SESSION_SECRET y la gestión de cookies de sesión son manejados por tu propio backend (ej. Lovable). Ozzie no emite tokens de sesión — solo valida el OTP y devuelve el user_id y el onboarding_stage que tu aplicación necesita para inicializar la sesión.

Para una referencia completa sobre los parámetros de solicitud/verificación OTP y los códigos de error, consulta la referencia de Auth.


Multi-tenancy y alcance del cliente

Tu client_id es la raíz de tu espacio de nombres de tenant. Cada usuario que creas con POST /users pertenece a tu cliente, y tus credenciales de API solo pueden acceder a los usuarios que tú creaste. No puedes leer ni modificar usuarios creados por otros clientes de API.

Esto significa:

  • Gestionas todos tus usuarios finales a través de un único conjunto de credenciales
  • Los usuarios se identifican por tu propio external_user_id — tú posees el mapeo entre los registros de usuario de Ozzie y tu base de datos
  • Toda la actividad (intake financiero, transacciones, planes, chat) está limitada a los usuarios bajo tu client_id
info

No existe autenticación por usuario. Tu backend del lado del servidor se autentica con Ozzie usando tus credenciales de cliente y luego actúa en nombre de tus usuarios. Nunca envíes tus credenciales de API a un cliente frontend.


Buenas prácticas de seguridad

Nunca expongas las credenciales en el lado del cliente. Tu client_id y client_secret solo deben existir en tu entorno del lado del servidor. Un navegador o aplicación móvil que llame directamente a la API de Ozzie expondría tus credenciales a cualquiera que inspeccione el tráfico de red.

Usa variables de entorno. Almacena las credenciales en variables de entorno, no hardcodeadas en archivos de código fuente. Esto previene commits accidentales al control de versiones.

# .env (never commit this file)
OZZIE_CLIENT_ID=ozz_client_a1b2c3d4
OZZIE_CLIENT_SECRET=sk_live_xK9mP2qR7tL...

Rota los secretos periódicamente. Genera un nuevo client_secret desde el panel de Ozzie de forma regular (ej., cada 90 días), o de inmediato si sospechas que un secreto fue comprometido. Actualiza tus variables de entorno y realiza el despliegue antes de revocar el secreto anterior.

Usa credenciales separadas por entorno. Crea clientes de API distintos para tus entornos de desarrollo, staging y producción, de modo que el tráfico de prueba nunca toque datos reales de usuarios, y que un secreto de desarrollo comprometido no afecte la producción.

Limita el acceso saliente de tu servidor. Si tu infraestructura lo permite, restringe las llamadas HTTPS salientes a api.ozzieapp.com únicamente desde los servicios que lo necesitan — no desde cada servidor en tu stack.