Skip to main content

First API Call

This tutorial walks you through the complete flow of registering, logging in, and accessing protected resources.

Prerequisites

  • CORTEX running locally (see Quick Start)
  • A seeded database with at least one tenant
  • cURL or an API client like Postman

Step 1: Check the API is Running

curl http://localhost:8091/health

Expected response:

{
"status": "ok",
"service": "cortex-core",
"version": "0.1.0"
}

Step 2: Get Available Tenants

If you have access to the database, query for tenant IDs:

SELECT id, name, slug FROM "Tenant" LIMIT 5;

Or use the seeded tenant ID from the database seed script.

Step 3: Register a New User

curl -X POST http://localhost:8091/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"password": "SecureP@ss123",
"firstName": "John",
"lastName": "Doe",
"tenantId": "YOUR_TENANT_ID"
}'

Response (201 Created)

{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"tenantId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
Save the Tokens

Copy the accessToken value — you'll need it for subsequent requests.

Step 4: Login (If Already Registered)

curl -X POST http://localhost:8091/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"password": "SecureP@ss123"
}'

Step 5: Access a Protected Endpoint

Use the access token in the Authorization header:

curl http://localhost:8091/auth/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"tenantId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "ACTIVE"
}

Step 6: List Users in Your Tenant

curl http://localhost:8091/users \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"status": "ACTIVE"
}
],
"pagination": {
"total": 1,
"page": 1,
"limit": 20,
"totalPages": 1
}
}

Step 7: Refresh Your Token

When the access token expires (after 15 minutes), use the refresh token:

curl -X POST http://localhost:8091/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "YOUR_REFRESH_TOKEN"
}'

Response

{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Token Rotation

Note that both tokens are new. The old refresh token is now invalid. This is a security feature called token rotation.

Step 8: Logout

curl -X POST http://localhost:8091/auth/logout \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

After logout, the refresh token is invalidated and cannot be used to obtain new tokens.

Common Errors

401 Unauthorized

{
"type": "https://api.cortex.purplelab.ai/errors/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid or expired access token"
}

Solution: Login again or use the refresh token endpoint.

400 Bad Request

{
"type": "https://api.cortex.purplelab.ai/errors/validation",
"title": "Validation Error",
"status": 400,
"detail": "email must be a valid email address"
}

Solution: Check your request body matches the expected format.

Next Steps