Timesheets.com provides a public API for customers who need to read account data, build internal reports, or connect Timesheets.com data to another system.
API Dashboard:
https://secure.timesheets.com/api/public/v1/index.cfm
Base URL for API requests:
https://secure.timesheets.com/api/public/v1/
Before You Begin
The API is currently intended for customer-side integrations and reporting. Most API access should be treated as administrator-level access because the authorization token authenticates requests as a specific Timesheets.com user.
Keep these rules in mind:
- Every request requires an API key header and an authorization token header.
- The token authenticates the request as a specific user in the Timesheets.com account.
- Only the Primary Administrator can generate API credentials.
- API keys and tokens do not expire automatically, but they can be deleted.
- Treat keys and tokens like passwords. Do not paste them into source code, public repositories, help tickets, screenshots, or shared documents.
- Store credentials in environment variables, a secrets manager, or another private configuration system.
- The API is rate-limited to 5 requests per rolling 60 seconds per API key.
- Too many failed authentication attempts can temporarily lock the token.
Generating API Credentials
There are two ways to create credentials.
Option 1: Generate credentials in Timesheets.com
- Log in as the Primary Administrator.
- Open
Toolsfrom the left menu. - Select
Generate API Keys. - Click
Generate Credentials. - Copy the returned API key, authorization token, and header names.
Option 2: Generate credentials from the API dashboard
- Open the API Dashboard.
- Use the
/auth/tokenendpoint. - Post the Primary Administrator username and password.
- If the account is active and authorized, the response returns the API key, authorization token, and required header names.
Authentication Headers
Most examples use these headers:
apikey: YOUR_API_KEY
x-ts-authorization: YOUR_AUTH_TOKEN
Important: use the exact header names returned when the credentials are generated. The default examples are usually correct, but the returned credential response is the source of truth.
Example request:
curl --request GET \
"https://secure.timesheets.com/api/public/v1/server/constants" \
--header "apikey: YOUR_API_KEY" \
--header "x-ts-authorization: YOUR_AUTH_TOKEN" \
--header "Accept: application/json"
Using The API Dashboard
The API Dashboard lists available endpoints, supported request methods, parameters, and sample request forms.
To test an endpoint in the dashboard:
- Open an endpoint.
- Choose the request method, usually
GETorPOST. - Add the authentication headers.
- Fill in required parameters.
- Send the request.
- Review the returned JSON.
Some dashboard parameters may appear optional but are required for specific report combinations. If a report request returns an error such as “Group by selection required,” add the requested filter and retry.
Response Format
Most API responses return JSON with an errors key and a data payload.
Common response shape:
{
"errors": [],
"data": []
}
If errors is empty, the request succeeded. If errors contains messages, the request authenticated but could not be completed because of missing parameters, invalid filters, permissions, or other business rules.
Do not rely only on the HTTP status code. Many authenticated requests return HTTP 200 even when the response contains application-level errors.
Example error response:
{
"errors": [
"Group by selection required."
],
"data": []
}
Some report endpoints return a report object instead of a data object. For example, hourly report endpoints may return totals, filters, labels, included users, and ReportData inside report.
Column-Format Data
Some endpoints return query data in column format. This means field names are listed separately from the row values.
Example:
{
"columns": ["UserID", "FullName", "Hours"],
"data": [
[123, "Jane Example", 8.0]
]
}
Most integrations should normalize this into row objects:
[
{
"UserID": 123,
"FullName": "Jane Example",
"Hours": 8.0
}
]
Also note that some keys may be uppercase while others are camelcase. Integrations should avoid case-sensitive assumptions unless a specific endpoint requires them.
Useful Discovery Endpoint
Use /server/constants early when building an integration.
GET /server/constants
This endpoint returns account and system constants, including status codes, payroll result codes, time class IDs, record statuses, and labels.
This is especially useful because some labels can be account-specific. For example, time-off categories such as Sick, Vacation, PTO, Holiday, or custom categories may be enabled, disabled, renamed, or represented by different labels in report output.
Hourly Time And Time-Off Reports
Hourly report data is split into processed and unprocessed report endpoints.
Common endpoints include:
/report/hourly/customizable/unprocessed
/report/hourly/customizable/processed
/report/hourly/payroll/preview
/report/hourly/payroll/periods
/report/hourly/payroll/period/{PayrollID}
/report/hourly/record/history
The unprocessed customizable hourly report supports filtering by date range, users, account codes, signed status, approved status, time class, record status, grouping, report type, and optional detail fields.
For example, to report on a specific time-off class, first call /server/constants to identify the correct TimeClass value, then use that value in the unprocessed hourly report.
Example JSON body:
{
"StartDate": "2026-01-01",
"EndDate": "2026-07-21",
"AllUsers": "1",
"AllAccountCodes": "1",
"TimeClass": "2",
"RecordStatus": "0,1,3",
"Signed": "0,1",
"Approved": "0,1,2",
"GroupType": "User",
"ReportType": "Detailed",
"IncludeExtendedData": "1",
"IncludeWorkDescription": "1"
}
Report responses may include totals such as:
TotalReportHours
TotalSickReportHours
TotalVacationReportHours
TotalPTOReportHours
TotalHolidayReportHours
TotalRecords
ReportData
TimeClassLabels
When reporting on sick time or PTO, check TimeClassLabels in the response. An account may have Sick disabled and PTO enabled, or may use custom labels.
Handling Rate Limits
Limit integrations to no more than 5 requests per rolling 60 seconds per API key.
Recommended behavior:
- Queue requests instead of sending bursts.
- Retry only after waiting.
- Avoid retry loops on authentication failures.
- Cache stable reference data such as
/server/constants. - Pull reports in larger date ranges where practical.
Security Recommendations
Do not hardcode credentials like this:
API_KEY = "..."
TOKEN = "..."
Prefer environment variables:
TIMESHEETS_API_KEY=your-api-key
TIMESHEETS_AUTH_TOKEN=your-token
Then read them from your integration code.
Rotate credentials when:
- An employee with access leaves.
- Credentials were pasted into a shared document.
- Credentials were committed to source control.
- An integration is retired.
- You suspect unauthorized access.
Basic Integration Checklist
Before going live:
- Generate credentials as the Primary Administrator.
- Store the API key and token securely.
- Confirm the correct header names.
- Test
/server/constants. - Confirm the endpoint’s actual response shape.
- Handle
errorsin the JSON response. - Normalize column-format data if needed.
- Respect the 5 requests per 60 seconds limit.
- Log request failures without logging credentials.
- Delete unused or exposed credentials.
Error Keys
The code values and their keys can be pulled from the /server/constants API endpoint. This will return the name of the error/warning (e.g. PAYROLL_CODE_LOCKED = 2)
| Code | Description |
|---|---|
| PAYROLL_CODE_PROCESSED = “0” | Payroll was successfully processed The payroll report was generated as a summary only and does not include any time records |
| PAYROLL_CODE_SUMMARY_ONLY = “1” | The payroll report was generated as a summary only and does not include any time records |
| PAYROLL_CODE_LOCKED = “2” | Payroll report is locked and cannot be processed by current user |
| PAYROLL_CODE_INVALID_DATES = “3” | The payroll report contains invalid run dates |
| PAYROLL_CODE_NO_RECORDS_FOUND = “4” | There were no valid records in the payroll dates |
| PAYROLL_CODE_OVERLAPPING_PERIODS = “5” | Users included in the payroll overlap existing payroll periods |
| PAYROLL_CODE_OVERLAPPING_RECORDS = “6” | Users included in the payroll have overlapping records |
| PAYROLL_CODE_ALERTS_EXIST = “7” | Alerts exist on records included in the payroll report |
| PAYROLL_CODE_PROCESS_VALIDATION_ERROR = “8” | There was an error when attempting to validate the payroll records to process |
| PAYROLL_CODE_PROCESS_VALIDATION_FAILED = “9” | Underlying records in the payroll report have been modified |
| PAYROLL_CODE_DUPLICATE_USERS_FOUND = “10” | Duplicate UserIDs were detected in the payroll report |
| PAYROLL_CODE_NO_USERS_INCLUDED = “11” | No users were included in the report |
| PAYROLL_CODE_UNPAID_RECORDS_EXISTS = “12” | Unpaid records exist before the payroll date |
| PAYROLL_CODE_STANDARD_SPLITPAID_RECORDS_EXISTS = “13” | Standard split paid records exist in the payroll report |
| PAYROLL_CODE_SALARIED_SPLITPAID_RECORDS_EXISTS = “14” | Salaried split paid records exist in the payroll report |
| PAYROLL_CODE_INVALID_RUNBYID = “15” | The user attempting to run the payroll is not authorized or valid |
| PAYROLL_CODE_INVALID_APPEND_PAYROLLID = “16” | Attempt to append to an invalid payroll |
| PAYROLL_CODE_USERS_ALREADY_EXIST_IN_PAYROLL = “17” | Attempt to add users to a payroll report they already exist in |
| PAYROLL_CODE_USERS_HAVE_POSTDATED_PAYROLL = “18” | Attempt to add users to a payroll report already exist in a post dated payroll |
| PAYROLL_CODE_INVALID_PAYROLLID = “19” | Payroll ID was not valid |
| PAYROLL_CODE_INVALID_PARTIAL_USER_DELETE = “20” | The list of partial users to delete was not valid for the payroll period |
| PAYROLL_CODE_INVALID_TIMEZONE_FOR_PERIOD = “21” | There were multiple time zones detected in the payroll period for a single user |
| PAYROLL_CODE_NONSEQUENTIAL_RECORDS = “22” | Non-sequential records were detected while running payroll |
| PAYROLL_CODE_INVALID_ACCRUAL_SETTINGS_FOR_USER = “23” | There was one or more users with invalid accrual by hours worked settings |
| PAYROLL_CODE_RECORDS_EXCEED_MAX_THRESHOLD = “24” | Records in the payroll report were identified as exceeding the specified max threshold |