Toggl Track to Attio Sync

Toggl Track has the time data. Attio has the client and project context. This custom sync brings Toggl Time Entries and project metadata onto Attio Project records so client teams can see profitability and utilization in the CRM without leaving Attio. The sync is bidirectional: inbound Toggl webhooks handle Time Entry, project, and client changes, while outbound Attio handling creates the matching Toggl project when an Attio Project is created with a linked Company. This is a scoped custom-build engagement.

Who this is for

This build is for agencies, consultancies, and professional-services teams that track time in Toggl and manage clients in Attio. It fits when project profitability and utilization views belong in the CRM, but time tracking still belongs in Toggl.

It is not a generic time-tracking mirror. The sync is shaped around Attio Project records, Company links, Toggl clients, and eligibility rules that decide where new Time Entries should land.

How the sync works

The sync has three paths: inbound Toggl webhook handling, outbound Attio project creation, and workspace-specific routing rules for Time Entries that do not cleanly match an active Attio Project.

Inbound: Toggl webhook flow

Toggl Subscriptions for time_entry, project, and client entity filters stream matching changes into Attio within seconds. Time Entries land on a dedicated toggl_time_entries list parented to Attio Projects with the Toggl payload fields needed for reporting: description, duration, billable, project metadata, client metadata, user metadata, and UTC start and stop timestamps.

Project and client changes update the matching Attio Project, Company, and toggl_clients records. The goal is to keep the CRM reporting surface current without making users round-trip to Toggl for project or client context.

Outbound: Attio to Toggl creation flow

When a new Attio Project is created with a linked Company, the integration creates the matching Toggl project under the right Toggl client. If the Company does not have a toggl_client_id yet, the integration creates or links the Toggl client first, then writes toggl_client_id on the Company and toggl_project_id on the Project.

The outbound flow is idempotent. Re-runs are safe because the receiver checks existing Toggl IDs and uses receiver-side locking to avoid two simultaneous first-sync attempts creating duplicate clients for the same Company.

Eligibility and fallback routing

Eligibility rules are configured per workspace. A common rule excludes certain Attio Project type and status combinations, such as retainer plus complete, from receiving new Time Entries. The fallback Project catches Time Entries that cannot be resolved or are excluded by those rules.

This is implementation logic, not a Toggl API concept. Toggl exposes Time Entry, project, and client data. The routing decision belongs to the Attio integration because each workspace has its own project taxonomy.

What we configure during scope

The scoping call turns the Toggl-to-Attio pattern into your build. These decisions are made before the custom app is installed.

Decision What we decide with you
Workspace Which Toggl Workspace feeds Attio, resolved at connection time through GET /api/v9/me.
Inbound coverage Which Event Filters are subscribed for time_entry, project, and client. Toggl Subscription limits scale by plan: Free is 1 Subscription with up to 3 events, Starter is 2 with up to 6, and Premium is 3 with up to 12 per Workspace.
Eligibility rules Which Attio Project type and status combinations should be excluded from receiving new Time Entries, such as retainer plus complete.
Fallback project Which Attio Project catches Time Entries that cannot be resolved to a specific eligible Project.
Outbound triggers Which Attio events create Toggl projects and clients. The default is projects.record.created with a linked Company.
Field map Which Toggl fields land in Attio, including descriptions, durations, billable, and project metadata.
Audit visibility What webhook delivery history appears in Attio for support without exposing application logs.

Why this works with the Toggl Track API

Toggl exposes the API pieces this pattern needs: Webhooks API v1 Subscriptions for live changes, endpoint validation before delivery, signed webhook callbacks, Track API v9 reads for setup and reconciliation, and Track API v9 writes for outbound project and client creation.

The Webhooks API v1 Subscription model is documented around POST /webhooks/api/v1/subscriptions/{workspace_id} (Toggl Webhooks overview). Each Subscription has a unique description per Workspace, an event_filters array, an enabled state, validation state, secret, and url_callback. The Subscription event_filters array selects from the Workspace available filters for time_entry, project, and client entity types with their action variants. The actual action enum comes from GET /webhooks/api/v1/event_filters at runtime, so this page does not enumerate exact delete variants.

Toggl validates the URL callback before normal events flow. The receiver gets a PING event with a validation_code and can echo that code, or validate asynchronously through GET /webhooks/api/v1/validate/... (URL endpoint validation). The Subscription must be enabled and validated before Toggl sends normal webhook events.

Setup and outbound writes use Track API v9 endpoints. GET /api/v9/me resolves the user and Workspace (Me API). Project reads and creation use GET /api/v9/workspaces/{workspace_id}/projects and POST /api/v9/workspaces/{workspace_id}/projects (Projects API). Client reads and creation use GET /api/v9/workspaces/{workspace_id}/clients and POST /api/v9/workspaces/{workspace_id}/clients (Clients API).

Toggl rate limits shape backfills and reconciliation. The Track API quota is per user and organization: Free allows 30 requests per hour, Starter allows 240, and Premium allows 600. Quota exhaustion returns 402 with X-Toggl-Quota-Remaining and X-Toggl-Quota-Resets-In headers. Toggl also documents a leaky-bucket throttle where 1 request per second per API token per IP is safe, and that throttle returns 429 (Track API overview).

Time Entry data is what makes the Attio reporting surface useful. GET /api/v9/me/time_entries exposes billable, duration in seconds, negative duration for running entries, project_id, project_name, client_id, client_name, user_id, user_name, and UTC start and stop timestamps (Time Entries API).

How reliability is handled

Toggl signs webhook deliveries with HMAC-SHA256 in the X-Webhook-Signature-256 header. The signature is computed over the raw request body using the Subscription secret, so the receiver verifies the untouched body before parsing or writing to Attio (validating received events).

Toggl retries webhook deliveries when the URL callback returns a non-2xx response. The public docs do not document the exact retry count, retry schedule, or disable-after-failure rules, so the receiver does not depend on a fixed Toggl retry policy.

Receiver-side idempotency handles repeated deliveries. The integration de-duplicates Toggl event_id values within a sliding window and uses KV-based locking to prevent racing simultaneous first-sync attempts on the same Company. That is receiver implementation logic, not a Toggl-side feature.

Backfill and reconciliation use Track API v9 current-state pulls rather than webhook history. Time Entry windows use GET /api/v9/me/time_entries with since, before, start_date, or end_date. Project reconciliation uses GET /api/v9/workspaces/{workspace_id}/projects with page and per_page; Toggl documents the default per_page as 151 and the max as 200.

How setup works

Setup separates Toggl authorization, webhook validation, Attio provisioning, and live sync. The token proves API access. The validation handshake proves the URL callback can receive Toggl events. Attio provisioning creates the fields and lists the client team will use.

  1. Scope the integration. We confirm the Toggl Workspace, eligibility rules, fallback Attio Project, outbound triggers, field map, and audit visibility for the Attio workspace.
  2. Generate a Toggl API token. In Toggl Track Profile, copy the API token. The Webhooks API uses HTTP Basic auth with the token as username and the literal string api_token as password.
  3. Install the Attio app and provision the connection. We install the custom Attio app, paste the token, validate it with GET /api/v9/me, and resolve the Toggl Workspace ID.
  4. Create and validate webhook subscriptions. The connection-added handler provisions toggl_project_id, toggl_client_id, and toggl_client references on Projects and Companies, creates the toggl_time_entries and toggl_webhook_audit lists, creates the Toggl Subscription set, and completes the validation_code handshake before live events flow.
  5. Real-time sync begins. Toggl Time Entry, project, and client changes start writing to Attio, and the resync action remains available for catch-ups.

Known limitations

Custom app, not a marketplace install

This is a scoped custom engagement. It is not a public Toggl Track marketplace app, not an Attio Marketplace app, and not a one-click install.

No automatic historical backfill from the live integration

Webhooks carry events forward after Subscriptions are enabled and validated. Historical Time Entries are imported through a one-time backfill job during the engagement when that work is in scope.

Project deletion does not propagate to Attio

Toggl project deletion does not delete Attio Project records. By design, accidental Toggl deletes should not destroy CRM records. Even though the static Toggl docs do not explicitly document a project.deleted Event Filter, the integration treats deletion-style updates as non-destructive on the Attio side.

Eligibility rules need an explicit fallback

Eligibility rules can exclude Time Entries from certain Attio Projects, such as retainer plus complete combinations. Without a configured fallback Project, excluded or unresolved entries land in the audit list only.

Attio Projects without a Company link do not auto-create in Toggl

The outbound flow requires a linked Company because the integration needs to create or resolve the Toggl client before it creates the Toggl project. A Project without a Company link can be handled after the Company is added.

Webhook subscription count is plan-limited

Toggl limits Subscriptions and Event Filters per Workspace by plan. The documented limits are Free 1 Subscription with up to 3 events, Starter 2 with up to 6, and Premium 3 with up to 12. Enterprise limits can be custom.

Subscription descriptions must be unique per Workspace

Toggl rejects duplicate Subscription descriptions in the same Workspace. Reinstalls use timestamp-suffixed descriptions so a previous Subscription does not block the new one.

Schema changes need controlled reprovisioning

Changed Attio attributes, new Toggl field requirements, or changed routing rules need an update to the field map and a controlled reprovisioning pass before relying on new webhook writes.

Frequently asked questions

Is this a public Toggl Track marketplace app?

No. This is a client-proven Toggl-Track-to-Attio custom app pattern, not a public marketplace app or a one-click install. We adapt the same scaffolding to the Toggl Workspace, Attio schema, eligibility rules, fallback routing, and support controls each engagement needs.

What Toggl Track data flows into Attio?

The standard pattern syncs Toggl Time Entries, project metadata, and client metadata. Time Entries can include description, duration, billable, project and client metadata, user metadata, and UTC start and stop timestamps. We map the fields that support profitability and utilization reporting in Attio.

Is this a two-way sync?

Yes. Inbound Toggl webhooks update Attio from Time Entry, project, and client changes. Outbound Attio handling creates a Toggl project when an Attio Project is created with a linked Company, creating the Toggl client first when the Company does not already have a toggl_client_id.

Which Toggl webhook events are used?

The Subscription event_filters array selects from the Workspace available entity and action filters for time_entry, project, and client. The exact action enum comes from Toggl runtime GET /webhooks/api/v1/event_filters, so the integration does not hard-code public claims such as exactly eight events or specific delete variants.

How does Toggl validate the webhook endpoint?

Toggl sends a PING event with a validation_code. The receiver can echo that code in the response or validate asynchronously through the Toggl validation endpoint. The Subscription must be enabled and validated before normal events flow.

How are Toggl time entries matched to Attio Projects?

The receiver resolves the Toggl project_id, follows the Toggl client_id, matches the Attio toggl_clients record, finds the linked Company, then finds the eligible Attio Project through the Company link. Eligibility rules run after matching. Entries that still do not resolve route to the configured fallback Project.

How fast does a Toggl change show up in Attio?

The live path is real-time webhook delivery. Typical delivery is single-digit seconds, with receiver-side idempotency handling repeated Toggl event_id values before Attio writes run.

Does the integration backfill historical Toggl data?

No automatic historical backfill runs from the live integration. Toggl webhooks carry events forward from the time Subscriptions are enabled and validated. A one-time bulk import is a scope item during the engagement.

What about multi-workspace Toggl setups?

Toggl webhook Subscriptions are Workspace-scoped. One Attio workspace usually maps to one Toggl Workspace. Multi-Workspace setups need explicit scope because each Workspace needs its own Subscription and field-mapping decisions.

API sources checked

Need this to do something it doesn't?

We started by building Toggl Sync for Attio for our own client projects. If you need a version that handles your specific workflow, different fields, different triggers, custom mapping, we can build that. Most custom integrations ship in 2 to 4 weeks.