Expensicat
API Reference

Time Entries

GET
/v1/time-entries/timer

The authenticated user’s running time entry, or null when no timer runs

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/time-entries/timer"
{  "data": {    "id": "string",    "organization_id": "string",    "user_id": "string",    "project_id": "string",    "start_time": "string",    "end_time": "string",    "duration": 0,    "description": "string",    "billable": true,    "billing": "non_billable",    "invoice_id": "string",    "created_at": "string",    "updated_at": "string",    "user": {      "id": "string",      "full_name": "string",      "email": "string",      "avatar_url": "string"    },    "project": {      "id": "string",      "name": "string",      "customer_id": "string",      "hourly_rate": 0,      "currency": "string",      "customer": {        "id": "string",        "name": "string",        "website": "string"      }    },    "invoice": {      "id": "string",      "number": "string",      "status": "string",      "date": "string",      "due_date": "string"    }  }}
POST
/v1/time-entries/timer/start

Start a timer for the authenticated user. A timer already running is stopped first.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/time-entries/timer/start" \  -H "Content-Type: application/json" \  -d '{}'
{  "data": {    "entry": {      "id": "string",      "organization_id": "string",      "user_id": "string",      "project_id": "string",      "start_time": "string",      "end_time": "string",      "duration": 0,      "description": "string",      "billable": true,      "billing": "non_billable",      "invoice_id": "string",      "created_at": "string",      "updated_at": "string",      "user": {        "id": "string",        "full_name": "string",        "email": "string",        "avatar_url": "string"      },      "project": {        "id": "string",        "name": "string",        "customer_id": "string",        "hourly_rate": 0,        "currency": "string",        "customer": {          "id": "string",          "name": "string",          "website": "string"        }      },      "invoice": {        "id": "string",        "number": "string",        "status": "string",        "date": "string",        "due_date": "string"      }    },    "stopped": {      "id": "string",      "organization_id": "string",      "user_id": "string",      "project_id": "string",      "start_time": "string",      "end_time": "string",      "duration": 0,      "description": "string",      "billable": true,      "billing": "non_billable",      "invoice_id": "string",      "created_at": "string",      "updated_at": "string",      "user": {        "id": "string",        "full_name": "string",        "email": "string",        "avatar_url": "string"      },      "project": {        "id": "string",        "name": "string",        "customer_id": "string",        "hourly_rate": 0,        "currency": "string",        "customer": {          "id": "string",          "name": "string",          "website": "string"        }      },      "invoice": {        "id": "string",        "number": "string",        "status": "string",        "date": "string",        "due_date": "string"      }    }  }}
POST
/v1/time-entries/timer/stop

Stop the authenticated user’s running timer. Under a minute it is discarded.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Response Body

application/json

application/json

curl -X POST "https://example.com/v1/time-entries/timer/stop"
{  "data": {    "outcome": "stopped",    "entry": {      "id": "string",      "organization_id": "string",      "user_id": "string",      "project_id": "string",      "start_time": "string",      "end_time": "string",      "duration": 0,      "description": "string",      "billable": true,      "billing": "non_billable",      "invoice_id": "string",      "created_at": "string",      "updated_at": "string",      "user": {        "id": "string",        "full_name": "string",        "email": "string",        "avatar_url": "string"      },      "project": {        "id": "string",        "name": "string",        "customer_id": "string",        "hourly_rate": 0,        "currency": "string",        "customer": {          "id": "string",          "name": "string",          "website": "string"        }      },      "invoice": {        "id": "string",        "number": "string",        "status": "string",        "date": "string",        "due_date": "string"      }    }  }}
POST
/v1/time-entries/invoice

Create a draft invoice from unbilled, billable, stopped time: the given entries, or all of a project’s or customer’s. The entries must share one customer and one currency.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/time-entries/invoice" \  -H "Content-Type: application/json" \  -d '{}'
{  "data": {    "outcome": "created",    "invoice_id": "string",    "skipped": 0  }}
GET
/v1/time-entries

List time entries, newest first, with filtering and pagination. Members only see their own time.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Query Parameters

cursor?string

Pagination cursor

limit?integer

Number of items per page (1-100; higher values cap at 100)

Range1 <= value
Default20
start_date?string

Start date (YYYY-MM-DD)

end_date?string

End date (YYYY-MM-DD)

q?string

Search description, project and customer

project_id?|

Filter by project ID, or "none" for time without a project

billing?string

Filter by billing state

Value in

  • "non_billable"
  • "unbilled"
  • "draft"
  • "invoiced"
  • "paid"
user_id?|

Filter by user ID. Pass "me" to scope to the authenticated user, a UUID to filter to a specific user, or omit for org-wide results. Members only see their own time.

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/time-entries"
{  "data": [    {      "id": "string",      "organization_id": "string",      "user_id": "string",      "project_id": "string",      "start_time": "string",      "end_time": "string",      "duration": 0,      "description": "string",      "billable": true,      "billing": "non_billable",      "invoice_id": "string",      "created_at": "string",      "updated_at": "string",      "user": {        "id": "string",        "full_name": "string",        "email": "string",        "avatar_url": "string"      },      "project": {        "id": "string",        "name": "string",        "customer_id": "string",        "hourly_rate": 0,        "currency": "string",        "customer": {          "id": "string",          "name": "string",          "website": "string"        }      },      "invoice": {        "id": "string",        "number": "string",        "status": "string",        "date": "string",        "due_date": "string"      }    }  ],  "meta": {    "count": 0,    "next_cursor": "string"  }}
POST
/v1/time-entries

Log finished time. To track time as it happens, use the timer endpoints.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/time-entries" \  -H "Content-Type: application/json" \  -d '{    "start_time": "string",    "end_time": "string"  }'
{  "data": {    "id": "string",    "organization_id": "string",    "user_id": "string",    "project_id": "string",    "start_time": "string",    "end_time": "string",    "duration": 0,    "description": "string",    "billable": true,    "billing": "non_billable",    "invoice_id": "string",    "created_at": "string",    "updated_at": "string",    "user": {      "id": "string",      "full_name": "string",      "email": "string",      "avatar_url": "string"    },    "project": {      "id": "string",      "name": "string",      "customer_id": "string",      "hourly_rate": 0,      "currency": "string",      "customer": {        "id": "string",        "name": "string",        "website": "string"      }    },    "invoice": {      "id": "string",      "number": "string",      "status": "string",      "date": "string",      "due_date": "string"    }  }}
GET
/v1/time-entries/{id}

Get a single time entry by ID

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Path Parameters

id*string
Formatuuid

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/v1/time-entries/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "data": {    "id": "string",    "organization_id": "string",    "user_id": "string",    "project_id": "string",    "start_time": "string",    "end_time": "string",    "duration": 0,    "description": "string",    "billable": true,    "billing": "non_billable",    "invoice_id": "string",    "created_at": "string",    "updated_at": "string",    "user": {      "id": "string",      "full_name": "string",      "email": "string",      "avatar_url": "string"    },    "project": {      "id": "string",      "name": "string",      "customer_id": "string",      "hourly_rate": 0,      "currency": "string",      "customer": {        "id": "string",        "name": "string",        "website": "string"      }    },    "invoice": {      "id": "string",      "number": "string",      "status": "string",      "date": "string",      "due_date": "string"    }  }}
PATCH
/v1/time-entries/{id}

Update time entry fields. Time on an invoice cannot change: remove its line from the draft first.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Path Parameters

id*string
Formatuuid

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X PATCH "https://example.com/v1/time-entries/497f6eca-6276-4993-bfeb-53cbbbba6f08" \  -H "Content-Type: application/json" \  -d '{}'
{  "data": {    "id": "string",    "organization_id": "string",    "user_id": "string",    "project_id": "string",    "start_time": "string",    "end_time": "string",    "duration": 0,    "description": "string",    "billable": true,    "billing": "non_billable",    "invoice_id": "string",    "created_at": "string",    "updated_at": "string",    "user": {      "id": "string",      "full_name": "string",      "email": "string",      "avatar_url": "string"    },    "project": {      "id": "string",      "name": "string",      "customer_id": "string",      "hourly_rate": 0,      "currency": "string",      "customer": {        "id": "string",        "name": "string",        "website": "string"      }    },    "invoice": {      "id": "string",      "number": "string",      "status": "string",      "date": "string",      "due_date": "string"    }  }}
DELETE
/v1/time-entries/{id}

Delete a time entry by ID. Time on an invoice cannot be deleted: remove its line from the draft first.

Authorization

bearerAuth
AuthorizationBearer <token>

Session JWT or OAuth2 access token

In: header

Path Parameters

id*string
Formatuuid

Response Body

application/json

application/json

application/json

curl -X DELETE "https://example.com/v1/time-entries/497f6eca-6276-4993-bfeb-53cbbbba6f08"
Empty