Authentication
The Leezy API uses OAuth 2.0 for authentication. This guide covers the authorization flow and token management.
Overview
Leezy implements the OAuth 2.0 Authorization Code flow with optional PKCE (Proof Key for Code Exchange) for enhanced security.
┌──────────┐ ┌───────────┐
│ Client │ │ Leezy │
└────┬─────┘ └─────┬─────┘
│ 1. Redirect to /api/oauth/authorize │
│──────────────────────────────────────────>│
│ │
│ 2. User logs in and authorizes │
│<──────────────────────────────────────────│
│ │
│ 3. Redirect with authorization code │
│<──────────────────────────────────────────│
│ │
│ 4. POST /api/oauth/token │
│──────────────────────────────────────────>│
│ │
│ 5. Return access_token + refresh_token │
│<──────────────────────────────────────────│
OAuth Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/oauth/authorize | GET | Authorization page |
/api/oauth/token | POST | Token exchange |
Step 1: Authorization Request
Redirect the user to the authorization endpoint:
https://app.leezy.ai/api/oauth/authorize?
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
response_type=code&
scope=leads:read%20webhooks:manage&
state=random_state_string
Parameters
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your application's client ID |
redirect_uri | Yes | URL to redirect after authorization |
response_type | Yes | Must be code |
scope | Yes | Space-separated list of scopes |
state | Recommended | Random string for CSRF protection |
code_challenge | Optional | PKCE code challenge (recommended) |
code_challenge_method | Optional | Must be S256 if using PKCE |
Step 2: Token Exchange
After authorization, exchange the code for tokens:
curl -X POST "https://app.leezy.ai/api/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "AUTHORIZATION_CODE",
"redirect_uri": "https://yourapp.com/callback",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"code_verifier": "OPTIONAL_PKCE_VERIFIER"
}'
Response
{
"access_token": "lzy_at_abc123...",
"refresh_token": "lzy_rt_xyz789...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "leads:read webhooks:manage",
"api_base_url": "https://app.leezy.ai"
}
Step 3: Using Access Tokens
Include the access token in API requests:
curl -X GET "https://app.leezy.ai/api/v1/leads" \
-H "Authorization: Bearer lzy_at_abc123..."
Refreshing Tokens
Access tokens expire after 1 hour. Use the refresh token to get a new access token:
curl -X POST "https://app.leezy.ai/api/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"refresh_token": "lzy_rt_xyz789...",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'
Token Lifecycle
| Token | Prefix | Lifetime |
|---|---|---|
| Access Token | lzy_at_ | 1 hour |
| Refresh Token | lzy_rt_ | 30 days |
Token Prefixes
Leezy tokens use prefixes to help identify token types. Access tokens start with lzy_at_ and refresh tokens with lzy_rt_.
Available Scopes
| Scope | Description |
|---|---|
leads:read | Read qualification leads |
leads:write | Create and update leads |
conversations:read | Read chat conversations |
conversations:write | Write to conversations |
tickets:read | Read support tickets |
tickets:write | Create and update tickets |
meetings:read | Read scheduled meetings |
webhooks:manage | Create and manage webhooks |
PKCE (Recommended)
For enhanced security, use PKCE:
// 1. Generate code_verifier (random 43-128 char string)
const code_verifier = generateRandomString(64);
// 2. Create code_challenge
const code_challenge = base64url(sha256(code_verifier));
// 3. Include in authorization URL
// ?code_challenge=ABC123&code_challenge_method=S256
// 4. Include code_verifier in token exchange
// "code_verifier": "your_code_verifier"
Error Codes
| Error | Description |
|---|---|
invalid_request | Missing required parameter |
invalid_client | Invalid client_id or client_secret |
invalid_grant | Expired or invalid authorization code |
unsupported_grant_type | Grant type not supported |
invalid_scope | Requested scope is invalid |
Next Steps
- API Overview - Response formats and rate limits
- Webhooks - Set up real-time notifications