Getting Started with the InLoox API
This guide helps you set up authentication, understand OData basics, and send your first API request.
Prerequisites
Before you begin, you need:
- An active InLoox account (Cloud or Self-Hosted)
- An HTTP client like cURL, Postman, or a programming language of your choice
- A valid Personal Access Token (PAT)
In InLoox, click your profile picture in the top-right corner, then click My Profile, followed by the Personal Access Tokens tab. Click New Token. Enter a token name, select an account (if you have access to multiple accounts), and click Create New Token. Copy the generated token — it is only displayed once.
Please note that the user permission "Allow authentication via personal access token" is required to use the token. The token can only be used once this permission has been granted. This permission is cached. It may take up to 1 hour for the permission to become active.
Your Personal Access Token grants full API access on your behalf. Treat it like a password — never commit it to version control and do not share it publicly.
A token is as powerful as the user it belongs to. For production environments, it is recommended to create a dedicated service user account with permissions restricted to the minimum required scope.
Authentication
The InLoox API uses Personal Access Tokens for authentication. Include your token with every request as an x-api-key HTTP header.
cURL
curl -X GET "https://app.inloox.com/api/odata/Project" \
-H "x-api-key: YOUR_API_TOKEN"
C# (HttpClient)
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_TOKEN");
var response = await client.GetAsync("https://app.inloox.com/api/odata/Project");
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
C# (Simple.OData.Client)
var settings = new ODataClientSettings(new Uri("https://app.inloox.com/api/odata/"));
settings.BeforeRequest += delegate (HttpRequestMessage message)
{
message.Headers.Add("x-api-key", "YOUR_API_TOKEN");
};
var client = new ODataClient(settings);
JavaScript (fetch)
const response = await fetch("https://app.inloox.com/api/odata/Project", {
headers: {
"x-api-key": "YOUR_API_TOKEN"
}
});
const data = await response.json();
console.log(data);
A quick way to test your token is to call the AccountInfo endpoint:
curl -X GET "https://app.inloox.com/api/odata/AccountInfo" \
-H "x-api-key: YOUR_API_TOKEN"
On successful authentication, you will receive the account information, including the AccountId and account name.
Use the UserInfo/Me() endpoint to retrieve the profile of the currently authenticated user:
curl -X GET "https://app.inloox.com/api/odata/UserInfo/Me()" \
-H "x-api-key: YOUR_API_TOKEN"
Response:
{
"ContactId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"FirstName": "John",
"LastName": "Doe",
"DisplayName": "John Doe",
"Email": "john.doe@example.com",
"ImageId": null,
"NotifyFrequency": 1,
"TimeZoneInfo": "W. Europe Standard Time",
"EmailConfirmed": true,
"IsReader": false,
"UILanguage": "en-US"
}
To use the API with full read and write access, your account must have "EmailConfirmed": true and "IsReader": false. Users with an unconfirmed email address or a Read-Only license (IsReader: true) have limited API access.
Base URL
All API requests are made against a base URL that depends on your deployment:
| Deployment | Base URL |
|---|---|
| InLoox Cloud | https://app.inloox.com/api/ |
| InLoox Self-Hosted | https://YOUR-SELF-HOSTED-URL/api/v1/ |
All endpoint paths in this documentation are relative to the base URL. For example:
GET /odata/Project
means the full URL for the Cloud is https://app.inloox.com/api/odata/Project.
OData Basics
The InLoox API is based on the OData protocol (Open Data Protocol). OData provides a standardized query language that allows you to filter, sort, select, and paginate data — directly via the URL.
What is OData?
OData is an open standard for building and consuming REST APIs. It defines proven patterns for queries controlled through URL parameters ($filter, $select, $orderby, etc.). This allows you to precisely control what data you receive without requiring special endpoints.
Supported HTTP Methods
| Method | Usage |
|---|---|
GET | Read entities or collections |
POST | Create new entities or invoke actions |
PATCH | Update existing entities (partial update) |
DELETE | Delete entities |
Query Options
OData supports powerful query options as URL parameters. These allow you to filter, sort, paginate, and shape the data returned by the API.
$filter - Filter Data
Use $filter to restrict the returned records based on conditions.
Filter projects by name:
curl -X GET "https://app.inloox.com/api/odata/Project?\$filter=Name eq 'My Project'" \
-H "x-api-key: YOUR_API_TOKEN"
Projects created after a specific date:
curl -X GET "https://app.inloox.com/api/odata/Project?\$filter=CreatedDateTime gt 2024-01-01T00:00:00Z" \
-H "x-api-key: YOUR_API_TOKEN"
Combine multiple conditions (and / or):
curl -X GET "https://app.inloox.com/api/odata/Project?\$filter=IsArchived eq false and Name ne 'Archived'" \
-H "x-api-key: YOUR_API_TOKEN"
Common filter operators:
| Operator | Meaning | Example |
|---|---|---|
eq | Equal | Name eq 'Test' |
ne | Not equal | Status ne 'Closed' |
gt | Greater than | CreatedDateTime gt 2024-01-01T00:00:00Z |
lt | Less than | Progress lt 50 |
ge | Greater than or equal | Progress ge 80 |
le | Less than or equal | Progress le 100 |
and | Logical AND | IsArchived eq false and Progress gt 0 |
or | Logical OR | Status eq 'Open' or Status eq 'InProgress' |
contains() | Contains | contains(Name, 'Marketing') |
startswith() | Starts with | startswith(Name, 'Project') |
String values must be enclosed in single quotes: Name eq 'My Project'. GUIDs and dates do not require quotes.
// C# with Simple.OData.Client
var projects = await client
.For<ApiProject>("Project")
.Filter(p => p.Name == "Website Redesign")
.FindEntriesAsync();
$select - Select Fields
Use $select to specify which properties are returned in the response. This reduces the payload size and improves performance.
curl -X GET "https://app.inloox.com/api/odata/Project?\$select=ProjectId,Name,StartDate,EndDate" \
-H "x-api-key: YOUR_API_TOKEN"
C# example:
var response = await client.GetAsync("Project?$select=ProjectId,Name,StartDate");
// C# with Simple.OData.Client
var projects = await client
.For<ApiProject>("Project")
.Select(p => new { p.ProjectId, p.Name })
.FindEntriesAsync();
$orderby - Sorting
Use $orderby to sort results by one or more properties.
Sort ascending (default):
curl -X GET "https://app.inloox.com/api/odata/Project?\$orderby=Name" \
-H "x-api-key: YOUR_API_TOKEN"
Sort descending:
curl -X GET "https://app.inloox.com/api/odata/Project?\$orderby=CreatedDateTime desc" \
-H "x-api-key: YOUR_API_TOKEN"
Multiple sort criteria:
curl -X GET "https://app.inloox.com/api/odata/Project?\$orderby=IsArchived desc,Name asc" \
-H "x-api-key: YOUR_API_TOKEN"
// C# with Simple.OData.Client
var projects = await client
.For<ApiProject>("Project")
.OrderBy(p => p.StartDate)
.FindEntriesAsync();
$top and $skip - Paging
Use $top and $skip to retrieve results page by page.
| Parameter | Description | Example |
|---|---|---|
$top | Maximum number of entries returned | $top=20 |
$skip | Number of entries to skip | $skip=40 |
First 20 projects:
curl -X GET "https://app.inloox.com/api/odata/Project?\$top=20" \
-H "x-api-key: YOUR_API_TOKEN"
Page 3 (items 41–60):
curl -X GET "https://app.inloox.com/api/odata/Project?\$top=20&\$skip=40" \
-H "x-api-key: YOUR_API_TOKEN"
// C# with Simple.OData.Client
var page2 = await client
.For<ApiProject>("Project")
.Skip(10)
.Top(10)
.FindEntriesAsync();
Combining Query Options
You can combine multiple query options in a single request:
# Top 5 open tasks in a project, sorted by due date, key fields only
curl "https://app.inloox.com/api/odata/Task?\$filter=ProjectId eq {projectId} and IsDone eq false&\$orderby=EndDateTime asc&\$top=5&\$select=TaskItemId,Name,EndDateTime" \
-H "x-api-key: YOUR_API_TOKEN"
Pagination
The API returns a maximum of 100 items per request by default. To retrieve all records, you need to paginate through the pages.
Pagination Strategy
- Send a request with
$top - Check whether the response contains an
@odata.nextLinkfield - If so, send the next request to the URL specified in
@odata.nextLink - Repeat until no
@odata.nextLinkis present
How Pagination Works
When more results are available, the response contains an @odata.nextLink property with the URL for the next page:
{
"@odata.context": "https://app.inloox.com/api/odata/$metadata#Project",
"value": [ ... ],
"@odata.nextLink": "https://app.inloox.com/api/odata/Project?$skip=100"
}
Manual Pagination with $top and $skip
# Page 1 (entries 1–100)
curl "https://app.inloox.com/api/odata/Project?\$top=100&\$skip=0" \
-H "x-api-key: YOUR_API_TOKEN"
# Page 2 (entries 101–200)
curl "https://app.inloox.com/api/odata/Project?\$top=100&\$skip=100" \
-H "x-api-key: YOUR_API_TOKEN"
# Page 3 (entries 201–300)
curl "https://app.inloox.com/api/odata/Project?\$top=100&\$skip=200" \
-H "x-api-key: YOUR_API_TOKEN"
Manual Paging Example (C#)
var allProjects = new List<ApiProject>();
int skip = 0;
const int pageSize = 100;
while (true)
{
var response = await client.GetAsync($"Project?$top={pageSize}&$skip={skip}");
var json = await response.Content.ReadAsStringAsync();
var page = JsonSerializer.Deserialize<ODataResponse<ApiProject>>(json);
allProjects.AddRange(page.Value);
if (page.Value.Count < pageSize)
break;
skip += pageSize;
}
Console.WriteLine($"Total {allProjects.Count} projects loaded.");
Pagination with Simple.OData.Client (C#)
The ODataFeedAnnotations class handles pagination automatically:
var allEntries = new List<ApiProject>();
var annotations = new ODataFeedAnnotations();
var page = (await client
.For<ApiProject>("Project")
.FindEntriesAsync(annotations)).ToList();
allEntries.AddRange(page);
while (annotations.NextPageLink != null)
{
page = (await client
.For<ApiProject>("Project")
.FindEntriesAsync(annotations.NextPageLink, annotations)).ToList();
allEntries.AddRange(page);
}
Console.WriteLine($"Total projects loaded: {allEntries.Count}");
When retrieving large datasets, use $filter to narrow the query instead of paginating through all records. This reduces both network traffic and server load.
Response Format
All API responses use JSON with OData metadata annotations. A typical collection response looks like this:
{
"@odata.context": "https://app.inloox.com/api/odata/$metadata#Project",
"value": [
{
"ProjectId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"Name": "Website Relaunch",
"StartDate": "2024-01-15T00:00:00Z",
"EndDate": "2024-06-30T00:00:00Z"
}
]
}
Key elements:
| Property | Description |
|---|---|
@odata.context | URL to the entity metadata schema |
value | Array of entities (for collections) |
@odata.nextLink | URL of the next page (when more data is available) |
A single-entity response (e.g., GET Project({key})) returns the entity directly without the value wrapper:
{
"@odata.context": "https://app.inloox.com/api/odata/$metadata#Project/$entity",
"ProjectId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"Name": "Website Relaunch",
"StartDate": "2024-01-15T00:00:00Z",
"EndDate": "2024-06-30T00:00:00Z"
}
Error Handling
The API uses standard HTTP status codes to indicate the success or failure of a request.
| Status Code | Meaning | Description |
|---|---|---|
200 OK | Success | The request was successful. |
201 Created | Created | A new resource was successfully created. |
204 No Content | No Content | The request was successful, there is no return data (e.g., for DELETE). |
400 Bad Request | Bad Request | The request is invalid — check the parameters and request body. |
401 Unauthorized | Unauthorized | The API token is missing or invalid. |
403 Forbidden | Forbidden | You do not have permission for this resource. |
404 Not Found | Not Found | The requested resource does not exist. |
429 Too Many Requests | Rate Limited | Too many requests in a short period. |
500 Internal Server Error | Server Error | An internal error occurred — contact support. |
Error Response Example
{
"error": {
"code": "400",
"message": "The query specified in the URI is not valid. Could not find a property named 'InvalidField' on type 'ApiProject'."
}
}
- 401 errors: Check whether the
x-api-keyheader is set correctly and the token is valid. - 400 errors: Verify the syntax of your OData query and field names.
- 404 errors: Ensure the base URL and endpoint path are correct.
- Check the spelling of property names in
$select,$filter, and$orderbyif needed — they are case-sensitive. - Use the
$metadataendpoint to inspect available entities and properties:GET https://app.inloox.com/api/odata/$metadata
Rate Limits
The InLoox API does not publish strict rate limits, but follow these best practices to avoid throttling:
- Batch read operations — Use
$filterand$selectto minimize the number of requests - Do not poll aggressively — Wait at least a few seconds between repeated requests
- Paginate efficiently — Follow
@odata.nextLinkinstead of creating overlapping queries - Use caching — Cache results locally when data does not change frequently
If you receive a 429 Too Many Requests response, wait for the duration specified in the Retry-After header before retrying.
Next Steps
You are ready to get started! Here is where to go next:
- Code Examples — Complete, working C# examples to clone and run
- Projects — Work with the
Projectentity - Tasks — Query and manage tasks
- Time Entries — Record and retrieve time tracking data
- Documentation MCP — Connect AI tools to InLoox docs via MCP