List employee expenses (v2)
Lists employee expenses, newest first, optionally for one user and a date range, one page at a time (v2 route; no approval status).
The v2 route of GET /v1/employee-expense — same filters (userID, startDate, endDate), paging, ordering, $expand and 15-minute receipt URLs, and the same missing caller scope. Entities have no Status field, so approved expenses cannot be filtered client-side either.
Use it to:
Not for:
- Pulling approved expenses for payroll / finance — v2 has no approval status; use
GET /v1/employee-expense - One expense by ID —
GET /v2/employee-expense/{employeeExpenseID}(it enforces the owner check)
Behaviour:
- Idempotent.
- Safe to retry.
- Changes are visible to the next read immediately.
Call first: GET /v1/user
Next: GET /v2/employee-expense/{employeeExpenseID}, PUT /v2/employee-expense
See also: GET /v1/employee-expense
Not yet documented: request → query params → $expand.
curl -X GET "https://app3.timelog.com/your-account/api/v2/employee-expense?userID=123&startDate=2024-12-25T10%3A00%3A00Z&endDate=2024-12-25T10%3A00%3A00Z&$page=1&$pagesize=10&$expand=project" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN"
import requests
import json
url = "https://app3.timelog.com/your-account/api/v2/employee-expense?userID=123&startDate=2024-12-25T10%3A00%3A00Z&endDate=2024-12-25T10%3A00%3A00Z&$page=1&$pagesize=10&$expand=project"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
response = requests.get(url, headers=headers)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v2/employee-expense?userID=123&startDate=2024-12-25T10%3A00%3A00Z&endDate=2024-12-25T10%3A00%3A00Z&$page=1&$pagesize=10&$expand=project", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://app3.timelog.com/your-account/api/v2/employee-expense?userID=123&startDate=2024-12-25T10%3A00%3A00Z&endDate=2024-12-25T10%3A00%3A00Z&$page=1&$pagesize=10&$expand=project", nil)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://app3.timelog.com/your-account/api/v2/employee-expense?userID=123&startDate=2024-12-25T10%3A00%3A00Z&endDate=2024-12-25T10%3A00%3A00Z&$page=1&$pagesize=10&$expand=project')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
response = http.request(request)
puts response.body
{
"Properties": {
"TotalRecord": "example_string",
"TotalPage": "example_string",
"PageNumber": "example_string"
},
"Entities": [
{
"Properties": {
"EmployeeExpenseID": 123,
"Date": "2024-12-25T10:00:00Z",
"Amount": 3.14,
"VatAmount": 3.14,
"IsBillable": true,
"Number": "example_string",
"Comment": "null",
"ExchangeRate": 3.14,
"CurrencyID": 123,
"EmployeeUserID": 123,
"ExpenseTypeID": 123,
"PaymentMethodID": 123,
"ProjectID": 123,
"ProjectSubContractID": 123,
"FileUrls": [
"null"
],
"IsFileUrlLoaded": true,
"ImageUrls": [
"null"
],
"IsImageUrlLoaded": true,
"HasReceiptPictures": true,
"Project": {
"ProjectID": 123,
"ID": "123e4567-e89b-12d3-a456-426614174000",
"Name": "John Doe",
"No": "example_string",
"ExpenseIsBillable": "null",
"CustomerID": 123,
"Customer": {
"CustomerID": 123,
"ID": "123e4567-e89b-12d3-a456-426614174000",
"Name": "John Doe",
"No": "example_string",
"DefaultMileageDistance": 25,
"CustomerStatusID": 123,
"VATNo": "example_string",
"OrganizationNo": "example_string"
},
"MainContractId": 123
},
"Currency": {
"CurrencyID": 123,
"CurrencyABB": "example_string",
"DescriptiveName": "John Doe",
"CurrentRate": 3.14,
"IsActive": true
},
"ExpenseType": {
"ExpenseTypeID": 123,
"ExpenseTypeName": "John Doe",
"ShowInTravel": true,
"AccountNo": "example_string",
"VAT": 3.14,
"ProductNo": "example_string",
"SalaryCode": "example_string",
"IsActive": true,
"IsEquipment": true,
"CostPrice": 29.99,
"SalesPrice": 29.99,
"EquipmentText": "example_string"
},
"PaymentMethod": {
"PaymentMethodID": 123,
"Name": "John Doe",
"IsPaidByEmployee": true,
"IsDefaultForEmployeeExpense": true,
"IsDefaultForProjectExpense": true,
"IsActive": true,
"IsDefaultForImport": true,
"IsPersonalCreditCard": true,
"CreditCardEmployeeUserID": "null"
}
},
"Links": [
{
"Href": "example_string",
"Rel": "example_string"
}
],
"Actions": [
{}
]
}
],
"Links": [
{
"Href": "example_string",
"Rel": "example_string"
}
]
}
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred on the server",
"code": 500,
"requestId": "req_1234567890"
}
/v2/employee-expense
Target server for requests. Edit to use your own host.
OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).
The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.
> Not yet documented: how to obtain a token.
> Not yet documented: token lifetime.
Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).
The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.
> Not yet documented: how to obtain a token.
> Not yet documented: token lifetime.Only expenses of this user (a USER ID). Omitted = all employees.
Filters on EmployeeExpenseReadV2.EmployeeUserID (eq).
Inclusive lower bound on the expense date.
Filters on EmployeeExpenseReadV2.Date (gte).
Inclusive upper bound on the expense date (stored values are midnight).
Filters on EmployeeExpenseReadV2.Date (lte).
Page number.
Page size. No maximum enforced in the API layer.
Comma-separated list of nested objects to embed.
Several values: one string, separated by ,.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
| project | project | Fill Project (and its customer). |
| currency | currency | Fill Currency. |
| expenseType | expenseType | Fill ExpenseType. |
| paymentMethod | paymentMethod | Fill PaymentMethod. |
Request Preview
Response
Response will appear here after sending the request
Authentication
Bearer token. OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).
The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.
Not yet documented: how to obtain a token.
Not yet documented: token lifetime.
Query Parameters
Only expenses of this user (a USER ID). Omitted = all employees.
Filters on EmployeeExpenseReadV2.EmployeeUserID (eq).
Inclusive lower bound on the expense date.
Filters on EmployeeExpenseReadV2.Date (gte).
Inclusive upper bound on the expense date (stored values are midnight).
Filters on EmployeeExpenseReadV2.Date (lte).
Page number.
Page size. No maximum enforced in the API layer.
Comma-separated list of nested objects to embed.
Several values: one string, separated by ,.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
project | project | Fill Project (and its customer). |
currency | currency | Fill Currency. |
expenseType | expenseType | Fill ExpenseType. |
paymentMethod | paymentMethod | Fill PaymentMethod. |
projectcurrencyexpenseTypepaymentMethodResponses
Paging values. They are returned as STRINGS, for example "TotalRecord": "12".
Omitted (not []) when the list is empty.