Skip to content

timecamp-org/timecamp-api-ts

Repository files navigation

TimeCamp API TypeScript Client

A TypeScript client library for the TimeCamp API.

Source code: https://github.com/timecamp-org/timecamp-api-ts

Installation

npm install timecamp-api

Usage

import { TimeCampAPI } from 'timecamp-api'; const timecampApi = new TimeCampAPI("your-api-key"); // With custom configuration const timecampApi = new TimeCampAPI("your-api-key", { clientName: 'my-awesome-app', timeout: 15000 }); // Get current user const user = await timecampApi.user.get(); console.log(user); // Invite a user to your account await timecampApi.users.invite({ email: 'newuser@example.com', name: 'John Doe' }); // Get tasks const tasksResponse = await timecampApi.tasks.getActiveUserTasks({ user: 'me', includeFullBreadcrumb: true }); if (tasksResponse.success) { console.log(tasksResponse.data); // Array of non-archived tasks } // Get all tasks including archived ones const allTasksResponse = await timecampApi.tasks.getAll(); if (allTasksResponse.success) { console.log(allTasksResponse.data); // Active + archived tasks } // Get favourite tasks for the task picker widget const favourites = await timecampApi.tasks.getFavorites(); console.log(favourites.data.favourites); // Manage favourites await timecampApi.tasks.addFavorite(77390460); await timecampApi.tasks.removeFavorite(77189336); // Update a task and assign users await timecampApi.tasks.update({ task_id: 12345, name: 'Updated Task Name', user_ids: '100,200,300', // Comma-separated user IDs role: 5 // Role ID to assign }); // Tags and Tag Lists const tagLists = await timecampApi.tags.getTagLists(); const tagListId = await timecampApi.tags.createTagList({ name: 'Project Types' }); const tagId = await timecampApi.tags.createTag({ list: tagListId, name: 'Development' }); // Timer operations const timerStatus = await timecampApi.timer.status(); const startedTimer = await timecampApi.timer.start(); const stoppedTimer = await timecampApi.timer.stop(); // Time entries operations const timeEntries = await timecampApi.timeEntries.get({ date_from: '2024-01-01', date_to: '2024-01-31' }); const newEntry = await timecampApi.timeEntries.create({ date: '2024-01-15', duration: 3600, // 1 hour in seconds description: 'Working on API integration', start_time: '09:00:00', end_time: '10:00:00', tags: [{ tagId: 1 }, { tagId: 4 }] // Optional tags }); // Manage tags on time entries const entryTags = await timecampApi.timeEntries.getTags(entryId); await timecampApi.timeEntries.addTags(entryId, [5, 6]); await timecampApi.timeEntries.removeTags(entryId, [4]); const updatedEntry = await timecampApi.timeEntries.update(entryId, { description: 'Updated description', duration: 7200 // 2 hours }); const deleteResult = await timecampApi.timeEntries.delete(entryId); // Computer Activities (max 7 days, includes application names) const activities = await timecampApi.computerActivities.get({ date_from: '2024-01-01', date_to: '2024-01-07', }); // Each activity includes application_name resolved automatically // Computer activities for specific users const userActivities = await timecampApi.computerActivities.get({ date_from: '2024-01-01', date_to: '2024-01-03', user_ids: '123,456', }); // Billing Rates await timecampApi.billingRates.setTaskRate(12345, { rateTypeId: 1, value: 150 }); await timecampApi.billingRates.setUserRate(100, { rateTypeId: 1, value: 100 }); await timecampApi.billingRates.setTaskUserRate(12345, 100, { rateTypeId: 1, value: 175 }); const taskRates = await timecampApi.billingRates.getTaskRates(12345); // Groups const groups = await timecampApi.groups.getAll(); const newGroup = await timecampApi.groups.create({ name: 'Development Team', parent_id: 123 }); await timecampApi.groups.update({ group_id: newGroup.group_id, name: 'Dev Team' }); // Clients const clients = await timecampApi.clients.getAll(); const client = await timecampApi.clients.create({ organizationName: 'Acme Corp', firstName: 'John', lastName: 'Doe', email: 'john@acme.com', }); await timecampApi.clients.update({ clientId: client.clientId, organizationName: 'Acme Corp Updated' }); // Invoices const invoices = await timecampApi.invoices.getAll(); const invoice = await timecampApi.invoices.create({ clientId: client.clientId, issueDate: '2026-02-10', addDate: '2026-02-10', noteToClient: 'From 2026-01-26 to 2026-02-28', currencyId: 1, invoiceNumber: '1223', entries: [ { invoiceId: -1, invoiceEntryId: -1, description: '2026-01-26 07:53 ', type: 0, duration: 19980, quantity: 5.55, unitCost: 109, taxId: 198, name: '[ORG] Administration - Ewelina Łagos', subTotal: 604.95, ttEntriesIds: [263222996], }, ], });

API

Constructor

new TimeCampAPI(apiKey: string, config?: TimeCampAPIConfig)
  • apiKey: Your TimeCamp API key
  • config: Optional configuration object

Methods

Method Description Parameters Returns
user.get() Get information about the current user None Promise<TimeCampUser>
users.getAll() Get all users None Promise<Record<string, any>>
users.invite() Invite a user to TimeCamp account params: TimeCampUserInviteRequest Promise<TimeCampUserInviteResponse>
users.byId(id) Chainable selector for a user resource id: number { getAllCustomFields, getCustomField, setCustomField, updateCustomField, deleteCustomField }
tasks.byId(id) Chainable selector for a task resource id: number { getAllCustomFields, getCustomField, setCustomField, updateCustomField, deleteCustomField }
timeEntries.byId(id) Chainable selector for a time entry resource id: number { getAllCustomFields, getCustomField, setCustomField, updateCustomField, deleteCustomField }
customFields.getAll() List all custom fields templates (v3) None Promise<{ data: TimeCampCustomFieldTemplate[] }>
customFields.add(payload) Create a custom field template (v3) { name, resourceType, fieldType, required?, status?, defaultValue?, fieldOptions? } Promise<{ data: TimeCampCustomFieldTemplate }>
customFields.delete(templateId) Remove a custom field template (v3) templateId: number Promise<{ data: string }>
tasks.getAll() Get every task including archived None Promise<TasksAPIResponse>
tasks.getActiveUserTasks(options?: GetActiveUserTasksOptions) Get all non-archived tasks options: { user?: string; includeFullBreadcrumb?: boolean; } Promise<TasksAPIResponse>
tasks.add(params) Create a new task params: TimeCampCreateTaskRequest Promise<TimeCampCreateTaskResponse>
tasks.update(params) Update an existing task params: TimeCampUpdateTaskRequest Promise<TimeCampCreateTaskResponse>
tasks.getFavorites() Fetch task picker favourites and suggestions None Promise<TimeCampTaskFavoritesResponse>
tasks.addFavorite(taskId) Mark a task as favourite for the picker taskId: number Promise<TimeCampTaskFavoriteMutationResponse>
tasks.removeFavorite(taskId) Remove a task from favourites taskId: number Promise<TimeCampTaskFavoriteMutationResponse>
tags.getTagLists(options?) Get all tag lists options?: TimeCampGetTagListsOptions Promise<TimeCampTagListsResponse>
tags.getTagList(tagListId) Get specific tag list with tags tagListId: number Promise<TimeCampTagListWithTags>
tags.createTagList(params) Create new tag list params: { name: string } Promise<number>
tags.updateTagList(tagListId, params) Update tag list tagListId: number, params: { name?, archived? } Promise<{ message: string }>
tags.getTagListTags(tagListId) Get only tags from tag list tagListId: number Promise<{ [tagId: string]: TimeCampTagItem }>
tags.createTag(params) Create new tag params: { list: number, name: string } Promise<number>
tags.getTag(tagId) Get tag data tagId: number Promise<TimeCampTagItem>
tags.updateTag(tagId, params) Update tag tagId: number, params: { name?, archived? } Promise<{ message: string }>
timer.start() Start a new timer data?: TimerStartRequest Promise<any>
timer.stop() Stop the currently running timer data?: TimerStopRequest Promise<any>
timer.status() Get the current timer status None Promise<any>
timeEntries.get() Get time entries params?: TimeCampTimeEntriesRequest Promise<TimeCampTimeEntry[]>
timeEntries.create() Create a new time entry entry: TimeCampCreateTimeEntryRequest Promise<TimeCampCreateTimeEntryResponse>
timeEntries.update() Update an existing time entry id: number, data: Partial<TimeCampCreateTimeEntryRequest> Promise<TimeCampCreateTimeEntryResponse>
timeEntries.delete() Delete a time entry id: number Promise<{success: boolean, message: string}>
timeEntries.getTags(entryId) Get tags for time entry entryId: number Promise<TimeCampEntryTagsResponse>
timeEntries.addTags(entryId, tagIds) Add tags to time entry entryId: number, tagIds: number[] Promise<string[]>
timeEntries.removeTags(entryId, tagIds) Remove tags from time entry entryId: number, tagIds: number[] Promise<string[]>
computerActivities.get(params) Get computer activities with app names params: TimeCampComputerActivitiesRequest Promise<TimeCampComputerActivity[]>
billingRates.getTaskRates(taskId, rateTypeId?) Get billing rates for task taskId: number, rateTypeId?: string Promise<TimeCampBillingRatesResponse>
billingRates.setTaskRate(taskId, data) Set/update task billing rate taskId: number, data: TimeCampSetRateRequest Promise<TimeCampBillingRate>
billingRates.getUserRates(userId, rateTypeId?) Get billing rates for user userId: number, rateTypeId?: string Promise<TimeCampBillingRatesResponse>
billingRates.setUserRate(userId, data) Set/update user billing rate userId: number, data: TimeCampSetRateRequest Promise<TimeCampBillingRate>
billingRates.getTaskUserRates(taskId, userId, rateTypeId?) Get task-user billing rates taskId: number, userId: number, rateTypeId?: string Promise<TimeCampBillingRatesResponse>
billingRates.setTaskUserRate(taskId, userId, data) Set/update task-user rate taskId: number, userId: number, data: TimeCampSetRateRequest Promise<TimeCampBillingRate>
billingRates.getGroupRates(groupId, rateTypeId?) Get billing rates for group groupId: number, rateTypeId?: string Promise<TimeCampBillingRatesResponse>
billingRates.setGroupRate(groupId, data) Set/update group billing rate groupId: number, data: TimeCampSetRateRequest Promise<TimeCampBillingRate>
billingRates.getRateTypes() Get all rate types (Internal API) None Promise<TimeCampRateType[]>
groups.getAll() Get all groups None Promise<TimeCampGroupsResponse[]>
groups.create(params) Create a new group params: { name: string, parent_id?: number } Promise<TimeCampGroup>
groups.update(params) Update an existing group params: { group_id: number, name?, parent_id? } Promise<void>
groups.delete(groupId) Delete a group groupId: number Promise<void>
clients.getAll() Get all clients None Promise<TimeCampClientsResponse>
clients.create(params) Create a new client params: TimeCampCreateClientRequest Promise<TimeCampClient>
clients.update(params) Update an existing client params: TimeCampUpdateClientRequest Promise<TimeCampClient>
clients.delete(clientId) Delete a client clientId: number Promise<void>
invoices.getAll() Get all invoices None Promise<TimeCampInvoicesResponse>
invoices.create(params) Create a new invoice from time entries params: TimeCampCreateInvoiceRequest Promise<TimeCampInvoice>
invoices.update(params) Update an existing invoice params: TimeCampUpdateInvoiceRequest Promise<TimeCampInvoice>
invoices.delete(invoiceId) Delete an invoice invoiceId: number Promise<void>

user.get()

Get information about the current user.

Returns: Promise<TimeCampUser>

interface TimeCampUser { user_id: string; email: string; register_time: string; display_name: string; synch_time: string; root_group_id: string; }

tasks.getActiveUserTasks(options?: GetActiveUserTasksOptions)

Get all non-archived tasks accessible to a user.

Parameters:

  • options.user (optional): Defaults to 'me'. Pass a numerical user ID string to fetch tasks for a different user.
  • options.includeFullBreadcrumb (optional): Defaults to true. Controls whether full breadcrumb information is included in the API response.

Returns: Promise<TasksAPIResponse>

interface TasksAPIResponse { success: boolean; data?: TimeCampTask[]; message?: string; error?: string; } interface TimeCampTask { task_id: number; parent_id: number; assigned_by?: number; name: string; external_task_id?: string; external_parent_id?: string; task_key?: string | null; level: number; archived: number; keywords?: string; budgeted?: number; budget_unit: string; root_group_id?: number; billable: number; note?: string; public_hash?: string | null; add_date?: string; modify_time?: string; color?: string; user_access_type: number; users?: { [userId: string]: { user_id: number; role_id: number; }; }; groups?: string[]; roles?: string[]; perms?: { [permId: string]: number; }; canTrackTime?: boolean; [key: string]: any; }

tasks.getAll()

Get all tasks including archived ones.

Returns: Promise<TasksAPIResponse>

tasks.add(params: TimeCampCreateTaskRequest)

Create a new task in TimeCamp. This method allows you to create tasks with various parameters including external IDs for integrations.

Parameters:

  • params: Task creation parameters
    • name: Task name (required)
    • parent_id: Parent task ID as number (optional)
    • external_task_id: External task ID for integrations like Xero (optional)
    • external_parent_id: External parent task ID (optional)
    • budgeted: Budget value in the unit specified by budget_unit (optional)
    • note: Task description/note (optional)
    • archived: 0 for active, 1 for archived (optional, default: 0)
    • billable: 0 for non-billable, 1 for billable (optional, default: 1)
    • budget_unit: 'hours', 'fee', or '' (optional, default: 'hours')
    • user_ids: Comma-separated user IDs to add to task (optional, e.g., "22,521,2,25")
    • role: Role ID to assign to users if user_ids is provided (optional)
    • keywords: Task keywords, comma-separated (optional, e.g., "IT, R&D")
    • tags: (deprecated) Use keywords instead (optional)

Returns: Promise<TimeCampCreateTaskResponse>

interface TimeCampCreateTaskRequest { name: string; // required parent_id?: number; external_task_id?: string; external_parent_id?: string; budgeted?: number; note?: string; archived?: 0 | 1; billable?: 0 | 1; budget_unit?: 'hours' | 'fee' | ''; user_ids?: string; role?: number; keywords?: string; tags?: string; // deprecated } interface TimeCampCreateTaskResponse { [taskId: string]: { task_id: number; parent_id: number; name: string; external_task_id: string | null; external_parent_id: string | null; level: number; add_date: string; archived: number; color: string; tags: string; budgeted: number; checked_date: string | null; root_group_id: number; billable: number; budget_unit: string; note: string | null; keywords: string; // ... additional fields }; }

Example:

// Create a simple task const task = await api.tasks.add({ name: 'Development Task' }); // Create a task with external ID (for integrations) const taskWithExternal = await api.tasks.add({ name: 'Xero Invoice Task', external_task_id: 'xero_g8g89s78ds8', external_parent_id: 'xero_2b5b26tb295bb9' }); // Create a child task with full parameters const childTask = await api.tasks.add({ name: 'Backend Development', parent_id: 123456, // number type budgeted: 1000, budget_unit: 'hours', billable: 1, note: 'Development task for API integration', keywords: 'API, Backend, Development' }); // Access the created task data const taskId = Object.keys(task)[0]; const taskData = task[taskId]; console.log(`Created task: ${taskData.name} (ID: ${taskData.task_id})`);

tasks.update(params: TimeCampUpdateTaskRequest)

Update an existing task. This method supports all the same parameters as tasks.add() and is particularly useful for assigning users to tasks.

Parameters:

  • params: Task update parameters
    • task_id: Task ID to update (required)
    • name: Task name (optional)
    • parent_id: Parent task ID (optional)
    • user_ids: Comma-separated user IDs to assign to task (optional, e.g., "22,521,2,25")
    • role: Role ID to assign to users if user_ids is provided (optional)
    • All other parameters from tasks.add() are also supported

Returns: Promise<TimeCampCreateTaskResponse>

interface TimeCampUpdateTaskRequest { task_id: number; // required name?: string; parent_id?: number; user_ids?: string; // Comma-separated user IDs role?: number; // Role ID for assigned users // ... all other optional parameters from TimeCampCreateTaskRequest }

Example:

// Update task name await api.tasks.update({ task_id: 12345, name: 'Updated Task Name' }); // Assign users to a task await api.tasks.update({ task_id: 12345, user_ids: '100,200,300', // Assign users 100, 200, and 300 role: 5 // Assign them role ID 5 }); // Update multiple properties including user assignment await api.tasks.update({ task_id: 12345, name: 'Development Sprint 1', user_ids: '100,200', role: 5, billable: 1, budgeted: 40, budget_unit: 'hours' });

users.getAll()

List all users visible to the authenticated account.

Returns: Promise<Record<string, any>>

users.invite(params: TimeCampUserInviteRequest)

Invite a user to your TimeCamp account. The method resolves and returns the invited user's user_id, and when a name parameter is provided it will also update the user's display name after the invite is successful.

Parameters:

  • params: User invitation parameters
    • email: Email address of the user to invite (required)
    • name: Display name for the user (optional). If provided, an additional API call will be made to update the user's display name after the invite.
    • group_id: ID of the group to add the user to (optional, defaults to current user's root group)

Returns: Promise<TimeCampUserInviteResponse>

Retry Behavior: This method automatically retries up to 3 times with a 5-second delay when encountering a 429 (rate limit) error.

User ID Resolution & Display Name Update: The method will:

  1. Send the invitation
  2. Poll the group user list (up to 10 times with 2-second delays) to find the new user's ID
  3. If a name is provided, make an additional POST request to api/user with form-encoded data to update the user's display name
  4. Return the response with the user_id included

Note: There is typically a 2-4 second delay between when the invite succeeds and when the user appears in the group user list, which is why the method includes retry logic. If the user ID cannot be resolved after retries, the method throws an error.

interface TimeCampUserInviteRequest { email: string; name?: string; group_id?: number; } interface TimeCampUserInviteResponse { statuses: { [email: string]: { status: string; // e.g., "Invite", "Already exists", etc. }; }; user_id: string; // Always included after the user is resolved }

Example:

// Invite user with automatic group assignment and set display name const result = await timecampApi.users.invite({ email: 'newuser@example.com', name: 'John Doe' }); // Response: {  // statuses: { 'newuser@example.com': { status: 'Invite' } }, // user_id: '123456' // } // Invite user to a specific group with display name const result2 = await timecampApi.users.invite({ email: 'newuser@example.com', name: 'John Doe', group_id: 12345 }); // Invite user without setting a display name (skips name update) const result3 = await timecampApi.users.invite({ email: 'another@example.com', group_id: 12345 }); // Check the invite status and user ID console.log(result.statuses['newuser@example.com'].status); // "Invite" console.log(result.user_id); // "123456"

Custom Fields (v3)

Convenience helpers to manage Custom Fields for users, tasks and time entries.

// List all templates const templates = await timecampApi.customFields.getAll() // Create and delete a template const created = await timecampApi.customFields.add({ name: 'Customer Priority', resourceType: 'user', fieldType: 'string', required: false, defaultValue: '' }) await timecampApi.customFields.delete(created.data.id) // Users await timecampApi.users.getAll() await timecampApi.users.byId(123).getAllCustomFields() await timecampApi.users.byId(123).getCustomField(66) await timecampApi.users.byId(123).setCustomField(66, 'In Progress') await timecampApi.users.byId(123).updateCustomField(66, 'Done') await timecampApi.users.byId(123).deleteCustomField(66) // Tasks await timecampApi.tasks.byId(456).getAllCustomFields() await timecampApi.tasks.byId(456).getCustomField(66) await timecampApi.tasks.byId(456).setCustomField(66, '5') await timecampApi.tasks.byId(456).deleteCustomField(66) // Time Entries await timecampApi.timeEntries.byId(789).getAllCustomFields()

Tags and Tag Lists

Manage tags and tag lists for organizing time entries.

Tag Lists

// Get all tag lists const tagLists = await timecampApi.tags.getTagLists(); // Get tag lists with options const tagLists = await timecampApi.tags.getTagLists({ archived: 0, // Exclude archived tags: 1, // Include tags in response exclude_empty_tag_lists: 1 // Exclude empty tag lists }); // Get specific tag list with all its tags const tagList = await timecampApi.tags.getTagList(8); console.log(tagList.name); // "My tag list" console.log(tagList.tags); // Object with tag IDs as keys // Create a new tag list const tagListId = await timecampApi.tags.createTagList({ name: 'Project Types' }); // Update a tag list await timecampApi.tags.updateTagList(tagListId, { name: 'Updated Tag List Name', archived: 0 }); // Get only the tags from a tag list (without tag list details) const tags = await timecampApi.tags.getTagListTags(8);

Tags

// Create a new tag in a tag list const tagId = await timecampApi.tags.createTag({ list: 52, // Tag list ID name: 'Development' }); // Get tag details const tag = await timecampApi.tags.getTag(13); console.log(tag.name); // "Development" console.log(tag.tagListId); // "52" // Update a tag await timecampApi.tags.updateTag(13, { name: 'Backend Development', archived: 0 });

Tags on Time Entries

Add, retrieve, and remove tags from time entries.

// Create time entry with tags const entry = await timecampApi.timeEntries.create({ date: '2024-01-09', duration: 3600, start_time: '09:00', end_time: '10:00', description: 'Development work', task_id: 12345, tags: [ { tagId: 1 }, { tagId: 4 } ] }); // Get tags for a time entry const entryTags = await timecampApi.timeEntries.getTags(101434259); // Returns: { '101434259': [{ tagListName, tagListId, tagId, name, mandatory }] } // Add tags to an existing time entry await timecampApi.timeEntries.addTags(101434259, [13, 14]); // Returns: ['13'] (IDs of successfully added tags) // Remove tags from time entry await timecampApi.timeEntries.removeTags(101434259, [15]); // Returns: ['15'] (IDs of successfully removed tags)

Computer Activities

Retrieve computer activity tracking data with application names automatically resolved.

// Get activities for current user (default: 'me') const activities = await timecampApi.computerActivities.get({ date_from: '2024-01-01', date_to: '2024-01-07', }); // Get activities for specific users const activities = await timecampApi.computerActivities.get({ date_from: '2024-01-01', date_to: '2024-01-03', user_ids: '123,456', }); // Each activity includes the resolved application_name for (const activity of activities) { console.log(`${activity.date} ${activity.start_time} - ${activity.application_name}: ${activity.window_title}`); }

Important Notes:

  • Maximum date range is 7 days. Exceeding this will throw an error.
  • user_ids defaults to 'me' (current authenticated user)
  • Multiple users result in separate API calls combined into one result
  • Application names are automatically fetched via the /application endpoint and merged into each activity

Computer Activity Types:

interface TimeCampComputerActivitiesRequest { date_from: string; // YYYY-MM-DD format (required) date_to: string; // YYYY-MM-DD format (required) user_ids?: string; // Comma-separated user IDs or 'me' (default: 'me') } interface TimeCampComputerActivity { user_id: string; application_id: string; end_time: string; time_span: number; window_title_id: string; end_date: string; task_id: string; entry_id: string; updated_at: string; update_date: string; application_name?: string; // Resolved from /application endpoint application_info?: string; // Additional info (e.g. domain) }

Billing Rates

Manage billing rates for tasks, users, groups, and task-user combinations.

Task Rates

// Get all billing rates for a task const taskRates = await timecampApi.billingRates.getTaskRates(12345); // Returns: { '12345': [{ rateId, rateTypeId, value, refType, addDate, refId }] } // Get specific rate type for a task const taskRates = await timecampApi.billingRates.getTaskRates(12345, '1,2'); // Comma-separated rate type IDs // Set or update a task billing rate const rate = await timecampApi.billingRates.setTaskRate(12345, { rateTypeId: 1, value: 150, addDate: '2024-01-09' // Optional });

User Rates

// Get all billing rates for a user const userRates = await timecampApi.billingRates.getUserRates(100); // Set or update a user billing rate const rate = await timecampApi.billingRates.setUserRate(100, { rateTypeId: 1, value: 100 });

Task-User Rates (Specific Override)

Task-user rates override both task and user rates for a specific user on a specific task.

// Get task-user specific rates const taskUserRates = await timecampApi.billingRates.getTaskUserRates(12345, 100); // Set task-user specific rate (overrides task and user rates) const rate = await timecampApi.billingRates.setTaskUserRate(12345, 100, { rateTypeId: 1, value: 175 // Higher rate for this user on this specific task });

Group Rates

// Get all billing rates for a group const groupRates = await timecampApi.billingRates.getGroupRates(50); // Set or update a group billing rate const rate = await timecampApi.billingRates.setGroupRate(50, { rateTypeId: 1, value: 125 });

Rate Types (Internal API)

Warning: This is an undocumented internal API method.

// Get all rate types const rateTypes = await timecampApi.billingRates.getRateTypes();

Billing Rate Types:

interface TimeCampSetRateRequest { rateTypeId: number; // Rate type identifier value: number; // Rate value (e.g., hourly rate) addDate?: string; // Optional date in YYYY-MM-DD format } interface TimeCampBillingRate { rateId: number; rateTypeId: number; value: string; refType: string; // 'task', 'user', 'task_user', or 'group' addDate: string; refId: string; } interface TimeCampRateType { rateTypeId: number; name: string; isCost: boolean; }

Groups

Manage groups (departments, teams) in your TimeCamp organization.

// Get all groups const groups = await timecampApi.groups.getAll(); console.log(groups); // [{ group_id: 530222, name: 'People', parent_id: 0 }] // Create a new group under a parent const newGroup = await timecampApi.groups.create({ name: 'Development Team', parent_id: 530222 }); console.log(newGroup.group_id); // 390673 console.log(newGroup.root_group_id); // 530222 // Create a root group (parent_id defaults to 0 if not provided) const rootGroup = await timecampApi.groups.create({ name: 'New Organization' }); // Update a group's name await timecampApi.groups.update({ group_id: 390673, name: 'Backend Development' }); // Move a group to a different parent await timecampApi.groups.update({ group_id: 390673, parent_id: 123456 // New parent group ID }); // Update both name and parent await timecampApi.groups.update({ group_id: 390673, name: 'Backend Team', parent_id: 123456 }); // Delete a group await timecampApi.groups.delete(390673);

Important Notes:

  • Maximum group tree depth is 4 levels
  • Root groups have parent_id = 0 (there can only be one root group)
  • When a group is deleted, all its subgroups are moved to the root group
  • Root groups cannot be deleted

Group Types:

interface TimeCampCreateGroupRequest { name: string; // Group name (required) parent_id?: number; // Parent group ID (optional, defaults to 0 for root) } interface TimeCampGroup { group_id: number; name: string; parent_id: number; admin_id?: number; root_group_id?: number; } interface TimeCampUpdateGroupRequest { group_id: number; // Group ID to update (required) name?: string; // New name (optional) parent_id?: number; // New parent ID (optional) }

Clients

Manage clients for invoicing. Requires the invoicing module to be enabled.

// List all clients const clients = await timecampApi.clients.getAll(); console.log('Clients:', clients); // Create a client const client = await timecampApi.clients.create({ organizationName: 'Acme Corp', firstName: 'John', lastName: 'Doe', email: 'john@acme.com', }); console.log('Created client:', client); // Update a client const updatedClient = await timecampApi.clients.update({ clientId: client.clientId, organizationName: 'Acme Corp Updated', address: '123 Main St, New York, NY', }); console.log('Updated client:', updatedClient); // Get tasks assigned to a client const clientTasks = await timecampApi.clients.getTasks(client.clientId); // Get tasks for multiple clients at once const multiClientTasks = await timecampApi.clients.getTasks([1412133, 1412134]); // Remove tasks from a client await timecampApi.clients.removeTasks(client.clientId, [101, 102]); // Delete a client (will fail if client has invoices) await timecampApi.clients.delete(client.clientId);

Important Notes:

  • organizationName is required when creating a client
  • Clients cannot be deleted if they have associated invoices

Client Types:

interface TimeCampClient { clientId: number; firstName: string; lastName: string; organizationName: string; address: string; currencyId: number; email: string; rootGroupId: number; addedBy: number; added: string; } interface TimeCampCreateClientRequest { organizationName: string; // required firstName?: string; lastName?: string; address?: string; currencyId?: number; email?: string; } interface TimeCampUpdateClientRequest { clientId: number; // required organizationName?: string; firstName?: string; lastName?: string; address?: string; currencyId?: number; email?: string; }

Invoices

Create and manage invoices from time entries. Requires the invoicing module to be enabled.

// List all invoices const invoices = await timecampApi.invoices.getAll(); console.log('Invoices:', invoices); // Create an invoice from time entries const invoice = await timecampApi.invoices.create({ clientId: 1412133, issueDate: '2026-02-10', addDate: '2026-02-10', noteToClient: 'From 2026-01-26 to 2026-02-28', currencyId: 1, invoiceNumber: '1223', entries: [ { invoiceId: -1, invoiceEntryId: -1, description: '2026-01-26 07:53 ', type: 0, duration: 19980, quantity: 5.55, unitCost: 109, taxId: 198, name: '[ORG] Administration - Ewelina Łagos', subTotal: 604.95, ttEntriesIds: [263222996], }, ], }); console.log('Created invoice:', invoice); // Update an existing invoice const updatedInvoice = await timecampApi.invoices.update({ invoiceId: invoice.invoiceId, noteToClient: 'Updated note', status: 1, }); console.log('Updated invoice:', updatedInvoice); // Delete an invoice await timecampApi.invoices.delete(invoice.invoiceId);

Key Concepts:

  • When creating a new invoice, set invoiceId: -1 on each entry (this is done automatically by the create method)
  • Set invoiceEntryId: -1 for new entries
  • ttEntriesIds links invoice entries to time tracking entries by their IDs
  • duration is in seconds, quantity is in hours (duration / 3600)
  • subTotal = quantity * unitCost

Invoice Types:

interface TimeCampInvoice { invoiceId: number; clientId: number; invoiceNumber: string; description: string; issueDate: string; dueDate: string; editDate: string; status: number; sentDate: string; viewedDate: string; addDate: string; paidDate: string; noteToClient: string; pass: string; poNumber: string; userId: number; currencyId: number; rootGroupId: string; publicHash: string; storedFileId: number | null; quote: boolean; entries: TimeCampInvoiceEntry[]; } interface TimeCampInvoiceEntry { invoiceId: number; invoiceEntryId: number; description: string; type: number; quantity: number; duration: number; unitCost: number; taxId: number; name: string; subTotal?: number; ttEntriesIds?: number[]; } interface TimeCampCreateInvoiceRequest { clientId: number; // required issueDate: string; // required entries: TimeCampCreateInvoiceEntryRequest[]; // required invoiceNumber?: string; description?: string; addDate?: string; dueDate?: string; noteToClient?: string; currencyId?: number; status?: number; userId?: number; rootGroupId?: number; quote?: boolean; // ... additional optional fields }

Fetch every task visible to the authenticated account, including archived tasks.

Returns: Promise<TasksAPIResponse>

timer.start(data?: TimerStartRequest)

Start a new timer.

Parameters:

  • data (optional): Timer start configuration
    • task_id: ID of the task to track (optional)
    • note: Description note for the timer (optional)
    • started_at: Custom start time in ISO 8601 format (optional, defaults to current time)

Returns: Promise<TimerEntry>

interface TimerStartRequest { task_id?: number; note?: string; started_at?: string; // ISO 8601 format }

timer.stop(data?: TimerStopRequest)

Stop the currently running timer.

Parameters:

  • data (optional): Timer stop configuration
    • stopped_at: Custom stop time in ISO 8601 format (optional, defaults to current time)

Returns: Promise<TimerEntry>

interface TimerStopRequest { stopped_at?: string; // ISO 8601 format }

timer.status()

Get the current timer status.

Returns: Promise<TimerStatus>

interface TimerStatus { timer_id?: number; task_id?: number; start_time?: string; running: boolean; duration?: number; } interface TimerEntry { id: number; task_id: number; user_id: number; name: string; note: string; start_time: string; end_time: string | null; duration: number; locked: boolean; billable: boolean; invoiced: boolean; approved: boolean; }

timeEntries.get(params?: TimeCampTimeEntriesRequest)

Get time entries with optional filtering.

Parameters:

  • params (optional): Filtering parameters
    • user_ids: Filter by user ID, to get only user entries use "me" (optional)
    • task_id: Filter by task ID (optional)
    • date_from: Start date in YYYY-MM-DD format (optional)
    • date_to: End date in YYYY-MM-DD format (optional)
    • format: Response format, 'json' is automatically set (optional)

Returns: Promise<TimeCampTimeEntry[]>

interface TimeCampTimeEntriesRequest { user_id?: string; task_id?: string; date_from?: string; date_to?: string; format?: string; } interface TimeCampTimeEntry { id: number; duration: number; // Duration in seconds user_id: string; user_name: string; task_id: string; task_note?: string; last_modify: string; date: string; start_time: string; end_time: string; locked: string; name: string; addons_external_id: string; billable: number; invoiceId: string; color: string; description: string; tags: TimeCampTag[]; hasEntryLocationHistory: boolean; } interface TimeCampTag { tagListName: string; tagListId: string; tagId: string; name: string; mandatory: string; }

timeEntries.create(entry: TimeCampCreateTimeEntryRequest)

Create a new time entry.

Parameters:

  • entry: Time entry data
    • date: Date in YYYY-MM-DD format (required)
    • duration: Duration in seconds (required)
    • start_time: Start time in HH:MM:SS format (required)
    • end_time: End time in HH:MM:SS format (required)
    • task_id: ID of the task (optional)
    • description: Description of the work done (optional)

Returns: Promise<TimeCampCreateTimeEntryResponse>

interface TimeCampCreateTimeEntryRequest { date: string; duration: number; // in seconds task_id?: number; description?: string; start_time: string; end_time: string; user_id?: number; billable?: boolean; tags?: Array<{ tagId: number }>; // Optional tags to add on creation } interface TimeCampCreateTimeEntryResponse { success: boolean; id?: string; message: string; }

timeEntries.update(id: number, data: Partial<TimeCampCreateTimeEntryRequest>)

Update an existing time entry.

Parameters:

  • id: ID of the time entry to update (required)
  • data: Partial time entry data to update (supports partial updates)

Returns: Promise<TimeCampCreateTimeEntryResponse>

timeEntries.delete(id: number)

Delete a time entry.

Parameters:

  • id: ID of the time entry to delete (required)

Returns: Promise<{success: boolean, message: string}>

API Reference

Based on the TimeCamp API documentation.

Recent Updates

Version 1.9.0

  • Added computer activities tracking (computerActivities.get()) with automatic application name resolution

Version 1.8.0

  • ✅ Added clients management (clients.getAll(), clients.create(), clients.update(), clients.delete(), clients.getTasks(), clients.removeTasks())
  • ✅ Added invoices management (invoices.getAll(), invoices.create(), invoices.update(), invoices.delete())
  • ✅ Invoice creation supports linking time entries via ttEntriesIds

Version 1.7.0

  • ✅ Added tasks.update() method for updating tasks and assigning users
  • ✅ Added complete tags and tag lists management (tags.* methods)
  • ✅ Added tag support for time entries (create with tags, add/remove tags)
  • ✅ Added billing rates management for tasks, users, groups, and task-user combinations
  • ✅ Added groups management (groups.getAll(), groups.create(), groups.update(), groups.delete())

Not Yet Implemented

  • Rename description to note in TimeCampTimeEntry
  • Many more endpoints to be added

License

MIT

Packages

 
 
 

Contributors