Toggl Track
by @byungkyu
Toggl Track API integration with managed OAuth. Track time, manage projects, clients, and tags. Use this skill when users want to create, read, update, or de...
clawhub install toggl-trackπ About This Skill
name: toggl-track description: | Toggl Track API integration with managed OAuth. Track time, manage projects, clients, and tags. Use this skill when users want to create, read, update, or delete time entries, projects, clients, or tags in Toggl Track. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). compatibility: Requires network access and valid Maton API key metadata: author: maton version: "1.0" clawdbot: emoji: π§ homepage: "https://maton.ai" requires: env: - MATON_API_KEY
Toggl Track
Access the Toggl Track API with managed OAuth authentication. Track time, manage projects, clients, tags, and workspaces.
Quick Start
# Get current user info
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/toggl-track/api/v9/me')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/toggl-track/{native-api-path}
Maton proxies requests to api.track.toggl.com and automatically injects your credentials.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key
Connection Management
Manage your Toggl Track OAuth connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=toggl-track&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'toggl-track'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2026-02-13T19:31:31.452264Z",
"last_updated_time": "2026-02-13T19:36:10.489069Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "toggl-track",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple Toggl Track connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/toggl-track/api/v9/me')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
API Reference
User & Workspace
#### Get Current User
GET /toggl-track/api/v9/me
Response:
{
"id": 12932942,
"email": "user@example.com",
"fullname": "John Doe",
"timezone": "America/Los_Angeles",
"default_workspace_id": 21180405,
"beginning_of_week": 1,
"image_url": "https://assets.track.toggl.com/images/profile.png"
}
#### List Workspaces
GET /toggl-track/api/v9/me/workspaces
#### Get Workspace
GET /toggl-track/api/v9/workspaces/{workspace_id}
#### List Workspace Users
GET /toggl-track/api/v9/workspaces/{workspace_id}/users
Time Entries
#### List Time Entries
GET /toggl-track/api/v9/me/time_entries
Query Parameters:
since (integer) - UNIX timestamp for entries modified after this timebefore (string) - Get entries before this date (RFC3339 or YYYY-MM-DD)start_date (string) - Filter start date (YYYY-MM-DD)end_date (string) - Filter end date (YYYY-MM-DD)#### Get Current (Running) Time Entry
GET /toggl-track/api/v9/me/time_entries/current
Returns null if no time entry is currently running.
#### Get Time Entry by ID
GET /toggl-track/api/v9/me/time_entries/{time_entry_id}
#### Create Time Entry
POST /toggl-track/api/v9/workspaces/{workspace_id}/time_entries
Content-Type: application/json{
"description": "Working on project",
"start": "2026-02-13T10:00:00Z",
"duration": -1,
"workspace_id": 21180405,
"project_id": 216896134,
"tag_ids": [20053808],
"created_with": "maton-api"
}
Note: Set duration to -1 to start a running timer. The created_with field is required.
Response:
{
"id": 4290254971,
"workspace_id": 21180405,
"project_id": null,
"task_id": null,
"billable": false,
"start": "2026-02-13T19:58:43Z",
"stop": null,
"duration": -1,
"description": "Working on project",
"tags": null,
"tag_ids": null,
"user_id": 12932942
}
#### Update Time Entry
PUT /toggl-track/api/v9/workspaces/{workspace_id}/time_entries/{time_entry_id}
Content-Type: application/json{
"description": "Updated description",
"project_id": 216896134
}
#### Stop Running Time Entry
PATCH /toggl-track/api/v9/workspaces/{workspace_id}/time_entries/{time_entry_id}/stop
#### Delete Time Entry
DELETE /toggl-track/api/v9/workspaces/{workspace_id}/time_entries/{time_entry_id}
Projects
#### List Projects
GET /toggl-track/api/v9/workspaces/{workspace_id}/projects
Query Parameters:
active (boolean) - Filter by active statussince (integer) - UNIX timestamp for modification filtername (string) - Filter by project namepage (integer) - Page numberper_page (integer) - Items per page (max 200)#### Get Project
GET /toggl-track/api/v9/workspaces/{workspace_id}/projects/{project_id}
#### Create Project
POST /toggl-track/api/v9/workspaces/{workspace_id}/projects
Content-Type: application/json{
"name": "New Project",
"active": true,
"is_private": true,
"client_id": 68493239,
"color": "#0b83d9",
"billable": true
}
Response:
{
"id": 216896134,
"workspace_id": 21180405,
"client_id": null,
"name": "New Project",
"is_private": true,
"active": true,
"color": "#0b83d9",
"billable": true,
"created_at": "2026-02-13T19:58:36+00:00"
}
#### Update Project
PUT /toggl-track/api/v9/workspaces/{workspace_id}/projects/{project_id}
Content-Type: application/json{
"name": "Updated Project Name",
"color": "#ff0000"
}
#### Delete Project
DELETE /toggl-track/api/v9/workspaces/{workspace_id}/projects/{project_id}
Clients
#### List Clients
GET /toggl-track/api/v9/workspaces/{workspace_id}/clients
Query Parameters:
status (string) - Filter: active, archived, or bothname (string) - Case-insensitive name filter#### Get Client
GET /toggl-track/api/v9/workspaces/{workspace_id}/clients/{client_id}
#### Create Client
POST /toggl-track/api/v9/workspaces/{workspace_id}/clients
Content-Type: application/json{
"name": "New Client",
"notes": "Client notes here"
}
Response:
{
"id": 68493239,
"wid": 21180405,
"archived": false,
"name": "New Client",
"at": "2026-02-13T19:58:36+00:00",
"creator_id": 12932942
}
#### Update Client
PUT /toggl-track/api/v9/workspaces/{workspace_id}/clients/{client_id}
Content-Type: application/json{
"name": "Updated Client Name"
}
#### Delete Client
DELETE /toggl-track/api/v9/workspaces/{workspace_id}/clients/{client_id}
#### Archive Client
POST /toggl-track/api/v9/workspaces/{workspace_id}/clients/{client_id}/archive
#### Restore Client
POST /toggl-track/api/v9/workspaces/{workspace_id}/clients/{client_id}/restore
Content-Type: application/json{
"restore_all_projects": true
}
Tags
#### List Tags
GET /toggl-track/api/v9/workspaces/{workspace_id}/tags
Query Parameters:
page (integer) - Page numberper_page (integer) - Items per page#### Create Tag
POST /toggl-track/api/v9/workspaces/{workspace_id}/tags
Content-Type: application/json{
"name": "New Tag"
}
Response:
{
"id": 20053808,
"workspace_id": 21180405,
"name": "New Tag",
"at": "2026-02-13T19:58:37.115714Z",
"creator_id": 12932942
}
#### Update Tag
PUT /toggl-track/api/v9/workspaces/{workspace_id}/tags/{tag_id}
Content-Type: application/json{
"name": "Updated Tag Name"
}
#### Delete Tag
DELETE /toggl-track/api/v9/workspaces/{workspace_id}/tags/{tag_id}
Pagination
Toggl Track uses page-based pagination for most list endpoints:
GET /toggl-track/api/v9/workspaces/{workspace_id}/projects?page=1&per_page=50
For time entries, use timestamp-based filtering:
GET /toggl-track/api/v9/me/time_entries?since=1707840000&start_date=2026-02-01&end_date=2026-02-28
Code Examples
JavaScript
const response = await fetch(
'https://api.maton.ai/toggl-track/api/v9/me/time_entries',
{
headers: {
'Authorization': Bearer ${process.env.MATON_API_KEY}
}
}
);
const timeEntries = await response.json();
Python
import os
import requestsresponse = requests.get(
'https://api.maton.ai/toggl-track/api/v9/me/time_entries',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
time_entries = response.json()
Start a Timer
import os
import requests
from datetime import datetime, timezoneresponse = requests.post(
'https://api.maton.ai/toggl-track/api/v9/workspaces/21180405/time_entries',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'description': 'Working on task',
'start': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'),
'duration': -1,
'workspace_id': 21180405,
'created_with': 'maton-api'
}
)
Notes
21180405)4290254971)-1 for running timers2026-02-13T19:58:43Z)created_with field is required when creating time entriescurl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environmentsError Handling
| Status | Meaning | |--------|---------| | 400 | Missing Toggl Track connection or invalid request | | 401 | Invalid or missing Maton API key | | 403 | Access denied | | 404 | Resource not found | | 429 | Rate limited | | 4xx/5xx | Passthrough error from Toggl Track API |
Troubleshooting: API Key Issues
1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
2. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Troubleshooting: Invalid App Name
1. Ensure your URL path starts with toggl-track. For example:
https://api.maton.ai/toggl-track/api/v9/mehttps://api.maton.ai/api/v9/meResources
π‘ Examples
# Get current user info
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/toggl-track/api/v9/me')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
π Tips & Best Practices
21180405)4290254971)-1 for running timers2026-02-13T19:58:43Z)created_with field is required when creating time entriescurl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments