Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 73 additions & 37 deletions toggl/README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,86 @@
# Toggl Track Integration for Autohive

Creates time entries in Toggl Track using the official API.
Creates time entries in Toggl Track using the official v9 API. Ideal for automating time tracking workflows, logging billable hours, and syncing work sessions into Toggl from external systems.

## Key Features

- Create time entries in any Toggl workspace
- Supports start/stop times, duration, project and task assignment
- Billable flag and tag support (by name or ID)
- API token authentication via HTTP Basic Auth

## Setup & Authentication

- Auth type: API token via HTTP Basic Auth.
- Field required in connection:
- `api_token` (password): Find it at https://track.toggl.com/profile
**Auth type:** Custom (API token)

**Required field:**
- `api_token` — Your Toggl API token. Find it at https://track.toggl.com/profile under "Profile settings" → "API Token".

The integration uses HTTP Basic Auth with `api_token` as both the username and the literal string `api_token` as the password, as required by Toggl's API.

## Actions

The request uses Basic auth with username = your API token and password = `api_token`.
#### create_time_entry

## Action: create_time_entry
Creates a new time entry in the specified Toggl workspace.

Creates a time entry in a workspace.
**Inputs:**

Inputs:
- `workspace_id` (integer, required)
- `start` (string, required) — UTC time, e.g. `2006-01-02T15:04:05Z`
- `stop` (string, optional)
- `duration` (integer, optional) — in seconds; for running entries use `-1`
- `description` (string, optional)
- `project_id` (integer, optional)
- `task_id` (integer, optional)
- `billable` (boolean, optional)
- `tags` (array[string], optional)
- `tag_ids` (array[integer], optional)
- `user_id` (integer, optional)
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `workspace_id` | integer | ✅ | Numeric Toggl workspace ID |
| `start` | string | ✅ | Start time in UTC, format `2006-01-02T15:04:05Z` |
| `stop` | string | optional | Stop time in UTC; omit if the entry is still running or using `duration` |
| `duration` | integer | optional | Duration in seconds. Use `-1` for a running (in-progress) entry |
| `description` | string | optional | Human-readable label for the time entry |
| `project_id` | integer | optional | ID of the project to assign the entry to |
| `task_id` | integer | optional | ID of the task within the project |
| `billable` | boolean | optional | Whether the entry is billable (default: `false`) |
| `tags` | array[string] | optional | Tag names to apply to the entry |
| `tag_ids` | array[integer] | optional | Tag IDs to apply to the entry |
| `user_id` | integer | optional | ID of the user creating the entry; defaults to the authenticated user |

Notes:
- The integration automatically sets `created_with` to `autohive-integrations` as required by Toggl.
- Provide either `stop` or `duration` unless you're creating a running entry with `duration = -1`.
**Notes:**
- Provide either `stop` or `duration` (not both) unless creating a running entry with `duration = -1`.
- The integration automatically sets `created_with: autohive-integrations` as required by Toggl.

**Outputs:**

The response mirrors the Toggl API time entry object, including fields such as `id`, `workspace_id`, `project_id`, `start`, `stop`, `duration`, `description`, `billable`, `tags`, and `at` (last updated timestamp).

## Requirements

- `autohive_integrations_sdk`

## Example

```json
{
"workspace_id": 1234567,
"start": "2025-08-14T10:00:00Z",
"stop": "2025-08-14T11:00:00Z",
"description": "Planning meeting",
"project_id": 7654321,
"billable": true,
"tags": ["meeting", "planning"]
}
```
- `autohive-integrations-sdk~=2.0.0`

## API Info

- **Base URL:** `https://api.track.toggl.com/api/v9`
- **Official docs:** https://developers.track.toggl.com/docs/
- **API version:** v9

## Rate Limiting

Toggl's API enforces per-user rate limits. Standard limits allow up to 1 request per second. Exceeding this returns HTTP 429. No automatic retry is built into this integration.

## Error Handling

| Error | Cause |
|-------|-------|
| `Missing API token` | `api_token` field not present in auth credentials |
| HTTP 403 | Invalid or expired API token |
| HTTP 400 | Missing required fields or malformed body (e.g. `workspace_id` mismatch) |
| HTTP 429 | Rate limit exceeded |

## Troubleshooting

- **403 Forbidden:** Double-check your API token at https://track.toggl.com/profile. Tokens can be regenerated there.
- **400 Bad Request:** Ensure `workspace_id` matches the workspace the project/task belong to. Toggl rejects mismatches.
- **Entry not appearing:** Confirm `start` is in UTC ISO 8601 format (`2006-01-02T15:04:05Z`). Local timezone offsets cause silent failures.
- **Running entry not stopping:** For running entries use `duration: -1` and omit `stop`. To stop it later, use the Toggl UI or a separate API call.
- **Tags not applying:** Tag names are case-sensitive and must already exist in the workspace. Use `tag_ids` for reliability.

## Version History

| Version | Notes |
|---------|-------|
| v1.0.0 | Initial release — `create_time_entry` action with full Toggl v9 API support |
2 changes: 1 addition & 1 deletion toggl/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Toggl Track",
"version": "0.1.0",
"version": "0.1.1",
"description": "Create time entries in Toggl Track via API.",
"entry_point": "toggl.py",
"auth": {
Expand Down
2 changes: 1 addition & 1 deletion toggl/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
autohive-integrations-sdk~=1.0.2
autohive-integrations-sdk~=2.0.0
16 changes: 9 additions & 7 deletions toggl/toggl.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, Any
import base64
from autohive_integrations_sdk import Integration, ExecutionContext, ActionHandler
from autohive_integrations_sdk import Integration, ExecutionContext, ActionHandler, ActionResult, ActionError

# Create the integration using the config.json
toggl = Integration.load()
Expand All @@ -18,7 +18,7 @@ class CreateTimeEntry(ActionHandler):
async def execute(self, inputs: Dict[str, Any], context: ExecutionContext):
api_token = context.auth.get("credentials").get("api_token")
if not api_token:
raise Exception("Toggl API token is required in auth (field 'api_token').")
return ActionError(message="Toggl API token is required in auth (field 'api_token').")

workspace_id = inputs["workspace_id"]

Expand All @@ -45,8 +45,10 @@ async def execute(self, inputs: Dict[str, Any], context: ExecutionContext):
headers = _basic_auth_header_for_api_token(api_token)
url = f"https://api.track.toggl.com/api/v9/workspaces/{workspace_id}/time_entries"

# Perform POST request via the SDK's HTTP client
resp = await context.fetch(url, method="POST", headers=headers, json=body)

# The SDK returns parsed JSON for JSON responses; if it's bytes/string parse may be needed.
return resp
try:
resp = await context.fetch(url, method="POST", headers=headers, json=body)
if resp.status < 200 or resp.status >= 300:
return ActionError(message=f"Toggl API error {resp.status}: {resp.data}")
return ActionResult(data=resp.data, cost_usd=0.0)
Comment thread
Shubhank-Jonnada marked this conversation as resolved.
except Exception as e:
return ActionError(message=str(e))
Loading