Users
Base URL: https://channel.ozzieapp.com/v1
The User Object
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Maria Santos",
"email": "maria@example.com",
"language": "en",
"created_at": "2026-05-15T14:30:00Z"
}
}
POST /v1/users
Creates a new user under your API client.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
external_user_id | string | Yes | Your internal user ID (max 100 chars). Do not include the "external:" prefix — that prefix is only used in path params. |
name | string | No | Display name |
email | string | No | Email address |
phone | string | No | Phone number in E.164 format, e.g. "+5511999990000" |
language | string | No | "en" | "pt" | "es" — defaults to "en" |
- curl
- Node.js
- Python
curl -X POST https://channel.ozzieapp.com/v1/users \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"external_user_id": "usr_8821",
"name": "Maria Santos",
"email": "maria@example.com",
"language": "en"
}'
const token = Buffer.from('your_client_id:your_client_secret').toString('base64');
const response = await fetch('https://channel.ozzieapp.com/v1/users', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_user_id: 'usr_8821',
name: 'Maria Santos',
email: 'maria@example.com',
language: 'en',
}),
});
const { data: user } = await response.json();
console.log('Created user:', user.id);
import requests, base64
token = base64.b64encode(b'your_client_id:your_client_secret').decode()
response = requests.post(
'https://channel.ozzieapp.com/v1/users',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json',
},
json={
'external_user_id': 'usr_8821',
'name': 'Maria Santos',
'email': 'maria@example.com',
'language': 'en',
}
)
user = response.json()['data']
print(f"Created: {user['id']}")
Response (201 Created):
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Maria Santos",
"email": "maria@example.com",
"language": "en",
"created_at": "2026-05-15T14:30:00Z"
}
}
Errors:
| Code | HTTP | When |
|---|---|---|
CONFLICT | 409 | A user with this external_user_id already exists |
VALIDATION_ERROR | 400 | Invalid email format |
GET /v1/users/:user_id
Retrieve a user by Ozzie UUID or by external:{external_user_id}.
# By Ozzie UUID
curl https://channel.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE \
-H "Authorization: Bearer YOUR_TOKEN"
# By external_user_id
curl "https://channel.ozzieapp.com/v1/users/external:usr_8821" \
-H "Authorization: Bearer YOUR_TOKEN"
Response (200 OK):
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Maria Santos",
"email": "maria@example.com",
"language": "en",
"created_at": "2026-05-15T14:30:00Z"
}
}
GET /v1/users/:user_id/profile
Returns the channel-side profile for a user, including onboarding stage and plan preferences.
curl https://channel.ozzieapp.com/v1/users/external:usr_8821/profile \
-H "Authorization: Bearer YOUR_TOKEN"
Response (200 OK):
{
"object": "channel_user_profile",
"data": {
"core_user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"onboarding_stage": "financial_intake",
"plan_speed": "moderate",
"created_at": "2026-05-16T14:30:00Z"
}
}
onboarding_stage values:
| Value | Meaning |
|---|---|
financial_intake | User has not yet submitted a financial intake |
personality | Intake complete; personality quiz not yet taken |
plan | Personality scored; plan not yet generated |
active | Onboarding complete — user is fully active |
PATCH /v1/users/:user_id/onboarding/complete
Advances the user's onboarding stage from plan to active. No request body is required. The endpoint is idempotent — calling it when the user is already active returns the same response without error.
curl -X PATCH https://channel.ozzieapp.com/v1/users/external:usr_8821/onboarding/complete \
-H "Authorization: Bearer YOUR_TOKEN"
Response (200 OK):
{
"object": "onboarding_complete",
"data": {
"onboarding_stage": "active"
}
}
Errors:
| Code | HTTP | When |
|---|---|---|
NOT_FOUND | 404 | User does not exist |
VALIDATION_ERROR | 400 | User is not in plan stage (and not already active) |