Skip to main content

Authentication

The Ozzie API uses HTTP Bearer authentication. Every request must include an Authorization header with a base64-encoded token derived from your client_id and client_secret.


Getting your credentials

To get API credentials, either:

  • Contact the Ozzie team at commercial@ozzieapp.com to discuss your use case and get access
  • Log in to the Ozzie dashboard and navigate to Settings → API Keys to generate a client_id and client_secret pair

You will receive two values:

ValueExampleDescription
client_idozz_client_a1b2c3d4A stable identifier for your API client. Safe to log.
client_secretsk_live_xK9mP2qR7tL...A secret key. Treat this like a password. Never expose it.
warning

Your client_secret is shown only once at generation time. Store it securely immediately — if you lose it, you will need to rotate your credentials.


How authentication works

Ozzie uses HTTP Basic Auth encoded as a Bearer token. The token is the base64 encoding of the string client_id:client_secret (colon-separated, no spaces).

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

This is a single, static token you generate once and reuse across all requests. You do not need to exchange it for a session token or refresh it on a schedule — it is valid until you rotate your credentials.


Encoding your 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...

Making authenticated requests

Once you have the token, attach it to every request in the Authorization header:

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

Build the token once at application startup and reuse it across all requests. There is no expiry — you don't need to regenerate it per-request.


Rate limiting

Every API response includes rate limit headers so you can track your usage:

HeaderDescription
X-RateLimit-LimitThe maximum number of requests allowed in the current window
X-RateLimit-RemainingHow many requests you have left in the current window
X-RateLimit-ResetUnix timestamp (seconds) when the window resets and your limit replenishes

Example response headers:

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

When you hit the rate limit, the API returns a 429 status. Back off and retry after the timestamp in 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

Rate limits vary by tier. Free tier clients have lower limits than Pro or Enterprise clients. Contact commercial@ozzieapp.com if you need higher throughput.


Authentication error codes

HTTP StatusError CodeWhen it happens
401 UnauthorizedUNAUTHORIZEDThe Authorization header is missing, malformed, or contains invalid credentials
429 Too Many RequestsRATE_LIMIT_EXCEEDEDYour client has sent more requests than allowed in the current window

Example 401 response:

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

Common causes of a 401:

  • Forgot to include the Authorization header
  • Encoded client_id:client_secret with spaces or extra characters
  • Using a client_secret that was rotated or revoked
  • Sending the raw client_id:client_secret string instead of the base64-encoded version

Multi-tenancy and client scoping

Your client_id is the root of your tenant namespace. Every user you create with POST /users belongs to your client, and your API credentials can only access users you created. You cannot read or modify users created by other API clients.

This means:

  • You manage all your end users through a single set of credentials
  • Users are identified by your own external_user_id — you own the mapping between Ozzie's user records and your database
  • All activity (financial intake, transactions, plans, chat) is scoped to users under your client_id
info

There is no per-user authentication. Your server-side backend authenticates with Ozzie using your client credentials, then acts on behalf of your users. Never send your API credentials to a frontend client.


Security best practices

Never expose credentials client-side. Your client_id and client_secret should only live in your server-side environment. A browser or mobile app that calls the Ozzie API directly would expose your credentials to anyone who inspects network traffic.

Use environment variables. Store credentials in environment variables, not hardcoded in source files. This prevents accidental commits to version control.

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

Rotate secrets periodically. Generate a new client_secret from the Ozzie dashboard on a regular schedule (e.g., every 90 days), or immediately if you suspect a secret has been compromised. Update your environment variables and deploy before revoking the old secret.

Use separate credentials per environment. Create distinct API clients for your development, staging, and production environments so that test traffic never touches real user data, and a compromised development secret cannot affect production.

Scope your server's outbound access. If your infrastructure supports it, restrict outbound HTTPS calls to api.ozzieapp.com from only the services that need it — not every server in your stack.