Node SDK: Filtering & Pagination
Filtering Time Entries
All list methods accept filter parameters:
const entries = await keito.timeEntries.list({
source: 'api',
project_id: 'prj_abc',
user_id: 'usr_agent_01',
from: '2026-03-01',
to: '2026-03-31',
is_running: false,
per_page: 100,
});
Available Filters
| Parameter | Type | Description |
|---|---|---|
source |
string | Filter recorded origin; see the REST contract |
project_id, client_id |
string | Filter by project or client |
task_id, task |
string | Task ID or matching alias |
is_billed, invoice_id |
boolean / string | Billed state or linked invoice |
approval_status |
string | Approval state |
exclude_calendar |
boolean | Exclude calendar-derived records, subject to credential policy |
updated_since |
string | ISO timestamp lower bound |
external_reference_id, external_reference_service |
string | External object pair; use together |
user_id |
string | Filter by user |
from |
string | Start date (inclusive, YYYY-MM-DD) |
to |
string | End date (inclusive, YYYY-MM-DD) |
is_running |
boolean | Filter running timers only |
page |
number | Page number, starting at 1 |
per_page |
number | Results per page |
Pagination
The SDK uses API page pagination. Each response includes the current page, total pages, and a nextPage() helper:
const allEntries = [];
let page = await keito.timeEntries.list({
project_id: 'prj_abc',
page: 1,
per_page: 200,
});
while (true) {
allEntries.push(...page.data);
if (!page.hasNextPage()) break;
page = await page.nextPage();
}
console.log(`Total entries: ${allEntries.length}`);
Filtering Expenses
Expense list filters include source, project_id, client_id, user_id, from, to, is_billed, updated_since, page and per_page. It also supports invoice_id, expense_category_id and approval_status. Time-only filters such as is_running do not apply. Follow all pages and keep currencies separate when aggregating costs:
const totalsByCurrency = new Map<string, number>();
for await (const expense of await keito.expenses.list({
source: 'api',
project_id: 'YOUR_PROJECT_ID',
from: '2026-10-01',
to: '2026-10-31',
})) {
const currency = expense.currency ?? 'unknown';
const amount = expense.total_cost;
if (typeof amount !== 'number') throw new Error('Expense has no amount; reconcile before totaling.');
totalsByCurrency.set(currency, (totalsByCurrency.get(currency) ?? 0) + amount);
}
console.log([...totalsByCurrency]);
Combining Filters
Filters are combined with AND logic:
// Agent entries for a specific project in March
const entries = await keito.timeEntries.list({
source: 'api',
project_id: 'prj_abc',
from: '2026-03-01',
to: '2026-03-31',
});