API Usage

actiTIME API provides access to the data stored in actiTIME and simplifies data extraction, entry, and update. In the sections below, you can find more details on performing various operations with actiTIME data and examples of how to use actiTIME API for common use cases.

Make sure your actiTIME installation is running while executing the examples below.
All examples require the latest versions of Chrome or Mozilla Firefox browsers.

To run the examples on your installation, first copy this code to your browser console or script and change parameters (API_URL, USER, PASSWORD) to your own ones.

const API_URL = "<your actiTIME URL>/api/v1/swagger"
const USER = "admin"
const PASSWORD = "manager"
const HEADERS = {"Authorization": "Basic " + btoa(USER + ":" + PASSWORD)}
const GET = {headers: HEADERS}
const POST = {method: "POST", headers: HEADERS, "Content-Type": "application/json"}
const TO_JSON = r => r.json()
const SUM = (a, b) => a + b
const DATE = (() => {let date = new Date(); date.setMonth(date.getMonth()-1); return date.toISOString().substring(0,10);})();

function formatTime(minutes) {
  let hours = Math.floor(minutes / 60) + ""
  let hourMinutes = (minutes % 60) + ""
  if (hourMinutes.length < 2) hourMinutes = "0" + hourMinutes
  return hours + ":" + hourMinutes
}

Then copy the examples below and call the necessary function, e.g. “example03_userList()”. The result will be shown in the browser console.

Getting Users’ Time-Track and Leave Time from actiTIME

With actiTIME API, you can extract users’ time-track and leave time for various periods of time from actiTIME database. The response is returned in JSON format, so you can easily import time-track and leave time to another system or just back up your data.

The code below gets time-track and leave time of all users for the selected date range:

async function example01_getTimetrack(outputTable = console.table, outputHeader = console.log) {
    let timetrack = await fetch(`${API_URL}/timetrack?dateFrom=${DATE}&stopAfter=100&includeReferenced=users`, GET).then(TO_JSON)
    let leaves = await fetch(`${API_URL}/leavetime?dateFrom=${DATE}&dateTo=${timetrack.dateTo}&includeReferenced=users`, GET).then(TO_JSON)
    let dateFrom = new Date(DATE)
    let dateTo = new Date(timetrack.dateTo)
    let userIds = new Set(timetrack.data.map(d => d.userId).concat(leaves.data.map(d => d.userId)))
	outputHeader(`Tracked time for ${dateFrom.toDateString()} - ${dateTo.toDateString()}`);
    outputTable([
        ["User", "Work time", "Leave time"],
        ...Array.from(userIds).map(id => [
            (timetrack.users[id] || leaves.users[id]).fullName,
            formatTime(
                timetrack.data
                    .filter(d => d.userId === id)
                    .map(d => d.records.map(r => r.time).reduce(SUM, 0))
                    .reduce(SUM, 0)
            ),
            formatTime(
                leaves.data
                    .filter(d => d.userId === id)
                    .map(d => d.leaveTime)
                    .reduce(SUM, 0)
            )
        ])
    ])
}

Creating New Objects in actiTIME

actiTIME API allows to easily create customers, projects and tasks. You can create both the entire hierarchical system and separate customers, projects and tasks.

The code below creates the following objects using only one request: 1 customer containing 1 project and 3 tasks.

async function example02_createStructure(outputTable = console.table) {
    const CUSTOMER_NAME = "Big Bang Company " + new Date().toString();
    let batch = [
    {
        id: "bbc_customer",
        relativeUrl: "/customers",
        method: "POST",
        body: {
            name: CUSTOMER_NAME
        },
        includeResponseBody: true
    },
    {
        id: "fo_project",
        relativeUrl: "/projects",
        method: "POST",
        body: {
            name: "Flight operations",
            customerId: "$bbc_customer.id"
        }
    },
    {
        relativeUrl: "/tasks",
        method: "POST",
        body: {
            name: "Flight analysis",
            projectId: "$fo_project.id",
            deadline: "2100-01-01"
        }
    },
    {
        relativeUrl: "/tasks",
        method: "POST",
        body: {
            name: "Flight support",
            projectId: "$fo_project.id",
            estimatedTime: 80
        }
    },
    {
        relativeUrl: "/tasks",
        method: "POST",
        body: {
            name: "NASA negotiations",
            projectId: "$fo_project.id",
            status: "completed"
        }
    }
    ];
    let batchResult = await fetch(`${API_URL}/batch`, {...POST, body: JSON.stringify(batch)}).then(TO_JSON);
    const URL_TO_ENTITY = {
        "/customers": "customer",
        "/projects": "project",
        "/tasks": "task"
    }
    function link(type, id) {
        return API_URL.replace('/api/v1','') + `/tasks/tasklist.do?` + new URLSearchParams({[`${type}id`]: id}).toString(); 
    }

    outputTable([
        ["Create", "Status", "Link to created"],
        ...batch.map((request, index) => [
            URL_TO_ENTITY[request.relativeUrl] + " '" + request.body.name + "'",
            batchResult[index].status === 200 ? "OK" : JSON.stringify(batchResult[index].body),
            batchResult[index].status === 200 ? `&lta target="_blank" href="${link(URL_TO_ENTITY[request.relativeUrl], batchResult[index].body.id)}"&gt Open in actiTIME&lt/a&gt` : ""
        ])
    ]);
}

Creating Customized Reports

actiTIME API helps extract custom data sets for importing them later into other systems. If you are missing some grouping options in reports available in actiTIME interfaces, you can create reports of your own configuration.

The code below gets the list of active system users with their IDs, full names, departments, and emails:

async function example03_userList(outputTable = console.table) {
    let users = await fetch(`${API_URL}/users?` + new URLSearchParams({"active":"true", "includeReferenced":"departments"}).toString(), GET).then(TO_JSON);
    outputTable([
        ["ID", "Full name", "Department", "Email"],
        ...users.items.map(user => [
            user.id + "",
            user.fullName,
            user.departmentId === -1 ? "" : users.departments[user.departmentId].name,
            user.email || ""        
        ])
    ])
}

The code below gets the full list of tasks existing in the system sorted by task name, along with their statuses and customers and projects they belong to:

async function example04_taskList(outputTable = console.table) {
    let tasks = await fetch(`${API_URL}/tasks?` + new URLSearchParams({"includeReferenced": "projects,customers", "sort": "+name"}), GET).then(TO_JSON);
    
    outputTable([
        ["Customer", "Project", "Task", "Status"],
        ...tasks.items.map(task => [
            tasks.customers[task.customerId].name,
            tasks.projects[task.projectId].name,
            task.name,
            task.status
        ])
    ])

}

The code below gets the time-track grouped by customers and types of work for selected date range:

async function example05_customersVsTypesOfWork(outputTable = console.table) {
    let timetrack = await fetch(`${API_URL}/timetrack?dateFrom=${DATE}&includeReferenced=customers,tasks,typesOfWork`, GET).then(TO_JSON);
    let dateTo = timetrack.dateTo;
    let typesOfWork = Object.values(timetrack.typesOfWork);
    let customers = Object.values(timetrack.customers);
    
    let timetrackRecords = timetrack.data.reduce((result,daytt) => result.concat(daytt.records), [])
    
    outputTable([
        ["Type Of Work/Customer", ...customers.map(customer => customer.name)],
        ...typesOfWork.map(tow => [
            tow.name,
            ...customers.map(customer => (
                formatTime(
                    timetrackRecords
                        .filter(tt => timetrack.tasks[tt.taskId].customerId === customer.id && timetrack.tasks[tt.taskId].typeOfWorkId === tow.id)
                        .map(tt => tt.time)
                        .reduce(SUM, 0)
                )
            ))
        ])
    ])
}