# How to Integrate Retool with Everhour

- Tool: Retool
- Difficulty: Beginner
- Time required: 15 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Everhour using a REST API Resource with your Everhour API key in the request header. Query time entries, projects, and members to build utilization dashboards that combine Everhour hours with project data from Asana, Jira, or other tools already connected to Retool — providing cross-tool visibility that neither platform offers on its own.

## Build Cross-Tool Time Tracking Dashboards in Retool with Everhour

Everhour's key differentiator is its deep integration with project management tools — time tracking happens inside Asana tasks, Jira issues, and Trello cards, not in a separate app. This means your time data is already organized by the projects and tasks your team actually works with. Retool amplifies this by connecting to Everhour's API alongside your other tools, enabling dashboards that show hours alongside project status, sprint progress, or sales pipeline data in a single view.

Everhour's API provides access to time records, projects (which map to your PM tool projects), team members, clients, and budgets. Authentication is a single API key passed in the X-Api-Key header. The API is paginated and returns JSON for all responses. Time records include the project ID, task ID (from the connected PM tool), team member, and time value in seconds.

Common Retool apps built on Everhour include: team utilization dashboards that combine Everhour hours with Asana project status, project budget trackers that show hours logged vs estimated hours with burn rate, client billing panels that aggregate hours by client across all projects, and sprint time analysis dashboards for engineering teams that overlay Jira sprint data with actual time spent.

## Before you start

- An Everhour account with at least one connected project management tool or standalone projects
- An Everhour API key (generated in Everhour Settings → Integrations → API)
- A Retool account with permission to create Resources
- Basic familiarity with Retool's Table and Chart components

## Step-by-step guide

### 1. Generate an Everhour API key

Log into your Everhour account and navigate to Settings by clicking the gear icon in the bottom-left sidebar. In the Settings menu, select the 'Integrations' tab, then scroll down to find the 'API' section. Click 'Generate API Key' to create a new key. Everhour displays the key value — copy it immediately. Unlike some platforms, Everhour allows you to regenerate this key at any time, but doing so will invalidate the old key and break any existing integrations. Store the key in a password manager or secure notes app before proceeding. Note that the API key is tied to your user account and inherits your Everhour permissions — if your account has access to all projects and all team members, the API key will too. For team-wide dashboards, use a dedicated admin account's API key to ensure access to all workspace data, not just your own time entries.

**Expected result:** You have an Everhour API key copied and ready to configure in Retool.

### 2. Create the Everhour REST API Resource in Retool

In Retool, navigate to the Resources tab in the left sidebar and click 'Create New'. Select 'REST API' from the resource type list. Set the Base URL to 'https://api.everhour.com'. This is Everhour's API base endpoint — all query paths will be appended to this URL. Under the Headers section, add one required header: set the key to 'X-Api-Key' and the value to '{{ retoolContext.configVars.EVERHOUR_API_KEY }}'. Before saving the resource, go to Retool Settings → Configuration Variables and add a new variable named 'EVERHOUR_API_KEY' with your API key value, checking the 'Secret' toggle so it cannot be accessed from frontend code. Return to the resource configuration and save. Click 'Test Resource' or create a quick query to GET '/team/members' — a successful response confirms the API key is valid and the resource is correctly configured. Name the resource 'Everhour' for easy identification across your Retool apps.

```
{
  "Base URL": "https://api.everhour.com",
  "Headers": {
    "X-Api-Key": "{{ retoolContext.configVars.EVERHOUR_API_KEY }}",
    "Content-Type": "application/json"
  }
}
```

**Expected result:** The Everhour REST API Resource is saved. A test GET to /team/members returns a list of your workspace team members with a 200 response.

### 3. Query time records with date and project filters

Create a new query in your Retool app using the Everhour resource. Set the method to GET and the path to '/time/records'. Everhour's time records endpoint accepts several query parameters for filtering the results: 'limit' sets the maximum number of records per page (up to 50), 'page' enables pagination starting from 1, 'from' and 'to' accept date strings in YYYY-MM-DD format to filter by date range, 'projects' accepts a comma-separated list of project IDs, and 'users' accepts comma-separated user IDs. Add a DateRangePicker component to your Retool app to drive the 'from' and 'to' parameters dynamically. The time records response is an array of objects, each containing a 'time' field (in seconds — divide by 3600 to get hours), 'date', 'user' object, and 'task' object with the project information. Run the query to inspect the response structure before building transformers.

```
// GET /time/records
// Query parameters:
// from: {{ dateRange.start || new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString().split('T')[0] }}
// to: {{ dateRange.end || new Date().toISOString().split('T')[0] }}
// limit: 50
// page: {{ pagination.page || 1 }}
// users: {{ userFilter.value || '' }}
// projects: {{ projectFilter.value || '' }}
```

**Expected result:** The query returns an array of time records for the selected date range, each showing the user, task, project, and time in seconds logged for that entry.

### 4. Build a utilization summary transformer

Add a JavaScript transformer to the time records query to aggregate raw records into per-member and per-project summaries. Open the query's Advanced tab and enable 'Transform query results'. The transformer receives the raw array of time records in the 'data' variable and should return a reshaped array suitable for display in a Retool Table or Chart. Group records by user ID, summing the total seconds logged. Convert to hours and calculate a utilization percentage based on a configurable target (such as 8 hours per working day). Add a second grouping by project to show the top projects per user. Bind the transformer output to a Table component by setting the Table's data property to '{{ getTimeRecords.data }}'. Add a Bar Chart component with the summary data to show team-level utilization visually, binding the x-axis to user names and the y-axis to total hours logged.

```
// Transformer: aggregate time records by user
const records = data || [];
const userMap = {};

records.forEach(record => {
  const userId = record.user ? record.user.id : 'unknown';
  const userName = record.user ? record.user.name : 'Unknown';
  const projectName = record.task && record.task.projects
    ? record.task.projects[0]
    : 'No Project';
  const hours = (record.time || 0) / 3600;

  if (!userMap[userId]) {
    userMap[userId] = {
      user_id: userId,
      user_name: userName,
      total_hours: 0,
      project_breakdown: {}
    };
  }

  userMap[userId].total_hours += hours;

  if (!userMap[userId].project_breakdown[projectName]) {
    userMap[userId].project_breakdown[projectName] = 0;
  }
  userMap[userId].project_breakdown[projectName] += hours;
});

return Object.values(userMap).map(user => ({
  user_name: user.user_name,
  total_hours: Math.round(user.total_hours * 100) / 100,
  top_project: Object.entries(user.project_breakdown)
    .sort((a, b) => b[1] - a[1])
    .map(([name, hrs]) => `${name}: ${Math.round(hrs * 10) / 10}h`)
    .slice(0, 3)
    .join(', ')
})).sort((a, b) => b.total_hours - a.total_hours);
```

**Expected result:** The Table shows each team member's name, total hours, and top projects by time spent for the selected date range. The Chart displays a bar graph comparing total hours across team members.

### 5. Add project budget tracking and cross-tool data joining

Create a second query to fetch Everhour project data including budget information. Use GET '/projects' with a 'status=active' parameter to get all active projects. The project response includes budget object with 'value' (estimated hours) and 'progress' (total logged seconds). Create a JavaScript transformer that computes the burn rate percentage for each project: (logged_hours / budget_hours) * 100. Display this in a Table with conditional row colors — green for under 70%, yellow for 70-90%, red for over 90% — using Retool's row color feature based on the percentage value. For cross-tool joining, if you have an Asana or Jira resource also configured in Retool, create a JavaScript query that takes '{{ everhourProjects.data }}' and matches project names or IDs against the other tool's project list, merging status and deadline fields. For complex integrations involving multiple Resources, custom transformers, and Workflows, RapidDev's team can help architect and build your Retool solution.

```
// GET /projects
// Query parameter: status=active

// Transformer: compute budget burn rate
const projects = data || [];
return projects.map(project => {
  const budgetHours = project.budget && project.budget.value
    ? project.budget.value
    : null;
  const loggedSeconds = project.budget && project.budget.progress
    ? project.budget.progress
    : 0;
  const loggedHours = Math.round(loggedSeconds / 3600 * 100) / 100;
  const burnPct = budgetHours && budgetHours > 0
    ? Math.round((loggedHours / budgetHours) * 100)
    : null;

  return {
    project_id: project.id,
    project_name: project.name,
    budget_hours: budgetHours || 'No budget',
    logged_hours: loggedHours,
    remaining_hours: budgetHours ? Math.max(0, budgetHours - loggedHours) : 'N/A',
    burn_pct: burnPct !== null ? `${burnPct}%` : 'N/A',
    status: burnPct === null ? 'no_budget'
      : burnPct < 70 ? 'on_track'
      : burnPct < 90 ? 'at_risk'
      : 'over_budget'
  };
}).sort((a, b) => {
  const order = { over_budget: 0, at_risk: 1, on_track: 2, no_budget: 3 };
  return order[a.status] - order[b.status];
});
```

**Expected result:** The project table shows all active projects sorted by budget risk, with over-budget projects at the top. Row colors visually indicate project health status.

## Best practices

- Store your Everhour API key in Retool configuration variables marked as secret — never hardcode it directly in query headers or transformer code
- Always include date range filters when querying time records — open-ended queries across large workspaces can be slow and may hit pagination limits requiring multiple requests
- Build a team members lookup query that runs on app load and store results in a Retool state variable — use this to populate dropdown filters with user names instead of requiring users to know numeric IDs
- Cache the projects query in Retool's query caching settings for 10-15 minutes — project lists change infrequently and do not need real-time refresh on every interaction
- Use Retool Workflows for end-of-week or end-of-month reports that aggregate large date ranges — Workflows can loop through all pagination pages and export combined results to Google Sheets or send via email
- Divide all time values by 3600 in transformers immediately after receiving the API response — Everhour stores time in seconds throughout its API, and doing the conversion once in the transformer prevents confusion in downstream calculations
- When joining Everhour data with Asana or Jira data in a JavaScript query, match on project names rather than IDs since each tool uses its own internal ID system for the same projects

## Use cases

### Build a team utilization dashboard combining Everhour and Asana data

Query Everhour time records for the current period grouped by team member, then join with Asana project status using a JavaScript query in Retool. Display each team member's total hours, hours by project category, and utilization percentage alongside the projects they are contributing to. This gives managers visibility into where team capacity is actually going across all active initiatives.

Prompt example:

```
Build a Retool team utilization dashboard that queries Everhour time records for the current month, groups hours by team member, and shows total hours, billable hours, and top three projects by time spent for each person. Include a bar chart comparing utilization rates across the team.
```

### Create a project budget and burn rate tracker

Pull Everhour project data including budget hours and logged hours for all active projects. Calculate the burn rate by comparing total hours logged so far against the project timeline and budget. Flag projects where at the current burn rate the budget will be exceeded before the deadline, giving project managers early warning to adjust scope or resources.

Prompt example:

```
Create a Retool project health panel showing all active Everhour projects with budget hours, total logged hours, remaining hours, percentage consumed, and a projected completion date based on current burn rate. Highlight rows in red where projected hours exceed budget.
```

### Build a client billing summary panel for finance teams

Query all Everhour time records grouped by client across all projects in the current billing period. Apply each client's billing rate to calculate billable amounts. Display a summary table showing total hours, billable hours, non-billable hours, and estimated invoice amount per client. Let finance teams review and adjust before generating invoices in their accounting tool.

Prompt example:

```
Build a Retool client billing panel showing all Everhour clients with total hours logged this month, billable hours, and estimated billing amount based on an hourly rate configured in a Retool editable table. Include a total row and an export button.
```

## Troubleshooting

### API returns 401 Unauthorized on every request

Cause: The X-Api-Key header is missing, the key value is incorrect, or the header name is spelled or capitalized incorrectly. Everhour requires this exact header name to authenticate requests.

Solution: Navigate to Everhour Settings → Integrations → API and verify your API key is still active — it may have been regenerated since you configured the resource. In Retool, open the Everhour resource settings and confirm the header name is exactly 'X-Api-Key' and the value correctly references your configuration variable. Test by temporarily hardcoding the key to rule out variable substitution issues.

### Time records query returns fewer records than expected or appears incomplete

Cause: Everhour paginates the /time/records endpoint with a maximum of 50 records per page. If the selected date range covers more than 50 time entries, only the first page is returned by default without a 'page' parameter.

Solution: Add a Pagination component to your Retool app and bind its current page to the 'page' query parameter in your time records query. For bulk data exports, use Retool Workflows to loop through all pages: start at page 1, check if the response length equals 50 (indicating more pages exist), and continue incrementing until a partial page is returned. Combine results into a single array.

### Project IDs in time records do not match the IDs returned by the /projects endpoint

Cause: Everhour time records associate time with tasks (from the connected PM tool), not directly with Everhour projects. The project information is nested inside the task object as task.projects — this is an array of project IDs, not a direct project reference.

Solution: Access the project ID via record.task.projects[0] in your transformer. Fetch the /projects list separately in a second query, build a lookup object keyed by project ID, and use it to enrich each time record with the project name and budget information. Run the projects query with 'Run when page loads' enabled so the lookup table is available before the transformer runs.

### Dashboard shows no data for some team members who have logged time

Cause: The API key belongs to a user account that does not have admin permissions in Everhour, limiting access to their own time records rather than all workspace members' records.

Solution: In Everhour, navigate to Settings → Team and ensure the account whose API key you are using has an Admin role. If you cannot change the role, create a dedicated admin service account, add it to the workspace with Admin permissions, and generate a new API key from that account's settings. Update the Retool configuration variable with the new key.

## Frequently asked questions

### Does Retool have a native Everhour connector?

No, Retool does not have a native Everhour connector. You connect using a REST API Resource with your Everhour API key in the X-Api-Key header. Everhour's REST API is straightforward and well-documented, providing access to time records, projects, team members, clients, and budget data.

### Can I create and edit time records from Retool?

Yes. Use POST to /time/records to create new time entries with a JSON body containing the task ID, user ID, time in seconds, and date. Use PUT to /time/records/{id} to update existing records. Use DELETE to /time/records/{id} to remove entries. All write operations require the API key to belong to a user with appropriate permissions for the project being modified.

### How do I get project IDs and user IDs for filtering queries?

Make GET requests to /projects and /team/members endpoints respectively. These return all accessible projects and team members with their Everhour IDs. Build Select dropdown components in your Retool app populated from these queries, then bind their selected values to the filter parameters in your time records query. This avoids requiring users to know internal numeric IDs.

### Can I access Everhour time data for tasks from Asana or Jira?

Yes. Everhour's API returns task objects that include the connected PM tool's task ID in the task.foreignId field and the platform name in task.type (e.g., 'asana', 'jira'). You can use these foreign IDs to join Everhour time data with Asana or Jira data from other Retool Resources, enabling dashboards that show time logged alongside task status and project milestones.

### Are there rate limits on the Everhour API?

Everhour enforces rate limiting on API requests, though the exact limits are not publicly documented. For typical Retool dashboard use with cached queries refreshing every few minutes, you are unlikely to hit limits. For Workflows that process large datasets in loops, add a short delay between iterations and handle 429 responses by waiting and retrying.

---

Source: https://www.rapidevelopers.com/retool-integrations/everhour
© RapidDev — https://www.rapidevelopers.com/retool-integrations/everhour
