Zealdash Tenant API

REST API for tenant-specific CRM data. 238 endpoints. JWT authentication. Documentation-first reference.

REST API Overview

Zealdash SaaS CRM provides a Tenant API for programmatic access to tenant-specific CRM data in an isolated environment.

URL Structure

{{base_url}}/api/v1/{endpoint}

Environments

EnvironmentBase URL
Productionhttps://app.zealdash.com
Staginghttps://app-sandbox.zealdash.com
Developmenthttp://localhost:8080

Tenant slug is provided during onboarding (lowercase, alphanumeric, hyphens). Example: https://app.zealdash.com/api/v1/clients

Technology Stack

  • Style: REST · Format: JSON · Methods: GET, POST, PUT, DELETE
  • Versioning: /api/v1/
  • Authentication: JWT (HS256), Access & Refresh tokens

Response Standard

Success:

{
  "status": "success",
  "message": "Operation completed",
  "data": { ... }
}

Error:

{
  "status": "error",
  "message": "Validation failed",
  "errors": {},
  "code": 422
}

HTTP status codes: 200 Success · 201 Created · 400 Bad Request · 401 Unauthorized · 403 Forbidden · 404 Not Found · 422 Validation Error · 500 Server Error

Authentication

Authentication endpoints handle login, token refresh, user identity, password reset and logout. All secured APIs (other than login) require a JWT Bearer token obtained from these endpoints.

1.1 – POST Login

POST /api/v1/auth/login

Login with email, password and tenant slug. Returns access and refresh tokens and basic user info.

Headers

Content-Type: application/json

Request Body

{
  "email": "[email protected]",      "_comment": "required",
  "password": "yourpassword",        "_comment": "required",
  "tenant_slug": "my-company"        "_comment": "required; selects tenant"
}

Response

{
  "status": "success",
  "message": "Login successful",
  "data": {
    "access_token": "eyJhbGciOi...",
    "refresh_token": "9rk3j...",
    "expires_in": 3600,
    "user": {
      "id": 1,
      "name": "Admin User",
      "email": "[email protected]"
    }
  }
}

Field Explanation

Field Description
email Tenant admin or user email. Required.
password User password. Required.
tenant_slug Tenant identifier used to select the workspace. Required.

1.2 – GET Refresh

GET /api/v1/auth/refresh

Exchange a valid refresh token for a new access token. The response has the same structure as login.

Headers

Authorization: Bearer <refresh_token>
Content-Type: application/json

Alternative Request Body

{
  "refresh_token": "your_refresh_token_here"
}

The response returns new access/refresh tokens in the same shape as Login.

1.3 – GET Me

GET /api/v1/auth/me

Returns the currently authenticated user and tenant information for the supplied access token.

Headers

Authorization: Bearer <access_token>
Content-Type: application/json

Response

{
  "status": "success",
  "data": {
    "user": {
      "id": 1,
      "name": "Admin User",
      "email": "[email protected]"
    },
    "tenant": {
      "id": 12,
      "name": "My Company",
      "slug": "my-company"
    }
  }
}

Forgot Password – POST /auth/forgot_password

POST /api/v1/auth/forgot_password

Starts the password reset flow by generating a reset key for the specified tenant user.

Request Body

{
  "email": "[email protected]",              "_comment": "required",
  "tenant_slug": "gold-plan-2"           "_comment": "required"
}

Response

{
  "status": "success",
  "message": "Password reset link generated",
  "data": {
    "email": "[email protected]",
    "reset_key": "ddea754640155a214d9d55cf8ac5071e"
  }
}

Reset Password – POST /auth/reset_password

POST /api/v1/auth/reset_password

Completes the password reset flow by setting a new password using a valid reset key.

Request Body

{
  "email": "[email protected]",                      "_comment_email": "required",
  "reset_key": "d523b6192e556ccafc4a5eb6774362dd",   "_comment_reset_key": "required",
  "password": "Password@12",
  "_comment_password": "required | min 8 chars | must match confirmation",
  "password_confirm": "Password@12",
  "_comment_password_confirm": "required | must match password",
  "tenant_slug": "gold-plan-2",     "_comment_tenant_slug": "required"
}

Response

{
  "status": "success",
  "message": "Password reset successfully",
  "data": {}
}

Logout – POST /auth/logout

POST /api/v1/auth/logout

Logs the current user out and invalidates the supplied access token.

Headers

Authorization: Bearer <access_token>
Content-Type: application/json

Request Body

{
  "email": "[email protected]",                      "_comment_email": "required",
  "reset_key": "d523b6192e556ccafc4a5eb6774362dd",   "_comment_reset_key": "required",
  "password": "Password@12",
  "_comment_password": "required | min 8 chars | must match confirmation",
  "password_confirm": "Password@12",
  "_comment_password_confirm": "required | must match password",
  "tenant_slug": "gold-plan-2",     "_comment_tenant_slug": "required"
}

Response

{
  "status": "success",
  "message": "Logged out successfully",
  "data": {}
}

Dashboard

Dashboard endpoints return overview widgets such as summary cards, finance metrics and charts. The main endpoint is an overview that aggregates key CRM metrics for the tenant.

2.1 – GET Overview

GET /api/v1/dashboard

Load the tenant dashboard overview including summary cards, finance breakdown and charts.

Headers

Authorization: Bearer <access_token>
Content-Type: application/json

Query Parameters

No query parameters. Uses the authenticated tenant context.

Response

{
  "status": "success",
  "message": "Dashboard overview loaded",
  "data": {
    "summary_cards": [
      {
        "key": "clients_total",
        "label": "Clients",
        "countValue": 58
      },
      {
        "key": "invoices_pending",
        "label": "Invoices awaiting payment",
        "countValue": 12,
        "total": 34,
        "percent": 35.3
      },
      {
        "key": "projects_in_progress",
        "label": "Projects - In Progress",
        "countValue": 6,
        "total": 15,
        "percent": 40
      }
    ],
    "finance": {
      "currency": {
        "name": "USD",
        "symbol": "$"
      },
      "values": {
        "due": 3200,
        "paid": 11800,
        "overdue": 450
      }
    },
    "charts": {
      "weekly_payments": {
        "labels": ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
        "datasets": [
          {
            "label": "This week",
            "data": [0,300,250,0,0,0,0]
          }
        ]
      },
      "projects_status": {
        "labels": ["In Progress","Completed"],
        "datasets": [
          {
            "label": "Projects by status",
            "data": [5,10]
          }
        ]
      }
    }
  }
}

Clients

Client endpoints manage customer organisations and contacts. This section includes list, create, retrieve, update, delete and contact listing APIs.

3.1 – GET List Clients

GET /api/v1/clients/index

Returns a paginated list of clients with optional search and pagination parameters.

Query Parameters

ParameterDescription
pagePage number (default 1).
per_pageItems per page (default 20, max 100).
searchOptional search string to filter by client fields.

Response

{
  "status": "success",
  "data": {
    "items": [
      {
        "userid": 1,
        "company": "ACME Corp",
        "email": "[email protected]",
        "phonenumber": "+1234567890"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 50
    }
  }
}

3.2 – POST Create Clients

POST /api/v1/clients/store

Creates a new client record with basic company and contact information.

Request Body

{
  "company": "New Company Ltd",      "_comment": "required",
  "email": "[email protected]",   "_comment": "required",
  "firstname": "John",               "_comment": "optional but recommended",
  "lastname": "Doe",
  "password": "securepassword123",   "_comment": "required",
  "phonenumber": "+1987654321"
}

Response

{
  "status": "success",
  "message": "Client created successfully",
  "data": {
    "id": 123
  }
}

3.3 – GET Get Clients

GET /api/v1/clients/show

Retrieve a single client by ID.

Query Parameters

ParameterDescription
idRequired client ID (integer).

Response

{
  "status": "success",
  "data": {
    "client": {
      "userid": 1,
      "company": "ACME Corp",
      "email": "[email protected]",
      "phonenumber": "+1234567890"
    }
  }
}

3.4 – PUT Update Clients

PUT /api/v1/clients/update

Update an existing client. Only fields provided in the body will be changed.

Request Body

{
  "id": 1,                           "_comment": "required client id",
  "company": "ACME Corp Updated",    "_comment": "optional",
  "email": "[email protected]",       "_comment": "optional",
  "firstname": "John",
  "lastname": "Doe",
  "phonenumber": "+1234567890",
  "password": "newpass123"           "_comment": "optional; set to update"
}

Response

{
  "status": "success",
  "message": "Client updated successfully"
}

3.5 – DELETE Delete Clients

DELETE /api/v1/clients/destroy

Permanently delete a client by ID.

Parameters

Send id (required, integer) as query parameter or in the body.

Response

{
  "status": "success",
  "message": "Client deleted successfully"
}

3.6 – GET Contacts

GET /api/v1/clients/contacts

List contacts for a given client ID with optional pagination.

Query Parameters

ParameterDescription
client_idRequired client ID (integer).
pageOptional page number.
per_pageOptional page size.

Response

{
  "status": "success",
  "data": {
    "contacts": [
      {
        "id": 10,
        "firstname": "Jane",
        "lastname": "Smith",
        "email": "[email protected]",
        "phonenumber": "+123"
      }
    ]
  }
}

Finance

Finance endpoints cover expenses, estimates, invoices and payments, including categories, statuses and invoice payment helpers.

4.1 – GET List Expenses

GET /api/v1/expenses/index

Returns a paginated list of expenses with optional search and category filters.

Query Parameters

ParameterDescription
pagePage number.
per_pageItems per page.
searchOptional text search.
category_idOptional expense category ID.

Response

{
  "status": "success",
  "data": {
    "items": [
      {
        "id": 1,
        "category": "Travel",
        "amount": 120.50,
        "date": "2024-02-01"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 30
    }
  }
}

4.2 – POST Create Expenses

POST /api/v1/expenses/store

Create a new expense entry with category, amount, date and optional links to client or project.

Request Body

{
  "category": 3,                     "_comment": "required; category id",
  "amount": 120.50,                  "_comment": "required",
  "date": "2024-02-01",              "_comment": "required",
  "note": "Taxi ride",               "_comment": "optional",
  "customer_id": 1,                  "_comment": "optional link to client",
  "project_id": 2                    "_comment": "optional"
}

Response

{
  "status": "success",
  "message": "Expense created",
  "data": {
    "id": 123
  }
}

4.3 – GET Get Expenses

GET /api/v1/expenses/show

Retrieve a single expense by ID.

Query Parameters

id – required expense ID.

Response

{
  "status": "success",
  "data": {
    "expense": {
      "...": "full expense fields"
    }
  }
}

4.4 – PUT Update Expenses

PUT /api/v1/expenses/update

Update an existing expense. Provide the expense id and the fields to change.

Body: same fields as create plus required id.

Response

{
  "status": "success",
  "message": "Expense updated"
}

4.5 – DELETE Delete Expenses

DELETE /api/v1/expenses/destroy

Delete an expense by ID.

id – required, provided as query or body.

Response

{
  "status": "success",
  "message": "Expense deleted"
}

4.6 – GET Expense Categories

GET /api/v1/expenses/categories

Returns the list of available expense categories.

Response

{
  "status": "success",
  "data": {
    "categories": [
      {
        "id": 1,
        "name": "Travel"
      }
    ]
  }
}

4.7 – 4.12 Estimates APIs

GET/POST/PUT/DELETE /api/v1/estimates/*

Endpoints to list, create, retrieve, update, delete and list statuses for estimates.

4.7 – GET List Estimates — /estimates/index

Query: page, per_page, status, client_id optional. Response includes estimate items and pagination.

4.8 – POST Create Estimates — /estimates/store

{
  "clientid": 1,                     "_comment": "required",
  "date": "2024-02-01",
  "expirydate": "2024-02-15",
  "subtotal": 1000,
  "total": 1100,
  "newitems": [
    {
      "description": "Design work",
      "qty": 1,
      "rate": 1000
    }
  ]
}

Create Response

{
  "status": "success",
  "data": {
    "id": 456
  }
}

4.9 – GET Get Estimates — /estimates/show

id required; response contains full estimate payload.

4.10 – PUT Update Estimates — /estimates/update

Body: same as create plus required id; response {"status":"success","message":"Estimate updated"}.

4.11 – DELETE Delete Estimates — /estimates/destroy

id required; response {"status":"success","message":"Estimate deleted"}.

4.12 – GET Estimate Statuses — /estimates/statuses

Returns list of estimate statuses as {id,label} pairs.

4.13 – 4.20 Invoices APIs

GET/POST/PUT/DELETE /api/v1/invoices/*

Endpoints to list, create, retrieve, update, delete and manage invoice statuses.

4.13 – GET List Invoices — /invoices/index

Query: page, per_page, status, client_id optional; returns invoices and pagination.

4.14 – POST Create Invoices — /invoices

{
  "clientid": 1,                     "_comment": "required",
  "date": "2024-01-15",
  "duedate": "2024-02-15",
  "subtotal": 1000.00,
  "total_tax": 100.00,
  "total": 1100.00,
  "newitems": [
    {
      "description": "Web Development",
      "qty": 1,
      "rate": 1000
    }
  ]
}

Create Response

{
  "status": "success",
  "data": {
    "id": 123
  }
}

4.15 – GET Get Invoices — /invoices/{id}

Path id required; returns full invoice payload.

4.16 – PUT Update Invoices — /invoices/{id}

Path id; body same shape as create; response {"status":"success","message":"Invoice updated"}.

4.17 – DELETE Delete Invoices — /invoices/{id}

Response {"status":"success","message":"Invoice deleted"}.

4.18 – POST Mark Sent — /invoices/{id}/mark-sent

Marks invoice as sent; returns success message.

4.19 – POST Mark Cancelled — /invoices/{id}/mark-cancelled

Marks invoice as cancelled; returns success message.

4.20 – GET Invoice Statuses — /invoices/statuses

Returns list of invoice statuses with IDs and labels.

4.21 – 4.27 Payments APIs

GET/POST/PUT/DELETE /api/v1/payments/*

Endpoints for listing, creating, updating and deleting payments, plus invoice-specific payment lists and payment mode metadata.

4.21 – GET List Payments — /payments/index

Query: page, per_page, client_id, invoice_id optional; returns payments and pagination.

4.23 – POST Create Payments — /payments/store

{
  "invoice_id": 10,                  "_comment": "required",
  "amount": 200.00,                  "_comment": "required",
  "paymentmode": 2,                  "_comment": "required; payment mode id",
  "date": "2024-02-01",
  "note": "Partial payment"
}

Create Response

{
  "status": "success",
  "data": {
    "id": 789
  }
}

Other Payment Endpoints

  • 4.22 – GET Get Payments/payments/show, query id required; returns a single payment.
  • 4.24 – PUT Update Payments/payments/update, body similar to create with required id; returns success message.
  • 4.25 – DELETE Delete Payments/payments/destroy, id required; returns success message.
  • 4.26 – GET Invoice Payments/payments/invoice_payments, query invoice_id required; returns list of payments for the invoice.
  • 4.27 – GET Modes/payments/modes, returns available payment modes.

Projects

Project endpoints manage project records, their lifecycle and status metadata.

5.1 – GET List Projects

GET /api/v1/projects

Returns a paginated list of projects for the tenant, with optional filters by status and client.

Query Parameters

ParameterDescription
pagePage number (optional).
per_pageItems per page (optional).
searchOptional search term for project name.
statusOptional project status ID.
client_idOptional client filter.

Response

{
  "status": "success",
  "data": {
    "projects": [
      {
        "id": 1,
        "name": "Website Redesign",
        "status": 2,
        "clientid": 1,
        "progress": 45,
        "deadline": "2024-03-15"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 50
    }
  }
}

5.2 – POST Create Projects

POST /api/v1/projects

Create a new project linked to a client, with optional start/end dates and budget.

Request Body

{
  "name": "Website Redesign Project", "_comment": "required",
  "clientid": 1,                      "_comment": "required",
  "status": 1,                        "_comment": "status id",
  "start_date": "2024-01-15",
  "deadline": "2024-03-15",
  "project_cost": 10000.00
}

Response

{
  "status": "success",
  "data": {
    "id": 123
  }
}

5.3 – GET Get Projects

GET /api/v1/projects/{id}

Retrieve a full project payload by its ID.

Path parameter id (required) – project ID.

Response

Returns the full project object, including status, client and progress fields.

5.4 – PUT Update Projects

PUT /api/v1/projects/{id}

Update an existing project by ID. Only supplied fields are updated.

Path parameter id (required). Body uses the same structure as create.

Response

{
  "status": "success",
  "message": "Project updated"
}

5.5 – DELETE Delete Projects

DELETE /api/v1/projects/{id}

Permanently delete a project by ID.

Path parameter id (required) – project ID.

Response

{
  "status": "success",
  "message": "Project deleted"
}

5.6 – GET Project Statuses

GET /api/v1/projects/statuses

Retrieve all available project statuses with colors and ordering information.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Response

{
  "status": "success",
  "message": "Project statuses retrieved successfully",
  "data": [
    {
      "id": 1,
      "name": "Not Started",
      "color": "#475569",
      "order": 1,
      "filter_default": true
    },
    {
      "id": 2,
      "name": "In Progress",
      "color": "#3b82f6",
      "order": 2,
      "filter_default": false
    },
    {
      "id": 3,
      "name": "On Hold",
      "color": "#f59e0b",
      "order": 3,
      "filter_default": false
    },
    {
      "id": 4,
      "name": "Completed",
      "color": "#10b981",
      "order": 4,
      "filter_default": false
    },
    {
      "id": 5,
      "name": "Cancelled",
      "color": "#ef4444",
      "order": 5,
      "filter_default": false
    }
  ]
}

Tasks

Tasks endpoints expose operations around CRM task management including listing, creating, retrieving, updating and deleting tasks.

6.1 – GET List Tasks

GET /api/v1/tasks

Retrieve a paginated list of tasks with optional filtering by search, status, project and assignee.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParameterDescription
pageOptional integer, default 1 – page number.
per_pageOptional integer, default 20, max 100 – items per page.
searchOptional string – search by task name.
statusOptional integer – filter by status ID (1–5).
project_idOptional integer – filter by project ID.
assigned_toOptional integer – filter by assigned staff ID.

Response

{
  "status": "success",
  "message": "Tasks retrieved successfully",
  "data": {
    "tasks": [
      {
        "id": 1,
        "name": "Design homepage",
        "description": "Create homepage design mockup",
        "status": 1,
        "priority": 2,
        "rel_type": "project",
        "rel_id": 1,
        "startdate": "2024-01-15",
        "duedate": "2024-01-20",
        "dateadded": "2024-01-10 09:00:00",
        "addedfrom": 1,
        "milestone": 1,
        "hourly_rate": "75.00",
        "is_public": 0,
        "billable": 1,
        "billed": 0
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 75,
      "total_pages": 4
    }
  }
}

6.2 – POST Create Tasks

POST /api/v1/tasks

Create a new task associated with a project or other related entity.

Request Body

{
  "_comment": "Required fields: name, rel_type, rel_id",
  "name": "Design homepage",
  "_comment_name": "Required - Task name (max 200 characters)",
  "description": "Create homepage design mockup",
  "_comment_description": "Optional - Task description (max 65000 characters)",
  "rel_type": "project",
  "_comment_rel_type": "Required - Related entity type: 'project', 'customer', etc. (max 40 characters)",
  "rel_id": 1,
  "_comment_rel_id": "Required - Related entity ID (integer)",
  "status": 1,
  "_comment_status": "Optional - Task status: 1=Not Started, 2=In Progress, 3=Testing, 4=Awaiting Feedback, 5=Complete (default: 1)",
  "priority": 2,
  "_comment_priority": "Optional - Priority: 1=Low, 2=Medium, 3=High, 4=Urgent (default: 2)",
  "startdate": "2024-01-15",
  "_comment_startdate": "Optional - Start date (format: Y-m-d)",
  "duedate": "2024-01-20",
  "_comment_duedate": "Optional - Due date (format: Y-m-d)",
  "milestone": 1,
  "_comment_milestone": "Optional - Milestone ID (integer)",
  "hourly_rate": 75.00,
  "_comment_hourly_rate": "Optional - Hourly rate (decimal)",
  "is_public": false,
  "_comment_is_public": "Optional - Is task public: true/false (default: false)",
  "billable": true,
  "_comment_billable": "Optional - Is task billable: true/false (default: true)",
  "assignees": [1, 2],
  "_comment_assignees": "Optional - Array of staff IDs assigned to task",
  "followers": [3],
  "_comment_followers": "Optional - Array of staff IDs following task"
}

Response

{
  "status": "success",
  "message": "Task created successfully",
  "data": {
    "id": 123
  }
}

6.3 – GET Get Tasks

GET /api/v1/tasks/{id}

Retrieve a specific task by ID with all related data including assignees and milestones.

Path parameter id (required, integer) – task ID.

Response

{
  "status": "success",
  "message": "Task retrieved successfully",
  "data": {
    "id": 1,
    "name": "Design homepage",
    "description": "Create homepage design mockup",
    "status": 1,
    "priority": 2,
    "rel_type": "project",
    "rel_id": 1,
    "startdate": "2024-01-15",
    "duedate": "2024-01-20",
    "dateadded": "2024-01-10 09:00:00",
    "addedfrom": 1,
    "milestone": 1,
    "milestone_name": "Phase 1",
    "hourly_rate": "75.00",
    "is_public": 0,
    "billable": 1,
    "billed": 0,
    "assignees": [
      {
        "staffid": 1,
        "firstname": "John",
        "lastname": "Doe"
      }
    ],
    "followers": [],
    "attachments": [],
    "timesheets": [],
    "checklist_items": [],
    "comments": [],
    "current_user_is_assigned": true,
    "current_user_is_creator": false
  }
}

6.4 – PUT Update Tasks

PUT /api/v1/tasks/{id}

Update an existing task. All fields in the body are optional; only included fields are changed.

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Design homepage updated",
  "_comment_name": "Optional - Task name (max 200 characters)",
  "description": "Updated task description",
  "_comment_description": "Optional - Task description (max 65000 characters)",
  "status": 2,
  "_comment_status": "Optional - Task status: 1-5",
  "priority": 3,
  "_comment_priority": "Optional - Priority: 1-4",
  "startdate": "2024-01-16",
  "_comment_startdate": "Optional - Start date (format: Y-m-d)",
  "duedate": "2024-01-25",
  "_comment_duedate": "Optional - Due date (format: Y-m-d)",
  "milestone": 2,
  "_comment_milestone": "Optional - Milestone ID",
  "hourly_rate": 80.00,
  "_comment_hourly_rate": "Optional - Hourly rate",
  "is_public": true,
  "_comment_is_public": "Optional - Is task public",
  "billable": false,
  "_comment_billable": "Optional - Is task billable",
  "assignees": [1, 2, 3],
  "_comment_assignees": "Optional - Array of staff IDs",
  "followers": [2, 4],
  "_comment_followers": "Optional - Array of staff IDs"
}

Response

{
  "status": "success",
  "message": "Task updated successfully"
}

6.5 – DELETE Delete Tasks

DELETE /api/v1/tasks/{id}

Delete a task by ID.

Path parameter id (required) – task ID.

Response

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

Error Response (404 Not Found)

{
  "status": "error",
  "message": "Task not found",
  "code": 404
}

Todos

Todo endpoints manage lightweight personal todo items for staff, including list, create, retrieve, update, delete and toggle status operations.

7.1 – GET List Todos

GET /api/v1/todos

Retrieve list of todos for the current authenticated user, optionally filtered by finished status.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParameterDescription
finishedOptional, integer (default 0). 0 = Unfinished, 1 = Finished.
pageOptional, integer (default 0). Page number.

Response

{
  "status": "success",
  "message": "Todos retrieved successfully",
  "data": {
    "todos": [
      {
        "id": 1,
        "description": "Review project proposal",
        "finished": 0,
        "dateadded": "2024-01-10 09:00:00",
        "item_order": 1,
        "staffid": 1
      },
      {
        "id": 2,
        "description": "Call client for feedback",
        "finished": 0,
        "dateadded": "2024-01-11 10:30:00",
        "item_order": 2,
        "staffid": 1
      }
    ]
  }
}

7.2 – POST Create Todos

POST /api/v1/todos

Create a new todo item for the current user.

Request Body

{
  "_comment": "Required field: description",
  "description": "Review project proposal",
  "_comment_description": "Required - Todo description"
}

Response

{
  "status": "success",
  "message": "Todo created successfully",
  "data": {
    "id": 123
  }
}

Error Response (422 Validation Error)

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "description": "The description field is required"
  },
  "code": 422
}

7.3 – GET Get Todos

GET /api/v1/todos/{id}

Retrieve a specific todo item by ID.

Path parameter id (required, integer) – todo ID.

Response

{
  "status": "success",
  "message": "Todo retrieved successfully",
  "data": {
    "id": 1,
    "description": "Review project proposal",
    "finished": 0,
    "dateadded": "2024-01-10 09:00:00",
    "item_order": 1,
    "staffid": 1
  }
}

Error Response (403 Forbidden)

{
  "status": "error",
  "message": "Access denied",
  "code": 403
}

7.4 – PUT Update Todos

PUT /api/v1/todos/{id}

Update an existing todo item. Only fields present in the body are updated.

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "description": "Review project proposal - Updated",
  "_comment_description": "Optional - Todo description",
  "finished": 0,
  "_comment_finished": "Optional - Finished status: 0=Unfinished, 1=Finished",
  "item_order": 2,
  "_comment_item_order": "Optional - Order position (integer)"
}

Response

{
  "status": "success",
  "message": "Todo updated successfully"
}

7.5 – DELETE Delete Todos

DELETE /api/v1/todos/destroy

Delete a todo item by ID.

Query parameter id (required, integer) – todo ID.

Response

{
  "status": "success",
  "message": "Todo deleted successfully"
}

7.6 – Toggle Todo Status

POST /api/v1/todos/{id}/toggle_status

Toggle the finished status of a todo item. The documentation notes that although a GET variant exists, the correct implementation uses POST at /todos/{id}/toggle_status.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Optional field: status",
  "status": 1,
  "_comment_status": "Optional - Status: 0=Unfinished, 1=Finished (default: 1)"
}

Response (200 OK)

{
  "status": "success",
  "message": "Todo status updated successfully"
}

Activity Logs

Activity log endpoints surface audit-style event history for entities. (Details for these endpoints are covered by the general Activity Log utilities in the Tenant API docs.)

Departments

Department endpoints configure organisational units used across tickets, leads and other modules.

9.1 – GET List Departments

GET /api/v1/departments/index

Retrieve list of all departments configured for the tenant.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Response

{
  "status": "success",
  "message": "Departments retrieved successfully",
  "data": {
    "departments": [
      {
        "departmentid": 1,
        "name": "Sales",
        "email": "[email protected]",
        "calendar_id": "",
        "hidefromclient": 0,
        "host": "",
        "password": "",
        "encryption": "",
        "delete_mail_after_import": 0,
        "imap_username": "",
        "notify_lead_imported": 1,
        "notify_lead_contact_more_times": 1,
        "notify_type": "",
        "notify_ids": "",
        "responsible": 0,
        "no_default_mailbox": 0
      }
    ]
  }
}

9.2 – GET Get Departments

GET /api/v1/departments/show

Retrieve a specific department by ID.

Query Parameters

id – required, integer department ID.

Response

{
  "status": "success",
  "message": "Department retrieved successfully",
  "data": {
    "departmentid": 1,
    "name": "Sales",
    "email": "[email protected]",
    "calendar_id": "",
    "hidefromclient": 0,
    "host": "",
    "password": "",
    "encryption": "",
    "delete_mail_after_import": 0,
    "imap_username": "",
    "notify_lead_imported": 1,
    "notify_lead_contact_more_times": 1,
    "notify_type": "",
    "notify_ids": "",
    "responsible": 0,
    "no_default_mailbox": 0
  }
}

Error Response (404 Not Found)

{
  "status": "error",
  "message": "Department not found",
  "code": 404
}

9.3 – POST Create Departments

POST /api/v1/departments/store

Create a new department with email configuration and notification settings.

Request Body

{
  "_comment": "Required field: name",
  "name": "Sales",
  "_comment_name": "Required - Department name (max 100 characters)",
  "email": "[email protected]",
  "_comment_email": "Optional - Department email (valid email, max 100 characters)",
  "calendar_id": "",
  "_comment_calendar_id": "Optional - Calendar ID",
  "hidefromclient": 0,
  "_comment_hidefromclient": "Optional - Hide from client: 0=No, 1=Yes",
  "host": "",
  "_comment_host": "Optional - Email host",
  "password": "",
  "_comment_password": "Optional - Email password",
  "encryption": "",
  "_comment_encryption": "Optional - Encryption type",
  "delete_mail_after_import": 0,
  "_comment_delete_mail_after_import": "Optional - Delete mail after import: 0=No, 1=Yes",
  "imap_username": "",
  "_comment_imap_username": "Optional - IMAP username",
  "notify_lead_imported": 1,
  "_comment_notify_lead_imported": "Optional - Notify when lead imported: 0=No, 1=Yes",
  "notify_lead_contact_more_times": 1,
  "_comment_notify_lead_contact_more_times": "Optional - Notify when lead contacts more times: 0=No, 1=Yes",
  "notify_type": "",
  "_comment_notify_type": "Optional - Notification type",
  "notify_ids": "",
  "_comment_notify_ids": "Optional - Notification IDs",
  "responsible": 0,
  "_comment_responsible": "Optional - Responsible staff ID",
  "no_default_mailbox": 0,
  "_comment_no_default_mailbox": "Optional - No default mailbox: 0=No, 1=Yes"
}

Response

{
  "status": "success",
  "message": "Department created successfully",
  "data": {
    "id": 123
  }
}

Error Response (422 Validation Error)

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "name": "The name field is required",
    "email": "The email field must be a valid email address"
  },
  "code": 422
}

9.4 – PUT Update Departments

PUT /api/v1/departments/update

Update an existing department by ID. All fields in the body are optional.

Query parameter id (required, integer) – department ID.

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Sales Department",
  "_comment_name": "Optional - Department name (max 100 characters)",
  "email": "[email protected]",
  "_comment_email": "Optional - Department email (valid email, max 100 characters)",
  "calendar_id": "cal_123",
  "_comment_calendar_id": "Optional - Calendar ID",
  "hidefromclient": 1,
  "_comment_hidefromclient": "Optional - Hide from client: 0=No, 1=Yes"
}

Response

{
  "status": "success",
  "message": "Department updated successfully"
}

9.5 – DELETE Delete Departments

DELETE /api/v1/departments/destroy

Delete a department by ID.

Query parameter id (required, integer).

Response

{
  "status": "success",
  "message": "Department deleted successfully"
}

Email Templates

Email template endpoints allow you to list and manage automated email templates by type and language.

10.1 – GET List Email Templates

GET /api/v1/emailtemplates/index

Retrieve list of email templates filtered by type and language.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParameterDescription
type Optional. Template type (e.g. invoice, estimate, proposal, ticket, etc.).
language Optional. Template language, default english.

Response

{
  "status": "success",
  "message": "Email templates retrieved successfully",
  "data": {
    "templates": [
      {
        "emailtemplateid": 1,
        "type": "invoice",
        "slug": "invoice-send-to-client",
        "language": "english",
        "name": "Invoice Send to Client",
        "subject": "Invoice #{invoice_number}",
        "message": "Dear {contact_firstname} {contact_lastname},\n\nPlease find attached invoice #{invoice_number}.\n\nAmount: {invoice_total}\nDue Date: {invoice_date}\n\nThank you!",
        "fromname": "",
        "fromemail": "",
        "plaintext": 0,
        "active": 1,
        "order": 1
      }
    ]
  }
}

10.2 – GET Get Email Templates

GET /api/v1/emailtemplates/show

Retrieve a specific email template by its ID.

Query Parameters

id – required, integer email template ID.

Response

{
  "status": "success",
  "message": "Email template retrieved successfully",
  "data": {
    "emailtemplateid": 1,
    "type": "invoice",
    "slug": "invoice-send-to-client",
    "language": "english",
    "name": "Invoice Send to Client",
    "subject": "Invoice #{invoice_number}",
    "message": "Dear {contact_firstname} {contact_lastname},\n\nPlease find attached invoice #{invoice_number}.\n\nAmount: {invoice_total}\nDue Date: {invoice_date}\n\nThank you!",
    "fromname": "",
    "fromemail": "",
    "plaintext": 0,
    "active": 1,
    "order": 1
  }
}

10.3 – PUT Update Email Templates

PUT /api/v1/emailtemplates/update

Update an existing email template. All fields in the body are optional.

Query parameter id (required, integer) – email template ID.

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Invoice Send to Client - Updated",
  "_comment_name": "Optional - Template name",
  "subject": "Invoice #{invoice_number} - Updated Subject",
  "_comment_subject": "Optional - Email subject (can include placeholders like {invoice_number})",
  "message": "Dear {contact_firstname} {contact_lastname},\n\nPlease find attached invoice #{invoice_number}.\n\nAmount: {invoice_total}\nDue Date: {invoice_date}\n\nThank you for your business!",
  "_comment_message": "Optional - Email message body (can include HTML and placeholders)",
  "fromname": "Company Name",
  "_comment_fromname": "Optional - From name",
  "fromemail": "[email protected]",
  "_comment_fromemail": "Optional - From email address",
  "plaintext": 0,
  "_comment_plaintext": "Optional - Plain text mode: 0=HTML, 1=Plain text",
  "active": 1,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active",
  "order": 1,
  "_comment_order": "Optional - Display order"
}

Response

{
  "status": "success",
  "message": "Email template updated successfully"
}

Estimate Requests

Estimate request endpoints manage inbound estimate or quote requests and allow updates, assignment changes and conversions.

11.1 – GET List Estimate Requests

GET /api/v1/estimaterequests/index

Retrieve a paginated list of estimate requests submitted by prospects.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParameterDescription
pageOptional, default 1 – page number.
per_pageOptional, default 20, max 100 – items per page.

Response

{
  "status": "success",
  "message": "Estimate requests retrieved successfully",
  "data": {
    "requests": [
      {
        "id": 1,
        "name": "Website Development",
        "email": "[email protected]",
        "phonenumber": "+1234567890",
        "message": "We need a new website",
        "assigned": 1,
        "status": 1,
        "date": "2024-01-15 10:30:00",
        "date_converted": null,
        "converted": 0
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    }
  }
}

11.2 – GET Get Estimate Requests

GET /api/v1/estimaterequests/show

Retrieve a single estimate request by its ID.

Query parameter id (required, integer) – estimate request ID.

Response

{
  "status": "success",
  "message": "Estimate request retrieved successfully",
  "data": {
    "id": 1,
    "name": "Website Development",
    "email": "[email protected]",
    "phonenumber": "+1234567890",
    "message": "We need a new website",
    "assigned": 1,
    "status": 1,
    "date": "2024-01-15 10:30:00",
    "date_converted": null,
    "converted": 0
  }
}

11.3 – POST Create Estimate Requests

POST /api/v1/estimaterequests/store

Create a new estimate request from a prospect or customer.

Request Body

{
  "_comment": "Required fields may vary - check validation",
  "name": "Website Development",
  "_comment_name": "Required - Request name/company name",
  "email": "[email protected]",
  "_comment_email": "Required - Contact email",
  "phonenumber": "+1234567890",
  "_comment_phonenumber": "Optional - Phone number",
  "message": "We need a new website with e-commerce functionality",
  "_comment_message": "Optional - Request message/description",
  "assigned": 1,
  "_comment_assigned": "Optional - Assigned staff ID",
  "status": 1,
  "_comment_status": "Optional - Status ID"
}

Response

{
  "status": "success",
  "message": "Estimate request created successfully",
  "data": {
    "id": 123
  }
}

11.4 – PUT Update Estimate Requests

PUT /api/v1/estimaterequests/update

Update an existing estimate request. All body fields are optional.

Query parameter id (required, integer) – estimate request ID.

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Website Development - Updated",
  "_comment_name": "Optional - Request name",
  "email": "[email protected]",
  "_comment_email": "Optional - Contact email",
  "phonenumber": "+1987654321",
  "_comment_phonenumber": "Optional - Phone number",
  "message": "Updated request message",
  "_comment_message": "Optional - Request message",
  "assigned": 2,
  "_comment_assigned": "Optional - Assigned staff ID",
  "status": 2,
  "_comment_status": "Optional - Status ID"
}

Response

{
  "status": "success",
  "message": "Estimate request updated successfully"
}

11.5 – DELETE Delete Estimate Requests

DELETE /api/v1/estimaterequests/destroy

Delete an estimate request by ID.

Query parameter id (required, integer) – estimate request ID.

Response

{
  "status": "success",
  "message": "Estimate request deleted successfully"
}

11.6 – Update Assigned Staff

POST /api/v1/estimaterequests/{id}/update_assigned

Update the assigned staff member for an estimate request. The documentation notes that, although a GET URL variant exists, the correct implementation uses POST with the ID in the path.

Path parameter id (required) – estimate request ID.

Request Body

{
  "_comment": "Required field: assigned",
  "assigned": 2,
  "_comment_assigned": "Required - Staff ID to assign"
}

Response

{
  "status": "success",
  "message": "Assigned staff updated successfully"
}

11.7 – Convert Estimate Request

POST /api/v1/estimaterequests/{id}/convert

Convert an estimate request into an estimate or proposal. The docs clarify that this should be a POST to /estimaterequests/{id}/convert.

Path parameter id (required, integer) – estimate request ID.

Request Body

{
  "_comment": "Optional field: convert_to",
  "convert_to": "estimate",
  "_comment_convert_to": "Optional - Conversion type: 'estimate' or 'proposal' (default: 'estimate')"
}

Response

{
  "status": "success",
  "message": "Conversion initiated. Use the returned URL to complete the conversion.",
  "data": {
    "convert_to": "estimate",
    "request_id": 1
  }
}

Error Response (400 Bad Request)

{
  "status": "error",
  "message": "Invalid convert_to value. Must be \"estimate\" or \"proposal\"",
  "code": 400
}

Filters

Filter endpoints provide saved view/filter definitions for various modules such as customers, invoices, projects, tasks and more.

12.1 – GET List Filters

GET /api/v1/filters/index

Retrieve list of saved filters for a given identifier and view.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParameterDescription
identifier Optional. Module identifier such as customers, invoices, estimates, projects, tasks, leads, tickets, etc.
view Optional. View type such as list, table, kanban, calendar.

Response

{
  "status": "success",
  "message": "Filters retrieved successfully",
  "data": {
    "filters": [
      {
        "id": 1,
        "name": "Active Customers",
        "identifier": "customers",
        "view": "list",
        "builder": "{\"condition\":\"AND\",\"rules\":[{\"id\":\"active\",\"field\":\"active\",\"type\":\"integer\",\"input\":\"select\",\"operator\":\"equal\",\"value\":\"1\"}]}",
        "is_shared": 1,
        "is_default": 0,
        "staff_id": 1,
        "date_created": "2024-01-10 09:00:00"
      }
    ]
  }
}

12.2 – GET Get Filters

GET /api/v1/filters/show

Retrieve a single filter definition by ID.

Query parameter id (required, integer) – filter ID.

Response

{
  "status": "success",
  "message": "Filter retrieved successfully",
  "data": {
    "id": 1,
    "name": "Active Customers",
    "identifier": "customers",
    "view": "list",
    "builder": "{\"condition\":\"AND\",\"rules\":[{\"id\":\"active\",\"field\":\"active\",\"type\":\"integer\",\"input\":\"select\",\"operator\":\"equal\",\"value\":\"1\"}]}",
    "is_shared": 1,
    "is_default": 0,
    "staff_id": 1,
    "date_created": "2024-01-10 09:00:00"
  }
}

12.3 – POST Create Filters

POST /api/v1/filters/store

Create a new saved filter for a module and view combination.

Request Body

{
  "_comment": "Required fields: name, identifier, view",
  "name": "Active Customers",
  "_comment_name": "Required - Filter name (max 191 characters)",
  "identifier": "customers",
  "_comment_identifier": "Required - Filter identifier (max 50 characters): 'customers', 'invoices', 'estimates', 'projects', 'tasks', 'leads', 'tickets', 'expenses', 'credit_notes', 'proposals', 'subscriptions', 'contracts', 'knowledge_base'",
  "view": "list",
  "_comment_view": "Required - Filter view (max 50 characters): 'list', 'table', 'kanban', 'calendar'",
  "rules": {
    "_comment_rules": "Optional - Filter rules object (JSON structure for query builder)",
    "condition": "AND",
    "rules": [
      {
        "id": "active",
        "field": "active",
        "type": "integer",
        "input": "select",
        "operator": "equal",
        "value": "1"
      }
    ]
  },
  "is_shared": 1,
  "_comment_is_shared": "Optional - Is shared: 0=No, 1=Yes (default: 0)",
  "is_default": 0,
  "_comment_is_default": "Optional - Is default: 0=No, 1=Yes (default: 0)"
}

Response

{
  "status": "success",
  "message": "Filter created successfully",
  "data": {
    "id": 123,
    "name": "Active Customers",
    "identifier": "customers",
    "view": "list",
    "builder": "{\"condition\":\"AND\",\"rules\":[{\"id\":\"active\",\"field\":\"active\",\"type\":\"integer\",\"input\":\"select\",\"operator\":\"equal\",\"value\":\"1\"}]}",
    "is_shared": 1,
    "is_default": 0,
    "staff_id": 1,
    "date_created": "2024-01-15 10:30:00"
  }
}

Error Response (422 Validation Error)

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "name": "The name field is required",
    "identifier": "The identifier field is required"
  },
  "code": 422
}

12.4 – PUT Update Filters

PUT /api/v1/filters/update

Update an existing filter configuration. All body fields are optional.

Query parameter id (required, integer) – filter ID.

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Active Customers - Updated",
  "_comment_name": "Optional - Filter name",
  "is_shared": 0,
  "_comment_is_shared": "Optional - Is shared: 0=No, 1=Yes",
  "is_default": 1,
  "_comment_is_default": "Optional - Is default: 0=No, 1=Yes",
  "rules": {
    "_comment_rules": "Optional - Filter rules object (JSON structure)",
    "condition": "OR",
    "rules": [
      {
        "id": "active",
        "field": "active",
        "type": "integer",
        "input": "select",
        "operator": "equal",
        "value": "1"
      }
    ]
  }
}

Response

{
  "status": "success",
  "message": "Filter updated successfully",
  "data": {
    "id": 1,
    "name": "Active Customers - Updated",
    "identifier": "customers",
    "view": "list",
    "builder": "{\"condition\":\"OR\",\"rules\":[{\"id\":\"active\",\"field\":\"active\",\"type\":\"integer\",\"input\":\"select\",\"operator\":\"equal\",\"value\":\"1\"}]}",
    "is_shared": 0,
    "is_default": 1,
    "staff_id": 1,
    "date_created": "2024-01-10 09:00:00"
  }
}

12.5 – DELETE Delete Filters

DELETE /api/v1/filters/destroy

Delete a saved filter by ID.

Query parameter id (required, integer) – filter ID.

Response

{
  "status": "success",
  "message": "Filter deleted successfully"
}

Error Response (403 Forbidden)

{
  "status": "error",
  "message": "Access denied",
  "code": 403
}

Currencies

Currency endpoints.

13.1 – GET List Currencies

GET/api/v1/currencies/index

Retrieve list of all currencies (Admin only).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Currencies retrieved successfully",
  "data": {
    "currencies": [
      {
        "id": 1,
        "name": "USD",
        "symbol": "$",
        "decimal_separator": ".",
        "thousand_separator": ",",
        "placement": "before",
        "isdefault": 1
      },
      {
        "id": 2,
        "name": "EUR",
        "symbol": "€",
        "decimal_separator": ".",
        "thousand_separator": ",",
        "placement": "before",
        "isdefault": 0
      }
    ]
  }
}

Error Example

{
  "status": "error",
  "message": "Access denied",
  "code": 403
}

13.2 – GET Get Currencies

GET/api/v1/currencies/show?id={id}

Retrieve a specific currency by ID (Admin only).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idCurrency ID

Sample Response

{
  "status": "success",
  "message": "Currency retrieved successfully",
  "data": {
    "id": 1,
    "name": "USD",
    "symbol": "$",
    "decimal_separator": ".",
    "thousand_separator": ",",
    "placement": "before",
    "isdefault": 1
  }
}

13.3 – POST Create Currencies

POST/api/v1/currencies/store

Create a new currency (Admin only).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: name, symbol",
  "name": "GBP",
  "_comment_name": "Required - Currency name/code (max 10 characters)",
  "symbol": "£",
  "_comment_symbol": "Required - Currency symbol (max 10 characters)",
  "decimal_separator": ".",
  "_comment_decimal_separator": "Optional - Decimal separator (default: '.')",
  "thousand_separator": ",",
  "_comment_thousand_separator": "Optional - Thousand separator (default: ',')",
  "placement": "before",
  "_comment_placement": "Optional - Symbol placement: 'before' or 'after' (default: 'before')"
}

Sample Response

{
  "status": "success",
  "message": "Currency created successfully"
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "name": "The name field is required",
    "symbol": "The symbol field is required"
  },
  "code": 422
}

13.4 – PUT Update Currencies

PUT/api/v1/currencies/update?id={id}

Update an existing currency (Admin only).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idCurrency ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "GBP",
  "_comment_name": "Optional - Currency name/code (max 10 characters)",
  "symbol": "£",
  "_comment_symbol": "Optional - Currency symbol (max 10 characters)",
  "decimal_separator": ".",
  "_comment_decimal_separator": "Optional - Decimal separator",
  "thousand_separator": ",",
  "_comment_thousand_separator": "Optional - Thousand separator",
  "placement": "after",
  "_comment_placement": "Optional - Symbol placement: 'before' or 'after'"
}

Sample Response

{
  "status": "success",
  "message": "Currency updated successfully"
}

13.5 – DELETE Delete Currencies

DELETE/api/v1/currencies/destroy?id={id}

Delete a currency (Admin only). Cannot delete the default currency.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idCurrency ID

Sample Response

{
  "status": "success",
  "message": "Currency deleted successfully"
}

Error Example

{
  "status": "error",
  "message": "Cannot delete default currency",
  "code": 400
}

Boards

Board endpoints.

14.1 – GET Board Data

GET/api/v1/kanban/boards?type={type}&rel_id={rel_id}

Retrieve kanban board data for a specific entity type.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
typeEntity type (e.g., 'projects', 'tasks', 'leads', 'invoices', 'estimates')
rel_idRelated entity ID (e.g., project ID for task boards)

Sample Response

{
  "status": "success",
  "message": "Board data retrieved successfully",
  "data": {
    "boards": [
      {
        "id": 1,
        "name": "To Do",
        "type": "tasks",
        "rel_id": 1,
        "order": 1,
        "color": "#64748b",
        "items": [
          {
            "id": 1,
            "name": "Task 1",
            "status": 1,
            "priority": 2,
            "duedate": "2024-01-20"
          }
        ]
      },
      {
        "id": 2,
        "name": "In Progress",
        "type": "tasks",
        "rel_id": 1,
        "order": 2,
        "color": "#3b82f6",
        "items": []
      }
    ]
  }
}

14.2 – POST Create Board

POST/api/v1/kanban/boards

Create a new kanban board.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: name, type",
  "name": "To Do",
  "_comment_name": "Required - Board name",
  "type": "tasks",
  "_comment_type": "Required - Entity type: 'projects', 'tasks', 'leads', 'invoices', 'estimates'",
  "rel_id": 1,
  "_comment_rel_id": "Optional - Related entity ID (e.g., project ID for task boards)",
  "order": 1,
  "_comment_order": "Optional - Display order (integer)",
  "color": "#64748b",
  "_comment_color": "Optional - Board color (hex code)"
}

Sample Response

{
  "status": "success",
  "message": "Board created successfully",
  "data": {
    "id": 123
  }
}

14.3 – PUT Update Board

PUT/api/v1/kanban/boards/{id}

Update an existing kanban board.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "To Do - Updated",
  "_comment_name": "Optional - Board name",
  "order": 2,
  "_comment_order": "Optional - Display order",
  "color": "#3b82f6",
  "_comment_color": "Optional - Board color (hex code)"
}

Sample Response

{
  "status": "success",
  "message": "Board updated successfully"
}

14.4 – DELETE Delete Board

DELETE/api/v1/kanban/boards/{id}

Delete a kanban board.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Board deleted successfully"
}

14.5 – GET Board Items

GET/api/v1/kanban/items?board_id={board_id}&type={type}&rel_id={rel_id}

Retrieve items for a kanban board.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
board_idBoard ID
typeEntity type
rel_idRelated entity ID

Sample Response

{
  "status": "success",
  "message": "Board items retrieved successfully",
  "data": {
    "items": [
      {
        "id": 1,
        "name": "Task 1",
        "board_id": 1,
        "type": "tasks",
        "rel_id": 1,
        "status": 1,
        "priority": 2,
        "duedate": "2024-01-20",
        "order": 1
      }
    ]
  }
}

14.6 – POST Create Board Item

POST/api/v1/kanban/items

Create a new item on a kanban board.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: name, board_id, type",
  "name": "New Task",
  "_comment_name": "Required - Item name",
  "board_id": 1,
  "_comment_board_id": "Required - Board ID (integer)",
  "type": "tasks",
  "_comment_type": "Required - Entity type: 'projects', 'tasks', 'leads', 'invoices', 'estimates'",
  "rel_id": 1,
  "_comment_rel_id": "Optional - Related entity ID",
  "status": 1,
  "_comment_status": "Optional - Status ID",
  "priority": 2,
  "_comment_priority": "Optional - Priority: 1=Low, 2=Medium, 3=High, 4=Urgent",
  "duedate": "2024-01-20",
  "_comment_duedate": "Optional - Due date (format: Y-m-d)",
  "order": 1,
  "_comment_order": "Optional - Display order within board"
}

Sample Response

{
  "status": "success",
  "message": "Board item created successfully",
  "data": {
    "id": 123
  }
}

14.7 – PUT Update Board Item

PUT/api/v1/kanban/items/{id}

Update an existing kanban board item.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Updated Task",
  "_comment_name": "Optional - Item name",
  "board_id": 2,
  "_comment_board_id": "Optional - Move to different board",
  "status": 2,
  "_comment_status": "Optional - Status ID",
  "priority": 3,
  "_comment_priority": "Optional - Priority",
  "duedate": "2024-01-25",
  "_comment_duedate": "Optional - Due date",
  "order": 2,
  "_comment_order": "Optional - Display order"
}

Sample Response

{
  "status": "success",
  "message": "Board item updated successfully"
}

14.8 – DELETE Delete Board Item

DELETE/api/v1/kanban/items/{id}

Delete a kanban board item.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Board item deleted successfully"
}

Categories / Knowledgebase

Knowledgebase endpoints.

15.1 – GET List Categories

GET/api/v1/kb/categories

Retrieve list of knowledge base categories (groups).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Groups retrieved successfully",
  "data": {
    "groups": [
      {
        "groupid": 1,
        "name": "Getting Started",
        "group_slug": "getting-started",
        "description": "Basic information to get you started",
        "active": 1,
        "color": "#3b82f6",
        "group_order": 1,
        "articles_count": 5
      },
      {
        "groupid": 2,
        "name": "FAQ",
        "group_slug": "faq",
        "description": "Frequently asked questions",
        "active": 1,
        "color": "#10b981",
        "group_order": 2,
        "articles_count": 12
      }
    ]
  }
}

15.2 – POST Create Category

POST/api/v1/kb/categories

Create a new knowledge base category.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required field: name",
  "name": "API Documentation",
  "_comment_name": "Required - Category name",
  "description": "API related articles",
  "_comment_description": "Optional - Category description",
  "active": 1,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active (default: 1)",
  "color": "#8b5cf6",
  "_comment_color": "Optional - Category color (hex code)",
  "group_order": 3,
  "_comment_group_order": "Optional - Display order (integer)"
}

Sample Response

{
  "status": "success",
  "message": "Category created successfully",
  "data": {
    "id": 123
  }
}

15.3 – PUT Update Category

PUT/api/v1/kb/categories/{id}

Update an existing knowledge base category.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "API Documentation - Updated",
  "_comment_name": "Optional - Category name",
  "description": "Updated description",
  "_comment_description": "Optional - Category description",
  "active": 0,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active",
  "color": "#6366f1",
  "_comment_color": "Optional - Category color",
  "group_order": 4,
  "_comment_group_order": "Optional - Display order"
}

Sample Response

{
  "status": "success",
  "message": "Category updated successfully"
}

15.4 – DELETE Delete Category

DELETE/api/v1/kb/categories/{id}

Delete a knowledge base category.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Category deleted successfully"
}

15.5 – GET List Articles

GET/api/v1/kb/articles?groupid={groupid}&page=1&per_page=20

Retrieve list of knowledge base articles.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
groupidFilter by category/group ID
pagePage number
per_pageItems per page

Sample Response

{
  "status": "success",
  "message": "Articles retrieved successfully",
  "data": {
    "articles": [
      {
        "articleid": 1,
        "subject": "How to Get Started",
        "slug": "how-to-get-started",
        "articlegroup": 1,
        "description": "This article explains how to get started with the platform.",
        "staff_article": 0,
        "datecreated": "2024-01-15 10:30:00",
        "article_order": 1,
        "views": 150,
        "active": 1
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    }
  }
}

15.6 – POST Create Article

POST/api/v1/kb/articles

Create a new knowledge base article.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: subject, articlegroup, description",
  "subject": "How to Use the API",
  "_comment_subject": "Required - Article title/subject (max 191 characters)",
  "articlegroup": 1,
  "_comment_articlegroup": "Required - Category/group ID (integer)",
  "description": "This article explains how to use the API endpoints.",
  "_comment_description": "Required - Article content/description",
  "staff_article": 0,
  "_comment_staff_article": "Optional - Staff only article: 0=No, 1=Yes (default: 0)",
  "article_order": 1,
  "_comment_article_order": "Optional - Display order within category (integer)",
  "active": 1,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active (default: 1)"
}

Sample Response

{
  "status": "success",
  "message": "Article created successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "subject": "The subject field is required",
    "articlegroup": "The articlegroup field is required",
    "description": "The description field is required"
  },
  "code": 422
}

15.7 – GET Get Article

GET/api/v1/kb/articles/{id}

Retrieve a specific knowledge base article by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Article retrieved successfully",
  "data": {
    "articleid": 1,
    "subject": "How to Get Started",
    "slug": "how-to-get-started",
    "articlegroup": 1,
    "group_name": "Getting Started",
    "description": "This article explains how to get started with the platform.",
    "staff_article": 0,
    "datecreated": "2024-01-15 10:30:00",
    "article_order": 1,
    "views": 150,
    "active": 1,
    "attachments": []
  }
}

15.8 – PUT Update Article

PUT/api/v1/kb/articles/{id}

Update an existing knowledge base article.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "subject": "How to Use the API - Updated",
  "_comment_subject": "Optional - Article title (max 191 characters)",
  "articlegroup": 2,
  "_comment_articlegroup": "Optional - Category/group ID",
  "description": "Updated article content.",
  "_comment_description": "Optional - Article content",
  "staff_article": 1,
  "_comment_staff_article": "Optional - Staff only article: 0=No, 1=Yes",
  "article_order": 2,
  "_comment_article_order": "Optional - Display order",
  "active": 0,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active"
}

Sample Response

{
  "status": "success",
  "message": "Article updated successfully"
}

15.9 – DELETE Delete Article

DELETE/api/v1/kb/articles/{id}

Delete a knowledge base article.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Article deleted successfully"
}

Leads

Lead endpoints.

16.1 – GET List Leads

GET/api/v1/leads/index?page=1&per_page=20&search=john&status=1&source=2&assigned=3

Retrieve paginated list of leads with optional filtering.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
searchSearch by lead name, email, or company
statusFilter by status ID
sourceFilter by source ID
assignedFilter by assigned staff ID

Sample Response

{
  "status": "success",
  "message": "Leads retrieved successfully",
  "data": {
    "leads": [
      {
        "id": 1,
        "name": "John Doe",
        "email": "[email protected]",
        "phonenumber": "+1234567890",
        "company": "ACME Corp",
        "status": 1,
        "status_name": "New",
        "source": 1,
        "source_name": "Website",
        "assigned": 1,
        "lead_value": "5000.00",
        "dateadded": "2024-01-15 10:30:00",
        "lastcontact": "2024-01-16 14:20:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 150,
      "total_pages": 8
    }
  }
}

16.2 – POST Create Leads

POST/api/v1/leads/store

Create a new lead.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: name, email",
  "name": "John Doe",
  "_comment_name": "Required - Lead name (max 100 characters)",
  "email": "[email protected]",
  "_comment_email": "Required - Lead email (valid email, max 100 characters)",
  "phonenumber": "+1234567890",
  "_comment_phonenumber": "Optional - Phone number (max 50 characters)",
  "company": "ACME Corp",
  "_comment_company": "Optional - Company name (max 200 characters)",
  "title": "CEO",
  "_comment_title": "Optional - Job title (max 100 characters)",
  "website": "https://example.com",
  "_comment_website": "Optional - Website URL (max 150 characters)",
  "description": "Potential client for web development",
  "_comment_description": "Optional - Lead description (max 65000 characters)",
  "address": "123 Main St, City, State",
  "_comment_address": "Optional - Address (max 200 characters)",
  "city": "New York",
  "_comment_city": "Optional - City (max 100 characters)",
  "state": "NY",
  "_comment_state": "Optional - State (max 50 characters)",
  "country": 1,
  "_comment_country": "Optional - Country ID (integer)",
  "zip": "10001",
  "_comment_zip": "Optional - ZIP code (max 15 characters)",
  "status": 1,
  "_comment_status": "Optional - Lead status ID (default: system default)",
  "source": 1,
  "_comment_source": "Optional - Lead source ID (default: system default)",
  "assigned": 1,
  "_comment_assigned": "Optional - Assigned staff ID (integer)",
  "lead_value": 5000.00,
  "_comment_lead_value": "Optional - Potential lead value (decimal)",
  "is_public": false,
  "_comment_is_public": "Optional - Is lead public: true/false (default: false)"
}

Sample Response

{
  "status": "success",
  "message": "Lead created successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "Lead with this email already exists",
  "code": 400
}

16.3 – GET Get Leads

GET/api/v1/leads/show?id={id}

Retrieve a specific lead by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idLead ID

Sample Response

{
  "status": "success",
  "message": "Lead retrieved successfully",
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "[email protected]",
    "phonenumber": "+1234567890",
    "company": "ACME Corp",
    "title": "CEO",
    "website": "https://example.com",
    "description": "Potential client",
    "address": "123 Main St",
    "city": "New York",
    "state": "NY",
    "country": 1,
    "zip": "10001",
    "status": 1,
    "status_name": "New",
    "source": 1,
    "source_name": "Website",
    "assigned": 1,
    "lead_value": "5000.00",
    "dateadded": "2024-01-15 10:30:00",
    "lastcontact": "2024-01-16 14:20:00",
    "is_public": 0,
    "attachments": [],
    "public_url": "https://example.com/leads/public/abc123"
  }
}

16.4 – PUT Update Leads

PUT/api/v1/leads/update?id={id}

Update an existing lead.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idLead ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "John Doe Updated",
  "_comment_name": "Optional - Lead name (max 100 characters)",
  "email": "[email protected]",
  "_comment_email": "Optional - Lead email (valid email, max 100 characters)",
  "phonenumber": "+1987654321",
  "_comment_phonenumber": "Optional - Phone number",
  "company": "ACME Corp Updated",
  "_comment_company": "Optional - Company name",
  "status": 2,
  "_comment_status": "Optional - Lead status ID",
  "source": 2,
  "_comment_source": "Optional - Lead source ID",
  "assigned": 2,
  "_comment_assigned": "Optional - Assigned staff ID",
  "lead_value": 7500.00,
  "_comment_lead_value": "Optional - Potential lead value",
  "is_public": true,
  "_comment_is_public": "Optional - Is lead public"
}

Sample Response

{
  "status": "success",
  "message": "Lead updated successfully"
}

16.5 – DELETE Delete Leads

DELETE/api/v1/leads/destroy?id={id}

Delete a lead.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idLead ID

Sample Response

{
  "status": "success",
  "message": "Lead deleted successfully"
}

16.6 – GET Import Leads

GET/api/v1/leads/import?format={format}

Get import template or initiate lead import process.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
formatImport format: 'csv', 'xlsx', 'json' (default: 'csv')

Sample Response

{
  "status": "success",
  "message": "Import template retrieved successfully",
  "data": {
    "template_url": "https://example.com/templates/leads_import.csv",
    "format": "csv",
    "required_fields": ["name", "email"],
    "optional_fields": ["phonenumber", "company", "status", "source", "assigned", "lead_value"],
    "instructions": "Download the template, fill in the data, and upload via POST /api/v1/leads/import"
  }
}

16.7 – GET Convert Lead

GET/api/v1/leads/convert?id={id}&convert_to={type}

Convert a lead to a customer or other entity.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Optional field: convert_to",
  "convert_to": "customer",
  "_comment_convert_to": "Optional - Conversion type: 'customer' (default: 'customer')",
  "do_not_redirect": false,
  "_comment_do_not_redirect": "Optional - Do not redirect: true/false (default: false)"
}

Sample Response

{
  "status": "success",
  "message": "Lead converted successfully",
  "data": {
    "converted_to": "customer",
    "customer_id": 123,
    "redirect_url": "https://example.com/clients/client/123"
  }
}

Notes

Notes endpoints.

17.1 – GET List Notes

GET/api/v1/notes/index?rel_type={type}&rel_id={id}&page=1&per_page=20

Retrieve list of notes for a specific entity.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
rel_typeRelated entity type (e.g., 'customer', 'lead', 'project', 'task', 'invoice', 'estimate', 'ticket')
rel_idRelated entity ID
pagePage number
per_pageItems per page

Sample Response

{
  "status": "success",
  "message": "Notes retrieved successfully",
  "data": {
    "notes": [
      {
        "id": 1,
        "rel_type": "customer",
        "rel_id": 123,
        "description": "Customer called regarding invoice payment",
        "date_contacted": "2024-01-15 10:30:00",
        "addedfrom": 1,
        "addedfrom_name": "John Doe",
        "dateadded": "2024-01-15 10:30:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    }
  }
}

17.2 – POST Create Notes

POST/api/v1/notes/store

Create a new note.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: rel_type, rel_id, description",
  "rel_type": "customer",
  "_comment_rel_type": "Required - Related entity type: 'customer', 'lead', 'project', 'task', 'invoice', 'estimate', 'ticket'",
  "rel_id": 123,
  "_comment_rel_id": "Required - Related entity ID (integer)",
  "description": "Customer called regarding invoice payment. Will pay by end of week.",
  "_comment_description": "Required - Note description/content",
  "date_contacted": "2024-01-15 10:30:00",
  "_comment_date_contacted": "Optional - Contact date (format: Y-m-d H:i:s)",
  "is_public": 0,
  "_comment_is_public": "Optional - Is note public: 0=No, 1=Yes (default: 0)"
}

Sample Response

{
  "status": "success",
  "message": "Note created successfully",
  "data": {
    "id": 123
  }
}

17.3 – GET Get Notes

GET/api/v1/notes/show?id={id}

Retrieve a specific note by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idNote ID

Sample Response

{
  "status": "success",
  "message": "Note retrieved successfully",
  "data": {
    "id": 1,
    "rel_type": "customer",
    "rel_id": 123,
    "description": "Customer called regarding invoice payment. Will pay by end of week.",
    "date_contacted": "2024-01-15 10:30:00",
    "addedfrom": 1,
    "addedfrom_name": "John Doe",
    "dateadded": "2024-01-15 10:30:00",
    "is_public": 0
  }
}

17.4 – PUT Update Notes

PUT/api/v1/notes/update?id={id}

Update an existing note.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idNote ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "description": "Updated note content - Customer confirmed payment will be made.",
  "_comment_description": "Optional - Note description/content",
  "date_contacted": "2024-01-16 14:20:00",
  "_comment_date_contacted": "Optional - Contact date (format: Y-m-d H:i:s)",
  "is_public": 1,
  "_comment_is_public": "Optional - Is note public: 0=No, 1=Yes"
}

Sample Response

{
  "status": "success",
  "message": "Note updated successfully"
}

17.5 – DELETE Delete Notes

DELETE/api/v1/notes/destroy?id={id}

Delete a note.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idNote ID

Sample Response

{
  "status": "success",
  "message": "Note deleted successfully"
}

Notifications

Notification endpoints.

18.1 – GET List Notifications

GET/api/v1/notifications/index?is_read={status}&page=1&per_page=20

Retrieve list of notifications for the current user.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
is_readFilter by read status: 0=Unread, 1=Read
pagePage number
per_pageItems per page

Sample Response

{
  "status": "success",
  "message": "Notifications retrieved successfully",
  "data": {
    "notifications": [
      {
        "id": 1,
        "description": "New invoice #INV-000001 created",
        "date": "2024-01-15 10:30:00",
        "is_read": 0,
        "from_user_id": 1,
        "from_user_name": "John Doe",
        "from_company": null,
        "link": "/invoices/list_invoices/1",
        "additional_data": null
      },
      {
        "id": 2,
        "description": "Task assigned to you: Design homepage",
        "date": "2024-01-15 09:15:00",
        "is_read": 1,
        "from_user_id": 2,
        "from_user_name": "Jane Smith",
        "from_company": null,
        "link": "/tasks/view/5",
        "additional_data": null
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    },
    "unread_count": 12
  }
}

18.2 – POST Mark As Read

POST/api/v1/notifications/mark_as_read

Mark one or more notifications as read.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Optional fields: notification_id, mark_all",
  "notification_id": 1,
  "_comment_notification_id": "Optional - Specific notification ID to mark as read (integer). If not provided and mark_all is false, marks all as read.",
  "mark_all": false,
  "_comment_mark_all": "Optional - Mark all notifications as read: true/false (default: false)"
}

Sample Response

{
  "status": "success",
  "message": "Notification(s) marked as read successfully",
  "data": {
    "marked_count": 1
  }
}

18.3 – DELETE Clear Notifications

DELETE/api/v1/notifications/clear?is_read={status}

Clear/delete notifications for the current user.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
is_readFilter by read status: 0=Unread, 1=Read (if not provided, clears all)

Sample Response

{
  "status": "success",
  "message": "Notifications cleared successfully",
  "data": {
    "cleared_count": 25
  }
}

Tags

Tags endpoints.

19.1 – GET List Tags

GET/api/v1/tags/index?rel_type={type}&page=1&per_page=20

Retrieve list of tags, optionally filtered by related entity type.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
rel_typeFilter by related entity type (e.g., 'customer', 'lead', 'project', 'task', 'invoice', 'estimate', 'ticket', 'proposal')
pagePage number
per_pageItems per page

Sample Response

{
  "status": "success",
  "message": "Tags retrieved successfully",
  "data": {
    "tags": [
      {
        "id": 1,
        "name": "VIP",
        "rel_type": "customer",
        "rel_id": 123,
        "color": "#ff0000",
        "datecreated": "2024-01-15 10:30:00"
      },
      {
        "id": 2,
        "name": "Urgent",
        "rel_type": "task",
        "rel_id": 456,
        "color": "#ff9900",
        "datecreated": "2024-01-15 11:00:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    }
  }
}

19.2 – POST Create Tags

POST/api/v1/tags/store

Create a new tag.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: name, rel_type, rel_id",
  "name": "Important",
  "_comment_name": "Required - Tag name",
  "rel_type": "customer",
  "_comment_rel_type": "Required - Related entity type: 'customer', 'lead', 'project', 'task', 'invoice', 'estimate', 'ticket', 'proposal'",
  "rel_id": 123,
  "_comment_rel_id": "Required - Related entity ID (integer)",
  "color": "#3b82f6",
  "_comment_color": "Optional - Tag color (hex code)"
}

Sample Response

{
  "status": "success",
  "message": "Tag created successfully",
  "data": {
    "id": 123
  }
}

19.3 – GET Get Tags

GET/api/v1/tags/show?id={id}

Retrieve a specific tag by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTag ID

Sample Response

{
  "status": "success",
  "message": "Tag retrieved successfully",
  "data": {
    "id": 1,
    "name": "VIP",
    "rel_type": "customer",
    "rel_id": 123,
    "color": "#ff0000",
    "datecreated": "2024-01-15 10:30:00"
  }
}

19.4 – PUT Update Tags

PUT/api/v1/tags/update?id={id}

Update an existing tag.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTag ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "VIP - Updated",
  "_comment_name": "Optional - Tag name",
  "color": "#ff9900",
  "_comment_color": "Optional - Tag color (hex code)"
}

Sample Response

{
  "status": "success",
  "message": "Tag updated successfully"
}

19.5 – DELETE Delete Tags

DELETE/api/v1/tags/destroy?id={id}

Delete a tag.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTag ID

Sample Response

{
  "status": "success",
  "message": "Tag deleted successfully"
}

Proposals

Proposal endpoints.

20.1 – GET List Proposals

GET/api/v1/proposals/index?page=1&per_page=20&search=project&client_id=123&status=1

Retrieve paginated list of proposals with optional filtering.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
searchSearch by proposal subject
client_idFilter by client ID
statusFilter by status ID

Sample Response

{
  "status": "success",
  "message": "Proposals retrieved successfully",
  "data": {
    "proposals": [
      {
        "id": 1,
        "subject": "Website Development Proposal",
        "rel_type": "customer",
        "rel_id": 123,
        "client_name": "ACME Corp",
        "date": "2024-01-15",
        "open_till": "2024-02-15",
        "total": "5000.00",
        "status": 1,
        "datecreated": "2024-01-15 10:30:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 150,
      "total_pages": 8
    }
  }
}

20.2 – POST Create Proposal

POST/api/v1/proposals/store

Create a new proposal.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: subject, rel_type, rel_id, date",
  "subject": "Website Development Proposal",
  "_comment_subject": "Required - Proposal subject/title (max 191 characters)",
  "rel_type": "customer",
  "_comment_rel_type": "Required - Related entity type: 'customer' or 'lead'",
  "rel_id": 123,
  "_comment_rel_id": "Required - Related entity ID (integer)",
  "date": "2024-01-15",
  "_comment_date": "Required - Proposal date (format: Y-m-d)",
  "open_till": "2024-02-15",
  "_comment_open_till": "Optional - Proposal expiry date (format: Y-m-d)",
  "currency": 1,
  "_comment_currency": "Optional - Currency ID (integer)",
  "assigned": 1,
  "_comment_assigned": "Optional - Assigned staff ID (integer)",
  "discount_type": "percentage",
  "_comment_discount_type": "Optional - Discount type: 'percentage' or 'before_tax' or 'after_tax'",
  "discount_percent": 10,
  "_comment_discount_percent": "Optional - Discount percentage (decimal)",
  "discount_total": 500.00,
  "_comment_discount_total": "Optional - Discount total amount (decimal)",
  "subtotal": 5000.00,
  "_comment_subtotal": "Optional - Subtotal amount (decimal)",
  "total": 4500.00,
  "_comment_total": "Optional - Total amount (decimal)",
  "status": 1,
  "_comment_status": "Optional - Proposal status ID (integer)",
  "content": "Proposal content/description",
  "_comment_content": "Optional - Proposal content/description"
}

Sample Response

{
  "status": "success",
  "message": "Proposal created successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "subject": "The subject field is required",
    "rel_type": "The rel_type field must be one of: customer, lead",
    "date": "The date field is required"
  },
  "code": 422
}

20.3 – GET Get Proposal

GET/api/v1/proposals/show?id={id}

Retrieve a specific proposal by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idProposal ID

Sample Response

{
  "status": "success",
  "message": "Proposal retrieved successfully",
  "data": {
    "id": 1,
    "subject": "Website Development Proposal",
    "rel_type": "customer",
    "rel_id": 123,
    "date": "2024-01-15",
    "open_till": "2024-02-15",
    "total": "5000.00",
    "status": 1,
    "currency": 1,
    "assigned": 1,
    "content": "Proposal content/description",
    "attachments": [],
    "comments": []
  }
}

20.4 – PUT Update Proposal

PUT/api/v1/proposals/update?id={id}

Update an existing proposal.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idProposal ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "subject": "Website Development Proposal - Updated",
  "_comment_subject": "Optional - Proposal subject (max 191 characters)",
  "date": "2024-01-20",
  "_comment_date": "Optional - Proposal date (format: Y-m-d)",
  "open_till": "2024-02-20",
  "_comment_open_till": "Optional - Proposal expiry date (format: Y-m-d)",
  "status": 2,
  "_comment_status": "Optional - Proposal status ID",
  "total": 5500.00,
  "_comment_total": "Optional - Total amount"
}

Sample Response

{
  "status": "success",
  "message": "Proposal updated successfully"
}

20.5 – DELETE Delete Proposal

DELETE/api/v1/proposals/destroy?id={id}

Delete a proposal.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idProposal ID

Sample Response

{
  "status": "success",
  "message": "Proposal deleted successfully"
}

20.6 – POST Send Proposal

POST/api/v1/proposals/send?id={id}

Send a proposal to the client via email.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idProposal ID

Request Body

{
  "_comment": "All fields are optional",
  "attach_pdf": true,
  "_comment_attach_pdf": "Optional - Attach PDF to email: true/false (default: true)",
  "cc": "[email protected]",
  "_comment_cc": "Optional - CC email addresses (comma-separated)"
}

Sample Response

{
  "status": "success",
  "message": "Proposal sent to client successfully"
}

20.7 – GET Statuses

GET/api/v1/proposals/statuses

Retrieve all available proposal statuses.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Proposal statuses retrieved successfully",
  "data": {
    "statuses": [
      {
        "id": 1,
        "name": "Draft",
        "color": "#64748b"
      },
      {
        "id": 2,
        "name": "Sent",
        "color": "#3b82f6"
      },
      {
        "id": 3,
        "name": "Open",
        "color": "#10b981"
      },
      {
        "id": 4,
        "name": "Accepted",
        "color": "#22c55e"
      },
      {
        "id": 5,
        "name": "Declined",
        "color": "#ef4444"
      }
    ]
  }
}

Income Reports

Finance report endpoints.

21.1 – GET Income Report

GET/api/v1/reports/income?year=2024&month=1&currency=1

Retrieve income report data.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
yearYear for the report
monthMonth for the report (1-12)
currencyFilter by currency ID

Sample Response

{
  "status": "success",
  "message": "Income report retrieved successfully",
  "data": {
    "total_income": 125000.00,
    "invoices": {
      "total": 100000.00,
      "count": 45,
      "paid": 85000.00,
      "unpaid": 15000.00
    },
    "payments": {
      "total": 85000.00,
      "count": 38,
      "by_month": [
        {
          "month": "2024-01",
          "amount": 25000.00
        }
      ]
    },
    "by_currency": [
      {
        "currency_id": 1,
        "currency_name": "USD",
        "total": 125000.00
      }
    ]
  }
}

21.2 – GET Expense Report

GET/api/v1/reports/expenses?year=2024&category=1

Retrieve expense report data.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
yearYear for the report
categoryFilter by expense category ID

Sample Response

{
  "status": "success",
  "message": "Expenses report retrieved successfully",
  "data": {
    "total_expenses": 35000.00,
    "expenses_vs_income": [
      {
        "month": "2024-01",
        "income": 25000.00,
        "expenses": 5000.00,
        "profit": 20000.00
      }
    ],
    "by_category": [
      {
        "category_id": 1,
        "category_name": "Office Supplies",
        "total": 5000.00,
        "count": 12
      }
    ],
    "category_report": {
      "labels": ["Jan", "Feb", "Mar"],
      "data": [5000, 6000, 7000]
    }
  }
}

21.3 – GET Profit Loss Report

GET/api/v1/reports/profit-loss?year=2024&month=1

Retrieve profit and loss report data.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
yearYear for the report
monthMonth for the report (1-12)

Sample Response

{
  "status": "success",
  "message": "Profit loss report retrieved successfully",
  "data": {
    "total_income": 125000.00,
    "total_expenses": 35000.00,
    "net_profit": 90000.00,
    "profit_margin": 72.00,
    "by_month": [
      {
        "month": "2024-01",
        "income": 25000.00,
        "expenses": 5000.00,
        "profit": 20000.00,
        "margin": 80.00
      }
    ],
    "by_category": {
      "income": [
        {
          "category": "Invoices",
          "amount": 100000.00
        }
      ],
      "expenses": [
        {
          "category": "Office Supplies",
          "amount": 5000.00
        }
      ]
    }
  }
}

21.4 – GET Project Summary

GET/api/v1/reports/projects?status=1&assigned=1&client_id=123

Retrieve project summary report data.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
statusFilter by project status ID
assignedFilter by assigned staff ID
client_idFilter by client ID

Sample Response

{
  "status": "success",
  "message": "Project summary report retrieved successfully",
  "data": {
    "total_projects": 25,
    "by_status": [
      {
        "status_id": 1,
        "status_name": "Not Started",
        "count": 5
      },
      {
        "status_id": 2,
        "status_name": "In Progress",
        "count": 15
      },
      {
        "status_id": 3,
        "status_name": "On Hold",
        "count": 3
      },
      {
        "status_id": 4,
        "status_name": "Completed",
        "count": 2
      }
    ],
    "by_client": [
      {
        "client_id": 123,
        "client_name": "ACME Corp",
        "project_count": 5,
        "total_value": 50000.00
      }
    ],
    "by_staff": [
      {
        "staff_id": 1,
        "staff_name": "John Doe",
        "project_count": 10,
        "completed": 8
      }
    ],
    "total_value": 250000.00,
    "completed_value": 150000.00
  }
}

21.5 – GET Tasks Summary

GET/api/v1/reports/tasks?status=1&assigned=1&project_id=123

Retrieve tasks summary report data.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
statusFilter by task status ID
assignedFilter by assigned staff ID
project_idFilter by project ID

Sample Response

{
  "status": "success",
  "message": "Tasks summary report retrieved successfully",
  "data": {
    "total_tasks": 150,
    "by_status": [
      {
        "status_id": 1,
        "status_name": "Not Started",
        "count": 30
      },
      {
        "status_id": 2,
        "status_name": "In Progress",
        "count": 80
      },
      {
        "status_id": 3,
        "status_name": "Testing",
        "count": 20
      },
      {
        "status_id": 4,
        "status_name": "Awaiting Feedback",
        "count": 10
      },
      {
        "status_id": 5,
        "status_name": "Complete",
        "count": 10
      }
    ],
    "by_priority": [
      {
        "priority": 1,
        "priority_name": "Low",
        "count": 50
      },
      {
        "priority": 2,
        "priority_name": "Medium",
        "count": 70
      },
      {
        "priority": 3,
        "priority_name": "High",
        "count": 25
      },
      {
        "priority": 4,
        "priority_name": "Urgent",
        "count": 5
      }
    ],
    "by_staff": [
      {
        "staff_id": 1,
        "staff_name": "John Doe",
        "total": 50,
        "completed": 40,
        "in_progress": 8,
        "not_started": 2
      }
    ],
    "overdue": 5,
    "due_today": 10,
    "due_this_week": 25
  }
}

Roles

Role endpoints.

22.1 – GET List Roles

GET/api/v1/roles/index

Retrieve list of all roles.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Roles retrieved successfully",
  "data": {
    "roles": [
      {
        "roleid": 1,
        "name": "Administrator",
        "permissions": {}
      },
      {
        "roleid": 2,
        "name": "Manager",
        "permissions": {
          "customers": {
            "view": true,
            "create": true,
            "edit": true,
            "delete": false
          }
        }
      }
    ]
  }
}

22.2 – POST Create Role

POST/api/v1/roles/store

Create a new role.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required field: name",
  "name": "Sales Representative",
  "_comment_name": "Required - Role name (max 50 characters)",
  "permissions": {
    "_comment_permissions": "Optional - Role permissions object",
    "customers": {
      "view": true,
      "create": true,
      "edit": true,
      "delete": false
    },
    "invoices": {
      "view": true,
      "create": true,
      "edit": false,
      "delete": false
    }
  }
}

Sample Response

{
  "status": "success",
  "message": "Role created successfully",
  "data": {
    "id": 123
  }
}

22.3 – GET Get Role

GET/api/v1/roles/show?id={id}

Retrieve a specific role by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idRole ID

Sample Response

{
  "status": "success",
  "message": "Role retrieved successfully",
  "data": {
    "roleid": 2,
    "name": "Manager",
    "permissions": {
      "customers": {
        "view": true,
        "create": true,
        "edit": true,
        "delete": false
      }
    }
  }
}

22.4 – PUT Update Role

PUT/api/v1/roles/update?id={id}

Update an existing role.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idRole ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Sales Representative - Updated",
  "_comment_name": "Optional - Role name (max 50 characters)",
  "permissions": {
    "_comment_permissions": "Optional - Role permissions object",
    "customers": {
      "view": true,
      "create": true,
      "edit": true,
      "delete": true
    }
  }
}

Sample Response

{
  "status": "success",
  "message": "Role updated successfully"
}

22.5 – DELETE Delete Role

DELETE/api/v1/roles/destroy?id={id}

Delete a role.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idRole ID

Sample Response

{
  "status": "success",
  "message": "Role deleted successfully"
}

General Settings

General settings endpoints.

23.1 – GET General Settings

GET/api/v1/settings/general

Retrieve general settings.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Settings retrieved successfully",
  "data": {
    "company_name": "Zealdash CRM",
    "company_logo": "logo.png",
    "company_logo_dark": "logo_dark.png",
    "favicon": "favicon.ico",
    "admin_area_title": "Zealdash Admin",
    "clients_area_title": "Zealdash Client Portal",
    "company_phonenumber": "+1234567890",
    "company_address": "123 Main St",
    "company_city": "New York",
    "company_state": "NY",
    "company_zip": "10001",
    "company_country": 1,
    "company_vat": "VAT123456",
    "company_website": "https://example.com",
    "default_language": "english",
    "active_language": "english",
    "timezone": "America/New_York",
    "date_format": "d/m/Y",
    "time_format": "H:i"
  }
}

23.2 – PUT Update General Settings

PUT/api/v1/settings/general/update

Update general settings.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "company_name": "Updated Company Name",
  "_comment_company_name": "Optional - Company name (max 200 characters)",
  "company_phonenumber": "+1987654321",
  "_comment_company_phonenumber": "Optional - Phone number (max 50 characters)",
  "company_address": "456 Oak Ave",
  "_comment_company_address": "Optional - Address (max 500 characters)",
  "company_city": "Los Angeles",
  "_comment_company_city": "Optional - City",
  "company_state": "CA",
  "_comment_company_state": "Optional - State",
  "company_zip": "90210",
  "_comment_company_zip": "Optional - ZIP code",
  "company_country": 1,
  "_comment_company_country": "Optional - Country ID",
  "default_language": "english",
  "_comment_default_language": "Optional - Default language",
  "timezone": "America/Los_Angeles",
  "_comment_timezone": "Optional - Timezone (must be valid timezone identifier)",
  "date_format": "m/d/Y",
  "_comment_date_format": "Optional - Date format: 'd/m/Y', 'm/d/Y', 'Y/m/d', etc.",
  "time_format": "g:i A",
  "_comment_time_format": "Optional - Time format: 'H:i', 'g:i A', 'g:i a'"
}

Sample Response

{
  "status": "success",
  "message": "Settings updated successfully",
  "data": {
    "updated_count": 5
  }
}

23.3 – GET Invoice Settings

GET/api/v1/settings/invoice

Retrieve invoice-related settings.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Settings retrieved successfully",
  "data": {
    "invoice_prefix": "INV-",
    "invoice_number_format": "{number}",
    "next_invoice_number": 1001,
    "invoice_due_after": 30,
    "default_tax": 0,
    "invoice_auto_operations_hour": 9,
    "invoice_reminders_enabled": true,
    "invoice_reminder_days": [7, 3, 1]
  }
}

23.4 – PUT Update Invoice Settings

PUT/api/v1/settings/invoice/update

Update invoice-related settings.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "invoice_prefix": "INV-",
  "_comment_invoice_prefix": "Optional - Invoice number prefix",
  "invoice_number_format": "{number}",
  "_comment_invoice_number_format": "Optional - Invoice number format",
  "next_invoice_number": 1001,
  "_comment_next_invoice_number": "Optional - Next invoice number (integer)",
  "invoice_due_after": 30,
  "_comment_invoice_due_after": "Optional - Days until invoice due (integer)",
  "default_tax": 0,
  "_comment_default_tax": "Optional - Default tax ID (integer)",
  "invoice_auto_operations_hour": 9,
  "_comment_invoice_auto_operations_hour": "Optional - Auto operations hour (0-23)"
}

Sample Response

{
  "status": "success",
  "message": "Settings updated successfully"
}

23.5 – GET Email Settings

GET/api/v1/settings/email

Retrieve email-related settings.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Settings retrieved successfully",
  "data": {
    "mail_engine": "smtp",
    "smtp_host": "smtp.gmail.com",
    "smtp_port": "587",
    "smtp_username": "[email protected]",
    "smtp_password": "********",
    "smtp_encryption": "tls",
    "email_header": "Email header content",
    "email_footer": "Email footer content",
    "email_signature": "Best regards",
    "bcc_emails": ""
  }
}

23.6 – PUT Update Email Settings

PUT/api/v1/settings/email/update

Update email-related settings.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "mail_engine": "smtp",
  "_comment_mail_engine": "Optional - Mail engine: 'smtp' or 'sendmail'",
  "smtp_host": "smtp.example.com",
  "_comment_smtp_host": "Optional - SMTP host",
  "smtp_port": "465",
  "_comment_smtp_port": "Optional - SMTP port (1-65535)",
  "smtp_username": "[email protected]",
  "_comment_smtp_username": "Optional - SMTP username",
  "smtp_password": "newpassword",
  "_comment_smtp_password": "Optional - SMTP password",
  "smtp_encryption": "ssl",
  "_comment_smtp_encryption": "Optional - SMTP encryption: 'tls', 'ssl', or ''",
  "email_header": "Updated header",
  "_comment_email_header": "Optional - Email header content",
  "email_footer": "Updated footer",
  "_comment_email_footer": "Optional - Email footer content",
  "email_signature": "Best regards,\nTeam",
  "_comment_email_signature": "Optional - Email signature",
  "bcc_emails": "[email protected]",
  "_comment_bcc_emails": "Optional - BCC email addresses (comma-separated)"
}

Sample Response

{
  "status": "success",
  "message": "Settings updated successfully"
}

Staff

Staff endpoints.

24.1 – GET List Staff

GET/api/v1/staff/index?page=1&per_page=20&search=john&active=1

Retrieve paginated list of staff members with optional filtering.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
searchSearch by staff name or email
activeFilter by active status: 0=Inactive, 1=Active

Sample Response

{
  "status": "success",
  "message": "Staff retrieved successfully",
  "data": {
    "staff": [
      {
        "staffid": 1,
        "email": "[email protected]",
        "firstname": "John",
        "lastname": "Doe",
        "phonenumber": "+1234567890",
        "facebook": "john.doe",
        "linkedin": "john-doe",
        "skype": "john.doe",
        "role": 1,
        "active": 1,
        "profile_image": "profile.jpg",
        "last_ip": "192.168.1.1",
        "last_login": "2024-01-15 10:30:00",
        "last_activity": "2024-01-15 11:45:00",
        "datecreated": "2024-01-01 09:00:00",
        "hourly_rate": "50.00",
        "email_signature": "Best regards,\nJohn Doe"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 25,
      "total_pages": 2
    }
  }
}

24.2 – POST Create Staff

POST/api/v1/staff/store

Create a new staff member.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: firstname, lastname, email, password",
  "firstname": "Jane",
  "_comment_firstname": "Required - First name (max 50 characters)",
  "lastname": "Smith",
  "_comment_lastname": "Required - Last name (max 50 characters)",
  "email": "[email protected]",
  "_comment_email": "Required - Email address (valid email, must be unique)",
  "password": "securepassword123",
  "_comment_password": "Required - Password (min 6 characters)",
  "phonenumber": "+1987654321",
  "_comment_phonenumber": "Optional - Phone number (max 50 characters)",
  "facebook": "jane.smith",
  "_comment_facebook": "Optional - Facebook username (max 100 characters)",
  "linkedin": "jane-smith",
  "_comment_linkedin": "Optional - LinkedIn username (max 100 characters)",
  "skype": "jane.smith",
  "_comment_skype": "Optional - Skype username (max 100 characters)",
  "role": 2,
  "_comment_role": "Optional - Role ID (integer)",
  "active": true,
  "_comment_active": "Optional - Active status: true/false (default: true)",
  "hourly_rate": 45.00,
  "_comment_hourly_rate": "Optional - Hourly rate (decimal)",
  "email_signature": "Best regards,\nJane Smith",
  "_comment_email_signature": "Optional - Email signature",
  "direction": "ltr",
  "_comment_direction": "Optional - Text direction: 'ltr' or 'rtl' (default: 'ltr')",
  "send_welcome_email": true,
  "_comment_send_welcome_email": "Optional - Send welcome email: true/false (default: false)",
  "permissions": ["customers.view", "invoices.view"],
  "_comment_permissions": "Optional - Array of permission strings"
}

Sample Response

{
  "status": "success",
  "message": "Staff member created successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "email": "The email field must contain a unique value",
    "password": "The password field must be at least 6 characters in length"
  },
  "code": 400
}

24.3 – GET Get Staff

GET/api/v1/staff/show?id={id}

Retrieve a specific staff member by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idStaff ID

Sample Response

{
  "status": "success",
  "message": "Staff member retrieved successfully",
  "data": {
    "staffid": 1,
    "email": "[email protected]",
    "firstname": "John",
    "lastname": "Doe",
    "phonenumber": "+1234567890",
    "role": 1,
    "active": 1,
    "hourly_rate": "50.00",
    "permissions": {}
  }
}

24.4 – PUT Update Staff

PUT/api/v1/staff/update?id={id}

Update an existing staff member.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idStaff ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "firstname": "Jane Updated",
  "_comment_firstname": "Optional - First name (max 50 characters)",
  "lastname": "Smith Updated",
  "_comment_lastname": "Optional - Last name (max 50 characters)",
  "email": "[email protected]",
  "_comment_email": "Optional - Email address (valid email, must be unique if changed)",
  "password": "newpassword123",
  "_comment_password": "Optional - New password (min 6 characters)",
  "phonenumber": "+1555123456",
  "_comment_phonenumber": "Optional - Phone number",
  "role": 3,
  "_comment_role": "Optional - Role ID",
  "active": false,
  "_comment_active": "Optional - Active status: true/false",
  "hourly_rate": 55.00,
  "_comment_hourly_rate": "Optional - Hourly rate"
}

Sample Response

{
  "status": "success",
  "message": "Staff member updated successfully"
}

24.5 – DELETE Delete Staff

DELETE/api/v1/staff/destroy?id={id}

Delete a staff member. Cannot delete your own account.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idStaff ID

Sample Response

{
  "status": "success",
  "message": "Staff member deleted successfully"
}

Error Example

{
  "status": "error",
  "message": "Cannot delete your own account",
  "code": 400
}

24.6 – GET Staff Permissions

GET/api/v1/staff/permissions?staff_id={id}

Retrieve permissions for a specific staff member.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
staff_idStaff ID (if not provided, returns current user's permissions)

Sample Response

{
  "status": "success",
  "message": "Staff permissions retrieved successfully",
  "data": {
    "staff_id": 1,
    "staff_name": "John Doe",
    "role_id": 1,
    "role_name": "Administrator",
    "permissions": {
      "customers": {
        "view": true,
        "create": true,
        "edit": true,
        "delete": true
      },
      "invoices": {
        "view": true,
        "create": true,
        "edit": true,
        "delete": true
      },
      "projects": {
        "view": true,
        "create": true,
        "edit": true,
        "delete": true
      }
    }
  }
}

Tickets

Ticket endpoints.

25.1 – GET List Tickets

GET/api/v1/tickets/index?page=1&per_page=20&search=issue&status=1&department=2

Retrieve paginated list of support tickets with optional filtering.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
searchSearch by subject or ticket ID
statusFilter by status ID
departmentFilter by department ID

Sample Response

{
  "status": "success",
  "message": "Tickets loaded",
  "data": {
    "tickets": [
      {
        "id": 1,
        "subject": "Website login issue",
        "date": "2024-01-15 10:30:00",
        "lastreply": "2024-01-15 14:20:00",
        "userid": 123,
        "status": 1,
        "status_name": "Open",
        "priority": 2,
        "priority_name": "High",
        "department_name": "Technical Support"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 150,
      "total_pages": 8
    }
  }
}

25.2 – POST Create Ticket

POST/api/v1/tickets/store

Create a new support ticket.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: subject, department, message",
  "subject": "Website login issue",
  "_comment_subject": "Required - Ticket subject (max 191 characters)",
  "department": 1,
  "_comment_department": "Required - Department ID (integer)",
  "priority": 2,
  "_comment_priority": "Optional - Priority ID (integer)",
  "status": 1,
  "_comment_status": "Optional - Status ID (integer)",
  "message": "I am unable to log in to the website. Getting an error message.",
  "_comment_message": "Required - Ticket message/description",
  "userid": 123,
  "_comment_userid": "Optional - User/Client ID (integer)",
  "contactid": 456,
  "_comment_contactid": "Optional - Contact ID (integer)"
}

Sample Response

{
  "status": "success",
  "message": "Ticket created successfully",
  "data": {
    "id": 123
  }
}

25.3 – GET Get Ticket

GET/api/v1/tickets/show?id={id}

Retrieve a specific ticket by ID with full details and replies.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTicket ID

Sample Response

{
  "status": "success",
  "message": "Ticket loaded",
  "data": {
    "ticket": {
      "ticketid": 1,
      "subject": "Website login issue",
      "date": "2024-01-15 10:30:00",
      "userid": 123,
      "status": 1,
      "priority": 2,
      "department": 1,
      "message": "I am unable to log in to the website."
    },
    "replies": [
      {
        "replyid": 1,
        "ticketid": 1,
        "message": "We are looking into this issue.",
        "admin": 1,
        "date": "2024-01-15 11:00:00"
      }
    ]
  }
}

25.4 – PUT Update Ticket

PUT/api/v1/tickets/update?id={id}

Update an existing ticket.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTicket ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "subject": "Website login issue - Resolved",
  "_comment_subject": "Optional - Ticket subject (max 191 characters)",
  "department": 2,
  "_comment_department": "Optional - Department ID",
  "priority": 1,
  "_comment_priority": "Optional - Priority ID",
  "status": 3,
  "_comment_status": "Optional - Status ID"
}

Sample Response

{
  "status": "success",
  "message": "Ticket updated successfully"
}

25.5 – DELETE Delete Ticket

DELETE/api/v1/tickets/destroy?id={id}

Delete a ticket.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTicket ID

Sample Response

{
  "status": "success",
  "message": "Ticket deleted successfully"
}

Error Example

{
  "status": "error",
  "message": "Ticket not found",
  "code": 404
}

25.6 – GET Ticket Statuses

GET/api/v1/tickets/statuses

Retrieve all available ticket statuses.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "Ticket statuses retrieved successfully",
  "data": {
    "statuses": [
      {
        "ticketstatusid": 1,
        "name": "Open",
        "statuscolor": "#28a745",
        "statusorder": 1,
        "isdefault": 1
      },
      {
        "ticketstatusid": 2,
        "name": "In Progress",
        "statuscolor": "#ffc107",
        "statusorder": 2,
        "isdefault": 0
      },
      {
        "ticketstatusid": 3,
        "name": "Answered",
        "statuscolor": "#17a2b8",
        "statusorder": 3,
        "isdefault": 0
      },
      {
        "ticketstatusid": 4,
        "name": "Closed",
        "statuscolor": "#6c757d",
        "statusorder": 4,
        "isdefault": 0
      }
    ]
  }
}

25.7 – POST Reply to Ticket

POST/api/v1/tickets/reply?id={id}

Add a reply to a ticket.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTicket ID

Request Body

{
  "_comment": "Required field: message",
  "message": "Thank you for your inquiry. We are looking into this issue and will get back to you shortly.",
  "_comment_message": "Required - Reply message/content",
  "admin": 1,
  "_comment_admin": "Optional - Staff ID who is replying (default: current user)",
  "attachments": [],
  "_comment_attachments": "Optional - Array of attachment file IDs"
}

Sample Response

{
  "status": "success",
  "message": "Reply added successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "message": "The message field is required"
  },
  "code": 422
}

Time Logs

Time log endpoints.

26.1 – GET Time Logs

GET/api/v1/timetracker/logs?task_id={task_id}&project_id={project_id}&staff_id={staff_id}&start_date={start_date}&end_date={end_date}&page=1&per_page=20

Retrieve time logs with optional filtering.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
task_idFilter by task ID
project_idFilter by project ID
staff_idFilter by staff ID
start_dateFilter by start date (format: Y-m-d)
end_dateFilter by end date (format: Y-m-d)
pagePage number
per_pageItems per page

Sample Response

{
  "status": "success",
  "message": "Time logs retrieved successfully",
  "data": {
    "logs": [
      {
        "id": 1,
        "task_id": 5,
        "project_id": 2,
        "staff_id": 1,
        "staff_name": "John Doe",
        "start_time": "2024-01-15 09:00:00",
        "end_time": "2024-01-15 12:30:00",
        "note": "Working on feature implementation",
        "hours": 3.5,
        "billable": 1,
        "hourly_rate": 50.00,
        "date": "2024-01-15"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    }
  }
}

26.2 – POST Start Timer

POST/api/v1/timetracker/start

Start a timer for a task or project.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required field: task_id or project_id",
  "task_id": 5,
  "_comment_task_id": "Required if project_id not provided - Task ID (integer)",
  "project_id": 2,
  "_comment_project_id": "Required if task_id not provided - Project ID (integer)",
  "note": "Starting work on feature implementation",
  "_comment_note": "Optional - Note/description for the time entry"
}

Sample Response

{
  "status": "success",
  "message": "Timer started successfully",
  "data": {
    "id": 123,
    "start_time": "2024-01-15 14:30:00",
    "task_id": 5,
    "project_id": 2
  }
}

Error Example

{
  "status": "error",
  "message": "Either task_id or project_id is required",
  "code": 400
}

26.3 – POST Stop Timer

POST/api/v1/timetracker/stop

Stop the currently running timer for the current user.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Optional field: note",
  "note": "Completed feature implementation",
  "_comment_note": "Optional - Note/description for the time entry"
}

Sample Response

{
  "status": "success",
  "message": "Timer stopped successfully",
  "data": {
    "id": 123,
    "start_time": "2024-01-15 14:30:00",
    "end_time": "2024-01-15 17:45:00",
    "hours": 3.25,
    "task_id": 5,
    "project_id": 2
  }
}

Error Example

{
  "status": "error",
  "message": "No active timer found",
  "code": 400
}

26.4 – POST Manual Time Entry

POST/api/v1/timetracker/manual

Create a manual time entry (not from a timer).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: task_id or project_id, date, hours",
  "task_id": 5,
  "_comment_task_id": "Required if project_id not provided - Task ID (integer)",
  "project_id": 2,
  "_comment_project_id": "Required if task_id not provided - Project ID (integer)",
  "date": "2024-01-15",
  "_comment_date": "Required - Date of time entry (format: Y-m-d)",
  "hours": 3.5,
  "_comment_hours": "Required - Number of hours worked (decimal)",
  "note": "Manual entry for completed work",
  "_comment_note": "Optional - Note/description for the time entry",
  "billable": true,
  "_comment_billable": "Optional - Is time entry billable: true/false (default: true)",
  "hourly_rate": 50.00,
  "_comment_hourly_rate": "Optional - Hourly rate for billing (decimal)"
}

Sample Response

{
  "status": "success",
  "message": "Time entry created successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "date": "The date field is required",
    "hours": "The hours field is required"
  },
  "code": 422
}

26.5 – DELETE Delete Time Entry

DELETE/api/v1/timetracker/destroy?id={id}

Delete a time entry.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idTime entry ID

Sample Response

{
  "status": "success",
  "message": "Time entry deleted successfully"
}

Error Example

{
  "status": "error",
  "message": "Time entry not found",
  "code": 404
}

Users

User endpoints.

27.1 – GET List Users

GET/api/v1/users/index?page=1&per_page=20&search=john&active=1

Retrieve paginated list of users (client contacts).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
searchSearch by name or email
activeFilter by active status: 0=Inactive, 1=Active
client_idFilter by client ID

Sample Response

{
  "status": "success",
  "message": "Users retrieved successfully",
  "data": {
    "users": [
      {
        "id": 1,
        "userid": 123,
        "firstname": "John",
        "lastname": "Doe",
        "email": "[email protected]",
        "phonenumber": "+1234567890",
        "title": "CEO",
        "client_id": 123,
        "client_name": "ACME Corp",
        "active": 1,
        "is_primary": 1,
        "last_login": "2024-01-15 10:30:00",
        "datecreated": "2024-01-01 09:00:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 150,
      "total_pages": 8
    }
  }
}

27.2 – POST Create User

POST/api/v1/users/store

Create a new user (client contact).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: firstname, lastname, email, client_id",
  "firstname": "Jane",
  "_comment_firstname": "Required - First name (max 50 characters)",
  "lastname": "Smith",
  "_comment_lastname": "Required - Last name (max 50 characters)",
  "email": "[email protected]",
  "_comment_email": "Required - Email address (valid email, max 100 characters)",
  "client_id": 123,
  "_comment_client_id": "Required - Client ID (integer)",
  "phonenumber": "+1987654321",
  "_comment_phonenumber": "Optional - Phone number (max 50 characters)",
  "title": "CTO",
  "_comment_title": "Optional - Job title (max 100 characters)",
  "password": "securepassword123",
  "_comment_password": "Optional - Password (min 6 characters). If not provided, a random password will be generated.",
  "active": 1,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active (default: 1)",
  "is_primary": 0,
  "_comment_is_primary": "Optional - Is primary contact: 0=No, 1=Yes (default: 0)",
  "send_set_password_email": true,
  "_comment_send_set_password_email": "Optional - Send password setup email: true/false (default: false)"
}

Sample Response

{
  "status": "success",
  "message": "User created successfully",
  "data": {
    "id": 123
  }
}

Error Example

{
  "status": "error",
  "message": "User with this email already exists",
  "code": 400
}

27.3 – GET Get User

GET/api/v1/users/show?id={id}

Retrieve a specific user (client contact) by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idUser ID

Sample Response

{
  "status": "success",
  "message": "User retrieved successfully",
  "data": {
    "id": 1,
    "userid": 123,
    "firstname": "John",
    "lastname": "Doe",
    "email": "[email protected]",
    "phonenumber": "+1234567890",
    "title": "CEO",
    "client_id": 123,
    "client_name": "ACME Corp",
    "active": 1,
    "is_primary": 1,
    "last_login": "2024-01-15 10:30:00",
    "datecreated": "2024-01-01 09:00:00",
    "permissions": []
  }
}

27.4 – PUT Update User

PUT/api/v1/users/update?id={id}

Update an existing user (client contact).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idUser ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "firstname": "Jane",
  "_comment_firstname": "Optional - First name (max 50 characters)",
  "lastname": "Smith Updated",
  "_comment_lastname": "Optional - Last name (max 50 characters)",
  "email": "[email protected]",
  "_comment_email": "Optional - Email address (valid email, max 100 characters)",
  "phonenumber": "+1555123456",
  "_comment_phonenumber": "Optional - Phone number",
  "title": "CTO",
  "_comment_title": "Optional - Job title",
  "password": "newpassword123",
  "_comment_password": "Optional - New password (min 6 characters)",
  "active": 0,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active",
  "is_primary": 1,
  "_comment_is_primary": "Optional - Is primary contact: 0=No, 1=Yes"
}

Sample Response

{
  "status": "success",
  "message": "User updated successfully"
}

27.5 – DELETE Delete User

DELETE/api/v1/users/destroy?id={id}

Delete a user (client contact).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idUser ID

Sample Response

{
  "status": "success",
  "message": "User deleted successfully"
}

Error Example

{
  "status": "error",
  "message": "Cannot delete primary contact",
  "code": 400
}

Webhooks

Webhook endpoints.

28.1 – GET List Webhooks

GET/api/v1/webhooks/index?page=1&per_page=20&active=1

Retrieve paginated list of webhooks.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
activeFilter by active status: 0=Inactive, 1=Active

Sample Response

{
  "status": "success",
  "message": "Webhooks retrieved successfully",
  "data": {
    "webhooks": [
      {
        "id": 1,
        "name": "Invoice Created",
        "url": "https://example.com/webhooks/invoice-created",
        "events": ["invoice.created", "invoice.updated"],
        "active": 1,
        "secret": "whsec_abc123...",
        "datecreated": "2024-01-15 10:30:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 10,
      "total_pages": 1
    }
  }
}

28.2 – POST Create Webhook

POST/api/v1/webhooks/store

Create a new webhook.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: name, url, events",
  "name": "Invoice Created",
  "_comment_name": "Required - Webhook name (max 100 characters)",
  "url": "https://example.com/webhooks/invoice-created",
  "_comment_url": "Required - Webhook URL (valid URL)",
  "events": ["invoice.created", "invoice.updated", "invoice.deleted"],
  "_comment_events": "Required - Array of event names to subscribe to",
  "active": 1,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active (default: 1)",
  "secret": "whsec_abc123...",
  "_comment_secret": "Optional - Webhook secret for signature verification. If not provided, one will be generated."
}

Sample Response

{
  "status": "success",
  "message": "Webhook created successfully",
  "data": {
    "id": 123,
    "secret": "whsec_abc123..."
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "name": "The name field is required",
    "url": "The url field is required",
    "events": "The events field is required"
  },
  "code": 422
}

28.3 – GET Get Webhook

GET/api/v1/webhooks/show?id={id}

Retrieve a specific webhook by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idWebhook ID

Sample Response

{
  "status": "success",
  "message": "Webhook retrieved successfully",
  "data": {
    "id": 1,
    "name": "Invoice Created",
    "url": "https://example.com/webhooks/invoice-created",
    "events": ["invoice.created", "invoice.updated"],
    "active": 1,
    "secret": "whsec_abc123...",
    "datecreated": "2024-01-15 10:30:00",
    "last_triggered": "2024-01-16 14:20:00",
    "total_requests": 45,
    "successful_requests": 43,
    "failed_requests": 2
  }
}

28.4 – PUT Update Webhook

PUT/api/v1/webhooks/update?id={id}

Update an existing webhook.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idWebhook ID

Request Body

{
  "_comment": "All fields are optional - only include fields to update",
  "name": "Invoice Created - Updated",
  "_comment_name": "Optional - Webhook name (max 100 characters)",
  "url": "https://example.com/webhooks/invoice-created-updated",
  "_comment_url": "Optional - Webhook URL (valid URL)",
  "events": ["invoice.created", "invoice.updated", "invoice.paid"],
  "_comment_events": "Optional - Array of event names to subscribe to",
  "active": 0,
  "_comment_active": "Optional - Active status: 0=Inactive, 1=Active"
}

Sample Response

{
  "status": "success",
  "message": "Webhook updated successfully"
}

28.5 – DELETE Delete Webhook

DELETE/api/v1/webhooks/destroy?id={id}

Delete a webhook.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idWebhook ID

Sample Response

{
  "status": "success",
  "message": "Webhook deleted successfully"
}

Audit Logs

Audit log endpoints.

29.1 – GET List Audit Logs

GET/api/v1/auditlogs/index?page=1&per_page=20&user_id={user_id}&action={action}&date_from={date_from}&date_to={date_to}

Retrieve paginated list of audit logs.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
pagePage number
per_pageItems per page
user_idFilter by user ID
actionFilter by action (e.g., 'create', 'update', 'delete', 'view')
date_fromFilter from date (format: Y-m-d)
date_toFilter to date (format: Y-m-d)
entity_typeFilter by entity type (e.g., 'invoice', 'client', 'project')

Sample Response

{
  "status": "success",
  "message": "Audit logs retrieved successfully",
  "data": {
    "logs": [
      {
        "id": 1,
        "user_id": 1,
        "user_name": "John Doe",
        "action": "create",
        "entity_type": "invoice",
        "entity_id": 123,
        "description": "Invoice #INV-000001 created",
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0...",
        "date": "2024-01-15 10:30:00"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 500,
      "total_pages": 25
    }
  }
}

29.2 – GET Get Audit Log

GET/api/v1/auditlogs/show?id={id}

Retrieve a specific audit log entry by ID.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
idAudit log ID

Sample Response

{
  "status": "success",
  "message": "Audit log retrieved successfully",
  "data": {
    "id": 1,
    "user_id": 1,
    "user_name": "John Doe",
    "action": "create",
    "entity_type": "invoice",
    "entity_id": 123,
    "description": "Invoice #INV-000001 created",
    "old_values": null,
    "new_values": {
      "number": "INV-000001",
      "client_id": 123,
      "total": 5000.00
    },
    "ip_address": "192.168.1.1",
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "date": "2024-01-15 10:30:00"
  }
}

Import APIs

Import endpoints.

30.1 – POST Import Clients

POST/api/v1/import/clients

Import clients from a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Request Body

Request Body (multipart/form-data):
file: [file upload]
format: csv (optional, default: auto-detect)
skip_duplicates: true (optional, default: false)
update_existing: false (optional, default: false)

Request Body (JSON alternative):
{
  "_comment": "Required field: file or data",
  "file": "base64_encoded_file_content",
  "_comment_file": "Optional - Base64 encoded file content (if not using multipart/form-data)",
  "format": "csv",
  "_comment_format": "Optional - File format: 'csv', 'xlsx', 'json' (default: auto-detect)",
  "skip_duplicates": true,
  "_comment_skip_duplicates": "Optional - Skip duplicate records: true/false (default: false)",
  "update_existing": false,
  "_comment_update_existing": "Optional - Update existing records: true/false (default: false)",
  "data": [
    {
      "company": "ACME Corp",
      "email": "[email protected]",
      "phonenumber": "+1234567890"
    }
  ],
  "_comment_data": "Optional - Direct JSON data array (if not using file upload)"
}

Sample Response

{
  "status": "success",
  "message": "Import completed successfully",
  "data": {
    "imported": 50,
    "updated": 5,
    "failed": 2,
    "errors": [
      {
        "row": 5,
        "error": "Invalid email format"
      }
    ]
  }
}

30.2 – POST Import Leads

POST/api/v1/import/leads

Import leads from a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Request Body

Request Body (multipart/form-data):
file: [file upload]
format: csv (optional, default: auto-detect)
skip_duplicates: true (optional, default: false)
update_existing: false (optional, default: false)

Request Body (JSON alternative):
{
  "_comment": "Required field: file or data",
  "file": "base64_encoded_file_content",
  "_comment_file": "Optional - Base64 encoded file content",
  "format": "csv",
  "_comment_format": "Optional - File format: 'csv', 'xlsx', 'json'",
  "skip_duplicates": true,
  "_comment_skip_duplicates": "Optional - Skip duplicate records",
  "update_existing": false,
  "_comment_update_existing": "Optional - Update existing records",
  "data": [
    {
      "name": "John Doe",
      "email": "[email protected]",
      "company": "ACME Corp",
      "phonenumber": "+1234567890"
    }
  ],
  "_comment_data": "Optional - Direct JSON data array"
}

Sample Response

{
  "status": "success",
  "message": "Import completed successfully",
  "data": {
    "imported": 75,
    "updated": 3,
    "failed": 1,
    "errors": []
  }
}

30.3 – POST Import Products

POST/api/v1/import/products

Import products/items from a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Request Body

Request Body (multipart/form-data):
file: [file upload]
format: csv (optional, default: auto-detect)
skip_duplicates: true (optional, default: false)
update_existing: false (optional, default: false)

Request Body (JSON alternative):
{
  "_comment": "Required field: file or data",
  "file": "base64_encoded_file_content",
  "_comment_file": "Optional - Base64 encoded file content",
  "format": "csv",
  "_comment_format": "Optional - File format: 'csv', 'xlsx', 'json'",
  "skip_duplicates": true,
  "_comment_skip_duplicates": "Optional - Skip duplicate records",
  "update_existing": false,
  "_comment_update_existing": "Optional - Update existing records",
  "data": [
    {
      "description": "Web Development Service",
      "rate": 100.00,
      "tax": 1
    }
  ],
  "_comment_data": "Optional - Direct JSON data array"
}

Sample Response

{
  "status": "success",
  "message": "Import completed successfully",
  "data": {
    "imported": 30,
    "updated": 2,
    "failed": 0,
    "errors": []
  }
}

30.4 – POST Import Staff

POST/api/v1/import/staff

Import staff members from a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Request Body

Request Body (multipart/form-data):
file: [file upload]
format: csv (optional, default: auto-detect)
skip_duplicates: true (optional, default: false)
update_existing: false (optional, default: false)
send_welcome_email: false (optional, default: false)

Request Body (JSON alternative):
{
  "_comment": "Required field: file or data",
  "file": "base64_encoded_file_content",
  "_comment_file": "Optional - Base64 encoded file content",
  "format": "csv",
  "_comment_format": "Optional - File format: 'csv', 'xlsx', 'json'",
  "skip_duplicates": true,
  "_comment_skip_duplicates": "Optional - Skip duplicate records",
  "update_existing": false,
  "_comment_update_existing": "Optional - Update existing records",
  "send_welcome_email": false,
  "_comment_send_welcome_email": "Optional - Send welcome email to imported staff: true/false",
  "data": [
    {
      "firstname": "Jane",
      "lastname": "Smith",
      "email": "[email protected]",
      "role": 2
    }
  ],
  "_comment_data": "Optional - Direct JSON data array"
}

Sample Response

{
  "status": "success",
  "message": "Import completed successfully",
  "data": {
    "imported": 20,
    "updated": 1,
    "failed": 0,
    "errors": []
  }
}

Export APIs

Export endpoints.

31.1 – GET Export Clients

GET/api/v1/export/clients?format={format}&status={status}

Export clients to a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
formatExport format: 'csv', 'xlsx', 'json' (default: 'csv')
statusFilter by status: 0=Inactive, 1=Active
date_fromFilter from date (format: Y-m-d)
date_toFilter to date (format: Y-m-d)

Sample Response

Content-Type: application/csv (or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for XLSX, or application/json)
Content-Disposition: attachment; filename="clients_export_2024-01-15.csv"

[File content]

31.2 – GET Export Leads

GET/api/v1/export/leads?format={format}&status={status}

Export leads to a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
formatExport format: 'csv', 'xlsx', 'json' (default: 'csv')
statusFilter by status ID
sourceFilter by source ID
date_fromFilter from date (format: Y-m-d)
date_toFilter to date (format: Y-m-d)

Sample Response

Content-Type: application/csv
Content-Disposition: attachment; filename="leads_export_2024-01-15.csv"

[File content]

31.3 – GET Export Invoices

GET/api/v1/export/invoices?format={format}&status={status}&date_from={date_from}&date_to={date_to}

Export invoices to a file (CSV, XLSX, or JSON).

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
formatExport format: 'csv', 'xlsx', 'json' (default: 'csv')
statusFilter by status ID
client_idFilter by client ID
date_fromFilter from date (format: Y-m-d)
date_toFilter to date (format: Y-m-d)

Sample Response

Content-Type: application/csv
Content-Disposition: attachment; filename="invoices_export_2024-01-15.csv"

[File content]

System APIs

System health/info endpoints.

32.1 – GET System Health

GET/api/v1/system/health

Check the health status of the system, including database connectivity, cache status, and other critical services.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "System health check completed",
  "data": {
    "status": "healthy",
    "timestamp": "2024-01-15 10:30:00",
    "services": {
      "database": {
        "status": "connected",
        "response_time_ms": 5
      },
      "cache": {
        "status": "connected",
        "response_time_ms": 2
      },
      "storage": {
        "status": "accessible",
        "disk_usage_percent": 45
      },
      "queue": {
        "status": "running",
        "pending_jobs": 3
      }
    },
    "version": "1.0.0",
    "uptime_seconds": 86400
  }
}

32.2 – GET System Info

GET/api/v1/system/info

Retrieve system information including version, PHP version, database version, and other system details.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "System information retrieved successfully",
  "data": {
    "application": {
      "name": "Zealdash CRM",
      "version": "1.0.0",
      "environment": "production",
      "timezone": "America/New_York"
    },
    "server": {
      "php_version": "8.1.0",
      "server_software": "Apache/2.4.41",
      "operating_system": "Linux",
      "server_time": "2024-01-15 10:30:00"
    },
    "database": {
      "type": "MySQL",
      "version": "8.0.28",
      "charset": "utf8mb4",
      "collation": "utf8mb4_unicode_ci"
    },
    "features": {
      "multitenancy": true,
      "api_enabled": true,
      "webhooks_enabled": true,
      "audit_logs_enabled": true
    },
    "limits": {
      "max_upload_size": "10M",
      "max_execution_time": 300,
      "memory_limit": "256M"
    }
  }
}

Support

Support endpoints.

33.1 – POST Contact Support

POST/api/v1/support/contact

Submit a support request or contact support team.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Request Body

{
  "_comment": "Required fields: subject, message",
  "subject": "Issue with invoice generation",
  "_comment_subject": "Required - Support request subject (max 200 characters)",
  "message": "I'm experiencing an issue where invoices are not being generated correctly. The PDF format seems corrupted.",
  "_comment_message": "Required - Support request message/description",
  "priority": "medium",
  "_comment_priority": "Optional - Priority level: 'low', 'medium', 'high', 'urgent' (default: 'medium')",
  "category": "technical",
  "_comment_category": "Optional - Category: 'technical', 'billing', 'feature_request', 'bug_report', 'other' (default: 'other')",
  "attachments": [],
  "_comment_attachments": "Optional - Array of attachment file IDs or URLs",
  "contact_email": "[email protected]",
  "_comment_contact_email": "Optional - Contact email (default: authenticated user's email)",
  "contact_phone": "+1234567890",
  "_comment_contact_phone": "Optional - Contact phone number"
}

Sample Response

{
  "status": "success",
  "message": "Support request submitted successfully",
  "data": {
    "ticket_id": "SUP-12345",
    "reference_number": "REF-20240115-001",
    "estimated_response_time": "24 hours"
  }
}

Error Example

{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "subject": "The subject field is required",
    "message": "The message field is required"
  },
  "code": 422
}

33.2 – GET Support Tickets

GET/api/v1/support/tickets?status={status}&page=1&per_page=20

Retrieve list of support tickets submitted by the current user or tenant.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
statusFilter by status: 'open', 'pending', 'resolved', 'closed'
pagePage number
per_pageItems per page
searchSearch by subject or ticket ID

Sample Response

{
  "status": "success",
  "message": "Support tickets retrieved successfully",
  "data": {
    "tickets": [
      {
        "id": "SUP-12345",
        "reference_number": "REF-20240115-001",
        "subject": "Issue with invoice generation",
        "message": "I'm experiencing an issue where invoices are not being generated correctly.",
        "status": "open",
        "priority": "medium",
        "category": "technical",
        "created_at": "2024-01-15 10:30:00",
        "updated_at": "2024-01-15 10:30:00",
        "resolved_at": null,
        "response_count": 0
      },
      {
        "id": "SUP-12344",
        "reference_number": "REF-20240114-002",
        "subject": "Feature request: Export functionality",
        "message": "Would like to request export functionality for reports.",
        "status": "resolved",
        "priority": "low",
        "category": "feature_request",
        "created_at": "2024-01-14 14:20:00",
        "updated_at": "2024-01-15 09:15:00",
        "resolved_at": "2024-01-15 09:15:00",
        "response_count": 3
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 5,
      "total_pages": 1
    }
  }
}

Locations

Countries/states/cities/timezones endpoints.

34.1 – GET Countries

GET/api/v1/misc/countries?search={search}

Retrieve list of countries.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
searchSearch countries by name or code

Sample Response

{
  "status": "success",
  "message": "Countries retrieved successfully",
  "data": {
    "countries": [
      {
        "id": 1,
        "name": "United States",
        "iso_code": "US",
        "iso_code_3": "USA",
        "phone_code": "+1",
        "currency_code": "USD"
      },
      {
        "id": 2,
        "name": "United Kingdom",
        "iso_code": "GB",
        "iso_code_3": "GBR",
        "phone_code": "+44",
        "currency_code": "GBP"
      },
      {
        "id": 3,
        "name": "Canada",
        "iso_code": "CA",
        "iso_code_3": "CAN",
        "phone_code": "+1",
        "currency_code": "CAD"
      }
    ],
    "total": 195
  }
}

34.2 – GET States

GET/api/v1/misc/states?country_id={id}&search={search}

Retrieve list of states/provinces for a specific country.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
country_idFilter by country ID
searchSearch states by name or code

Sample Response

{
  "status": "success",
  "message": "States retrieved successfully",
  "data": {
    "states": [
      {
        "id": 1,
        "name": "California",
        "code": "CA",
        "country_id": 1,
        "country_name": "United States"
      },
      {
        "id": 2,
        "name": "New York",
        "code": "NY",
        "country_id": 1,
        "country_name": "United States"
      },
      {
        "id": 3,
        "name": "Texas",
        "code": "TX",
        "country_id": 1,
        "country_name": "United States"
      }
    ],
    "total": 50
  }
}

34.3 – GET Cities

GET/api/v1/misc/cities?country_id={id}&state_id={id}&search={search}&page=1&per_page=20

Retrieve list of cities, optionally filtered by country and/or state.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
country_idFilter by country ID
state_idFilter by state/province ID
searchSearch cities by name
pagePage number
per_pageItems per page

Sample Response

{
  "status": "success",
  "message": "Cities retrieved successfully",
  "data": {
    "cities": [
      {
        "id": 1,
        "name": "New York",
        "state_id": 2,
        "state_name": "New York",
        "state_code": "NY",
        "country_id": 1,
        "country_name": "United States",
        "country_code": "US"
      },
      {
        "id": 2,
        "name": "Los Angeles",
        "state_id": 1,
        "state_name": "California",
        "state_code": "CA",
        "country_id": 1,
        "country_name": "United States",
        "country_code": "US"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 150,
      "total_pages": 8
    }
  }
}

34.4 – GET Timezones

GET/api/v1/misc/timezones?search={search}

Retrieve list of available timezones.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Query Parameters

ParamDescription
searchSearch timezones by name or identifier

Sample Response

{
  "status": "success",
  "message": "Timezones retrieved successfully",
  "data": {
    "timezones": [
      {
        "identifier": "America/New_York",
        "name": "Eastern Time (US & Canada)",
        "offset": "-05:00",
        "offset_seconds": -18000,
        "abbreviation": "EST"
      },
      {
        "identifier": "America/Chicago",
        "name": "Central Time (US & Canada)",
        "offset": "-06:00",
        "offset_seconds": -21600,
        "abbreviation": "CST"
      },
      {
        "identifier": "America/Los_Angeles",
        "name": "Pacific Time (US & Canada)",
        "offset": "-08:00",
        "offset_seconds": -28800,
        "abbreviation": "PST"
      },
      {
        "identifier": "Europe/London",
        "name": "Greenwich Mean Time",
        "offset": "+00:00",
        "offset_seconds": 0,
        "abbreviation": "GMT"
      },
      {
        "identifier": "Asia/Dubai",
        "name": "Gulf Standard Time",
        "offset": "+04:00",
        "offset_seconds": 14400,
        "abbreviation": "GST"
      }
    ],
    "total": 425
  }
}

API Version

API version endpoint.

35.1 – GET API Version

GET/api/v1/version

Retrieve the current API version and related information.

Headers

Authorization: Bearer {access_token}
Content-Type: application/json

Sample Response

{
  "status": "success",
  "message": "API version retrieved successfully",
  "data": {
    "api_version": "v1",
    "version": "1.0.0",
    "release_date": "2024-01-01",
    "changelog_url": "https://docs.example.com/api/v1/changelog",
    "documentation_url": "https://docs.example.com/api/v1",
    "deprecation_date": null,
    "end_of_life_date": null,
    "supported_versions": [
      "v1"
    ],
    "features": {
      "pagination": true,
      "filtering": true,
      "sorting": true,
      "webhooks": true,
      "rate_limiting": true
    },
    "rate_limits": {
      "requests_per_minute": 60,
      "requests_per_hour": 1000,
      "requests_per_day": 10000
    }
  }
}

Postman Collection Downloads

Import these Postman collections into your workspace to explore and test Zealdash Tenant APIs. In the next stage we will wire each download link to the corresponding JSON collection file.

Tenant APIs 5.6 – 12.5

Projects, Tasks, Todos, Activity Logs, Departments, Email Templates, Estimate Requests and Filters.

Download Postman Collection

Tenant APIs 32.1 – 35.1

System Health, System Info, Countries, States, Cities, Timezones and API Version.

Download Postman Collection