curl --request POST \
--url https://api.threadi.au/stopwatch/v1/timelogs/search \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"limit": 100,
"after": 100,
"properties": [
"a552213_record_id",
"hubspot_owner_id",
"a552213_category_text"
],
"sorts": [
{
"propertyName": "hs_lastmodifieddate",
"direction": "DESCENDING"
}
],
"filterGroups": [
{
"filters": [
{
"propertyName": "a552213_category_text",
"operator": "CONTAINS_TOKEN",
"value": "Meetings"
}
]
}
]
}
'import requests
url = "https://api.threadi.au/stopwatch/v1/timelogs/search"
payload = {
"limit": 100,
"after": 100,
"properties": ["a552213_record_id", "hubspot_owner_id", "a552213_category_text"],
"sorts": [
{
"propertyName": "hs_lastmodifieddate",
"direction": "DESCENDING"
}
],
"filterGroups": [{ "filters": [
{
"propertyName": "a552213_category_text",
"operator": "CONTAINS_TOKEN",
"value": "Meetings"
}
] }]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
limit: 100,
after: 100,
properties: ['a552213_record_id', 'hubspot_owner_id', 'a552213_category_text'],
sorts: [{propertyName: 'hs_lastmodifieddate', direction: 'DESCENDING'}],
filterGroups: [
{
filters: [
{
propertyName: 'a552213_category_text',
operator: 'CONTAINS_TOKEN',
value: 'Meetings'
}
]
}
]
})
};
fetch('https://api.threadi.au/stopwatch/v1/timelogs/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.threadi.au/stopwatch/v1/timelogs/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'limit' => 100,
'after' => 100,
'properties' => [
'a552213_record_id',
'hubspot_owner_id',
'a552213_category_text'
],
'sorts' => [
[
'propertyName' => 'hs_lastmodifieddate',
'direction' => 'DESCENDING'
]
],
'filterGroups' => [
[
'filters' => [
[
'propertyName' => 'a552213_category_text',
'operator' => 'CONTAINS_TOKEN',
'value' => 'Meetings'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.threadi.au/stopwatch/v1/timelogs/search"
payload := strings.NewReader("{\n \"limit\": 100,\n \"after\": 100,\n \"properties\": [\n \"a552213_record_id\",\n \"hubspot_owner_id\",\n \"a552213_category_text\"\n ],\n \"sorts\": [\n {\n \"propertyName\": \"hs_lastmodifieddate\",\n \"direction\": \"DESCENDING\"\n }\n ],\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"a552213_category_text\",\n \"operator\": \"CONTAINS_TOKEN\",\n \"value\": \"Meetings\"\n }\n ]\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.threadi.au/stopwatch/v1/timelogs/search")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"limit\": 100,\n \"after\": 100,\n \"properties\": [\n \"a552213_record_id\",\n \"hubspot_owner_id\",\n \"a552213_category_text\"\n ],\n \"sorts\": [\n {\n \"propertyName\": \"hs_lastmodifieddate\",\n \"direction\": \"DESCENDING\"\n }\n ],\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"a552213_category_text\",\n \"operator\": \"CONTAINS_TOKEN\",\n \"value\": \"Meetings\"\n }\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.threadi.au/stopwatch/v1/timelogs/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"limit\": 100,\n \"after\": 100,\n \"properties\": [\n \"a552213_record_id\",\n \"hubspot_owner_id\",\n \"a552213_category_text\"\n ],\n \"sorts\": [\n {\n \"propertyName\": \"hs_lastmodifieddate\",\n \"direction\": \"DESCENDING\"\n }\n ],\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"a552213_category_text\",\n \"operator\": \"CONTAINS_TOKEN\",\n \"value\": \"Meetings\"\n }\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"paging": {
"next": {
"after": 100
}
},
"results": [
{
"id": 1234567890,
"properties": {
"a552213_record_id": "28270412 -- 2026-03-20 04:22:15.536",
"a552213_toggle": true,
"a552213_assoc_record_id": 9876543210,
"a552213_first_start_date": "2026-02-27T21:24:18.038Z",
"a552213_first_end_date": "2026-02-28T21:24:18.038Z",
"a552213_last_start_date": "2026-02-27T21:24:18.038Z",
"a552213_last_end_date": "2026-02-28T21:24:18.038Z",
"a552213_total_minutes": 1440,
"a552213_total_hours": 24,
"a552213_total_days": 1,
"a552213_total_years": 0.00273785,
"a552213_total_decades": 0.00027379,
"a552213_total_centuries": 0.00002738,
"a552213_num_sessions": 1,
"a552213_week_year": "2026-02-23T00:00:00.000Z",
"a552213_month_year": "2026-02-01T00:00:00.000Z",
"a552213_is_split_week_record": true,
"a552213_is_split_month_record": true,
"a552213_workflow_managed_tag": "example_tag",
"a552213_billable_minutes": 0,
"a552213_billable_hours": 0,
"a552213_billable_days": 0,
"a552213_billable_years": 0,
"a552213_billable_decades": 0,
"a552213_billable_centuries": 0,
"a552213_billable_amount": 0,
"a552213_cost_amount": 0,
"a552213_margin_amount": 0,
"a552213_is_one_time_log_per_session_record": true,
"a552213_category_text": "Meetings",
"a552213_description": "Meeting about Project XYZ",
"a552213_billable_percentage": 0,
"a552213_service_name": "Training",
"a552213_total_hours_auto": 0,
"a552213_total_days_auto": 0,
"a552213_total_years_auto": 0,
"a552213_total_decades_auto": 0,
"a552213_total_centuries_auto": 0,
"a552213_billable_hours_auto": 0,
"a552213_billable_days_auto": 0,
"a552213_billable_years_auto": 0,
"a552213_billable_decades_auto": 0,
"a552213_billable_centuries_auto": 0,
"a552213_billable_rate": 0,
"a552213_cost_rate": 0,
"a552213_billable_amount_auto": 0,
"a552213_cost_amount_auto": 0,
"a552213_margin_amount_auto": 0,
"a552213_title": "Training Session X"
},
"createdAt": "2026-02-27T21:24:18.038Z",
"updatedAt": "2026-02-28T21:24:18.038Z",
"archived": true
}
],
"total": 123
}{
"error": "HubSpot API Error",
"details": "<hubspot error as string>"
}{
"error": "Invalid API key"
}{
"error": "API key has been deactivated"
}{
"error": "Daily quota exceeded",
"details": "This API key has reached its UTC daily request limit. Use response header x-stopwatch-ratelimit-reset to know when this quota will reset."
}{
"error": "Internal Server Error",
"details": "An unexpected error occurred."
}{
"error": "Service temporarily busy",
"details": "Unable to process request right now. Please retry shortly."
}Search Time Logs
Search for StopWatch Time Log records using HubSpot’s flexible CRM Search engine.
See HubSpot API documentation for the expected request Body structure
curl --request POST \
--url https://api.threadi.au/stopwatch/v1/timelogs/search \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"limit": 100,
"after": 100,
"properties": [
"a552213_record_id",
"hubspot_owner_id",
"a552213_category_text"
],
"sorts": [
{
"propertyName": "hs_lastmodifieddate",
"direction": "DESCENDING"
}
],
"filterGroups": [
{
"filters": [
{
"propertyName": "a552213_category_text",
"operator": "CONTAINS_TOKEN",
"value": "Meetings"
}
]
}
]
}
'import requests
url = "https://api.threadi.au/stopwatch/v1/timelogs/search"
payload = {
"limit": 100,
"after": 100,
"properties": ["a552213_record_id", "hubspot_owner_id", "a552213_category_text"],
"sorts": [
{
"propertyName": "hs_lastmodifieddate",
"direction": "DESCENDING"
}
],
"filterGroups": [{ "filters": [
{
"propertyName": "a552213_category_text",
"operator": "CONTAINS_TOKEN",
"value": "Meetings"
}
] }]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
limit: 100,
after: 100,
properties: ['a552213_record_id', 'hubspot_owner_id', 'a552213_category_text'],
sorts: [{propertyName: 'hs_lastmodifieddate', direction: 'DESCENDING'}],
filterGroups: [
{
filters: [
{
propertyName: 'a552213_category_text',
operator: 'CONTAINS_TOKEN',
value: 'Meetings'
}
]
}
]
})
};
fetch('https://api.threadi.au/stopwatch/v1/timelogs/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.threadi.au/stopwatch/v1/timelogs/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'limit' => 100,
'after' => 100,
'properties' => [
'a552213_record_id',
'hubspot_owner_id',
'a552213_category_text'
],
'sorts' => [
[
'propertyName' => 'hs_lastmodifieddate',
'direction' => 'DESCENDING'
]
],
'filterGroups' => [
[
'filters' => [
[
'propertyName' => 'a552213_category_text',
'operator' => 'CONTAINS_TOKEN',
'value' => 'Meetings'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.threadi.au/stopwatch/v1/timelogs/search"
payload := strings.NewReader("{\n \"limit\": 100,\n \"after\": 100,\n \"properties\": [\n \"a552213_record_id\",\n \"hubspot_owner_id\",\n \"a552213_category_text\"\n ],\n \"sorts\": [\n {\n \"propertyName\": \"hs_lastmodifieddate\",\n \"direction\": \"DESCENDING\"\n }\n ],\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"a552213_category_text\",\n \"operator\": \"CONTAINS_TOKEN\",\n \"value\": \"Meetings\"\n }\n ]\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.threadi.au/stopwatch/v1/timelogs/search")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"limit\": 100,\n \"after\": 100,\n \"properties\": [\n \"a552213_record_id\",\n \"hubspot_owner_id\",\n \"a552213_category_text\"\n ],\n \"sorts\": [\n {\n \"propertyName\": \"hs_lastmodifieddate\",\n \"direction\": \"DESCENDING\"\n }\n ],\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"a552213_category_text\",\n \"operator\": \"CONTAINS_TOKEN\",\n \"value\": \"Meetings\"\n }\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.threadi.au/stopwatch/v1/timelogs/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"limit\": 100,\n \"after\": 100,\n \"properties\": [\n \"a552213_record_id\",\n \"hubspot_owner_id\",\n \"a552213_category_text\"\n ],\n \"sorts\": [\n {\n \"propertyName\": \"hs_lastmodifieddate\",\n \"direction\": \"DESCENDING\"\n }\n ],\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"a552213_category_text\",\n \"operator\": \"CONTAINS_TOKEN\",\n \"value\": \"Meetings\"\n }\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"paging": {
"next": {
"after": 100
}
},
"results": [
{
"id": 1234567890,
"properties": {
"a552213_record_id": "28270412 -- 2026-03-20 04:22:15.536",
"a552213_toggle": true,
"a552213_assoc_record_id": 9876543210,
"a552213_first_start_date": "2026-02-27T21:24:18.038Z",
"a552213_first_end_date": "2026-02-28T21:24:18.038Z",
"a552213_last_start_date": "2026-02-27T21:24:18.038Z",
"a552213_last_end_date": "2026-02-28T21:24:18.038Z",
"a552213_total_minutes": 1440,
"a552213_total_hours": 24,
"a552213_total_days": 1,
"a552213_total_years": 0.00273785,
"a552213_total_decades": 0.00027379,
"a552213_total_centuries": 0.00002738,
"a552213_num_sessions": 1,
"a552213_week_year": "2026-02-23T00:00:00.000Z",
"a552213_month_year": "2026-02-01T00:00:00.000Z",
"a552213_is_split_week_record": true,
"a552213_is_split_month_record": true,
"a552213_workflow_managed_tag": "example_tag",
"a552213_billable_minutes": 0,
"a552213_billable_hours": 0,
"a552213_billable_days": 0,
"a552213_billable_years": 0,
"a552213_billable_decades": 0,
"a552213_billable_centuries": 0,
"a552213_billable_amount": 0,
"a552213_cost_amount": 0,
"a552213_margin_amount": 0,
"a552213_is_one_time_log_per_session_record": true,
"a552213_category_text": "Meetings",
"a552213_description": "Meeting about Project XYZ",
"a552213_billable_percentage": 0,
"a552213_service_name": "Training",
"a552213_total_hours_auto": 0,
"a552213_total_days_auto": 0,
"a552213_total_years_auto": 0,
"a552213_total_decades_auto": 0,
"a552213_total_centuries_auto": 0,
"a552213_billable_hours_auto": 0,
"a552213_billable_days_auto": 0,
"a552213_billable_years_auto": 0,
"a552213_billable_decades_auto": 0,
"a552213_billable_centuries_auto": 0,
"a552213_billable_rate": 0,
"a552213_cost_rate": 0,
"a552213_billable_amount_auto": 0,
"a552213_cost_amount_auto": 0,
"a552213_margin_amount_auto": 0,
"a552213_title": "Training Session X"
},
"createdAt": "2026-02-27T21:24:18.038Z",
"updatedAt": "2026-02-28T21:24:18.038Z",
"archived": true
}
],
"total": 123
}{
"error": "HubSpot API Error",
"details": "<hubspot error as string>"
}{
"error": "Invalid API key"
}{
"error": "API key has been deactivated"
}{
"error": "Daily quota exceeded",
"details": "This API key has reached its UTC daily request limit. Use response header x-stopwatch-ratelimit-reset to know when this quota will reset."
}{
"error": "Internal Server Error",
"details": "An unexpected error occurred."
}{
"error": "Service temporarily busy",
"details": "Unable to process request right now. Please retry shortly."
}Authorizations
Bearer Authorization header of the form Bearer {token}, where {token} is your API key. By default, each API key is rate-limited to 1,000 requests per day (UTC). If you need a higher daily limit, please submit a support request.
Body
The maximum number of records to return. Maximum is 200.
100
The paging cursor for fetching the next page of results. Supplied in the response as paging.next.after.
100
The StopWatch Time Log properties that you'd like included in the response
[
"a552213_record_id",
"hubspot_owner_id",
"a552213_category_text"
]A free text search query to apply to the search. See HubSpot API documentation for more details on how this is applied.
"Meeting about Project XYZ"
Show child attributes
Show child attributes
Show child attributes
Show child attributes

