API Reference

Last updated March 23, 2026

The Tidyflow API is a RESTful JSON API that allows you to programmatically manage clients, jobs, contacts, time logs, and users within your Tidyflow account.

Base URL: https://app.tidyflow.com/api/v1


Authentication

All API requests require a Personal Access Token sent via the Authorization header. Tokens are scoped to the user who created them — all actions are performed as that user, respecting their role and permissions.

To create a token:

  1. Log in to your Tidyflow account.
  2. Go to Settings → API Tokens.
  3. Click New Token and copy the token immediately — it won’t be shown again.

Required Headers

HeaderValueWhen
AuthorizationBearer YOUR_API_TOKENAlways
Acceptapplication/jsonAlways
Content-Typeapplication/jsonPOST and PUT requests

Verify Your Token

GET /api/v1/me HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Returns the authenticated user’s profile:

{
  "id": 25,
  "firstname": "Sarah",
  "lastname": "Johnson",
  "email": "[email protected]",
  "fullname": "Sarah Johnson",
  "timezone": "America/New_York",
  "active": true
}

Clients

List Clients

GET /api/v1/clients HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Query Parameters:

ParameterTypeDescription
searchstringFilter by name
tagsarrayFilter by tag IDs
country_idintegerFilter by country
limitintegerResults per page (default: 1000)
pageintegerPage number

Response:

{
  "data": [
    {
      "uuid": "7c4d3e3c-7fc5-4895-925c-d3b6f70eec02",
      "name": "Acme Corp",
      "client_id": null,
      "website": "https://acme.com",
      "reg_number": "12345678",
      "country": "United States",
      "state": "TX",
      "city": "Austin",
      "street_address": "123 Main St",
      "postal_code": "73301",
      "is_archived": false,
      "contacts": []
    }
  ],
  "links": { "first": "...", "last": "...", "prev": null, "next": "..." },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 1000, "total": 12 }
}

Custom field values are included as additional top-level keys on each client object when custom fields are configured.

Get Client

GET /api/v1/clients/{uuid} HTTP/1.1

Returns a single client by UUID.

Search Clients

GET /api/v1/clients/search?q={query} HTTP/1.1

Returns a lightweight list of matching clients (id, uuid, name).

Create Client

POST /api/v1/clients HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
  "name": "Acme Corp",
  "website": "https://acme.com",
  "contact": {
    "firstname": "John",
    "lastname": "Doe",
    "email": "[email protected]"
  }
}

Fields:

FieldTypeRequiredDescription
namestringYesClient name (max 100)
client_idstringNoYour internal client ID (max 100, unique)
reg_numberstringNoRegistration number (max 100, unique)
websitestringNoWebsite URL
country_idintegerNoCountry ID
statestringNoState/province
citystringNoCity
street_addressstringNoStreet address
postal_codestringNoPostal/ZIP code
client_groupsarrayNoArray of client group IDs
contactobjectNoCreate and link a contact (see below)

Nested contact object (all fields required when contact is provided):

FieldTypeDescription
contact.firstnamestringFirst name
contact.lastnamestringLast name
contact.emailstringEmail address (must be unique)
contact.titlestringJob title (optional)
contact.phone_numberstringPhone number (optional)

Update Client

PUT /api/v1/clients/{uuid} HTTP/1.1

Supports partial updates — only include the fields you want to change. Accepts the same fields as Create, plus:

FieldTypeDescription
tagsarrayArray of tag IDs to assign

Jobs

List Jobs

GET /api/v1/jobs HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Query Parameters:

ParameterTypeDescription
searchstringSearch by job name
client_uuidstringFilter by client UUID
usersarrayFilter by assigned user IDs
statusesarrayFilter by status slugs
tagsarrayFilter by tag IDs
start_date_rangestringFilter by start date range
due_date_rangestringFilter by due date range
include_completedbooleanInclude completed jobs (default: false)
sort_bystringSort field
sort_directionstringasc or desc
pageintegerPage number

Response:

{
  "data": [
    {
      "uuid": "8cbfec20-ec1e-4539-8352-aa49196c95c2",
      "name": "Tax Return",
      "status": null,
      "client_uuid": "7c4d3e3c-...",
      "estimated_hours": 5.0,
      "start_date": "2026-03-01",
      "due_date": "2026-03-31",
      "is_overdue": false,
      "is_completed": false,
      "is_repeating": false
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Get Job

GET /api/v1/jobs/{uuid} HTTP/1.1

Returns a single job with related data (client, users, tags, subtasks).

Create Job

POST /api/v1/jobs HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
  "name": "Monthly Bookkeeping",
  "client_uuid": "7c4d3e3c-7fc5-4895-925c-d3b6f70eec02",
  "due_date": "2026-04-15",
  "estimated_hours": 3
}

Fields:

FieldTypeRequiredDescription
namestringYesJob name (max 150)
descriptionstringNoJob description
client_uuidstringNoClient UUID to link to
user_idintegerNoAssigned user ID
statusstringNoStatus slug
tagsarrayNoArray of tag IDs
start_datedateNoStart date (YYYY-MM-DD)
due_datedateNoDue date (YYYY-MM-DD)
estimated_hoursnumberNoEstimated hours (0–1000)

Contacts

List Contacts

GET /api/v1/contacts HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Query Parameters:

ParameterTypeDescription
searchstringFilter by name
limitintegerResults per page (default: 1000)
pageintegerPage number

Response:

{
  "data": [
    {
      "uuid": "7d3c7935-ac14-45d7-a75e-eb77ac5eb741",
      "firstname": "John",
      "lastname": "Doe",
      "preferred_name": "John",
      "email": "[email protected]",
      "phone_number": "+1 (555) 123-4567",
      "portal_enabled": true
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Get Contact

GET /api/v1/contacts/{uuid} HTTP/1.1

Returns a single contact by UUID.

Create Contact

POST /api/v1/contacts HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
  "firstname": "John",
  "lastname": "Doe",
  "email": "[email protected]"
}

Fields:

FieldTypeRequiredDescription
firstnamestringYesFirst name
lastnamestringYesLast name
emailstringYesEmail address (must be unique)
preferred_namestringNoPreferred/display name
phone_numberstringNoPhone number
portal_enabledbooleanNoEnable contact portal access (default: true)

Update Contact

PUT /api/v1/contacts/{uuid} HTTP/1.1

Supports partial updates — only include the fields you want to change. Accepts the same fields as Create.


Users

List Users

GET /api/v1/users HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Query Parameters:

ParameterTypeDescription
searchstringFilter by name or email

Response:

{
  "data": [
    {
      "id": 245,
      "firstname": "Emily",
      "lastname": "Chen",
      "fullname": "Emily Chen",
      "email": "[email protected]",
      "initials": "EC",
      "timezone": "America/Chicago",
      "role_name": "Standard"
    }
  ]
}

Get User

GET /api/v1/users/{id} HTTP/1.1

Find User by Email

GET /api/v1/users/email/{email} HTTP/1.1

Returns the user matching the given email, or {"data": null} if not found.


Time Logs

List Time Logs

GET /api/v1/time-logs HTTP/1.1
Host: app.tidyflow.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Query Parameters:

ParameterTypeDescription
rangestringDate range filter
client_uuidstringFilter by client UUID
tasksarrayFilter by task IDs
usersarrayFilter by user IDs
searchstringSearch by note
per_pageintegerResults per page
pageintegerPage number

Response:

{
  "data": [
    {
      "uuid": "e3f9da02-d916-43eb-a9e3-2687c7031934",
      "client": { "uuid": "8c1318a9-...", "name": "Acme Corp" },
      "task": { "uuid": "af5e5172-...", "name": "Tax Return" },
      "user": { "id": 25, "fullname": "Sarah Johnson" },
      "note": "Completed reconciliation",
      "hours": "8.00",
      "date": "2026-01-08"
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Pagination

All list endpoints return paginated results with links and meta objects:

{
  "data": [ ... ],
  "links": {
    "first": "https://app.tidyflow.com/api/v1/clients?page=1",
    "last": "https://app.tidyflow.com/api/v1/clients?page=5",
    "prev": null,
    "next": "https://app.tidyflow.com/api/v1/clients?page=2"
  },
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 15,
    "total": 72
  }
}

Error Responses

StatusMeaningDescription
401UnauthenticatedInvalid or missing API token
403ForbiddenValid token but insufficient permissions
404Not FoundResource not found or doesn’t belong to your account
422Validation ErrorInvalid request data

Validation errors include field-level detail:

{
  "message": "The name field is required.",
  "errors": {
    "name": ["The name field is required."]
  }
}

Rate Limiting

Rate limits are set at 500 requests per hour per user. Exceeding this limit results in a 429 Too Many Requests status code.

Can't find what you need?

Contact us at [email protected]