T
Tenanto
Documentation / Api Quickstart

Api Quickstart

Updated Jan 25, 2026

API Quick Start Guide

Tenanto provides a RESTful API for programmatic access to your SaaS data. This guide covers authentication and basic usage.


Base URL

All API endpoints are prefixed with:

https://your-tenant.yourdomain.com/api/v1/

Example: https://demo.tenanto.local/api/v1/projects


Authentication

The API uses Bearer token authentication via Laravel Sanctum.

Getting a Token

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

Response:

{
  "success": true,
  "message": "Login successful",
  "data": {
    "token": "1|abc123xyz...",
    "user": {
      "id": 1,
      "name": "John Doe",
      "email": "[email protected]"
    }
  }
}

Using the Token

Include the token in the Authorization header:

curl https://demo.tenanto.local/api/v1/projects \
  -H "Authorization: Bearer 1|abc123xyz..."

Token Expiration

Tokens expire after 7 days by default. Configure in .env:

SANCTUM_TOKEN_EXPIRATION_DAYS=7

Revoking a Token

curl -X POST https://demo.tenanto.local/api/v1/auth/logout \
  -H "Authorization: Bearer 1|abc123xyz..."

Rate Limiting

Endpoint Type Limit
Authentication 60/minute
Authenticated requests 60/minute
Guest requests 30/minute
Read operations 120/minute

Rate limit headers are included in responses:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58

Response Format

Success Response

{
  "success": true,
  "message": "Optional message",
  "data": {
    // Response data
  }
}

Error Response

{
  "success": false,
  "message": "Error description",
  "errors": {
    "field": ["Validation error message"]
  }
}

HTTP Status Codes

Code Meaning
200 Success
201 Created
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
422 Validation Error
429 Rate Limited
500 Server Error

API Endpoints

Authentication

Method Endpoint Description
POST /auth/login Login and get token
POST /auth/logout Revoke current token
GET /auth/me Get current user

Projects

Method Endpoint Description
GET /projects List projects
POST /projects Create project
GET /projects/{id} Get project
PUT /projects/{id} Update project
DELETE /projects/{id} Delete project
POST /projects/{id}/archive Archive project
POST /projects/{id}/unarchive Unarchive project

Tasks

Method Endpoint Description
GET /projects/{id}/tasks List project tasks
POST /projects/{id}/tasks Create task
GET /tasks/{id} Get task
PUT /tasks/{id} Update task
DELETE /tasks/{id} Delete task
POST /tasks/{id}/complete Mark task complete

Examples

List Projects

curl https://demo.tenanto.local/api/v1/projects \
  -H "Authorization: Bearer YOUR_TOKEN"

Query Parameters:

Parameter Type Description
search string Search in name/description
archived boolean Filter archived projects
per_page integer Items per page (max 100)
page integer Page number

Response:

{
  "success": true,
  "data": {
    "data": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Website Redesign",
        "description": "Complete overhaul of company website",
        "archived_at": null,
        "created_at": "2025-01-15T10:00:00Z",
        "updated_at": "2025-01-15T10:00:00Z"
      }
    ],
    "meta": {
      "current_page": 1,
      "last_page": 1,
      "per_page": 15,
      "total": 1
    }
  }
}

Create Project

curl -X POST https://demo.tenanto.local/api/v1/projects \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "New Project",
    "description": "Project description"
  }'

Create Task

curl -X POST https://demo.tenanto.local/api/v1/projects/PROJECT_ID/tasks \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Task title",
    "description": "Task description",
    "status": "todo",
    "priority": "high",
    "due_date": "2025-02-01"
  }'

Task Status Values:

Task Priority Values:

Update Task

curl -X PUT https://demo.tenanto.local/api/v1/tasks/TASK_ID \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "in_progress"
  }'

Complete Task

curl -X POST https://demo.tenanto.local/api/v1/tasks/TASK_ID/complete \
  -H "Authorization: Bearer YOUR_TOKEN"

Pagination

List endpoints return paginated results:

{
  "data": [...],
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 15,
    "total": 72,
    "from": 1,
    "to": 15
  },
  "links": {
    "first": "...?page=1",
    "last": "...?page=5",
    "prev": null,
    "next": "...?page=2"
  }
}

Error Handling

Validation Errors (422)

{
  "success": false,
  "message": "The given data was invalid.",
  "errors": {
    "name": ["The name field is required."],
    "email": ["The email must be a valid email address."]
  }
}

Authentication Error (401)

{
  "success": false,
  "message": "Unauthenticated."
}

Not Found (404)

{
  "success": false,
  "message": "Project not found"
}

Tenant Isolation

The API automatically scopes all requests to the current tenant:

You cannot access another tenant's data via API.


SDK Examples

JavaScript/TypeScript

const API_URL = 'https://demo.tenanto.local/api/v1';
let token = null;

async function login(email, password) {
  const response = await fetch(`${API_URL}/auth/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  });
  const data = await response.json();
  token = data.data.token;
  return data;
}

async function getProjects() {
  const response = await fetch(`${API_URL}/projects`, {
    headers: { 'Authorization': `Bearer ${token}` }
  });
  return response.json();
}

// Usage
await login('[email protected]', 'password');
const projects = await getProjects();

PHP

<?php
$apiUrl = 'https://demo.tenanto.local/api/v1';
$token = null;

function login($email, $password) {
    global $apiUrl, $token;

    $ch = curl_init("$apiUrl/auth/login");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS => json_encode([
            'email' => $email,
            'password' => $password
        ])
    ]);

    $response = json_decode(curl_exec($ch), true);
    curl_close($ch);

    $token = $response['data']['token'];
    return $response;
}

function getProjects() {
    global $apiUrl, $token;

    $ch = curl_init("$apiUrl/projects");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]
    ]);

    $response = json_decode(curl_exec($ch), true);
    curl_close($ch);

    return $response;
}

// Usage
login('[email protected]', 'password');
$projects = getProjects();

Next Steps