diff --git a/toggl/README.md b/toggl/README.md index 05ca3021..6407e703 100644 --- a/toggl/README.md +++ b/toggl/README.md @@ -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 | diff --git a/toggl/config.json b/toggl/config.json index 00501c9a..a109295a 100644 --- a/toggl/config.json +++ b/toggl/config.json @@ -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": { diff --git a/toggl/requirements.txt b/toggl/requirements.txt index b56fee2e..1af9591f 100644 --- a/toggl/requirements.txt +++ b/toggl/requirements.txt @@ -1 +1 @@ -autohive-integrations-sdk~=1.0.2 +autohive-integrations-sdk~=2.0.0 diff --git a/toggl/toggl.py b/toggl/toggl.py index ed3edcca..90b525bf 100644 --- a/toggl/toggl.py +++ b/toggl/toggl.py @@ -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() @@ -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"] @@ -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) + except Exception as e: + return ActionError(message=str(e))