Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with Clockify

To integrate Replit with Clockify, generate a Clockify API key from your profile settings, store it in Replit Secrets (lock icon πŸ”’), and use the Clockify API from Python or Node.js server-side code to create time entries, manage projects, and pull time reports. Use Autoscale deployment for web apps that record time from a custom interface.

What you'll learn

  • How to generate a Clockify API key and retrieve your Workspace ID
  • How to store Clockify credentials securely in Replit Secrets
  • How to create, read, and update time entries using Python and Node.js
  • How to fetch project lists and generate time reports from Replit
  • How to build an automated time tracking workflow that logs hours to Clockify programmatically
Book a free consultation
4.9Clutch rating ⭐
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read25 minutesProductivityMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with Clockify, generate a Clockify API key from your profile settings, store it in Replit Secrets (lock icon πŸ”’), and use the Clockify API from Python or Node.js server-side code to create time entries, manage projects, and pull time reports. Use Autoscale deployment for web apps that record time from a custom interface.

Why Connect Replit to Clockify?

Clockify offers a generous free tier that supports unlimited users and workspaces, making it one of the most accessible time tracking APIs for developers. By connecting your Replit app to Clockify, you can automate time entry logging, build custom reporting dashboards, sync time data with project management tools, and create internal tools that track billable hours without requiring your team to manually switch to the Clockify interface.

Common integration patterns include automatically starting a time entry when a user begins a task in your app, logging completed task durations to Clockify when a ticket is closed in a project management tool, and pulling time reports to generate client invoices. The Clockify API v1 is RESTful, well-documented, and uses simple API key authentication β€” making it one of the easier time tracking APIs to work with in a Replit environment.

Replit's Secrets system (lock icon πŸ”’ in the sidebar) keeps your Clockify API key secure and out of your codebase. The API key has the same permissions as the account that generated it, so treat it like a password. Store it in Replit Secrets and access it via os.environ['CLOCKIFY_API_KEY'] in Python or process.env.CLOCKIFY_API_KEY in Node.js β€” never paste it directly into code files.

Integration method

Standard API Integration

You connect Replit to Clockify by generating an API key in your Clockify profile settings, storing it in Replit Secrets, and calling the Clockify REST API v1 from your server-side Python or Node.js code. All requests are authenticated with an X-Api-Key header containing your API key. The API requires your Workspace ID for most resource endpoints, which you retrieve from the /workspaces endpoint on first setup.

Prerequisites

  • A Replit account with a Python or Node.js project created
  • A Clockify account (free tier available with full API access)
  • At least one workspace and one project created in Clockify
  • Basic familiarity with REST APIs and HTTP headers
  • Node.js 18+ or Python 3.10+ (both available on Replit by default)

Step-by-step guide

1

Generate a Clockify API Key and Find Your Workspace ID

Log in to your Clockify account and click your avatar or initials in the top-right corner. Select 'Profile Settings' from the dropdown menu. Scroll to the very bottom of the Profile Settings page to find the 'API' section. Click 'Generate' to create a new API key. The key is displayed once β€” copy it immediately before navigating away. Your Workspace ID is required for nearly all Clockify API endpoints. The easiest way to find it is to make a test API call to https://api.clockify.me/api/v1/workspaces using your API key. The response returns an array of workspace objects each containing an 'id' field β€” this is your Workspace ID. Alternatively, you can find it in the Clockify web app URL when you are viewing a workspace: it appears as the segment after '/workspaces/' in the URL. Copy both the API key and the Workspace ID. You will also want to note the IDs of any projects you want to log time against. In Clockify, navigate to Projects, click a project, and the project ID appears in the URL. You can also fetch all project IDs programmatically from /workspaces/{workspaceId}/projects once your integration is running.

Pro tip: On Clockify's free tier, API access is included with no rate limit restrictions for normal usage. Paid tiers (Standard, Pro) unlock features like custom fields and advanced reporting β€” your API access level matches your plan features.

Expected result: You have your Clockify API key and Workspace ID copied and ready to store in Replit Secrets.

2

Store Clockify Credentials in Replit Secrets

Open your Replit project and click the lock icon πŸ”’ in the left sidebar to open the Secrets pane. Add the following secrets using the 'Add a new secret' form: - Key: CLOCKIFY_API_KEY β€” Value: your generated API key - Key: CLOCKIFY_WORKSPACE_ID β€” Value: your Workspace ID Click 'Add Secret' after each one. Replit encrypts these values at rest and injects them as environment variables at runtime, keeping them out of your code files and Git history entirely. In Python, read these with os.environ['CLOCKIFY_API_KEY'] and os.environ['CLOCKIFY_WORKSPACE_ID']. In Node.js, use process.env.CLOCKIFY_API_KEY and process.env.CLOCKIFY_WORKSPACE_ID. Replit's built-in Secret Scanner will warn you if you accidentally type an API key directly into a code file. If you work with multiple Clockify workspaces, add a separate Secret for each: CLOCKIFY_WORKSPACE_DEVELOPMENT_ID, CLOCKIFY_WORKSPACE_CLIENT_ID, etc. This is cleaner than switching workspace IDs in code.

Pro tip: If you are building a multi-tenant app where each user logs time to their own Clockify account, do not store user API keys in Replit Secrets. Instead, store them encrypted in your database and pass them dynamically per request.

Expected result: Two Secrets (CLOCKIFY_API_KEY and CLOCKIFY_WORKSPACE_ID) appear in the Replit Secrets pane.

3

Create and Manage Time Entries with Python

The Clockify API uses a custom header X-Api-Key for authentication instead of the more common Authorization Bearer header. All requests to workspace-specific resources include the Workspace ID in the URL path. The base URL is https://api.clockify.me/api/v1/. Time entries in Clockify require a start time in ISO 8601 format with timezone offset. If you are creating an in-progress entry (timer running), omit the end time. If you are logging a completed entry (timesheet mode), provide both start and end. Durations in Clockify reports are expressed in ISO 8601 duration format (e.g., 'PT1H30M' for 1 hour 30 minutes). The code below provides a complete Python client covering the most common operations: listing projects, starting and stopping time entries, creating completed entries, and fetching time reports. Install the requests library if it is not already available (pip install requests).

clockify_client.py
1import os
2import requests
3from datetime import datetime, timezone, timedelta
4
5API_KEY = os.environ["CLOCKIFY_API_KEY"]
6WORKSPACE_ID = os.environ["CLOCKIFY_WORKSPACE_ID"]
7BASE_URL = "https://api.clockify.me/api/v1"
8
9# Clockify uses X-Api-Key header (not Authorization Bearer)
10HEADERS = {
11 "X-Api-Key": API_KEY,
12 "Content-Type": "application/json"
13}
14
15def get_workspaces() -> list:
16 """List all workspaces accessible with this API key."""
17 response = requests.get(f"{BASE_URL}/workspaces", headers=HEADERS)
18 response.raise_for_status()
19 return response.json()
20
21def get_projects() -> list:
22 """List all projects in the workspace."""
23 url = f"{BASE_URL}/workspaces/{WORKSPACE_ID}/projects"
24 response = requests.get(url, headers=HEADERS, params={"page-size": 200})
25 response.raise_for_status()
26 return response.json()
27
28def get_current_user() -> dict:
29 """Get the current authenticated user's info (includes userId)."""
30 response = requests.get(f"{BASE_URL}/user", headers=HEADERS)
31 response.raise_for_status()
32 return response.json()
33
34def create_time_entry(
35 start: datetime,
36 end: datetime,
37 project_id: str,
38 description: str = "",
39 billable: bool = True
40) -> dict:
41 """
42 Create a completed time entry.
43 start and end should be timezone-aware datetime objects.
44 """
45 data = {
46 "start": start.strftime("%Y-%m-%dT%H:%M:%SZ"),
47 "end": end.strftime("%Y-%m-%dT%H:%M:%SZ"),
48 "projectId": project_id,
49 "description": description,
50 "billable": billable
51 }
52 url = f"{BASE_URL}/workspaces/{WORKSPACE_ID}/time-entries"
53 response = requests.post(url, json=data, headers=HEADERS)
54 response.raise_for_status()
55 return response.json()
56
57def start_timer(project_id: str, description: str = "") -> dict:
58 """Start a running timer (no end time β€” Clockify tracks until stopped)."""
59 now = datetime.now(timezone.utc)
60 data = {
61 "start": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
62 "projectId": project_id,
63 "description": description
64 }
65 url = f"{BASE_URL}/workspaces/{WORKSPACE_ID}/time-entries"
66 response = requests.post(url, json=data, headers=HEADERS)
67 response.raise_for_status()
68 return response.json()
69
70def stop_timer(user_id: str) -> dict:
71 """Stop the currently running timer for a user."""
72 now = datetime.now(timezone.utc)
73 url = f"{BASE_URL}/workspaces/{WORKSPACE_ID}/user/{user_id}/time-entries"
74 data = {"end": now.strftime("%Y-%m-%dT%H:%M:%SZ")}
75 response = requests.patch(url, json=data, headers=HEADERS)
76 response.raise_for_status()
77 return response.json()
78
79def get_time_entries(user_id: str, start: datetime, end: datetime) -> list:
80 """Fetch time entries for a user within a date range."""
81 url = f"{BASE_URL}/workspaces/{WORKSPACE_ID}/user/{user_id}/time-entries"
82 params = {
83 "start": start.strftime("%Y-%m-%dT%H:%M:%SZ"),
84 "end": end.strftime("%Y-%m-%dT%H:%M:%SZ"),
85 "page-size": 500
86 }
87 response = requests.get(url, params=params, headers=HEADERS)
88 response.raise_for_status()
89 return response.json()
90
91# Example usage
92if __name__ == "__main__":
93 user = get_current_user()
94 print(f"Connected as: {user['name']} ({user['email']})")
95
96 projects = get_projects()
97 print(f"Projects: {[p['name'] for p in projects[:5]]}")
98
99 if projects:
100 # Log a 2-hour entry for the first project
101 end_time = datetime.now(timezone.utc)
102 start_time = end_time - timedelta(hours=2)
103 entry = create_time_entry(start_time, end_time, projects[0]['id'], "Example task")
104 print(f"Time entry created: {entry['id']}")

Pro tip: All Clockify timestamps must be in UTC (suffix Z) or include an offset. If your users are in different timezones, convert their local times to UTC before sending to the API. Use datetime.now(timezone.utc) in Python to always get UTC-aware datetimes.

Expected result: Running the script prints your Clockify username, lists up to 5 projects, and creates a 2-hour time entry on the first project.

4

Build a Node.js Time Tracking API

For Node.js projects, use the axios package (npm install axios) to call the Clockify API. The Express server below provides REST endpoints that your frontend can call to start and stop timers, list projects, and view time entries. All Clockify API calls are handled server-side to protect your API key. Note that Clockify requires the user ID for all user-specific operations like starting/stopping timers and fetching time entries. The user ID is available from the GET /user endpoint using your API key. In a multi-user app, each user would have their own Clockify API key stored in your database; for a single-admin integration, you can retrieve the user ID once and store it as CLOCKIFY_USER_ID in Replit Secrets. The server uses an axios instance pre-configured with the API key header so you do not need to add it to every request individually.

server.js
1const express = require('express');
2const axios = require('axios');
3
4const app = express();
5app.use(express.json());
6
7const API_KEY = process.env.CLOCKIFY_API_KEY;
8const WORKSPACE_ID = process.env.CLOCKIFY_WORKSPACE_ID;
9const BASE_URL = 'https://api.clockify.me/api/v1';
10
11// Axios instance with Clockify API key header
12const clockify = axios.create({
13 baseURL: BASE_URL,
14 headers: { 'X-Api-Key': API_KEY }
15});
16
17// Get current user (useful for retrieving userId)
18app.get('/user', async (req, res) => {
19 try {
20 const response = await clockify.get('/user');
21 res.json(response.data);
22 } catch (err) {
23 res.status(err.response?.status || 500).json({ error: err.message });
24 }
25});
26
27// List projects in the workspace
28app.get('/projects', async (req, res) => {
29 try {
30 const response = await clockify.get(
31 `/workspaces/${WORKSPACE_ID}/projects`,
32 { params: { 'page-size': 200 } }
33 );
34 res.json(response.data);
35 } catch (err) {
36 res.status(err.response?.status || 500).json({ error: err.message });
37 }
38});
39
40// Create a completed time entry
41app.post('/time-entries', async (req, res) => {
42 const { start, end, projectId, description, billable } = req.body;
43 if (!start || !end || !projectId) {
44 return res.status(400).json({ error: 'start, end, and projectId are required' });
45 }
46 try {
47 const response = await clockify.post(
48 `/workspaces/${WORKSPACE_ID}/time-entries`,
49 { start, end, projectId, description: description || '', billable: billable !== false }
50 );
51 res.status(201).json(response.data);
52 } catch (err) {
53 console.error('Time entry error:', err.response?.data);
54 res.status(err.response?.status || 500).json({ error: err.message });
55 }
56});
57
58// Get time entries for a user within a date range
59// Query params: userId, start (ISO), end (ISO)
60app.get('/time-entries', async (req, res) => {
61 const { userId, start, end } = req.query;
62 if (!userId || !start || !end) {
63 return res.status(400).json({ error: 'userId, start, and end are required' });
64 }
65 try {
66 const response = await clockify.get(
67 `/workspaces/${WORKSPACE_ID}/user/${userId}/time-entries`,
68 { params: { start, end, 'page-size': 500 } }
69 );
70 res.json(response.data);
71 } catch (err) {
72 res.status(err.response?.status || 500).json({ error: err.message });
73 }
74});
75
76// Stop running timer for a user
77app.post('/timers/stop', async (req, res) => {
78 const { userId } = req.body;
79 if (!userId) return res.status(400).json({ error: 'userId is required' });
80 const end = new Date().toISOString().replace('.000', '');
81 try {
82 const response = await clockify.patch(
83 `/workspaces/${WORKSPACE_ID}/user/${userId}/time-entries`,
84 { end }
85 );
86 res.json(response.data);
87 } catch (err) {
88 res.status(err.response?.status || 500).json({ error: err.message });
89 }
90});
91
92app.listen(3000, '0.0.0.0', () => {
93 console.log('Clockify integration server running on port 3000');
94});

Pro tip: Clockify's API rate limit is 10 requests per second per API key. If you are building reporting features that aggregate data across many projects and users, batch your requests and add a small delay (setTimeout in Node.js) between calls to avoid hitting the limit.

Expected result: The server starts on port 3000. A GET request to /user returns your Clockify profile JSON, and a GET to /projects returns the list of projects in your workspace.

5

Generate Time Reports and Deploy

The Clockify Reports API (at api.clockify.me/api/v1/workspaces/{workspaceId}/reports/) provides pre-aggregated summary and detailed reports that are more efficient than fetching raw time entries. The Summary report groups time by user, project, or client and returns totals with duration in seconds. For deployment, choose Autoscale in Replit if your app serves a web frontend and processes time entry submissions from users. Autoscale handles variable traffic and scales to zero when idle, keeping costs low. Choose Reserved VM if your app needs to run a continuous background process β€” for example, a timer sync service that polls an external project management tool and auto-creates Clockify entries. To access deployment options, click 'Deploy' in the Replit toolbar. Your deployed app gets a stable URL at https://your-app.replit.app, which is required if you want to use Clockify webhook callbacks (available on paid Clockify plans) to receive notifications when time entries are updated.

weekly_report.py
1import os
2import requests
3from datetime import datetime, timezone, timedelta
4
5API_KEY = os.environ["CLOCKIFY_API_KEY"]
6WORKSPACE_ID = os.environ["CLOCKIFY_WORKSPACE_ID"]
7HEADERS = {"X-Api-Key": API_KEY, "Content-Type": "application/json"}
8REPORTS_URL = f"https://api.clockify.me/api/v1/workspaces/{WORKSPACE_ID}/reports"
9
10def get_summary_report(start_date: datetime, end_date: datetime) -> dict:
11 """
12 Get a summary report grouped by project.
13 Returns total hours per project for the date range.
14 """
15 payload = {
16 "dateRangeStart": start_date.strftime("%Y-%m-%dT00:00:00Z"),
17 "dateRangeEnd": end_date.strftime("%Y-%m-%dT23:59:59Z"),
18 "summaryFilter": {
19 "groups": ["PROJECT", "USER"]
20 },
21 "exportType": "JSON"
22 }
23 response = requests.post(f"{REPORTS_URL}/summary", json=payload, headers=HEADERS)
24 response.raise_for_status()
25 return response.json()
26
27def format_duration(seconds: int) -> str:
28 """Convert seconds to hours and minutes string."""
29 hours = seconds // 3600
30 minutes = (seconds % 3600) // 60
31 return f"{hours}h {minutes}m"
32
33if __name__ == "__main__":
34 # Generate weekly report
35 end = datetime.now(timezone.utc)
36 start = end - timedelta(days=7)
37
38 print(f"Time report: {start.date()} to {end.date()}\n")
39 report = get_summary_report(start, end)
40
41 for group in report.get('groupOne', []):
42 project_name = group.get('name', 'No Project')
43 total_seconds = group.get('duration', 0)
44 print(f" {project_name}: {format_duration(total_seconds)}")
45
46 # Show per-user breakdown
47 for child in group.get('children', []):
48 user_name = child.get('name', 'Unknown')
49 user_seconds = child.get('duration', 0)
50 print(f" - {user_name}: {format_duration(user_seconds)}")
51
52 total = report.get('totals', [{}])[0].get('totalTime', 0)
53 print(f"\nTotal: {format_duration(total)}")

Pro tip: The Clockify Reports API requires POST requests (not GET) even for read-only data. The dateRangeStart and dateRangeEnd must be in ISO 8601 format with the Z suffix for UTC. Omitting the Z causes a 400 error.

Expected result: Running the script prints a formatted weekly report showing total hours per project and per user for the past 7 days.

Common use cases

Automatic Time Logging from a Task Management App

When a user marks a task as complete in your Replit app, automatically create a Clockify time entry for the duration spent on that task. The integration reads the task start and end timestamps from your database and posts a corresponding time entry to the correct Clockify project, eliminating manual time logging entirely.

Replit Prompt

Build a Flask endpoint that accepts a task completion event with start_time, end_time, project_id, and user_id, then creates a Clockify time entry for the calculated duration using CLOCKIFY_API_KEY and CLOCKIFY_WORKSPACE_ID from Replit Secrets.

Copy this prompt to try it in Replit

Weekly Time Report Generator

Build a scheduled Replit script that pulls all time entries for the past week from Clockify, groups them by project and user, and generates a summary report. The report can be emailed to stakeholders, posted to Slack, or written to a Google Sheet, giving managers visibility into team productivity without logging into Clockify.

Replit Prompt

Write a Python script that fetches all Clockify time entries for the current workspace for the past 7 days, groups hours by project name, calculates total billable hours per project, and outputs a formatted summary report showing project totals and top contributors.

Copy this prompt to try it in Replit

Client Billing Dashboard

Create a Replit web app that pulls Clockify time data for a specific client project, calculates billable amounts based on hourly rates, and displays an invoice-ready summary. This replaces the manual process of exporting Clockify reports and formatting them in a spreadsheet.

Replit Prompt

Build an Express server with a GET /billing/:projectId endpoint that fetches all time entries for a Clockify project, multiplies each entry's duration by a configurable hourly rate stored in the database, and returns a billing summary with total hours and amount due.

Copy this prompt to try it in Replit

Troubleshooting

API returns 401 Unauthorized with message 'Full authentication is required'

Cause: The X-Api-Key header is missing, incorrectly named, or contains an invalid/revoked API key. Clockify does not use the standard Authorization header β€” it requires X-Api-Key specifically.

Solution: Check that your request includes the header X-Api-Key (not Authorization or X-API-Key). Verify the key value in Replit Secrets matches the one shown in Clockify Profile Settings > API. If you recently regenerated the key in Clockify, update the CLOCKIFY_API_KEY Secret in Replit.

typescript
1# Python: correct header name
2HEADERS = {
3 "X-Api-Key": os.environ["CLOCKIFY_API_KEY"], # Must be exactly 'X-Api-Key'
4 "Content-Type": "application/json"
5}

POST /time-entries returns 400 with 'Start or end time is null or invalid'

Cause: The datetime strings are not in the correct ISO 8601 UTC format that Clockify requires. Common mistakes include missing the Z suffix, including milliseconds, or using a local timezone offset instead of UTC.

Solution: Format all datetimes as YYYY-MM-DDTHH:MM:SSZ (UTC, no milliseconds). In Python, use datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'). In Node.js, use new Date().toISOString().replace('.000Z', 'Z') or slice(0, 19) + 'Z'.

typescript
1// Node.js: correct UTC format for Clockify
2const start = new Date(startTime).toISOString().slice(0, 19) + 'Z';
3const end = new Date(endTime).toISOString().slice(0, 19) + 'Z';

GET /workspaces/{id}/projects returns empty array despite having projects in Clockify

Cause: The CLOCKIFY_WORKSPACE_ID in Replit Secrets does not match any workspace accessible to the API key, or the workspace ID is from the wrong Clockify account.

Solution: Call GET /workspaces first to retrieve the correct workspace ID for the account associated with your API key. The workspace ID is the 'id' field in the response array. Update CLOCKIFY_WORKSPACE_ID in Replit Secrets with the value from this response.

typescript
1# Python: fetch the correct workspace ID
2response = requests.get("https://api.clockify.me/api/v1/workspaces", headers=HEADERS)
3workspaces = response.json()
4for ws in workspaces:
5 print(f"Workspace: {ws['name']} β€” ID: {ws['id']}")

Reports API returns 403 Forbidden

Cause: The Clockify Reports API (at /reports/) is only available on Standard plan and above. Free tier accounts can only access the basic time entries API, not the aggregated reports endpoints.

Solution: Upgrade to Clockify's Standard plan for access to the Reports API. As an alternative on the free tier, fetch raw time entries from /workspaces/{id}/user/{userId}/time-entries and aggregate them manually in your Python or Node.js code.

typescript
1# Free tier alternative: manually aggregate time entries
2def get_project_totals(entries: list) -> dict:
3 totals = {}
4 for entry in entries:
5 project = entry.get('project', {}).get('name', 'No Project')
6 duration = entry.get('timeInterval', {}).get('duration', 'PT0S')
7 # Parse ISO 8601 duration (PT1H30M = 5400 seconds)
8 totals[project] = totals.get(project, 0) + parse_duration(duration)
9 return totals

Best practices

  • Always store CLOCKIFY_API_KEY and CLOCKIFY_WORKSPACE_ID in Replit Secrets (lock icon πŸ”’) β€” never hardcode them in source files.
  • Retrieve and cache your Clockify user ID once at startup using GET /user, rather than calling it on every request β€” the user ID does not change.
  • Format all timestamps as UTC with the Z suffix (YYYY-MM-DDTHH:MM:SSZ) β€” Clockify rejects local timezone offsets in most endpoints.
  • Use the Reports API for aggregated data when on a paid Clockify plan β€” it is significantly faster than fetching and aggregating raw time entries.
  • Implement pagination for project and time entry lists by using page and page-size query parameters β€” workspaces with many entries will not return all records in a single request.
  • Deploy with Autoscale for web apps that accept time entries from users; use Reserved VM for background scripts that sync time data on a schedule.
  • Use billable: true on time entries for client-facing projects so they are included in Clockify's billing reports and invoice exports.
  • Test your integration against a separate Clockify workspace rather than your production workspace to avoid polluting real time tracking data during development.

Alternatives

Frequently asked questions

How do I store my Clockify API key in Replit?

Click the lock icon πŸ”’ in the left sidebar of your Replit project to open the Secrets pane. Add CLOCKIFY_API_KEY with your API key from Clockify Profile Settings > API. Also add CLOCKIFY_WORKSPACE_ID with your workspace ID. Access them in Python with os.environ['CLOCKIFY_API_KEY'] and in Node.js with process.env.CLOCKIFY_API_KEY.

Can I use the Clockify API on the free tier?

Yes. Clockify's free tier includes full API access for basic operations: creating time entries, listing projects, and fetching raw time entry data. The Reports API (aggregated summaries) requires the Standard plan or above. All other endpoints work on the free tier with no rate limit restrictions for normal usage.

How do I find my Clockify Workspace ID?

Call GET https://api.clockify.me/api/v1/workspaces with your X-Api-Key header. The response returns an array of workspace objects β€” the 'id' field in each object is the Workspace ID. Copy this value and store it as CLOCKIFY_WORKSPACE_ID in Replit Secrets. It also appears in the Clockify web app URL as the segment after /workspaces/.

What datetime format does Clockify require?

Clockify requires ISO 8601 UTC format: YYYY-MM-DDTHH:MM:SSZ. The Z suffix means UTC. Do not include milliseconds (.000) and do not use local timezone offsets (+05:00). In Python, use datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'). In Node.js, use new Date().toISOString().slice(0, 19) + 'Z'.

Does Replit work with Clockify webhooks?

Clockify webhooks are available on the Standard plan and above. Once you have a deployed Replit app (using Autoscale or Reserved VM), register your webhook URL in Clockify under Workspace Settings > Integrations > Webhooks. Clockify sends POST requests with JSON payloads when time entries are created, updated, or deleted.

How do I handle multiple users logging time to the same Clockify workspace?

In Clockify, each user has their own account with their own API key. For a multi-user integration, you can either: (1) invite users to your workspace and use your own API key with admin permissions to create entries on their behalf by including their userId in requests, or (2) collect each user's API key during onboarding and store it encrypted in your database to make API calls as that user.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation β€” no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.