Skip to main content
A webhook sends workspace events to a URL you own, so your own systems can react when something happens in TimeTracker. Go to Settings → Webhooks.
Webhooks is a Pro feature and lives in the Webhooks & API app, which is on by default. See Plans and features.

What a webhook is

An HTTPS endpoint you register. When a matching event happens, TimeTracker sends it a signed POST with a JSON body describing what occurred. The page describes it as: “Send workspace events to your own systems over HTTPS. Every delivery is signed with a per-endpoint secret you can verify from the X-TimeTracker-Signature header.”

When to use one

  • Post approved timesheets into your payroll system.
  • Tell your accounting tool when an invoice is paid.
  • Push new tasks into a build pipeline or a support tool.
  • Feed workspace activity into your own dashboard.

Create an endpoint

1

Open Settings → Webhooks

You need to be an Owner or an Admin.
2

Click Add endpoint

The button sits in the page header. The empty state also offers it.
3

Enter the endpoint URL

Endpoint URL – required, and must be a public https:// address, for example https://api.example.com/webhooks/timetracker.
4

Choose event filters

Event filters – leave it empty to receive every event. This is the reliable choice for most teams.
5

Save

Click Add endpoint.
6

Copy the signing secret

A dialog appears titled Copy your signing secret. Copy it now – it is shown once and can never be read again.
The signing secret is shown exactly once. There is no screen anywhere that can show it again. If you lose it, rotate it and update your receiver.

Fields

The most robust setup is to leave the filter empty and route on event.key inside your own receiver. Your code then owns the routing, and adding a new event type never needs a settings change.

URL rules

Only public HTTPS addresses are accepted. TimeTracker rejects: The error reads: “This URL can’t be used. Endpoints must be public HTTPS addresses – private, loopback, and metadata addresses are blocked.” A hostname that passes here is re-checked when the request is actually sent, so a domain that later resolves to a private address is still blocked. Redirects are never followed – your endpoint must answer with a 2xx directly.

The request

Headers

X-TimeTracker-Delivery-Id is stable across retries of the same delivery. Deduplicate on it. Delivery is at least once, so the same id can arrive twice.

Body

data holds the values as they were at the moment the event happened. It is a snapshot, not a live record, so a later rename does not change an old delivery.

Verifying the signature

The signature header looks like:
The algorithm is HMAC-SHA-256, hex-encoded, over the exact string:
t is unix seconds. rawBody is the byte-identical JSON that arrived.
Sign the raw request body, exactly as received. Parsing the JSON and re-serialising it changes the bytes and the signature will never match.
Your receiver should:
1

Read the raw body as text

Before any JSON parsing.
2

Split the header

Split on , to get t= and v1=.
3

Check the timestamp

Reject if t is more than 300 seconds (5 minutes) away from now. This stops replay attacks.
4

Recompute the HMAC

HMAC-SHA-256 of t + "." + rawBody with your signing secret, hex-encoded.
5

Compare in constant time

Never use a plain string equality check.

Example verifier

Answer with any 2xx once you have accepted the event. Do the slow work afterwards.

Delivery and retries

Events are dispatched about once a minute, so a webhook normally lands within a minute of the action that caused it. Retries use exponential backoff with jitter: roughly 30 seconds, 1 minute, 2 minutes, 4 minutes, 8 minutes, up to a ceiling of 1 hour between attempts. There are at most 6 attempts.

Auto-disable

An endpoint that fails 20 times in a row is switched off automatically. The endpoint card then shows a red alert: “Endpoint disabled after repeated failures”“We stopped sending after N consecutive failures. Fix your receiver, then re-enable this endpoint.” Click Re-enable and confirm. The dialog reads “Deliveries resume immediately and the failure count resets. Make sure your receiver is fixed first.” Any success resets the counter to zero, so an endpoint that is merely flaky never gets disabled.

The endpoint card

Row actions

The menu on each endpoint holds:

Sending a test event

Pick Send test event from the menu. You get a toast – “Test event sent.” or Test event failed: <reason>. The test body is:
A test never touches your real event stream. It is safe to send at any time.

The delivery log

Each endpoint has a Delivery log button that expands a table. It holds the most recent 100 deliveries, newest first. Empty state: “No deliveries yet.”

Redelivering

Click Redeliver on any row. You get “Delivery re-queued.” Redelivery adds a new attempt and never rewrites the old row, so your history stays honest. The new attempt is signed with your current secret.

Rotating the secret

1

Open the endpoint menu

Click , then Rotate secret.
2

Confirm

The dialog reads “Rotating invalidates the current secret immediately. In-flight deliveries keep their existing signature; new deliveries use the new secret.”
3

Copy the new secret

A dialog appears titled New signing secret: “The previous secret is now invalid. Update your receiver with this value. It won’t be shown again.”
4

Update your receiver

Deploy the new secret before your next event arrives.
Deliveries already queued keep the secret they were signed with, so a rotation never breaks a retry that is already in flight.
Accept both the old and the new secret for a few minutes while you deploy. Try the new one first, then fall back to the old one.

Deleting an endpoint

Pick Delete from the menu. The confirmation is titled “Delete this endpoint?”“This permanently deletes the endpoint and its delivery history. This cannot be undone.” You must type the endpoint URL to confirm. Then click Delete endpoint.
Deleting removes the delivery history too. Export anything you need first.

Event types

There are 66 event keys, and almost all of them can be delivered by webhook. Full detail – trigger, recipients and channels – is in the notification types reference. Timesheets timesheet.submitted · timesheet.approved · timesheet.changes_requested · timesheet.reopened · timesheet.withdrawn · timesheet.reminder · timesheet.approval_overdue · timesheet.not_submitted · timesheet.period_closed Timecards timecard.submitted · timecard.approved · timecard.changes_requested · timecard.correction_approved · timecard.correction_rejected · timecard.missing_clock_out Time off time_off.requested · time_off.approved · time_off.rejected · time_off.withdrawn · time_off.approval_withdrawn · time_off.balance_adjusted · time_off.approval_overdue · time_off.upcoming Expenses expense.submitted · expense.approved · expense.rejected · expense.clarification_requested · expense.approval_overdue Tasks task.assigned · task.completed · task.reopened · task.status_changed · task.due_soon Projects project.member_added · project.member_removed · project.archived · project.status_changed · project.budget_threshold_reached Invoices and payments invoice.created · invoice.sent · invoice.paid · invoice.voided · invoice.overdue · payment.recorded · payment.reminder_sent Comments and portal comment.mentioned · portal.comment_posted · portal.deliverable_approved Members and access member.invited · member.invitation_accepted · member.invitation_revoked · membership.role_changed · membership.removed · workspace.member_deleted Security security.email_changed · security.suspicious_login Billing billing.trial_ending · billing.trial_expired · billing.subscription_activated · billing.payment_action_required Exports export.ready Testing webhook.test – sent only by Send test event, never by real activity.
Digest summaries are not delivered by webhook.

Example

Daniel Okafor wants Northwind Studio’s accounting system to record a payment the moment an invoice is marked paid.
1

Add the endpoint

URL https://api.northwind.example/hooks/timetracker. He leaves the filter empty.
2

Store the secret

He copies the signing secret into his server’s environment variables.
3

Write the receiver

It verifies the signature, checks event.key === "invoice.paid", and ignores everything else.
4

Test it

Send test event. His endpoint logs a webhook.test body and answers 200.
5

Watch the log

Bluebird Coffee pays their $40,000 invoice. Within a minute the delivery log shows Delivered · 200.

Permissions

Project Manager, Finance, Member, Contractor and Client do not hold it. A webhook can carry every workspace event to an external system, so it is deliberately restricted to the two roles that already administer the workspace. Every action is re-checked on the server. Endpoints from another workspace are never reachable.

What happens when the app is off

Turning the Webhooks & API app off under Settings → Apps stops delivery. Events that happen while it is off are queued and delivered when you turn it back on. Your configuration and delivery history are kept.

Common questions

No. It is shown once, at creation and after a rotation. If you lose it, rotate and update your receiver.
Normally within a minute of the event. Deliveries are dispatched on a short cycle rather than instantly.
Yes. Delivery is at least once. Deduplicate on X-TimeTracker-Delivery-Id, which stays the same across retries of the same delivery.
No. Only public HTTPS addresses are accepted, and loopback and private addresses are blocked. Use a public HTTPS tunnel while developing.
Any 2xx, as soon as you have accepted the event. Do the slow work after responding. A 3xx counts as a failure – redirects are never followed.
Fix your receiver, then click Re-enable on the endpoint card. The failure count resets and deliveries resume immediately.
No. Webhooks are a workspace-level integration, not a personal channel. They are configured per endpoint here, not on anyone’s profile.

Troubleshooting

Every delivery fails with a signature mismatch. You are almost certainly re-serialising the body before verifying. Sign the raw bytes exactly as they arrived. Deliveries stop after a while. Check the status badge. Twenty consecutive failures disables an endpoint. Fix the receiver and re-enable it. The URL will not save. It must be public HTTPS. Private, loopback and metadata addresses are blocked, including numeric forms of them. I get nothing at all. Confirm the endpoint is Active, the Webhooks & API app is on, and your plan includes it. Then use Send test event to prove the path end to end. Deliveries arrive but my filter drops them. Clear the filter so the endpoint receives everything, and route on event.key in your own code.

Integrations overview

Everything TimeTracker connects to.

Notification types

What each event means and when it fires.

Webhook events reference

The event catalogue at a glance.

Roles and capabilities

Who holds webhook.manage.

Plans and features

Webhooks is a Pro feature.

Export your data

Getting data in and out.