WorkestraDocs
PlatformTime Tracking

Integrations

Where Time Tracking shows up across the rest of Workestra, plus webhooks, AI tools, and the public REST API.

Integrations

Time Tracking is connective tissue. This page lists every place it surfaces inside other modules, and every external integration point (webhooks, AI, public API).

Where it appears in the UI

Projects

Time tracking is deeply integrated with Projects:

SurfaceWhat you can do
Task detail pageEmbedded <TimeEntryQuickAdd> — log time directly from a task, no context-switch. Below it, a list of all time entries on that task.
Task list(Read-only) total hours logged per task in the table view.
Project detail / Budget tabProject actuals (sum of approved hours) shown alongside the budget. Estimate-vs-actual delta computed from tasks.estimate_hours.
Reports → Estimate vs. ActualPer-project bar chart fed from the time rollup service.
Time entry on task detail

Screenshot needed — task detail right rail with the QuickAdd form and entry list below

Support

SurfaceWhat you can do
Ticket detail pageEmbedded <TimeEntryQuickAdd> for the ticket.
Ticket list / ReportsTotal hours per ticket can roll up to a customer's billable total (when ticket is linked to a billable contract / project).

CRM

SurfaceWhat you can do
Deal detailLog time on a deal — useful for tracking pre-sales effort, demo prep, RFP responses.
Contact detail(read-only) Total billable hours for this contact across all entities.

Recruiting

SurfaceWhat you can do
Candidate detailRight-rail <TimeOnRecord> widget — total hours, recent entries, time-to-hire breakdown by stage, Start timer button.

Scheduling / Calendar

SurfaceWhat you can do
Calendar event detail"Convert to time entry" header action turns a meeting into a tracked entry.
Calendar import bridgeConnected Google / M365 events appear as ghost blocks in the timer's Calendar view. See Calendar Import.

Inbox

SurfaceWhat you can do
Conversation detail"Log time on this conversation" button — pre-fills the description from the thread subject.

Finance

SurfaceWhat you can do
Invoice formThe "Pull from time" button. See Rates & Billing.
Recurring invoices(v1.5) Auto-pull time on a schedule — not in v1.

People (when subscribed)

SurfaceWhat you can do
Employee profile / Utilization tabRead-only view of utilization (lights up only when the People module is subscribed).
Soft dependencyThe People module's employees.weekly_hours is used as the utilization denominator. Without People, falls back to time_tracking_settings.default_weekly_hours.

Webhooks

Time tracking emits events through the standard webhook factory. Configure them at /time/settings/integrations (Pro — requires Projects or Finance).

Available events

EventFired when
time_entry.createdA new entry is logged (timer or manual)
time_entry.updatedAn entry is edited
time_entry.deletedAn entry is deleted
time_entry.invoicedAn entry is consumed by the invoice bridge
timer.startedSomeone starts a timer
timer.stoppedSomeone stops a timer
timesheet.submittedA timesheet transitions draft → submitted
timesheet.approvedA timesheet transitions submitted → approved
timesheet.rejectedA timesheet transitions submitted → rejected

Payload shape

{
  "id": "evt_abc123",
  "event": "timesheet.approved",
  "workspace_id": "ws_xyz",
  "data": {
    "id": "ts_abc",
    "user_id": "u_def",
    "period_start": "2026-04-22",
    "period_end": "2026-04-28",
    "status": "approved",
    "total_hours": 38.5,
    "billable_hours": 32.0,
    "approved_at": "2026-04-29T10:23:00Z",
    "approved_by": "u_mgr"
  },
  "timestamp": "2026-04-29T10:23:00Z"
}

Delivery semantics

  • HMAC-SHA256 signed with <timestamp>.<body> — header X-Workestra-Signature: sha256=<hex>
  • Retries: 1 min → 5 min → 30 min → fail (4 attempts total)
  • Status code handling: 2xx delivered, 4xx (except 429) permanent fail, 429/5xx retry
  • Per-request timeout: 10s
  • Delivery log: every attempt is logged with status, response code, and response body — visible in the UI

Test webhook

The settings UI includes a Test button per webhook. It fires a synthetic webhook.test event so you can verify your endpoint receives + signs correctly without waiting for a real event.

AI tools

Ten time tools are auto-discovered by the AI chat (/api/ai/chat) and the MCP server.

ToolTypeWhat it does
get_active_timerreadReturns the running entry (or null)
get_my_timesheetreadCurrent week (or specified period_start)
get_utilizationreadStats for a user / project / range — Pro
log_time_entrywriteManual entry — needs entity_type, hours, log_date
start_timerwriteStarts a timer; auto-stops any running timer for the user
stop_timerwriteStops the user's active timer
submit_timesheetwriteSubmit a draft timesheet for the given week
approve_timesheetwriteApprove a submitted timesheet
reject_timesheetwriteReject with a reason
convert_time_to_invoice_lineswritePull approved billable hours onto an invoice — Pro

Write tools always return requires_confirmation: true with the prepared payload. The user sees a confirmation card in the chat UI, approves, and the mutation runs client-side (so the user's auth + permissions apply, not the AI's).

Examples:

  • "How many billable hours did I log this week?" → get_my_timesheet → answer + breakdown
  • "Start a timer on the Acme onboarding ticket" → start_timer (write — confirms first)
  • "Pull last month's billable hours for Acme onto invoice INV-2026-042" → convert_time_to_invoice_lines (write — preview + confirm)

Public REST API

All endpoints under /api/v1/. Bearer-auth via Supabase session token. Standard v1 response envelope: { data, pagination? } for success, { error: { code, message } } for errors. X-API-Version: v1 header on every response.

Time entries

MethodPathPurpose
GET/api/v1/time-entriesList with filters: entity_type, entity_id, project_id, user_id, status, from, to, billable, page, limit
POST/api/v1/time-entriesCreate a new entry
GET/api/v1/time-entries/{id}Read one entry
PATCH/api/v1/time-entries/{id}Update fields
DELETE/api/v1/time-entries/{id}Delete (soft — sets invoice_line_id to null on cascade)

Timesheets

MethodPathPurpose
GET/api/v1/timesheetsList with filters: user_id, status, period_start_from, period_start_to
GET/api/v1/timesheets/{id}Read one — includes joined entries
PATCH/api/v1/timesheets/{id}Update fields
POST/api/v1/timesheets/{id}/submitTransition draft → submitted
POST/api/v1/timesheets/{id}/approveTransition submitted → approved (requires time:approve)
POST/api/v1/timesheets/{id}/rejectTransition submitted → rejected (requires time:approve); body: { reason }

State-transition endpoints enforce the same status-precondition guards as the UI — calling approve on a draft timesheet returns a 4xx with a clear error.

Timer

MethodPathPurpose
GET/api/v1/time/timer/activeReturns the running timer for the calling user, or null
POST/api/v1/time/timer/startBody: { entity_type, entity_id?, project_id?, description?, billable? }. Atomically stops any prior timer first.
POST/api/v1/time/timer/stopStops the running timer. No body required.

These three are the surface the Browser Extension consumes.

Rates

MethodPathPurpose
GET/api/v1/time/ratesList rate overrides for the workspace
POST/api/v1/time/ratesUpsert (create on no id, update on id)
DELETE/api/v1/time/rates/{id}Delete an override

Settings + reports

MethodPathPurpose
GET/api/v1/time/settingsRead workspace time-tracking settings
PATCH/api/v1/time/settingsPartial update
GET/api/v1/time/webhooksList configured webhooks
GET/api/v1/time/reports/summary?from=&to=Workspace-wide totals over a date range — used by the browser extension and external dashboards

Crons

Four daily crons drive automated time-tracking behavior. All on Vercel Hobby's daily-only schedule.

CronUTC timeWhat it does
deliver-time-webhooks04:00Drain pending time_webhook_deliveries, retry failed
time-calendar-refresh04:00Pull last-7-days events from connected Google / M365 calendars into time_calendar_imports
time-running-timer-nudges01:00Notify (free) or auto-stop (Pro) timers exceeding runaway_timer_hours
time-auto-submit-timesheets (Pro)22:00If auto_submit_dow matches today, transition draft → submitted
time-weekly-digest (Pro)16:00Wed + Fri only — email each user their week-so-far summary

Each cron is CRON_SECRET-guarded.

Audit log

Every state-changing operation writes an entry to audit_log:

ActionEntity typeFired by
time_entry.createdtime_entryManual + timer + AI tool + API
time_entry.updatedtime_entryEdits
time_entry.deletedtime_entryDeletes
timer.startedtime_entryTimer start
timer.stoppedtime_entryTimer stop
timesheet.submittedtimesheetSubmit action
timesheet.approvedtimesheetApprove action
timesheet.rejectedtimesheetReject action
time_entry.rate_override.upsertedtime_rate_overrideRate edits
invoice.lines_filled_from_timeinvoiceInvoice bridge convert
time_webhook.upsertedtime_webhookWebhook config saved
time_webhook.deletedtime_webhookWebhook config deleted

All audit rows include workspace_id, user_id, changes (small jsonb diff), and ip_address / user_agent when available.


Next steps