Back to Time Tracking & Billable Hours

Integration and API Spec

The reference during the build: every tool connection, field mapping, error scenario, and change-control rule.

4 pagesPDF · Technical
FS-DOC-05Technical

Integration and API Spec

Time Tracking and Billable Hours

01Tool inventory

The table below lists every external tool connected in this automation, its role in the process, the authentication method required, the minimum subscription tier needed to access the API, and which agent or component uses it.

Tool
Role
Auth method
Min plan
Used by
Karbon
Jobs and time entry source
API key (Bearer token)
Team
Time Capture Agent, Reconciliation Agent
Xero
Billing export destination
OAuth 2.0 (PKCE)
Starter
Reconciliation Agent
Slack
Targeted gap nudges
OAuth 2.0 (Bot token)
Free
Gap Chaser Agent
Gmail
Email fallback nudges
OAuth 2.0 (Google Workspace)
Google Workspace (any)
Gap Chaser Agent
FullSpec Automation
Orchestration and monitoring
API key (header)
Standard ($129/month)
All agents, orchestration layer
Karbon API access requires a Team plan or above. Confirm the active subscription tier before provisioning credentials. Xero requires an OAuth 2.0 connected app registered in the Xero Developer portal.

02Per-tool integration detail

Karbon

Primary source of job records, work items, and time entries. The Time Capture Agent reads open time entries and work items; the Reconciliation Agent writes reconciled hours back and marks work items as ready to bill.

Auth method
Bearer token passed in Authorization header. Token generated from Karbon account settings under API access.
Scopes
Read: contacts, work, time_entries. Write: time_entries (status update), work (billing status flag).
Base URL
https://api.karbonhq.com/v3
Key endpoints
GET /timesheets, GET /work, POST /time_entries, PATCH /time_entries/{id}, GET /contacts/{id}
Rate limits
300 requests/minute per API key. Burst ceiling: 500 requests in any 10-second window. Retry-After header returned on 429.
Pagination
Cursor-based. Use next_cursor from response envelope. Page size default 50, max 200.
Constraints
Time entries cannot be deleted via API; status can be set to voided. Work item billing status is a write-once flag per period; validate before writing. All timestamps are UTC ISO 8601.
// Input (Time Capture Agent)
GET /timesheets?period=current&status=draft
GET /work?assignee={user_id}&status=open
// Output (Reconciliation Agent)
PATCH /time_entries/{id} { "status": "approved", "billable": true }
PATCH /work/{id} { "billing_status": "ready_to_bill" }
Xero

Billing export destination. The Reconciliation Agent pushes approved time entries as invoice line items against the matched Xero contact and tracking category.

Auth method
OAuth 2.0 with PKCE. Register a connected app at developer.xero.com. Scopes granted at connection time. Access token valid for 30 minutes; refresh token valid for 60 days.
Scopes
accounting.transactions, accounting.contacts.read, accounting.settings.read
Base URL
https://api.xero.com/api.xro/2.0
Key endpoints
GET /Contacts, GET /TrackingCategories, POST /Invoices, GET /Invoices/{InvoiceID}, PUT /Invoices/{InvoiceID}
Rate limits
60 API calls/minute per app per Xero organisation. Daily limit: 5,000 calls. Minute-level throttle returns HTTP 429 with Retry-After.
Tenant header
Xero-tenant-id header must be set on every request after token exchange. Retrieve tenant ID from GET https://api.xero.com/connections after OAuth flow.
Constraints
Invoices in SUBMITTED or AUTHORISED status cannot have line items deleted. Draft invoices only for initial push. Date format: YYYY-MM-DD. Amount is in the organisation's base currency.
// Input (Reconciliation Agent)
POST /Invoices
{
  "Type": "ACCREC",
  "Contact": { "ContactID": "{xero_contact_id}" },
  "Status": "DRAFT",
  "LineItems": [
    {
      "Description": "{job_name} - {period}",
      "Quantity": {total_hours},
      "UnitAmount": {rate},
      "TrackingCategories": [{ "TrackingCategoryID": "{category_id}" }]
    }
  ]
}
// Output
InvoiceID, InvoiceNumber, Status: DRAFT
Slack

Delivers targeted gap nudges to individual team members. The Gap Chaser Agent sends a direct message only to users whose timesheets have missing or thin entries, citing the specific gaps.

Auth method
OAuth 2.0 Bot token (xoxb-). Install app to workspace via OAuth flow in api.slack.com/apps. Bot token stored as credential in n8n.
Scopes
chat:write, users:read, users:read.email, im:write
Base URL
https://slack.com/api
Key endpoints
POST /chat.postMessage, GET /users.lookupByEmail, POST /conversations.open
Rate limits
Tier 3: 50 requests/minute for chat.postMessage. Tier 2: 20 requests/minute for users.lookupByEmail. Retry-After header on 429.
Message format
Block Kit JSON. Include context block with period name and list of missing dates. Keep message under 3,000 characters.
Constraints
Bot must be invited to any channel it posts into. For DMs, use conversations.open to open an IM channel before posting. Do not use incoming webhooks for user-targeted messages.
// Input (Gap Chaser Agent)
POST /chat.postMessage
{
  "channel": "{user_slack_id}",
  "blocks": [
    { "type": "section", "text": { "type": "mrkdwn",
      "text": "*Timesheet gaps detected for {period}*\nMissing: {gap_dates}" } },
    { "type": "context", "elements": [
      { "type": "mrkdwn", "text": "Please update by {deadline}" }
    ]}
  ]
}
// Output
ts (message timestamp), channel, ok: true
Gmail

Email fallback channel for gap nudges when a team member cannot be reached via Slack or when the firm prefers email as the primary nudge channel.

Auth method
OAuth 2.0 via Google Workspace. Credential created in Google Cloud Console, scopes granted to service account or delegated user. Token refreshed automatically by n8n.
Scopes
https://www.googleapis.com/auth/gmail.send
Base URL
https://gmail.googleapis.com/gmail/v1
Key endpoints
POST /users/{userId}/messages/send
Rate limits
250 quota units/second per user. Sending limit: 2,000 messages/day for Workspace accounts. HTTP 429 or 503 returned when exceeded.
Message format
RFC 2822 MIME message, base64url-encoded in the raw field. Plain text body with HTML alternative part.
Constraints
Sending user must match the authenticated OAuth identity. Do not send bulk messages to more than 50 recipients in a single batch. Include unsubscribe header for compliance.
// Input (Gap Chaser Agent - email fallback)
POST /users/me/messages/send
{
  "raw": "<base64url encoded RFC2822 message>"
}
// Decoded message headers
To: {recipient_email}
Subject: Timesheet gaps for {period} - action needed
Content-Type: text/plain
Body: Missing entries on {gap_dates}. Please update by {deadline}.
// Output
id (Gmail message ID), threadId, labelIds: [SENT]
FullSpec Automation

Orchestration and monitoring layer. Manages workflow execution, schedules periodic triggers, logs run state, and exposes a webhook for inbound events. All agents execute within this runtime.

Auth method
API key passed as X-FullSpec-Key header on all management API calls. Key generated in workspace settings.
Base URL
https://api.fullspec.com/v1
Key endpoints
POST /workflows/{id}/trigger, GET /runs/{run_id}, POST /webhooks, GET /logs?workflow_id={id}
Rate limits
Standard plan: 500 workflow executions/day, 100 API management calls/minute. Execution concurrency: 5 parallel runs.
Webhook inbound
Unique webhook URL generated per workflow. Accepts POST with JSON body. Signature verified via X-FullSpec-Signature HMAC-SHA256 header.
Constraints
Credentials for connected tools (Karbon, Xero, Slack, Gmail) are stored encrypted in the FullSpec credential vault, not in workflow JSON. Maximum payload size per execution: 5 MB.
// Scheduled trigger (period close)
POST /workflows/time-capture-agent/trigger
{ "payload": { "period": "2024-W08", "close_date": "2024-02-23" } }
// Run status check
GET /runs/{run_id}
// Response
{ "run_id": "run_abc123", "status": "completed", "steps_completed": 7,
  "errors": [], "duration_ms": 4210 }
Integration and API SpecPage 1 of 3
FS-DOC-05Technical

03Field mappings between tools

The tables below document field-level mappings for each agent handoff. Source and destination field names are shown in monospace. Transformation notes describe any enrichment or conversion applied in transit.

Handoff 1: Time Capture Agent output to Gap Chaser Agent input (Karbon to Slack and Gmail)

Source tool
Source field
Destination tool
Destination field
Transform
Karbon
time_entry.user_id
Slack
channel (user_slack_id)
Lookup email via Karbon contacts, resolve to Slack user ID via users.lookupByEmail
Karbon
time_entry.user_email
Gmail
To (recipient_email)
Direct passthrough
Karbon
timesheet.period_label
Slack
blocks[].text (period)
Format as YYYY-WXX or human-readable week string
Karbon
timesheet.period_label
Gmail
Subject (period)
Inserted into subject line template
Karbon
time_entry.missing_dates[]
Slack
blocks[].text (gap_dates)
Array joined as comma-separated date list
Karbon
time_entry.missing_dates[]
Gmail
Body (gap_dates)
Array joined as newline-separated list
Karbon
timesheet.close_deadline
Slack
blocks[].text (deadline)
Format as Day, DD Mon YYYY
Karbon
timesheet.close_deadline
Gmail
Body (deadline)
Format as Day, DD Mon YYYY

Handoff 2: Gap Chaser Agent output to Reconciliation Agent input (Karbon updated entries to Xero invoice)

Source tool
Source field
Destination tool
Destination field
Transform
Karbon
time_entry.id
FullSpec Automation
run.context.karbon_entry_id
Stored in run context for audit log
Karbon
time_entry.duration_minutes
Xero
LineItems[].Quantity
Divide by 60 to convert to decimal hours, round to 2 dp
Karbon
work.client_id
Xero
Contact.ContactID
Lookup Xero contact by client name or pre-mapped ID table
Karbon
work.title
Xero
LineItems[].Description
Concatenate: work.title + ' - ' + period_label
Karbon
work.billing_rate
Xero
LineItems[].UnitAmount
Direct passthrough; must be in base currency
Karbon
work.tracking_code
Xero
LineItems[].TrackingCategories[].TrackingCategoryID
Pre-mapped lookup table: Karbon tracking code to Xero tracking category ID
Karbon
timesheet.period_end_date
Xero
DueDate
Format as YYYY-MM-DD; add configured payment terms (default +14 days)
Karbon
time_entry.status (approved)
Xero
Status: DRAFT
All pushed invoices start as DRAFT pending partner approval
The Karbon client ID to Xero ContactID mapping must be seeded in the configuration lookup table before the Reconciliation Agent runs for the first time. Any unmapped client will halt the reconciliation step and raise an alert.

04Build stack and orchestration

The Standard build uses FullSpec Automation as the primary orchestration runtime. The table below lists every component in the build stack, its version or tier, and its function in the pipeline.

Component
Version / tier
Function
Hosted by
FullSpec Automation
Standard plan
Workflow orchestration, scheduling, credential vault, run logging
FullSpec (cloud)
n8n (embedded runtime)
1.x (latest stable)
Low-code workflow nodes inside FullSpec for HTTP requests and data transforms
FullSpec (cloud)
Karbon API
v3
Time entries and work item source and write-back
Karbon (cloud)
Xero API
2.0
Invoice creation and billing export
Xero (cloud)
Slack Web API
Latest
Targeted DM nudges
Slack (cloud)
Gmail API
v1
Email fallback nudges
Google (cloud)
Client-ID mapping table
JSON config file
Maps Karbon client IDs to Xero ContactIDs and tracking categories
[YourCompany.com] hosted config

The orchestration flow runs as three sequenced workflows: Time Capture Agent fires first on a weekly schedule (Friday 08:00 local time), passes its output into the Gap Chaser Agent via a run context handoff, and then the Reconciliation Agent fires after a configurable wait period (default: 24 hours after the nudge window closes) or immediately if no gaps are detected.

The n8n credential store below lists the credential entry names exactly as they must be configured in the FullSpec credential vault. All credentials are encrypted at rest and never appear in workflow JSON.
n8n credential store - entries required before first run
// n8n Credential Store - required entries

// 1. Karbon API Key
Credential name : karbon_api_key
Type            : Header Auth
Header name     : Authorization
Header value    : Bearer <KARBON_API_KEY>

// 2. Xero OAuth 2.0
Credential name : xero_oauth2
Type            : OAuth2 (PKCE)
Client ID       : <XERO_CLIENT_ID>
Client Secret   : <XERO_CLIENT_SECRET>
Auth URL        : https://login.xero.com/identity/connect/authorize
Token URL       : https://identity.xero.com/connect/token
Scopes          : accounting.transactions accounting.contacts.read accounting.settings.read
Tenant ID       : <XERO_TENANT_ID>  // retrieved post-auth from /connections

// 3. Slack Bot Token
Credential name : slack_bot_token
Type            : Header Auth
Header name     : Authorization
Header value    : Bearer <SLACK_BOT_TOKEN>  // xoxb- prefix

// 4. Gmail OAuth 2.0
Credential name : gmail_oauth2
Type            : OAuth2
Client ID       : <GOOGLE_CLIENT_ID>
Client Secret   : <GOOGLE_CLIENT_SECRET>
Auth URL        : https://accounts.google.com/o/oauth2/auth
Token URL       : https://oauth2.googleapis.com/token
Scopes          : https://www.googleapis.com/auth/gmail.send

// 5. FullSpec Automation API Key
Credential name : fullspec_api_key
Type            : Header Auth
Header name     : X-FullSpec-Key
Header value    : <FULLSPEC_API_KEY>
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

05Error handling and retry logic

The table below defines how the orchestration layer handles each error condition. All non-recoverable errors halt the affected workflow branch, log to FullSpec run history, and alert the Practice Manager via Slack or email. Retryable errors follow exponential backoff with the configured attempt limits.

Error condition
HTTP / code
Agent
Retry strategy
Fallback action
Alert
Karbon 429 rate limit
429
Time Capture, Reconciliation
Exponential backoff: 1s, 2s, 4s; max 5 attempts
If all retries fail, pause and resume next run cycle
No (auto-resolved)
Karbon 401 unauthorized
401
Time Capture, Reconciliation
No retry
Halt workflow; flag credential expiry
Yes - Practice Manager
Karbon 404 work item not found
404
Reconciliation
No retry
Skip entry, log to audit report, flag for manual review
Yes - Practice Manager
Xero 429 rate limit
429
Reconciliation
Exponential backoff: 2s, 4s, 8s; max 5 attempts; respect Retry-After header
Queue remaining invoices for next minute window
No (auto-resolved)
Xero 401 token expired
401
Reconciliation
Auto-refresh access token once using refresh token; retry original request
If refresh fails, halt and alert
Yes - if refresh fails
Xero unmapped client ID
400 / mapping miss
Reconciliation
No retry
Halt reconciliation for that client; log unmapped entry
Yes - Practice Manager
Slack 429 rate limit
429
Gap Chaser
Linear backoff: wait Retry-After value; max 3 attempts
Fall back to Gmail nudge for affected users
No
Slack user not found
users_not_found
Gap Chaser
Retry once with lowercase email
Fall back to Gmail nudge; log missing Slack user
Yes - Practice Manager
Gmail send failure
429 / 500 / 503
Gap Chaser
Exponential backoff: 5s, 10s, 20s; max 3 attempts
Log failed send; add to manual follow-up report
Yes - Practice Manager
FullSpec workflow timeout
Execution > 300s
Any
Auto-retry full workflow once after 10-minute delay
If second attempt fails, halt and log; notify Practice Manager
Yes - Practice Manager
Malformed API response
200 with invalid JSON
Any
No retry
Log raw response body; halt affected step; alert developer
Yes - developer contact
Network / DNS failure
0 / ECONNREFUSED
Any
Retry 3 times with 30s intervals
Halt workflow after all retries; log outage window
Yes - Practice Manager
All errors and retry outcomes are written to the FullSpec run log with timestamps, agent name, error code, and resolution status. The Practice Manager can review the run log dashboard at any time. A weekly digest of failed or flagged runs is recommended during the first month after go-live.

06Versioning and change control

The following table defines the versioning scheme, change categories, and the required approvals before any change is deployed to the live automation. All changes must be logged in the workflow change register maintained in the project workspace.

Change type
Examples
Version bump
Approval required
Test required before deploy
Breaking change
API endpoint change, field rename, auth method change
Major (1.x to 2.x)
Practice Manager and developer
Full regression suite
Non-breaking feature
New agent, additional field mapping, new nudge channel
Minor (1.0 to 1.1)
Practice Manager
Affected workflow tests
Config or threshold change
Nudge timing, retry count, period schedule, billing rate
Patch (1.0.0 to 1.0.1)
Practice Manager
Smoke test on affected agent
Credential rotation
API key refresh, OAuth token re-grant
Patch
Developer
Connectivity check for affected tool
Lookup table update
New client ID to Xero ContactID mapping
Patch
Practice Manager
Reconciliation dry-run against staging
Hotfix
Critical error causing data loss or billing failure
Patch with hotfix tag
Developer (immediate) and Practice Manager (retrospective)
Targeted test case for the fixed path

Version history is maintained as a changelog entry in the FullSpec project workspace. Each entry records the version number, date of deploy, description of change, the initiating party, and the approver. The current live version is tagged in the FullSpec workflow settings panel.

  • All workflow exports (JSON) are committed to the version-controlled project repository with the version tag and deploy date in the filename.
  • Staging and production environments are kept separate. No change is promoted to production without passing the required test level above.
  • API version pinning: Karbon v3, Xero 2.0, Slack Web API (versioned by endpoint), Gmail v1. Any upstream deprecation notice triggers a minor or major version review within 30 days of the notice.
  • Credential rotation schedule: API keys reviewed every 90 days; OAuth tokens are auto-refreshed but reviewed for scope accuracy every 6 months.
  • The change register is reviewed at each weekly operations check-in during the first 90 days post-launch, then monthly thereafter.
Any change to the Xero invoice push logic must be validated against a Xero sandbox organisation before deploying to production. Xero does not support bulk deletion of invoices via API; errors in production require manual correction inside Xero.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for Time Tracking & Billable Hours.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Developer Handover Pack
Technical · Developer
View
Test and QA Plan
Quality · Developer
View