MENU navbar-image

Introduction

This documentation aims to provide all the information you need to work with our API.

<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).
You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).</aside>

Authenticating requests

This API is not authenticated.

Authentication

Endpoints for JWT authentication and session lifecycle.

Login and get tokens

Authenticate with email and password to receive an access token and refresh token.

Example request:
curl --request POST \
    "http://localhost/api/auth/login" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"user@example.com\",
    \"password\": \"secret123\"
}"
const url = new URL(
    "http://localhost/api/auth/login"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "user@example.com",
    "password": "secret123"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "refresh_token": "abc123def456",
    "token_type": "bearer",
    "expires_in": 3600,
    "user": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Alice Johnson",
        "email": "user@example.com",
        "role": "manager"
    }
}
 

Example response (401):


{
    "message": "Invalid credentials"
}
 

Example response (403):


{
    "message": "Account is inactive"
}
 

Example response (422):


{
    "errors": {
        "email": [
            "The email field is required."
        ],
        "password": [
            "The password field is required."
        ]
    }
}
 

Request      

POST api/auth/login

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

User email address. Example: user@example.com

password   string     

User password. Example: secret123

Refresh access token

requires authentication

Exchange a valid refresh token for a new access token and refresh token pair.

Example request:
curl --request POST \
    "http://localhost/api/auth/refresh" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"refresh_token\": \"abc123def456\"
}"
const url = new URL(
    "http://localhost/api/auth/refresh"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "refresh_token": "abc123def456"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "refresh_token": "newtoken123",
    "token_type": "bearer",
    "expires_in": 3600
}
 

Example response (401):


{
    "message": "Invalid or expired refresh token"
}
 

Request      

POST api/auth/refresh

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

refresh_token   string     

Refresh token returned by login. Example: abc123def456

Logout current session

requires authentication

Invalidate a refresh token and end the active authenticated session.

Example request:
curl --request POST \
    "http://localhost/api/auth/logout" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"refresh_token\": \"abc123def456\"
}"
const url = new URL(
    "http://localhost/api/auth/logout"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "refresh_token": "abc123def456"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "message": "Logged out successfully"
}
 

Request      

POST api/auth/logout

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

refresh_token   string  optional    

Optional refresh token to invalidate immediately. Example: abc123def456

Team Members

Endpoints for managing team members.

List all team members

requires authentication

Get a list of all team members with optional filtering by active status.

Example request:
curl --request GET \
    --get "http://localhost/api/team-members?active=1" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/team-members"
);

const params = {
    "active": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


[
    {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "John Doe",
        "role_id": 1,
        "role": {
            "id": 1,
            "name": "Backend Developer"
        },
        "hourly_rate": "150.00",
        "active": true,
        "created_at": "2024-01-15T10:00:00.000000Z",
        "updated_at": "2024-01-15T10:00:00.000000Z"
    }
]
 

Request      

GET api/team-members

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

active   boolean  optional    

Filter by active status. Example: true

Create a new team member

requires authentication

Create a new team member with name, role, and hourly rate.

Example request:
curl --request POST \
    "http://localhost/api/team-members" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"John Doe\",
    \"role_id\": 1,
    \"hourly_rate\": \"150.00\",
    \"active\": true
}"
const url = new URL(
    "http://localhost/api/team-members"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "John Doe",
    "role_id": 1,
    "hourly_rate": "150.00",
    "active": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201):


{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "role_id": 1,
    "role": {
        "id": 1,
        "name": "Backend Developer"
    },
    "hourly_rate": "150.00",
    "active": true,
    "created_at": "2024-01-15T10:00:00.000000Z",
    "updated_at": "2024-01-15T10:00:00.000000Z"
}
 

Example response (422):


{
    "message": "Validation failed",
    "errors": {
        "name": [
            "The name field is required."
        ],
        "hourly_rate": [
            "Hourly rate must be greater than 0"
        ]
    }
}
 

Request      

POST api/team-members

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

name   string     

Team member name. Example: John Doe

role_id   integer     

Role ID. Example: 1

hourly_rate   numeric     

Hourly rate (must be > 0). Example: 150.00

active   boolean  optional    

Active status (defaults to true). Example: true

Get a single team member

requires authentication

Get details of a specific team member by ID.

Example request:
curl --request GET \
    --get "http://localhost/api/team-members/550e8400-e29b-41d4-a716-446655440000" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/team-members/550e8400-e29b-41d4-a716-446655440000"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "role_id": 1,
    "role": {
        "id": 1,
        "name": "Backend Developer"
    },
    "hourly_rate": "150.00",
    "active": true,
    "created_at": "2024-01-15T10:00:00.000000Z",
    "updated_at": "2024-01-15T10:00:00.000000Z"
}
 

Example response (404):


{
    "message": "Team member not found"
}
 

Request      

GET api/team-members/{id}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

Team member UUID. Example: 550e8400-e29b-41d4-a716-446655440000

Update a team member

requires authentication

Update details of an existing team member.

Example request:
curl --request PUT \
    "http://localhost/api/team-members/550e8400-e29b-41d4-a716-446655440000" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"John Doe\",
    \"role_id\": 1,
    \"hourly_rate\": \"175.00\",
    \"active\": false
}"
const url = new URL(
    "http://localhost/api/team-members/550e8400-e29b-41d4-a716-446655440000"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "John Doe",
    "role_id": 1,
    "hourly_rate": "175.00",
    "active": false
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "role_id": 1,
    "role": {
        "id": 1,
        "name": "Backend Developer"
    },
    "hourly_rate": "175.00",
    "active": false,
    "created_at": "2024-01-15T10:00:00.000000Z",
    "updated_at": "2024-01-15T11:00:00.000000Z"
}
 

Example response (404):


{
    "message": "Team member not found"
}
 

Example response (422):


{
    "message": "Validation failed",
    "errors": {
        "hourly_rate": [
            "Hourly rate must be greater than 0"
        ]
    }
}
 

Request      

PUT api/team-members/{id}

PATCH api/team-members/{id}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

Team member UUID. Example: 550e8400-e29b-41d4-a716-446655440000

Body Parameters

name   string  optional    

Team member name. Example: John Doe

role_id   integer  optional    

Role ID. Example: 1

hourly_rate   numeric  optional    

Hourly rate (must be > 0). Example: 175.00

active   boolean  optional    

Active status. Example: false

Delete a team member

requires authentication

Delete a team member. Cannot delete if member has allocations or actuals.

Example request:
curl --request DELETE \
    "http://localhost/api/team-members/550e8400-e29b-41d4-a716-446655440000" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/team-members/550e8400-e29b-41d4-a716-446655440000"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (200):


{
    "message": "Team member deleted successfully"
}
 

Example response (404):


{
    "message": "Team member not found"
}
 

Example response (422):


{
    "message": "Cannot delete team member with active allocations",
    "suggestion": "Consider deactivating the team member instead"
}
 

Example response (422):


{
    "message": "Cannot delete team member with historical data",
    "suggestion": "Consider deactivating the team member instead"
}
 

Request      

DELETE api/team-members/{id}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

Team member UUID. Example: 550e8400-e29b-41d4-a716-446655440000