REST API reference

ClockShark API

15 endpoints for ClockShark. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/clockshark
Connects with
Your ClockShark admin or manager account
Integration page
ClockShark
ClockShark Endpoints
Endpoint Access Description
list_time_entries read Shifts from Time > View: employee, job, task, start, end, breaks, notes, alerts and approval status.
list_clocked_in read Employees on an active shift now, with job, task and the GPS location of their last punch.
list_shifts read Scheduled shifts, published and draft, with employee, job, task, times and notes.
list_jobs read Jobs from Work > Jobs with number, stage, customer and address.
get_job read Job details: description, address, customer, stage, labor budget, comments and attachment list.
list_time_off_requests read Requests from Time > Requests with employee, policy, dates, hours and status. Pro plan.
export_time_csv read The CSV Export report: paid, regular, overtime and double time minutes per shift, as a download link.
add_time_entry write Manually add a shift to an employee timesheet, the way a manager does on the web.
edit_time_entry write Change start, end, job, task or notes of an unapproved shift. Saved to the audit log.
approve_timesheets write Approve, or unapprove, employee timesheets for a day, week or pay period. Needs timesheet approvals turned on.
create_job write New job employees can clock into, with customer, address and description.
create_shift write Schedule one or more employees on a job, saved as a draft until you publish it.
publish_shifts write Publish draft shifts so they appear in employees' mobile app.
respond_time_off_request write Approve or decline a request. ClockShark emails the employee; a decline cannot be undone.
add_job_comment write Comment on a job thread; @mentioned users get a notification.

POST https://cotlet.dev/api/v1/clockshark/list_time_entries

Returns shifts for a date range, oldest first, with the alerts ClockShark raised on each, such as a missing clock out. Filter by employee, by approval status or to shifts with alerts only. Use entry_id and employee_id from here in the edit and approve tools.

Parameters

Parameters: list_time_entries
NameTypeDescription
from required date First day of the range.
to required date Last day of the range.
employee_ids string[] Only these employees. Default: everyone you manage.
approval_status enum all, approved or unapproved. Default: all.
with_alerts_only boolean Only shifts with timesheet alerts, such as a missing clock out.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/list_time_entries \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01","to":"2026-10-01"}'
Python
result = client.call("clockshark", "list_time_entries", {"from":"2026-10-01","to":"2026-10-01"})
Node.js
const result = await cotlet.call('clockshark', 'list_time_entries', {"from":"2026-10-01","to":"2026-10-01"});
CLI
cotlet call clockshark list_time_entries --data '{"from":"2026-10-01","to":"2026-10-01"}'

Example response

{
  "entries": [
    {
      "entry_id": "te_90412",
      "employee_id": "e_48213",
      "employee": "Mike Torres",
      "job": "42 Oak Street",
      "task": "Framing",
      "start": "2026-10-09T07:00:00-05:00",
      "end": null,
      "break_minutes": 30,
      "alerts": [
        "Missing clock out"
      ],
      "approved": false
    },
    {
      "entry_id": "te_90420",
      "employee_id": "e_48219",
      "employee": "Luis Ortega",
      "job": "42 Oak Street",
      "task": "Framing",
      "start": "2026-10-09T07:02:00-05:00",
      "end": "2026-10-09T15:31:00-05:00",
      "break_minutes": 30,
      "alerts": [],
      "approved": false
    }
  ]
}

POST https://cotlet.dev/api/v1/clockshark/list_clocked_in

Returns employees with an open shift at the moment of the call. Each item has the job, the task, the clock in time and the location of the last punch. An employee with no open shift is not listed.

Parameters

No parameters.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/list_clocked_in \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("clockshark", "list_clocked_in")
Node.js
const result = await cotlet.call('clockshark', 'list_clocked_in');
CLI
cotlet call clockshark list_clocked_in

Example response

{
  "clocked_in": [
    {
      "employee_id": "e_48219",
      "employee": "Luis Ortega",
      "job": "42 Oak Street",
      "task": "Framing",
      "since": "2026-10-11T07:02:00-05:00",
      "last_punch": {
        "lat": 41.8781,
        "lng": -87.6298
      }
    }
  ]
}

POST https://cotlet.dev/api/v1/clockshark/list_shifts

Returns scheduled shifts for a date range, earliest first. Status shows whether crews can already see a shift in the mobile app (published) or not yet (draft). Use shift_id with publish_shifts.

Parameters

Parameters: list_shifts
NameTypeDescription
from required date First day of the range.
to required date Last day of the range.
employee_ids string[] Only these employees. Default: everyone you manage.
status enum all, published or draft. Default: all.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/list_shifts \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01","to":"2026-10-01"}'
Python
result = client.call("clockshark", "list_shifts", {"from":"2026-10-01","to":"2026-10-01"})
Node.js
const result = await cotlet.call('clockshark', 'list_shifts', {"from":"2026-10-01","to":"2026-10-01"});
CLI
cotlet call clockshark list_shifts --data '{"from":"2026-10-01","to":"2026-10-01"}'

Example response

{
  "shifts": [
    {
      "shift_id": "s_77120",
      "employee_id": "e_48213",
      "job_id": "j_3307",
      "start": "2026-10-12T07:00:00-05:00",
      "end": "2026-10-12T15:30:00-05:00",
      "status": "published",
      "notes": ""
    }
  ]
}

List jobs

read

POST https://cotlet.dev/api/v1/clockshark/list_jobs

Returns jobs your account can see. By default only active jobs are listed. Use job_id from here in time, schedule and comment tools.

Parameters

Parameters: list_jobs
NameTypeDescription
active boolean Only active jobs. Default: true.
customer string Only jobs of this customer.
search string Match on job name or number.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/list_jobs \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("clockshark", "list_jobs")
Node.js
const result = await cotlet.call('clockshark', 'list_jobs');
CLI
cotlet call clockshark list_jobs

Example response

{
  "jobs": [
    {
      "job_id": "j_3307",
      "number": "2041",
      "name": "42 Oak Street",
      "stage": "Active",
      "customer": "Harlow Homes",
      "address": "42 Oak Street, Springfield"
    }
  ]
}

Get job

read

POST https://cotlet.dev/api/v1/clockshark/get_job

Returns one job with its labor budget, the comment thread and the names of attached files. Attachments are listed, not downloaded.

Parameters

Parameters: get_job
NameTypeDescription
job_id required string Job ID from list_jobs.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/get_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2"}'
Python
result = client.call("clockshark", "get_job", {"job_id":"job_8c41d2"})
Node.js
const result = await cotlet.call('clockshark', 'get_job', {"job_id":"job_8c41d2"});
CLI
cotlet call clockshark get_job --data '{"job_id":"job_8c41d2"}'

Example response

{
  "job_id": "j_3307",
  "number": "2041",
  "name": "42 Oak Street",
  "stage": "Active",
  "customer": "Harlow Homes",
  "address": "42 Oak Street, Springfield",
  "description": "Wall framing, level 1.",
  "budget_hours": 320,
  "comments": [
    {
      "author": "Dana Reed",
      "body": "Lumber arrives Monday 6:30.",
      "created_at": "2026-10-08T16:10:00-05:00"
    }
  ],
  "attachments": [
    "floor-plan.pdf"
  ]
}

POST https://cotlet.dev/api/v1/clockshark/list_time_off_requests

Returns time off requests, pending ones by default, newest first. Each has the policy, the dates and the hours requested. Time off requests are a Pro plan feature, so the call fails on other plans.

Parameters

Parameters: list_time_off_requests
NameTypeDescription
status enum pending, approved, declined or all. Default: pending.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/list_time_off_requests \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("clockshark", "list_time_off_requests")
Node.js
const result = await cotlet.call('clockshark', 'list_time_off_requests');
CLI
cotlet call clockshark list_time_off_requests

Example response

{
  "requests": [
    {
      "request_id": "r_20871",
      "employee_id": "e_48219",
      "employee": "Luis Ortega",
      "policy": "Vacation",
      "from": "2026-10-19",
      "to": "2026-10-20",
      "hours": 16,
      "status": "pending"
    }
  ]
}

POST https://cotlet.dev/api/v1/clockshark/export_time_csv

Returns a download link to the CSV Export report for the range, plus the row count and totals in minutes, so your agent can answer without opening the file. Notes are left out unless include_notes is true. It reads the report and changes nothing.

Parameters

Parameters: export_time_csv
NameTypeDescription
from required date First day of the range.
to required date Last day of the range.
employee_ids string[] Only these employees. Default: everyone you manage.
include_notes boolean Add timesheet notes. Default: false.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/export_time_csv \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01","to":"2026-10-01"}'
Python
result = client.call("clockshark", "export_time_csv", {"from":"2026-10-01","to":"2026-10-01"})
Node.js
const result = await cotlet.call('clockshark', 'export_time_csv', {"from":"2026-10-01","to":"2026-10-01"});
CLI
cotlet call clockshark export_time_csv --data '{"from":"2026-10-01","to":"2026-10-01"}'

Example response

{
  "download_url": "https://app.clockshark.com/exports/csv/2026-10-05_2026-10-11.csv",
  "rows": 3,
  "totals": {
    "paid_minutes": 1530,
    "regular_minutes": 1440,
    "overtime_minutes": 90,
    "double_time_minutes": 0
  }
}

POST https://cotlet.dev/api/v1/clockshark/add_time_entry

Adds a shift for one employee against a job and a task, with start and end as ISO 8601 times with a time zone. It reaches no one and a wrong entry is fixed with edit_time_entry, so it runs without asking. The new entry is unapproved.

Parameters

Parameters: add_time_entry
NameTypeDescription
employee_id required string Employee ID from list_time_entries.
job_id required string Job ID from list_jobs.
task_id required string Task to log the time against.
start required datetime ISO 8601 with time zone.
end required datetime ISO 8601 with time zone.
notes string Timesheet note.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/add_time_entry \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"employee_id":"employee_8c41d2","job_id":"job_8c41d2","task_id":"task_8c41d2","start":"2026-10-01T09:00:00Z","end":"2026-10-01T09:00:00Z"}'
Python
result = client.call("clockshark", "add_time_entry", {"employee_id":"employee_8c41d2","job_id":"job_8c41d2","task_id":"task_8c41d2","start":"2026-10-01T09:00:00Z","end":"2026-10-01T09:00:00Z"})
Node.js
const result = await cotlet.call('clockshark', 'add_time_entry', {"employee_id":"employee_8c41d2","job_id":"job_8c41d2","task_id":"task_8c41d2","start":"2026-10-01T09:00:00Z","end":"2026-10-01T09:00:00Z"});
CLI
cotlet call clockshark add_time_entry --data '{"employee_id":"employee_8c41d2","job_id":"job_8c41d2","task_id":"task_8c41d2","start":"2026-10-01T09:00:00Z","end":"2026-10-01T09:00:00Z"}'

Example response

{
  "entry_id": "te_90433",
  "employee_id": "e_48213",
  "job_id": "j_3307",
  "start": "2026-10-09T07:00:00-05:00",
  "end": "2026-10-09T15:30:00-05:00",
  "approved": false
}

POST https://cotlet.dev/api/v1/clockshark/edit_time_entry

Changes the fields you pass and leaves the rest. It works on unapproved shifts only, so unapprove the timesheet first if needed. Each edit is saved to the audit log. It reaches no one and is undone by editing again, so it runs without asking.

Parameters

Parameters: edit_time_entry
NameTypeDescription
entry_id required string Entry ID from list_time_entries.
fields required object Any of start, end, job_id, task_id, notes.
ignore_alerts boolean Mark the shift alerts as ignored.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/edit_time_entry \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entry_id":"te_90412","fields":{"end":"2026-10-09T16:30:00-05:00","notes":"End set to schedule, confirmed by text"},"ignore_alerts":true}'
Python
result = client.call("clockshark", "edit_time_entry", {"entry_id":"te_90412","fields":{"end":"2026-10-09T16:30:00-05:00","notes":"End set to schedule, confirmed by text"},"ignore_alerts":True})
Node.js
const result = await cotlet.call('clockshark', 'edit_time_entry', {"entry_id":"te_90412","fields":{"end":"2026-10-09T16:30:00-05:00","notes":"End set to schedule, confirmed by text"},"ignore_alerts":true});
CLI
cotlet call clockshark edit_time_entry --data '{"entry_id":"te_90412","fields":{"end":"2026-10-09T16:30:00-05:00","notes":"End set to schedule, confirmed by text"},"ignore_alerts":true}'

Example response

{
  "entry_id": "te_90412",
  "start": "2026-10-09T07:00:00-05:00",
  "end": "2026-10-09T16:30:00-05:00",
  "alerts": [],
  "approved": false
}

POST https://cotlet.dev/api/v1/clockshark/approve_timesheets

Approves every shift of the listed employees in the range and returns paid and overtime hours per employee. Timesheet approvals must be turned on in your account. It reaches no one and action unapprove reverses it, so it runs without asking.

Parameters

Parameters: approve_timesheets
NameTypeDescription
employee_ids required string[] Employees whose timesheets to approve.
from required date First day of the range.
to required date Last day of the range.
action enum approve or unapprove. Default: approve.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/approve_timesheets \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"employee_ids":["e_48213","e_48219"],"from":"2026-10-05","to":"2026-10-11","action":"approve"}'
Python
result = client.call("clockshark", "approve_timesheets", {"employee_ids":["e_48213","e_48219"],"from":"2026-10-05","to":"2026-10-11","action":"approve"})
Node.js
const result = await cotlet.call('clockshark', 'approve_timesheets', {"employee_ids":["e_48213","e_48219"],"from":"2026-10-05","to":"2026-10-11","action":"approve"});
CLI
cotlet call clockshark approve_timesheets --data '{"employee_ids":["e_48213","e_48219"],"from":"2026-10-05","to":"2026-10-11","action":"approve"}'

Example response

{
  "approved": 2,
  "period": {
    "from": "2026-10-05",
    "to": "2026-10-11"
  },
  "timesheets": [
    {
      "employee_id": "e_48213",
      "paid_hours": 41.5,
      "overtime_hours": 1.5,
      "status": "approved"
    },
    {
      "employee_id": "e_48219",
      "paid_hours": 38,
      "overtime_hours": 0,
      "status": "approved"
    }
  ]
}

Create job

write

POST https://cotlet.dev/api/v1/clockshark/create_job

Creates a job with an optional number, customer, address and description, and a labor budget in hours. The description shows to field employees in the mobile app. It reaches no one by itself and runs without asking.

Parameters

Parameters: create_job
NameTypeDescription
name required string Job name.
number string Job number.
customer string Existing customer name or ID.
address string Job site address.
description string Shown to field employees in the mobile app.
budget_hours integer Total hours budgeted for the labor budget.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/create_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Jane Doe"}'
Python
result = client.call("clockshark", "create_job", {"name":"Jane Doe"})
Node.js
const result = await cotlet.call('clockshark', 'create_job', {"name":"Jane Doe"});
CLI
cotlet call clockshark create_job --data '{"name":"Jane Doe"}'

Example response

{
  "job_id": "j_3307",
  "number": "2041",
  "name": "42 Oak Street",
  "stage": "Active",
  "budget_hours": 320
}

Create shift

write

POST https://cotlet.dev/api/v1/clockshark/create_shift

Creates one shift per employee on a job with start and end as ISO 8601 times. Shifts are saved as drafts, so crews see nothing until publish_shifts. It runs without asking for that reason.

Parameters

Parameters: create_shift
NameTypeDescription
employee_ids required string[] Employees to schedule.
job_id required string Job ID from list_jobs.
start required datetime ISO 8601 with time zone.
end required datetime ISO 8601 with time zone.
task_id string Task for the shift.
notes string Shift notes for the crew.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/create_shift \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"employee_ids":["e_48213","e_48219"],"job_id":"j_3307","start":"2026-10-13T07:00:00-05:00","end":"2026-10-13T15:30:00-05:00"}'
Python
result = client.call("clockshark", "create_shift", {"employee_ids":["e_48213","e_48219"],"job_id":"j_3307","start":"2026-10-13T07:00:00-05:00","end":"2026-10-13T15:30:00-05:00"})
Node.js
const result = await cotlet.call('clockshark', 'create_shift', {"employee_ids":["e_48213","e_48219"],"job_id":"j_3307","start":"2026-10-13T07:00:00-05:00","end":"2026-10-13T15:30:00-05:00"});
CLI
cotlet call clockshark create_shift --data '{"employee_ids":["e_48213","e_48219"],"job_id":"j_3307","start":"2026-10-13T07:00:00-05:00","end":"2026-10-13T15:30:00-05:00"}'

Example response

{
  "shifts": [
    {
      "shift_id": "s_77201",
      "employee_id": "e_48213",
      "job_id": "j_3307",
      "start": "2026-10-12T07:00:00-05:00",
      "end": "2026-10-12T15:30:00-05:00",
      "status": "draft"
    },
    {
      "shift_id": "s_77202",
      "employee_id": "e_48219",
      "job_id": "j_3307",
      "start": "2026-10-12T07:00:00-05:00",
      "end": "2026-10-12T15:30:00-05:00",
      "status": "draft"
    }
  ]
}

Publish shifts

write Confirm

POST https://cotlet.dev/api/v1/clockshark/publish_shifts

Publishes the shifts you name, or all drafts in a date range, and returns how many went out. Employees see published shifts in their mobile app. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: publish_shifts
NameTypeDescription
shift_ids string[] Shifts to publish. Default: all drafts in the range.
from date First day of the range.
to date Last day of the range.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/publish_shifts \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("clockshark", "publish_shifts")
Node.js
const result = await cotlet.call('clockshark', 'publish_shifts');
CLI
cotlet call clockshark publish_shifts

Example response

{
  "published": 2,
  "shift_ids": [
    "s_77201",
    "s_77202"
  ]
}

POST https://cotlet.dev/api/v1/clockshark/respond_time_off_request

Approves or declines one pending request. ClockShark emails the employee, and a note is shown with a decline. A decline cannot be undone. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: respond_time_off_request
NameTypeDescription
request_id required string Request ID from list_time_off_requests.
decision required enum approve or decline.
note string Reason, shown with a decline.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/respond_time_off_request \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"request_id":"r_20871","decision":"approve"}'
Python
result = client.call("clockshark", "respond_time_off_request", {"request_id":"r_20871","decision":"approve"})
Node.js
const result = await cotlet.call('clockshark', 'respond_time_off_request', {"request_id":"r_20871","decision":"approve"});
CLI
cotlet call clockshark respond_time_off_request --data '{"request_id":"r_20871","decision":"approve"}'

Example response

{
  "request_id": "r_20871",
  "employee": "Luis Ortega",
  "decision": "approve",
  "status": "approved"
}

Add job comment

write Confirm

POST https://cotlet.dev/api/v1/clockshark/add_job_comment

Posts a comment on the job thread under your name. Users you @mention get a notification. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: add_job_comment
NameTypeDescription
job_id required string Job ID from list_jobs.
body required string Comment text. Mention users as @Name.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/clockshark/add_job_comment \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2","body":"body"}'
Python
result = client.call("clockshark", "add_job_comment", {"job_id":"job_8c41d2","body":"body"})
Node.js
const result = await cotlet.call('clockshark', 'add_job_comment', {"job_id":"job_8c41d2","body":"body"});
CLI
cotlet call clockshark add_job_comment --data '{"job_id":"job_8c41d2","body":"body"}'

Example response

{
  "comment_id": "c_5521",
  "job_id": "j_3307",
  "body": "@Dana Reed lumber is confirmed for Monday 6:30.",
  "created_at": "2026-10-09T16:12:00-05:00"
}