Authentication
Cookie-based authentication, API tokens, and cross-origin configuration for the Tuli REST API.
Authentication
Tuli uses cookie-based authentication for web applications and API tokens for server-to-server integrations.
Cookie-Based Authentication
The primary authentication method for web applications. After login, the server sets a secure HTTP-only cookie.
Login Flow
POST /api/v1/identity/login
Content-Type: application/json
{
"Email": "user@company.com",
"Password": "your-password",
"CompanyKey": "company-1CAjiqwbu2g3LkcoByCL4Y"
}
Response:
{
"Success": true,
"Data": {
"Id": "user-2DBkjrxcv3h4MldpCzDM5Z",
"Email": "user@company.com",
"Name": "John Doe",
"Company": {
"Id": "company-1CAjiqwbu2g3LkcoByCL4Y",
"Name": "Acme Corp"
},
"Roles": ["Leasing_Executive", "FM_Supervisor"]
}
}
The server sets a cookie named .tuli.auth that is automatically included in subsequent requests.
Cookie Configuration
For cross-subdomain authentication (e.g., app.example.com and api.example.com), cookies are configured with a leading dot domain:
Set-Cookie: .tuli.auth=...; Domain=.example.com; Path=/; HttpOnly; Secure; SameSite=None
API Token Authentication
For server-to-server integrations, background jobs, and scripts.
Creating an API Token
Navigate to Settings → API Tokens → Create Token or request one from your administrator.
Using API Tokens
Include the token in the Authorization header:
curl -H "Authorization: Bearer tuli_sk_live_abc123..." \
https://api.tuli.io/api/v1/contracts
Request/Response Format
Important: Keys vs IDs
All entity references in API requests and responses use string Keys, not numeric IDs:
{
"Id": "contract-1CAjiqwbu2g3LkcoByCL4Y",
"Tenant": "tenant-2DBkjrxcv3h4MldpCzDM5Z",
"Building": "building-3ECljsydw4i5NmeqDaEN6A"
}
Never expose or use internal numeric database IDs. Always use the Key field for entity references.
Property Naming
All response properties use PascalCase:
{
"Success": true,
"Data": {
"Id": "contract-1CAjiqwbu2g3LkcoByCL4Y",
"ContractNumber": "CON-2025-00042",
"MonthlyRent": {
"Amount": 5000,
"Currency": "AED"
},
"CreatedAt": "2025-01-15T10:30:00Z"
}
}
Response Wrappers
All API responses follow a consistent structure:
Success Response:
{
"Success": true,
"Data": { ... }
}
Success List Response:
{
"Success": true,
"Data": [ ... ],
"Pagination": {
"Page": 1,
"PageSize": 25,
"TotalRecords": 142,
"TotalPages": 6
}
}
Error Response:
{
"Success": false,
"Error": {
"Code": "VALIDATION_ERROR",
"Message": "Validation failed",
"Details": [
{ "Field": "MonthlyRent", "Message": "MonthlyRent is required" }
]
}
}
CORS Configuration
For cross-origin requests, include credentials:
fetch('https://api.tuli.io/api/v1/contracts', {
method: 'GET',
credentials: 'include', // Required for cookies
headers: {
'Content-Type': 'application/json'
}
});
The API is configured to allow credentials from trusted origins:
Access-Control-Allow-Origin: https://app.tuli.io
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Session Management
- Sessions are maintained via HTTP-only cookies
- Session timeout: configurable per tenant (default 24 hours)
- Logout:
POST /api/v1/identity/logout
Security Best Practices
- Always use HTTPS — All API communication must be encrypted
- Use Keys, not IDs — Never expose internal database IDs
- Include credentials — Set
credentials: 'include'for cross-origin requests - Handle token expiration — Implement refresh logic for long-running integrations
- Secure token storage — Store API tokens in environment variables, never in code