# Create Client Source: https://developers.everhour.com/api-reference/clients/create-client /openapi.json post /clients Create a new client. Names are not deduplicated — posting the same name creates another client. # Delete Client Source: https://developers.everhour.com/api-reference/clients/delete-client /openapi.json delete /clients/{client_id} Delete a client. # Delete Client Budget Source: https://developers.everhour.com/api-reference/clients/delete-client-budget /openapi.json delete /clients/{client_id}/budget Remove the budget attached to a client. The client itself is kept. # Get All Clients Source: https://developers.everhour.com/api-reference/clients/get-all-clients /openapi.json get /clients Search Clients by Name using the query parameter. # Get Client Source: https://developers.everhour.com/api-reference/clients/get-client /openapi.json get /clients/{client_id} Retrieve a single client by ID. # Update Client Source: https://developers.everhour.com/api-reference/clients/update-client /openapi.json put /clients/{client_id} Update an existing client. Only the fields supplied in the body are modified. # Update Client Budget Source: https://developers.everhour.com/api-reference/clients/update-client-budget /openapi.json put /clients/{client_id}/budget Create or replace the budget attached to a client. Send a complete budget object; partial updates are not supported. # Create Field in Project Source: https://developers.everhour.com/api-reference/custom-fields/create-field-in-project /openapi.json post /projects/{project_id}/fields Create a new custom field on a project. # Delete Field Source: https://developers.everhour.com/api-reference/custom-fields/delete-field /openapi.json delete /fields/{field_id} Delete a custom field. Existing task values for that field are discarded. # Get Project Fields Configuration Source: https://developers.everhour.com/api-reference/custom-fields/get-project-fields-configuration /openapi.json get /projects/{project_id}/fields List the custom fields configured on a project, in display order. # Reorder Fields Source: https://developers.everhour.com/api-reference/custom-fields/reorder-fields /openapi.json put /projects/{project_id}/fields-order Reorder a project's custom fields. Send the full list of field IDs in the desired order. # Update Field Source: https://developers.everhour.com/api-reference/custom-fields/update-field /openapi.json put /fields/{field_id} Update a custom field's name, type-specific options, or visibility. # Add Attachment To Expense Source: https://developers.everhour.com/api-reference/expenses/add-attachment-to-expense /openapi.json post /expenses/{expense_id}/attachments Attach a previously uploaded file (by its token from `POST /attachments`) to an existing expense. # Create Attachment Source: https://developers.everhour.com/api-reference/expenses/create-attachment /openapi.json post /attachments Upload a file and receive a one-time attachment token. The token can then be attached to an expense via `POST /expenses/{expense_id}/attachments` or included in `POST /expenses`. # Create Category Source: https://developers.everhour.com/api-reference/expenses/create-category /openapi.json post /expenses/categories Create a new expense category. # Create Expense Source: https://developers.everhour.com/api-reference/expenses/create-expense /openapi.json post /expenses Log a new expense. Amounts are in cents (see [Concepts](/concepts)); attach files first via `POST /attachments` and reference their IDs in the request body. # Delete Attachment Source: https://developers.everhour.com/api-reference/expenses/delete-attachment /openapi.json delete /attachments/{attachment_id} Delete an attachment and its underlying file. # Delete Category Source: https://developers.everhour.com/api-reference/expenses/delete-category /openapi.json delete /expenses/categories/{category_id} Delete an expense category. Expenses already assigned to it are kept but become uncategorized. # Delete Expense Source: https://developers.everhour.com/api-reference/expenses/delete-expense /openapi.json delete /expenses/{expense_id} Delete an expense entry. Attached files are also removed. # Download Attachment Source: https://developers.everhour.com/api-reference/expenses/download-attachment /openapi.json get /attachments/{attachment_token}/download Download the binary contents of an attachment by its token. The response is the raw file, not JSON. # Get All Categories Source: https://developers.everhour.com/api-reference/expenses/get-all-categories /openapi.json get /expenses/categories List expense categories available in the team. # Get All Expenses Source: https://developers.everhour.com/api-reference/expenses/get-all-expenses /openapi.json get /expenses List expenses logged by the authenticated user. # Update Category Source: https://developers.everhour.com/api-reference/expenses/update-category /openapi.json put /expenses/categories/{category_id} Update an expense category. # Update Expense Source: https://developers.everhour.com/api-reference/expenses/update-expense /openapi.json put /expenses/{expense_id} Update an existing expense entry. # Create Invoice Source: https://developers.everhour.com/api-reference/invoices/create-invoice /openapi.json post /clients/{client_id}/invoices Create an invoice for a client. The invoice is generated from the client's tracked time over the requested date range — see [Dates](/dates-and-timezones). # Delete Invoice Source: https://developers.everhour.com/api-reference/invoices/delete-invoice /openapi.json delete /invoices/{invoice_id} Delete an invoice. Time records attached to the invoice are released and become billable again. # Export Invoice to Xero/QB/FB Source: https://developers.everhour.com/api-reference/invoices/export-invoice-to-xeroqbfb /openapi.json post /invoices/{invoice_id}/export Export an invoice to a connected external accounting system. Supports Xero, QuickBooks, and FreshBooks integrations — the destination must be linked to the team beforehand. An invoice can only be exported once; subsequent calls return an error. # Get All Invoices Source: https://developers.everhour.com/api-reference/invoices/get-all-invoices /openapi.json get /invoices List invoices in the team. Supports filtering by date and client. # Get Invoice Source: https://developers.everhour.com/api-reference/invoices/get-invoice /openapi.json get /invoices/{invoice_id} Retrieve a single invoice with its full line-item breakdown. # Refresh Invoice Line Items Source: https://developers.everhour.com/api-reference/invoices/refresh-invoice-line-items /openapi.json post /invoices/{invoice_id}/reset-time Refresh an invoice's line items from current time records. The invoice's billable items are rebuilt from the underlying time tracked against the invoice's client over its date range. Useful when time records have been added, edited, or deleted after the invoice was first generated. # Update Invoice Source: https://developers.everhour.com/api-reference/invoices/update-invoice /openapi.json put /invoices/{invoice_id} Update invoice metadata (notes, dates, custom totals). To change the lifecycle state, set `manualStatus` to `draft`, `sent`, or `paid`. # Archive/Unarchive Project Source: https://developers.everhour.com/api-reference/projects/archiveunarchive-project /openapi.json patch /projects/{project_id}/archive Archive or unarchive a project. Archived projects are hidden from default listings but their data is preserved. # Create Project Source: https://developers.everhour.com/api-reference/projects/create-project /openapi.json post /projects Create a new project. To copy from an existing template use the `template` or `publicTemplate` body field. To sync a project from a connected integration use `POST /projects/{project_id}/sync` instead. # Create Section Source: https://developers.everhour.com/api-reference/projects/create-section /openapi.json post /projects/{project_id}/sections Create a new section in a project. # Delete Project Source: https://developers.everhour.com/api-reference/projects/delete-project /openapi.json delete /projects/{project_id} Delete a project, its tasks, and all associated time records. This is irreversible. # Delete Section Source: https://developers.everhour.com/api-reference/projects/delete-section /openapi.json delete /sections/{section_id} Delete a section. Tasks in the section are kept but become section-less. # Get All Projects Source: https://developers.everhour.com/api-reference/projects/get-all-projects /openapi.json get /projects List projects the caller has access to. Use the `query` parameter to search by name and `limit`/`page` for pagination — see [Pagination](/pagination). # Get Project Source: https://developers.everhour.com/api-reference/projects/get-project /openapi.json get /projects/{project_id} Retrieve a single project. See [Concepts](/concepts) for the project model. # Get Project Sections Source: https://developers.everhour.com/api-reference/projects/get-project-sections /openapi.json get /projects/{project_id}/sections List sections (groupings of tasks) within a project. # Get Section Source: https://developers.everhour.com/api-reference/projects/get-section /openapi.json get /sections/{section_id} Retrieve a single section by ID. # Sync Integration Project Source: https://developers.everhour.com/api-reference/projects/sync-integration-project /openapi.json post /projects/{project_id}/sync Sync new integration projects to Everhour. Traditionally, project sync relied on background jobs which could delay access to Everhour functionality. This endpoint allows instant synchronization of a project from a connected integration (like Trello, Asana, ClickUp, etc.) into Everhour. Useful for automation flows where you want to start working with a project immediately after creating it in your external tool. Safe to call multiple times — if the project already exists in Everhour, it simply returns it without creating duplicates. **Workflow** - Create a project in your external tool (Asana, Trello, etc.) and retrieve its ID. - Sync it to Everhour using this endpoint in Everhour API. - Proceed with other Everhour API actions — assign a budget, link a client, or set task estimates. Supported platform codes: as, b2, b3, bb, cl, gh, gl, in, li, mo, no, td, tw, tr, wr. # Update Project Source: https://developers.everhour.com/api-reference/projects/update-project /openapi.json put /projects/{project_id} Update project settings. To change budget or billable rate, use `PUT /projects/{project_id}/billing` instead. # Update Project Billing/Budget Source: https://developers.everhour.com/api-reference/projects/update-project-billingbudget /openapi.json put /projects/{project_id}/billing Set or update the project's budget, billable rate, and billing type in a single call. Amounts are in cents (see [Concepts](/concepts)). # Update Section Source: https://developers.everhour.com/api-reference/projects/update-section /openapi.json put /sections/{section_id} Update a section's name or position. # Clients Report Source: https://developers.everhour.com/api-reference/reports/clients-report /openapi.json get /dashboards/clients Aggregated client report. Same filters and units as `GET /dashboards/projects` — see [Concepts](/concepts). # Estimates Report (deprecated) Source: https://developers.everhour.com/api-reference/reports/estimates-report-deprecated /openapi.json get /team/estimate/export Legacy export of team estimates, returned as JSON. Requires admin access. Kept for backward compatibility; new integrations should use the dashboard reports. # Projects Report Source: https://developers.everhour.com/api-reference/reports/projects-report /openapi.json get /dashboards/projects Aggregated project report. Returns time, billing, and budget figures grouped by project. Filter the result with `date.gte`, `date.lte`, `projectId`, `clientId`, and `memberId` query parameters — see [Dates](/dates-and-timezones) for parameter formats. Time columns are in seconds, amounts in cents (see [Concepts](/concepts)). # Time Report (deprecated) Source: https://developers.everhour.com/api-reference/reports/time-report-deprecated /openapi.json get /team/time/export Legacy export of team time records, returned as JSON. Kept for backward compatibility; new integrations should use `GET /team/time` or the dashboard reports. # Users Report Source: https://developers.everhour.com/api-reference/reports/users-report /openapi.json get /dashboards/users Aggregated member report. Same filters and units as `GET /dashboards/projects` — see [Concepts](/concepts). # Create Assignment Source: https://developers.everhour.com/api-reference/schedule/create-assignment /openapi.json post /resource-planner/assignments Create a schedule assignment. To create time-off use `POST /resource-planner/assignments/time-off` instead. # Delete Assignment Source: https://developers.everhour.com/api-reference/schedule/delete-assignment /openapi.json delete /resource-planner/assignments/{assignment_id} Delete a schedule assignment. You can include an optional `reason` (max 1000 characters) in the request body. # Get All Assignments Source: https://developers.everhour.com/api-reference/schedule/get-all-assignments /openapi.json get /resource-planner/assignments List schedule assignments across the team. Supports filtering by date range, project, and member. # Update Assignment Source: https://developers.everhour.com/api-reference/schedule/update-assignment /openapi.json put /resource-planner/assignments/{assignment_id} Update an existing schedule assignment. # Create Task Source: https://developers.everhour.com/api-reference/tasks/create-task /openapi.json post /projects/{project_id}/tasks Create a task in a project. For tasks coming from connected integrations, sync them via `POST /projects/{project_id}/sync` instead. # Delete Task Source: https://developers.everhour.com/api-reference/tasks/delete-task /openapi.json delete /tasks/{task_id} Delete a task and all of its time records. # Delete Task Estimate Source: https://developers.everhour.com/api-reference/tasks/delete-task-estimate /openapi.json delete /tasks/{task_id}/estimate Remove a task's estimate. # Get Project Tasks Source: https://developers.everhour.com/api-reference/tasks/get-project-tasks /openapi.json get /projects/{project_id}/tasks List tasks in a project. By default all tasks are returned; set `exclude-closed=true` to hide closed/completed tasks. See [Pagination](/pagination) for `limit`/`page` rules. # Get Task Source: https://developers.everhour.com/api-reference/tasks/get-task /openapi.json get /tasks/{task_id} Retrieve a single task with its time totals, estimate, and custom fields. # Search Project Tasks Source: https://developers.everhour.com/api-reference/tasks/search-project-tasks /openapi.json get /projects/{project_id}/tasks/search Search tasks within a single project. Same query semantics as `GET /tasks/search`; `limit` must be between 1 and 100. # Search Tasks Source: https://developers.everhour.com/api-reference/tasks/search-tasks /openapi.json get /tasks/search Search tasks across all projects by name. The `limit` parameter must be between 1 and 100. # Update Task Source: https://developers.everhour.com/api-reference/tasks/update-task /openapi.json put /tasks/{task_id} Update task fields (name, status, due date, section, labels). # Update Task Billing Source: https://developers.everhour.com/api-reference/tasks/update-task-billing /openapi.json put /tasks/{task_id}/billing Set a task's billing rate or mark it non-billable. Requires admin access. The same values are returned on task responses when you pass `opts_include_billing=1`. # Update Task Estimate Source: https://developers.everhour.com/api-reference/tasks/update-task-estimate /openapi.json put /tasks/{task_id}/estimate Set or replace a task's estimate (in seconds). Send a complete estimate object; partial updates are not supported. # Create Allocation Source: https://developers.everhour.com/api-reference/time-off/create-allocation /openapi.json post /allocations Create a time-off allocation for a user and time-off type. # Create Time Off Type Source: https://developers.everhour.com/api-reference/time-off/create-time-off-type /openapi.json post /resource-planner/time-off-types Create a new time-off type. # Delete Allocation Source: https://developers.everhour.com/api-reference/time-off/delete-allocation /openapi.json delete /allocations/{allocation_id} Delete a time-off allocation. # Delete Time Off Type Source: https://developers.everhour.com/api-reference/time-off/delete-time-off-type /openapi.json delete /resource-planner/time-off-types/{type_id} Delete a time-off type. Existing time-off entries that reference it are kept. # Get All Allocations Source: https://developers.everhour.com/api-reference/time-off/get-all-allocations /openapi.json get /allocations List per-user time-off allocations (e.g. annual vacation balances). # Get Time Off Types Source: https://developers.everhour.com/api-reference/time-off/get-time-off-types /openapi.json get /resource-planner/time-off-types List the time-off types defined for the team (e.g. Vacation, Sick Leave). # Update Allocation Source: https://developers.everhour.com/api-reference/time-off/update-allocation /openapi.json put /allocations/{allocation_id} Update a time-off allocation's amount or period. # Update Time Off Type Source: https://developers.everhour.com/api-reference/time-off/update-time-off-type /openapi.json put /resource-planner/time-off-types/{type_id} Update a time-off type's name, color, or settings. # Add Time Source: https://developers.everhour.com/api-reference/time-records/add-time /openapi.json post /time Add a time record (in seconds) for a user on a given task and date. **Upsert:** at most one time record exists per `(user, date, task)`. Posting again with the same combination updates the existing record's duration instead of creating a duplicate. To update a specific record by ID, use `PUT /time/{time_id}`. See [Dates](/dates-and-timezones) for accepted date and duration formats. # Delete Time Record Source: https://developers.everhour.com/api-reference/time-records/delete-time-record /openapi.json delete /time/{time_id} Remove a time record by setting its duration to zero. The history trail is preserved; the row no longer appears in time listings, which filter for `time > 0`. # Get All Time Records Source: https://developers.everhour.com/api-reference/time-records/get-all-time-records /openapi.json get /team/time List time records across the entire team for a date range. When `from`/`to` are omitted, only the current day is returned. See [Dates](/dates-and-timezones). # Get Project Time Records Source: https://developers.everhour.com/api-reference/time-records/get-project-time-records /openapi.json get /projects/{project_id}/time List time records logged against a single project, across all users and tasks. # Get Task Time Records Source: https://developers.everhour.com/api-reference/time-records/get-task-time-records /openapi.json get /tasks/{task_id}/time List time records logged against a single task, across all users. # Get User Time Records Source: https://developers.everhour.com/api-reference/time-records/get-user-time-records /openapi.json get /users/{user_id}/time List time records for a single user. Supports the same filters as `GET /team/time`. # Update Time Record Source: https://developers.everhour.com/api-reference/time-records/update-time-record /openapi.json put /time/{time_id} Update a specific time record by ID. To add or upsert time, use `POST /time` instead. # Clock In Source: https://developers.everhour.com/api-reference/timecards/clock-in /openapi.json post /users/{user_id}/timecards/clock-in Clock a user in. Starts a new timecard segment at the current time. # Clock Out Source: https://developers.everhour.com/api-reference/timecards/clock-out /openapi.json post /users/{user_id}/timecards/clock-out Clock a user out. Closes the current timecard segment. # Delete Timecard Source: https://developers.everhour.com/api-reference/timecards/delete-timecard /openapi.json delete /users/{user_id}/timecards/{date} Delete a user's timecard entry for a specific date. # Get All Timecards Source: https://developers.everhour.com/api-reference/timecards/get-all-timecards /openapi.json get /timecards List timecards across the team. Defaults to the last two weeks when no date range is provided — see [Dates](/dates-and-timezones). # Get Timecard Source: https://developers.everhour.com/api-reference/timecards/get-timecard /openapi.json get /users/{user_id}/timecards/{date} Retrieve a user's timecard for a specific date. # Get User Timecards Source: https://developers.everhour.com/api-reference/timecards/get-user-timecards /openapi.json get /users/{user_id}/timecards List timecards for a single user. Defaults to the last two weeks when no date range is provided. # Update Timecard Source: https://developers.everhour.com/api-reference/timecards/update-timecard /openapi.json put /users/{user_id}/timecards/{date} Update (or create, if missing) a user's timecard for a specific date. Suitable for manual edits — clock-in and clock-out have dedicated endpoints. # Get All Team Timers Source: https://developers.everhour.com/api-reference/timers/get-all-team-timers /openapi.json get /team/timers List the timers currently running across the team — one entry per active user. # Get Running Timer Source: https://developers.everhour.com/api-reference/timers/get-running-timer /openapi.json get /timers/current Retrieve the authenticated user's currently running timer, or an empty timer payload if none is running. # Start Timer Source: https://developers.everhour.com/api-reference/timers/start-timer /openapi.json post /timers Start a timer for the authenticated user on a given task. Only one timer can run per user at a time. If the user already has a timer running on another task, that timer is stopped automatically before the new one starts; the stopped run is committed to a time record on its own date (the date the timer was started, which may not be today for cross-midnight runs). See [Concepts](/concepts) for timer semantics. # Stop Timer Source: https://developers.everhour.com/api-reference/timers/stop-timer /openapi.json delete /timers/current Stop the authenticated user's currently running timer. The accumulated duration is committed to a time record on the timer's task for the current date and returned in the response. # Approve or Reject Approval Request Source: https://developers.everhour.com/api-reference/timesheets/approve-or-reject-approval-request /openapi.json put /timesheets/{timesheet_id}/approval Approve or reject an existing timesheet approval request. Use this endpoint to act on a request previously created with `POST /timesheets/{timesheet_id}/approval`. The response reflects the resulting approval state. # Approve Week/Request for Approval Source: https://developers.everhour.com/api-reference/timesheets/approve-weekrequest-for-approval /openapi.json post /timesheets/{timesheet_id}/approval Submit a timesheet week for approval. The week's owner uses this endpoint to request review; an approver acts on the request via `PUT /timesheets/{timesheet_id}/approval`. The `timesheet_id` is the concatenation of `user_id` and a 4-digit `week_id` in `YYWW` format (no separator). Example: user `14856` for week `2535` (week 35 of 2025) → `timesheet_id = 148562535`. See the Timesheets overview for the full Week ID definition. # Discard Your Approval Request Source: https://developers.everhour.com/api-reference/timesheets/discard-your-approval-request /openapi.json put /timesheets/{timesheet_id}/discard-approval Retract the caller's previously submitted approval request for a week. The week returns to draft state. # Get Team Timesheets Source: https://developers.everhour.com/api-reference/timesheets/get-team-timesheets /openapi.json get /timesheets List timesheet weeks across the team, grouped by user. # Get User Timesheets Source: https://developers.everhour.com/api-reference/timesheets/get-user-timesheets /openapi.json get /users/{user_id}/timesheets List timesheet weeks for a single user. The week id is the Monday date of the week (see [Dates](/dates-and-timezones)). # Get All Users Source: https://developers.everhour.com/api-reference/users/get-all-users /openapi.json get /team/users List all members of the team. Supports `query` for name search and `limit` for pagination — see [Pagination](/pagination). # Get Current User Source: https://developers.everhour.com/api-reference/users/get-current-user /openapi.json get /users/me Retrieve the user that owns the API key, including personal settings (timezone, formats, API key). # Create Webhook Source: https://developers.everhour.com/api-reference/webhooks/create-webhook /openapi.json post /hooks Register a new webhook subscription. **Handshake:** on create, Everhour sends a POST to the supplied `targetUrl` with an `X-Hook-Secret` header (HMAC-SHA512) and an empty body. The receiver must respond with a 2xx status to complete verification. Send `X-Skip-Handshake: 1` to skip verification when the receiver cannot participate. **Scope:** a webhook can listen across the whole team or be scoped to a single project. See [Webhooks](/webhooks) for event types, payload structure, and delivery semantics. # Delete Webhook Source: https://developers.everhour.com/api-reference/webhooks/delete-webhook /openapi.json delete /hooks/{hook_id} Delete a webhook subscription. Stops further deliveries; no event is sent for the deletion itself. # Get All Webhooks Source: https://developers.everhour.com/api-reference/webhooks/get-all-webhooks /openapi.json get /hooks List all webhook subscriptions created with your API key. # Get Webhook Source: https://developers.everhour.com/api-reference/webhooks/get-webhook /openapi.json get /hooks/{hook_id} Retrieve a single webhook subscription. # Update Webhook Source: https://developers.everhour.com/api-reference/webhooks/update-webhook /openapi.json put /hooks/{hook_id} Update a webhook's events or scope. The `targetUrl` cannot be changed and is ignored if sent; the handshake is repeated against the existing URL to confirm it is still reachable. Send `X-Skip-Handshake: 1` to skip it. # Authentication Source: https://developers.everhour.com/authentication How to authenticate requests to the Everhour API using an API key. All API requests must be authenticated. Everhour supports two methods: an **API key** for your own scripts and server-to-server jobs, and **[OAuth 2.1](/oauth)** for apps that act on behalf of another user. This page covers the API key — pass it in the `X-Api-Key` request header. ## Getting your API key 1. Sign in to your Everhour account. 2. Go to your [profile page](https://app.everhour.com/#/account/profile). 3. Scroll to the bottom — your API key is shown there. ## Using the API key Include the key in every request: ```http theme={null} X-Api-Key: YOUR_API_KEY ``` You can also pass the key as an `api_key` query parameter (for example, `?api_key=YOUR_API_KEY`). The `X-Api-Key` header is recommended — query strings can be recorded in server logs and browser history. **Example:** ```bash Bash/cURL theme={null} curl https://api.everhour.com/users/me \ -H "X-Api-Key: YOUR_API_KEY" ``` ```ruby Ruby theme={null} require "net/http" uri = URI("https://api.everhour.com/users/me") req = Net::HTTP::Get.new(uri) req["X-Api-Key"] = "YOUR_API_KEY" resp = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) } puts resp.body ``` ```python Python theme={null} import requests response = requests.get( "https://api.everhour.com/users/me", headers={"X-Api-Key": "YOUR_API_KEY"} ) print(response.json()) ``` ```php PHP theme={null} $ch = curl_init("https://api.everhour.com/users/me"); curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Api-Key: YOUR_API_KEY"]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); echo curl_exec($ch); curl_close($ch); ``` ```java Java theme={null} import java.net.URI; import java.net.http.*; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.everhour.com/users/me")) .header("X-Api-Key", "YOUR_API_KEY") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); ``` ```javascript JavaScript theme={null} const response = await fetch("https://api.everhour.com/users/me", { headers: { "X-Api-Key": "YOUR_API_KEY" } }); console.log(await response.json()); ``` ```go Go theme={null} // import "fmt"; "io"; "net/http" req, _ := http.NewRequest("GET", "https://api.everhour.com/users/me", nil) req.Header.Set("X-Api-Key", "YOUR_API_KEY") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) ``` ```csharp .NET theme={null} using var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-Api-Key", "YOUR_API_KEY"); var body = await client.GetStringAsync("https://api.everhour.com/users/me"); Console.WriteLine(body); ``` ## What happens without a valid key If the `X-Api-Key` header is missing or the key is invalid, the API returns: ```http theme={null} HTTP/1.1 403 Forbidden ``` ```json theme={null} { "code": 403, "message": "Access denied" } ``` ## Security recommendations * Store the API key in environment variables, not in source code. * Rotate the key if you suspect it has been compromised — you can regenerate it from your profile page. * Each API key is tied to a specific user account and inherits that user's permissions. Everhour issues one API key per user account. For apps that act on behalf of other users, use [OAuth 2.1](/oauth) instead of sharing a key. Fine-grained scopes aren't available with either method — access follows the user's role. # Key concepts Source: https://developers.everhour.com/concepts Core resources in the Everhour data model — what they are and how they relate. Before diving into individual endpoints, it helps to understand the vocabulary used throughout the API and these docs. ## Team The top-level tenant boundary. Every user belongs to exactly one team. Resources such as projects, clients, and invoices are scoped to a team. Your API key inherits the team context of the user account it belongs to. ## Project A container for work. Projects have members, tasks, budget settings, and billing configuration. A project may be linked to a client. The `GET /projects` endpoint lists all projects accessible to the authenticated user. ## Task The primary unit of work inside a project. Tasks have assignees, an estimate, a status, and they receive time records. Tasks may be organized into sections. ## Section A grouping of tasks within a project — equivalent to a column or swimlane in a board view. ## Time record A logged time entry. Each time record is attached to a task and carries a `date` (date-only) and a `time` value in **seconds**. It may also hold a comment and a billable flag. ## Timer A running, in-progress time record. Starting a timer creates an active entry; stopping it finalizes the `time` duration and saves the record. Only one timer can be active per user at a time. ## Client A billing-side entity. Projects may be linked to a client for reporting and invoicing purposes. ## Invoice A billing document generated from time records and expenses for a client. Invoices are created, updated, and tracked through the API. ## Expense A non-time cost attached to a project (for example, a software subscription or travel cost). Expenses have an `amount` (integer, in the smallest currency unit) and a `date`. ## Webhook An outbound HTTP callback. Users can subscribe their own endpoint to receive event notifications when resources change — for example, when a task is created or a timer is stopped. See [Webhooks](/webhooks) for setup and event reference. # Dates and timezones Source: https://developers.everhour.com/dates-and-timezones Date and time formats used in Everhour API requests and responses, including timezone handling and duration encoding. The Everhour API uses a small set of fixed string formats for all date and time values. None of these formats are ISO 8601 extended format, and Unix timestamps are not accepted or returned. Do not use ISO 8601 extended format or Unix timestamps — the API will reject or misparse the value. ## Accepted formats | Format | Field type | Example | | --------------------- | ------------------------------------------------------------------ | --------------------- | | `YYYY-MM-DD` | Date-only (`date`, `from`, `to`, expense `date`, assignment dates) | `2026-05-04` | | `YYYY-MM-DD HH:MM:SS` | Datetime (`createdAt`, `updatedAt`, screenshot timestamps) | `2026-05-04 09:30:00` | | `HH:MM` | Time of day (timecard `startTime`, `endTime`, clock-in) | `09:30` | ## Request fields Use `YYYY-MM-DD` for all date parameters such as `date`, `from`, and `to`. Use `YYYY-MM-DD HH:MM:SS` for datetime fields. Use `HH:MM` for time-of-day fields. Date range parameters are **inclusive on both ends**. A request with `from=2026-05-01&to=2026-05-31` returns records for every day from May 1 through May 31 inclusive. ## Response fields Datetime fields such as `createdAt` and `updatedAt` are returned as `YYYY-MM-DD HH:MM:SS` with no timezone suffix. Treat all such values as UTC. Date-only fields are returned as `YYYY-MM-DD`. ## Timezones The user object includes a `timezone` field that contains the user's UTC offset as a **float representing hours** — for example, `-5`, `5.5`, or `0`. Values are restricted to whole and half hours. This is not an IANA timezone name. No timezone conversion is applied to datetime values in API responses. All datetimes are UTC-naive; apply the user's `timezone` offset locally if you need to display times in the user's local time. ## Time durations The `time` field on time records and timer responses is an **integer in seconds**. To convert to hours, divide by `3600`. ``` 3600 → 1 h 5400 → 1 h 30 m 90 → 1 m 30 s ``` ## Money amounts `amount` fields on expenses and invoices are **integers in the smallest currency unit** (cents for USD/EUR). For example, `1500` represents \$15.00. `quantity` fields are floats. ## Clearing a date field Fields that accept the `DateTimeResettable` type treat an empty string `""` as a signal to clear the stored value rather than a parse error. This is the only way to unset such a field via the API. ## Code examples The examples below build a request to `GET /team/time` with a date range, then convert the `time` integer in each record to hours. ```bash Bash/cURL theme={null} curl -G "https://api.everhour.com/team/time" \ -H "X-Api-Key: YOUR_API_KEY" \ --data-urlencode "from=2026-05-01" \ --data-urlencode "to=2026-05-31" \ | jq '[.[] | {id: .id, hours: (.time / 3600)}]' ``` ```ruby Ruby theme={null} require "net/http" require "json" require "uri" uri = URI("https://api.everhour.com/team/time") uri.query = URI.encode_www_form(from: "2026-05-01", to: "2026-05-31") req = Net::HTTP::Get.new(uri) req["X-Api-Key"] = "YOUR_API_KEY" response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) } records = JSON.parse(response.body) records.each do |record| hours = record["time"] / 3600.0 puts "#{record["id"]}: #{hours} h" end ``` ```python Python theme={null} import requests response = requests.get( "https://api.everhour.com/team/time", headers={"X-Api-Key": "YOUR_API_KEY"}, params={"from": "2026-05-01", "to": "2026-05-31"}, ) response.raise_for_status() for record in response.json(): hours = record["time"] / 3600 print(f"{record['id']}: {hours:.2f} h") ``` ```php PHP theme={null} "2026-05-01", "to" => "2026-05-31"]); $url = "https://api.everhour.com/team/time?" . $query; $ctx = stream_context_create([ "http" => [ "header" => "X-Api-Key: YOUR_API_KEY\r\n", ], ]); $body = file_get_contents($url, false, $ctx); $records = json_decode($body, true); foreach ($records as $record) { $hours = $record["time"] / 3600; printf("%s: %.2f h\n", $record["id"], $hours); } ``` ```java Java theme={null} import java.net.URI; import java.net.http.*; import com.fasterxml.jackson.databind.*; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.everhour.com/team/time?from=2026-05-01&to=2026-05-31")) .header("X-Api-Key", "YOUR_API_KEY") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); ObjectMapper mapper = new ObjectMapper(); JsonNode records = mapper.readTree(response.body()); for (JsonNode record : records) { double hours = record.get("time").asDouble() / 3600; System.out.printf("%s: %.2f h%n", record.get("id").asText(), hours); } ``` ```javascript JavaScript theme={null} import fetch from "node-fetch"; const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" }); const response = await fetch(`https://api.everhour.com/team/time?${params}`, { headers: { "X-Api-Key": "YOUR_API_KEY" }, }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const records = await response.json(); for (const record of records) { const hours = record.time / 3600; console.log(`${record.id}: ${hours.toFixed(2)} h`); } ``` ```go Go theme={null} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) func main() { params := url.Values{"from": {"2026-05-01"}, "to": {"2026-05-31"}} req, _ := http.NewRequest("GET", "https://api.everhour.com/team/time?"+params.Encode(), nil) req.Header.Set("X-Api-Key", "YOUR_API_KEY") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var records []struct { ID string `json:"id"` Time int `json:"time"` } json.NewDecoder(resp.Body).Decode(&records) for _, r := range records { hours := float64(r.Time) / 3600 fmt.Printf("%s: %.2f h\n", r.ID, hours) } } ``` ```csharp .NET theme={null} using System.Net.Http; using System.Net.Http.Json; using System.Text.Json; var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-Api-Key", "YOUR_API_KEY"); var url = "https://api.everhour.com/team/time?from=2026-05-01&to=2026-05-31"; var records = await client.GetFromJsonAsync(url) ?? Array.Empty(); foreach (var record in records) { double hours = record.GetProperty("time").GetDouble() / 3600; Console.WriteLine($"{record.GetProperty("id").GetString()}: {hours:F2} h"); } ``` # Errors Source: https://developers.everhour.com/errors HTTP status codes and error response format used by the Everhour API. The Everhour API uses standard HTTP status codes. All error responses include a JSON body with a `code` and `message` field. ## Error response format ```json theme={null} { "code": 404, "message": "Resource not found" } ``` Some errors include an additional `errors` field with per-field validation details: ```json theme={null} { "code": 422, "message": "Validation failed", "errors": { "time": ["must be a positive integer"] } } ``` ## Status codes | Code | Meaning | | ----- | ---------------------------------------------------------------------------------------- | | `200` | Success | | `201` | Resource created | | `204` | Success, no content returned | | `400` | Bad request — malformed JSON or missing required parameter | | `403` | Forbidden — missing or invalid API key, or your account lacks permission for this action | | `404` | Not found — resource does not exist or is not accessible to your account | | `422` | Unprocessable entity — request was valid JSON but failed validation | | `429` | Too many requests — rate limit exceeded. See [Rate limits](/rate-limits) | | `503` | Service unavailable — something went wrong on our end | ## Handling errors Check the HTTP status code before parsing the response body. A `2xx` status indicates success. For anything else, read the `message` field for a human-readable explanation. ```bash Bash/cURL theme={null} response=$(curl -s -w "\n%{http_code}" https://api.everhour.com/projects \ -H "X-Api-Key: YOUR_API_KEY") body=$(echo "$response" | head -1) status=$(echo "$response" | tail -1) if [ "$status" -ge 400 ]; then echo "Error: $body" fi ``` ```ruby Ruby theme={null} require "net/http" require "json" uri = URI("https://api.everhour.com/projects") req = Net::HTTP::Get.new(uri, { "X-Api-Key" => "YOUR_API_KEY" }) resp = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) } unless resp.is_a?(Net::HTTPSuccess) error = JSON.parse(resp.body) puts "Error #{error['code']}: #{error['message']}" end ``` ```python Python theme={null} import requests response = requests.get( "https://api.everhour.com/projects", headers={"X-Api-Key": "YOUR_API_KEY"} ) if not response.ok: error = response.json() print(f"Error {error['code']}: {error['message']}") ``` ```php PHP theme={null} $ch = curl_init("https://api.everhour.com/projects"); curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Api-Key: YOUR_API_KEY"]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $body = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($status >= 400) { $error = json_decode($body, true); echo "Error {$error['code']}: {$error['message']}"; } ``` ```java Java theme={null} import java.net.URI; import java.net.http.*; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.everhour.com/projects")) .header("X-Api-Key", "YOUR_API_KEY") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() >= 400) { System.out.println("Error: " + response.body()); } ``` ```javascript JavaScript theme={null} const response = await fetch("https://api.everhour.com/projects", { headers: { "X-Api-Key": "YOUR_API_KEY" } }); if (!response.ok) { const error = await response.json(); console.error(`Error ${error.code}: ${error.message}`); } ``` ```go Go theme={null} // import "fmt"; "io"; "net/http" req, _ := http.NewRequest("GET", "https://api.everhour.com/projects", nil) req.Header.Set("X-Api-Key", "YOUR_API_KEY") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() if resp.StatusCode >= 400 { body, _ := io.ReadAll(resp.Body) fmt.Printf("Error: %s\n", body) } ``` ```csharp .NET theme={null} using var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-Api-Key", "YOUR_API_KEY"); var response = await client.GetAsync("https://api.everhour.com/projects"); if (!response.IsSuccessStatusCode) { var body = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Error: {body}"); } ``` If you encounter a `503` error that persists, contact support via chat inside your Everhour account or at [ask@everhour.com](mailto:ask@everhour.com) with the request details. # Everhour API Source: https://developers.everhour.com/introduction A REST API for programmatic access to your time tracking data, projects, users, and reports. The Everhour API lets you read and write your account data: time records, projects, tasks, users, clients, invoices, and reports. It uses standard REST conventions — predictable URLs, HTTP methods, and JSON for all requests and responses. ## Base URL ``` https://api.everhour.com ``` ## Request format The API accepts **JSON only**. Set the `Content-Type` header on all requests with a body: ```http theme={null} Content-Type: application/json ``` All text must be UTF-8 encoded. The API always returns JSON, including error responses. ## Explore the documentation Get your API key and make your first request in minutes. Understand the Everhour data model before diving into endpoints. How API key authentication works. How to page through list results. Date formats, time durations, and timezone handling. Receive real-time event notifications. HTTP status codes and error response format. # Connect an MCP client Source: https://developers.everhour.com/mcp-connect Connect Claude Code, Cursor, VS Code, Codex, ChatGPT, and Devin to the Everhour MCP server over OAuth. The Everhour MCP server works with any client that speaks the MCP Streamable HTTP transport. The server URL is the same everywhere: ``` https://api.everhour.com/mcp ``` Clients connect with OAuth 2.1. You don't register an application or manage a client ID and secret — the first time a client connects, Everhour registers it automatically ([Dynamic Client Registration](/oauth)) and opens your browser to approve access. Pick your client below. ## Prerequisites * An active Everhour account. You can sign in with Google, SAML SSO, or email and password. There's nothing to set up in Everhour ahead of time — no app to create, no credentials to copy, no redirect URL to register. Authorization happens in your browser when you connect. *** ## Claude Code [Claude Code](https://claude.com/claude-code) supports remote MCP servers with OAuth natively. ### Prerequisites Complete the [prerequisites](#prerequisites). No API key or app registration needed — Claude Code handles the OAuth flow for you. ### Add the server Add the server with one command: ```bash theme={null} claude mcp add --transport http everhour https://api.everhour.com/mcp ``` ### Authorize 1. Run `/mcp` in Claude Code and select **everhour**. 2. Choose **Authenticate**. Your browser opens Everhour's sign-in. 3. Sign in to Everhour, review the consent screen, and click **Allow**. 4. Return to Claude Code — `/mcp` now shows `everhour` as **connected**.