T
Tenanto

Api

Updated Jan 25, 2026

Tenanto API Documentation

Version: 1.0 Base URL: /api/v1/ Authentication: Bearer Token (Laravel Sanctum)


Table of Contents

  1. Authentication
  2. Demo
  3. Projects
  4. Tasks
  5. Response Formats
  6. Error Handling
  7. Rate Limiting
  8. Tenant Isolation

Authentication

All API requests (except login) require a Bearer token in the Authorization header:

Authorization: Bearer {token}

Login

Create an API token by providing valid credentials.

POST /api/v1/auth/login
Content-Type: application/json

Request Body:

{
  "email": "[email protected]",
  "password": "your-password",
  "device_name": "my-app"  // optional, defaults to "api-token"
}

Success Response (200):

{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": {
      "id": 1,
      "name": "John Doe",
      "email": "[email protected]",
      "email_verified_at": "2024-01-01T00:00:00+00:00",
      "is_tenant_owner": true,
      "created_at": "2024-01-01T00:00:00+00:00",
      "updated_at": "2024-01-01T00:00:00+00:00"
    },
    "token": "1|abc123...",
    "token_type": "Bearer"
  }
}

Error Responses:


Logout

Revoke the current API token.

POST /api/v1/auth/logout
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Logged out successfully"
}

Get Current User

Retrieve the authenticated user's profile.

GET /api/v1/auth/me
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Success",
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "[email protected]",
    "email_verified_at": "2024-01-01T00:00:00+00:00",
    "is_tenant_owner": true,
    "created_at": "2024-01-01T00:00:00+00:00",
    "updated_at": "2024-01-01T00:00:00+00:00"
  }
}

Demo

Create a demo tenant (public endpoint, rate-limited).

POST /api/v1/demo
Content-Type: application/json

Request Body:

{
  "email": "[email protected]",
  "name": "Demo User",
  "company_name": "Demo Company"
}

Success Response (201):

{
  "success": true,
  "message": "Demo tenant created successfully",
  "data": {
    "tenant_id": 123,
    "tenant_slug": "demo-abc123",
    "tenant_url": "https://demo-abc123.example.com",
    "app_url": "https://demo-abc123.example.com/app",
    "email": "[email protected]",
    "password": "demo-password-123",
    "expires_at": "2026-01-25T12:00:00+00:00"
  }
}

Error Responses:


Projects

List Projects

Retrieve a paginated list of projects for the current tenant.

GET /api/v1/projects
Authorization: Bearer {token}

Query Parameters:

Parameter Type Default Description
search string - Filter by project name
archived boolean false Show archived projects only
sort string created_at Sort field (name, created_at, updated_at)
direction string desc Sort direction (asc, desc)
per_page integer 15 Items per page (max 100)
page integer 1 Page number

Success Response (200):

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Marketing Campaign",
      "description": "Q1 marketing initiatives",
      "color": "#3B82F6",
      "is_archived": false,
      "settings": {},
      "open_tasks_count": 5,
      "completed_tasks_count": 12,
      "created_at": "2024-01-01T00:00:00+00:00",
      "updated_at": "2024-01-01T00:00:00+00:00"
    }
  ],
  "links": {
    "first": "/api/v1/projects?page=1",
    "last": "/api/v1/projects?page=3",
    "prev": null,
    "next": "/api/v1/projects?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 3,
    "per_page": 15,
    "to": 15,
    "total": 42
  }
}

Create Project

Create a new project.

POST /api/v1/projects
Authorization: Bearer {token}
Content-Type: application/json

Request Body:

{
  "name": "New Project",           // required, max 255 chars
  "description": "Description",    // optional, max 5000 chars
  "color": "#3B82F6",             // optional, hex color
  "settings": {}                   // optional, JSON object
}

Success Response (201):

{
  "success": true,
  "message": "Project created successfully",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "New Project",
    "description": "Description",
    "color": "#3B82F6",
    "is_archived": false,
    "settings": {},
    "created_at": "2024-01-01T00:00:00+00:00",
    "updated_at": "2024-01-01T00:00:00+00:00"
  }
}

Get Project

Retrieve a specific project by UUID.

GET /api/v1/projects/{uuid}
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Success",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Marketing Campaign",
    "description": "Q1 marketing initiatives",
    "color": "#3B82F6",
    "is_archived": false,
    "settings": {},
    "open_tasks_count": 5,
    "completed_tasks_count": 12,
    "created_at": "2024-01-01T00:00:00+00:00",
    "updated_at": "2024-01-01T00:00:00+00:00"
  }
}

Update Project

Update an existing project.

PUT /api/v1/projects/{uuid}
Authorization: Bearer {token}
Content-Type: application/json

Request Body:

{
  "name": "Updated Name",
  "description": "Updated description",
  "color": "#10B981"
}

Success Response (200):

{
  "success": true,
  "message": "Project updated successfully",
  "data": { ... }
}

Delete Project

Delete a project.

DELETE /api/v1/projects/{uuid}
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Project deleted successfully"
}

Archive Project

Archive a project to hide it from default listings.

POST /api/v1/projects/{uuid}/archive
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Project archived successfully",
  "data": {
    "is_archived": true,
    ...
  }
}

Unarchive Project

Restore an archived project.

POST /api/v1/projects/{uuid}/unarchive
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Project unarchived successfully",
  "data": {
    "is_archived": false,
    ...
  }
}

Tasks

List Tasks

Retrieve tasks for a specific project.

GET /api/v1/projects/{project_uuid}/tasks
Authorization: Bearer {token}

Query Parameters:

Parameter Type Description
status string Filter by status (todo, in_progress, in_review, done, cancelled)
priority string Filter by priority (low, medium, high, urgent)
open boolean Filter open (true) or completed (false) tasks
overdue boolean Show only overdue tasks
assigned_to integer Filter by assignee user ID
my_tasks boolean Show only tasks assigned to current user
search string Search by task title
sort string Sort field (title, status, priority, due_date, created_at, sort_order)
direction string Sort direction (asc, desc)
per_page integer Items per page (max 100)

Success Response (200):

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "title": "Design homepage mockup",
      "description": "Create wireframes for the new homepage",
      "status": {
        "value": "in_progress",
        "label": "In Progress",
        "color": "blue",
        "is_open": true
      },
      "priority": {
        "value": "high",
        "label": "High",
        "color": "orange"
      },
      "due_date": "2024-02-15",
      "completed_at": null,
      "is_overdue": false,
      "is_due_soon": true,
      "sort_order": 1,
      "assignee": {
        "id": 1,
        "name": "John Doe",
        "email": "[email protected]"
      },
      "creator": {
        "id": 2,
        "name": "Jane Smith",
        "email": "[email protected]"
      },
      "created_at": "2024-01-01T00:00:00+00:00",
      "updated_at": "2024-01-01T00:00:00+00:00"
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Create Task

Create a new task within a project.

POST /api/v1/projects/{project_uuid}/tasks
Authorization: Bearer {token}
Content-Type: application/json

Request Body:

{
  "title": "New Task",                    // required, max 255 chars
  "description": "Task description",       // optional, max 10000 chars
  "status": "todo",                        // optional: todo, in_progress, in_review, done, cancelled
  "priority": "medium",                    // optional: low, medium, high, urgent
  "due_date": "2024-02-15",               // optional, date (must be today or future)
  "assigned_to": 1,                        // optional, user ID
  "sort_order": 0                          // optional, integer
}

Success Response (201):

{
  "success": true,
  "message": "Task created successfully",
  "data": { ... }
}

Get Task

Retrieve a specific task.

GET /api/v1/tasks/{uuid}
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Success",
  "data": { ... }
}

Update Task

Update an existing task.

PUT /api/v1/tasks/{uuid}
Authorization: Bearer {token}
Content-Type: application/json

Request Body:

{
  "title": "Updated Title",
  "status": "in_progress",
  "priority": "high",
  "due_date": "2024-03-01",
  "assigned_to": 2
}

Success Response (200):

{
  "success": true,
  "message": "Task updated successfully",
  "data": { ... }
}

Delete Task

Delete a task.

DELETE /api/v1/tasks/{uuid}
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Task deleted successfully"
}

Complete Task

Mark a task as completed.

POST /api/v1/tasks/{uuid}/complete
Authorization: Bearer {token}

Success Response (200):

{
  "success": true,
  "message": "Task marked as completed",
  "data": {
    "status": {
      "value": "done",
      "label": "Done",
      "color": "green",
      "is_open": false
    },
    "completed_at": "2024-01-15T10:30:00+00:00",
    ...
  }
}

Response Formats

Success Response

{
  "success": true,
  "message": "Operation description",
  "data": { ... }
}

Error Response

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": { ... }  // optional, validation errors
  }
}

Error Handling

HTTP Status Codes

Code Description
200 Success
201 Created
400 Bad Request
401 Unauthorized (invalid/missing token)
403 Forbidden (insufficient permissions)
404 Not Found
422 Validation Error
429 Too Many Requests
500 Internal Server Error

Error Codes

Code Description
BAD_REQUEST Invalid request format
UNAUTHORIZED Authentication required
FORBIDDEN Permission denied
NOT_FOUND Resource not found
VALIDATION_ERROR Input validation failed
TOO_MANY_REQUESTS Rate limit exceeded
INTERNAL_SERVER_ERROR Server error

Rate Limiting

The API implements tiered rate limiting:

Limiter Limit Scope
api 60 requests/minute Authenticated users
api-auth 10 requests/minute Authentication endpoints
api-read 120 requests/minute Read operations (GET)
demo Configurable Demo creation endpoint

In addition, tenants are limited by their plan's daily API quota (api_requests_per_day).

When rate limit is exceeded, the API returns:


Tenant Isolation

All API endpoints enforce tenant isolation:

  1. Automatic Filtering: All queries are automatically filtered by the authenticated user's tenant
  2. Resource Access: Users can only access resources belonging to their tenant
  3. Cross-Tenant Protection: Attempting to access another tenant's resources returns 403 or 404
  4. Automatic Assignment: New resources are automatically assigned to the user's tenant

Important Notes


Examples

cURL Examples

Login:

curl -X POST https://example.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"password"}'

List Projects:

curl -X GET https://example.com/api/v1/projects \
  -H "Authorization: Bearer YOUR_TOKEN"

Create Task:

curl -X POST https://example.com/api/v1/projects/{uuid}/tasks \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"New Task","priority":"high"}'

Changelog

v1.0 (2025-11-29)


Related Documentation