Connect Bolt.new to Everhour using the Everhour REST API with a simple API token header. Fetch time records, projects, and team member data to build custom time tracking dashboards. Everhour's API uses X-Api-Key header auth — one of the easiest time tracking APIs to integrate. All outbound Everhour API calls work in Bolt's WebContainer preview. Webhooks for real-time updates require deployment to a public URL.
Build Custom Time Tracking Dashboards on Everhour Data with Bolt.new
Everhour's core strength is its deep integration with popular project management tools — when you track time in Everhour, you are tracking it against tasks that already exist in Asana, Jira, Trello, or GitHub. This means time data is automatically associated with the project context where work was planned, creating a natural link between estimation, execution, and reporting. For Bolt-built applications, this makes Everhour particularly useful as a backend for custom reporting dashboards that combine time data with project progress.
Everhour's REST API is among the most developer-friendly in the time tracking space. Authentication uses a single X-Api-Key header — no OAuth dance, no token refresh, no complex signature generation. The API follows consistent REST conventions: GET requests return lists with optional filter parameters, and most write operations use POST with straightforward JSON bodies. Rate limits are generous for typical dashboard use cases.
The API covers four main resource types: time records (individual timer entries), projects (synced from connected PM tools), tasks (the specific work items within projects), and users (team members). For building dashboards, the time records endpoint with date-range filtering and optional grouping is the primary resource. Time is represented as integers in seconds — convert to hours for display. Project IDs in Everhour use the provider prefix format: Asana tasks appear as 'as:{taskId}', Jira as 'jira:{issueId}', and Trello as 'tr:{cardId}' — handle these compound IDs when building cross-provider displays.
Integration method
Bolt generates Next.js API routes that call Everhour's REST API using an API token stored in the X-Api-Key header in .env. Everhour's API is straightforward JSON REST with simple header-based authentication — no OAuth, no complex setup. All outbound calls work in Bolt's WebContainer during development. Webhook notifications for time entry events require a deployed public URL, but polling the API from the preview works for most dashboard use cases.
Prerequisites
- A Bolt.new account with a Next.js project
- An Everhour account at everhour.com (free plan supports up to 5 team members)
- At least one project with time records in Everhour
- Your Everhour API token from Profile settings
Step-by-step guide
Get Your Everhour API Token
Get Your Everhour API Token
Everhour API authentication uses a simple API token passed as the X-Api-Key header on every request. There is no OAuth flow, no token refresh, and no complex signature generation — just a static token that identifies your account. To find your API token, log into Everhour and click your profile picture or name in the top-right corner to open the profile dropdown. Select Profile from the menu. On your profile page, scroll down to the API Token section — it is usually near the bottom of the page. Your API token is displayed there as a long alphanumeric string. Click the copy button or select and copy the token manually. If the API Token section is not visible, your Everhour account may be on a plan that does not include API access, or you may need to enable API access in your account settings. Everhour's free plan includes API access for accounts with up to 5 members. Paid plans have no API restrictions. Add the token to your Bolt project's .env file as EVERHOUR_API_KEY. This must not have the NEXT_PUBLIC_ prefix — the API key grants full account access and must only be used server-side in API routes, never bundled into client-side JavaScript. Also note your user ID if you plan to filter time records by specific team members. Your user ID appears in the profile URL when you view your own profile, or you can fetch it via GET /users/me from the Everhour API. Add it as EVERHOUR_USER_ID if needed. The Everhour API base URL is https://api.everhour.com. Every request must include two headers: X-Api-Key: YOUR_TOKEN and Content-Type: application/json. The API returns JSON for all responses and uses standard HTTP status codes.
Add EVERHOUR_API_KEY to the .env file with a placeholder value. Create a lib/everhour.ts utility that exports an everhourFetch helper. It should accept a path (e.g., '/time-records') and optional query params, build the URL as https://api.everhour.com{path}, and make GET requests with X-Api-Key and Content-Type headers from process.env. Export everhourPost for POST requests. Handle JSON error responses and throw typed errors.
Paste this in Bolt.new chat
1// lib/everhour.ts2const EVERHOUR_BASE_URL = 'https://api.everhour.com';34function getHeaders() {5 const apiKey = process.env.EVERHOUR_API_KEY;6 if (!apiKey) throw new Error('EVERHOUR_API_KEY must be set in .env');78 return {9 'X-Api-Key': apiKey,10 'Content-Type': 'application/json',11 };12}1314export async function everhourFetch<T = unknown>(15 path: string,16 params?: Record<string, string | number>17): Promise<T> {18 const url = new URL(`${EVERHOUR_BASE_URL}${path}`);19 if (params) {20 Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, String(v)));21 }2223 const response = await fetch(url.toString(), { headers: getHeaders() });2425 if (!response.ok) {26 const err = await response.json().catch(() => ({ message: response.statusText })) as { message?: string; error?: string };27 throw new Error(err.message || err.error || `Everhour API error: ${response.status}`);28 }2930 return response.json() as Promise<T>;31}3233export async function everhourPost<T = unknown>(path: string, body: unknown): Promise<T> {34 const response = await fetch(`${EVERHOUR_BASE_URL}${path}`, {35 method: 'POST',36 headers: getHeaders(),37 body: JSON.stringify(body),38 });3940 if (!response.ok) {41 const err = await response.json().catch(() => ({ message: response.statusText })) as { message?: string };42 throw new Error(err.message || `Everhour POST error: ${response.status}`);43 }4445 return response.json() as Promise<T>;46}Pro tip: Everhour time values are stored as integers in seconds. To display as hours and minutes, divide by 3600 for decimal hours, or use Math.floor(seconds / 3600) for hours and Math.floor((seconds % 3600) / 60) for minutes. A value of 3600 = 1 hour, 5400 = 1.5 hours, 7200 = 2 hours.
Expected result: The everhour.ts helper is configured. Test it by calling everhourFetch('/users/me') from an API route — you should see your Everhour user profile returned, confirming the API key is working correctly.
Build Time Records and Projects API Routes
Build Time Records and Projects API Routes
The core Everhour API resources for dashboard building are time records and projects. Understanding the response structure for each helps you design efficient API routes that return clean data to your React components. The time records endpoint (GET /time-records) accepts date range parameters: from and to in YYYY-MM-DD format. Without date parameters, it defaults to returning today's records. Always provide explicit date ranges for dashboard queries. Optional filter parameters include user_id (filter to one team member) and limit/offset for pagination (default is 50 records per request, maximum 50). Each time record in the response includes: id, time (integer seconds), date (YYYY-MM-DD string), task (nested object with id, name, and projects array), user (nested object with id, name, avatar), and optionally comment. The task.projects array contains the projects the task belongs to, each with an id and name. Task IDs use the provider prefix format for integrated PM tools — Asana tasks have IDs like 'as:1234567890', Jira issues like 'jira:PROJ-123'. The projects endpoint (GET /projects) returns all projects in the account including their budget settings and total tracked time. Each project has a name, status (active/archived), and budget object (type, progress, hours). The budget.progress value is the percentage of budget consumed — useful for over-budget alerts. For building aggregate reports (hours per project, hours per user), fetch all time records for the period and aggregate in your API route before returning to the client. This keeps the aggregation logic server-side and returns a smaller, pre-processed payload to React components. Use JavaScript's reduce method to build lookup objects keyed by project ID and user ID.
Create two Next.js API routes. First, /api/everhour/time-records/route.ts that accepts from, to, userId (optional) query params. Fetch from GET /time-records with date range. Handle pagination — if response is an array of 50, keep fetching with offset until array < 50. Aggregate into: total seconds, breakdown by project (project name, seconds), breakdown by user (user name, seconds). Cache 30 seconds. Second, /api/everhour/projects/route.ts that fetches GET /projects and returns active projects with name, budget info, and totalTime. Cache 60 seconds.
Paste this in Bolt.new chat
1// app/api/everhour/time-records/route.ts2import { NextResponse } from 'next/server';3import { everhourFetch } from '@/lib/everhour';45interface TimeRecord {6 id: number;7 time: number;8 date: string;9 task: { id: string; name: string; projects: Array<{ id: string; name: string }> };10 user: { id: number; name: string };11 comment?: string;12}1314const cache = new Map<string, { data: unknown; expiresAt: number }>();1516export async function GET(request: Request) {17 const { searchParams } = new URL(request.url);18 const from = searchParams.get('from');19 const to = searchParams.get('to');20 const userId = searchParams.get('userId');2122 if (!from || !to) {23 return NextResponse.json({ error: 'from and to are required' }, { status: 400 });24 }2526 const cacheKey = `${from}-${to}-${userId}`;27 const cached = cache.get(cacheKey);28 if (cached && Date.now() < cached.expiresAt) {29 return NextResponse.json(cached.data);30 }3132 try {33 const allRecords: TimeRecord[] = [];34 let offset = 0;35 const limit = 50;3637 while (true) {38 const params: Record<string, string | number> = { from, to, limit, offset };39 if (userId) params.userId = userId;4041 const records = await everhourFetch<TimeRecord[]>('/time-records', params);42 allRecords.push(...records);43 if (records.length < limit) break;44 offset += limit;45 }4647 const totalSeconds = allRecords.reduce((sum, r) => sum + r.time, 0);4849 // Group by project50 const byProject: Record<string, { name: string; seconds: number }> = {};51 for (const r of allRecords) {52 const project = r.task.projects?.[0];53 if (!project) continue;54 if (!byProject[project.id]) byProject[project.id] = { name: project.name, seconds: 0 };55 byProject[project.id].seconds += r.time;56 }5758 // Group by user59 const byUser: Record<number, { name: string; seconds: number }> = {};60 for (const r of allRecords) {61 if (!byUser[r.user.id]) byUser[r.user.id] = { name: r.user.name, seconds: 0 };62 byUser[r.user.id].seconds += r.time;63 }6465 const result = {66 totalSeconds,67 totalHours: Math.round((totalSeconds / 3600) * 100) / 100,68 byProject: Object.entries(byProject)69 .map(([id, v]) => ({ id, ...v, hours: Math.round((v.seconds / 3600) * 100) / 100 }))70 .sort((a, b) => b.seconds - a.seconds),71 byUser: Object.entries(byUser)72 .map(([id, v]) => ({ id, ...v, hours: Math.round((v.seconds / 3600) * 100) / 100 }))73 .sort((a, b) => b.seconds - a.seconds),74 records: allRecords,75 };7677 cache.set(cacheKey, { data: result, expiresAt: Date.now() + 30_000 });78 return NextResponse.json(result);79 } catch (err) {80 const message = err instanceof Error ? err.message : 'Failed to fetch time records';81 return NextResponse.json({ error: message }, { status: 500 });82 }83}Pro tip: Everhour time records can have tasks from multiple PM tools in the same account (some from Asana, some from Trello, some entered manually). Tasks without a connected PM tool have numeric IDs. When displaying task names in your UI, the task.name field is always present regardless of the source tool — use it as the primary display value rather than parsing the compound ID.
Expected result: The time records route fetches Everhour time data and returns aggregated breakdowns by project and user. Test by passing ?from=2025-04-01&to=2025-04-30 to see a full month of time records with pre-calculated hour totals.
Build a Team Hours Dashboard in React
Build a Team Hours Dashboard in React
With the API routes returning aggregated time data, build the React dashboard that presents this information visually. A team hours dashboard has three typical sections: a summary bar at the top, a visual breakdown of hours by project, and a table showing individual team member contributions. Fetch data on component mount using useEffect with the current week or month as the default date range. Store both the loading state and the data in component state. Show loading skeletons while the fetch is in progress — Everhour's API can take 1-3 seconds for large accounts with many records. For the summary bar, display three key metrics: total tracked hours for the period, number of active projects with logged time, and total number of team members who tracked time. Convert seconds to hours using the / 3600 conversion and round to one decimal place for display. For the project breakdown, a horizontal bar chart (Recharts BarChart with layout='vertical') works well because project names can be long and fit better on the Y axis. Each bar represents one project's total hours. Color bars by a consistent palette and truncate project names longer than 30 characters with an ellipsis tooltip. For the team member table, show each person's name, total hours for the period, and a mini bar showing their hours as a percentage of the top contributor's hours. Sort by hours descending. This gives managers a quick glance at workload distribution. Add date range quick-select buttons (This Week, Last Week, This Month, Last Month) that recalculate the from and to dates and trigger a new fetch. Use JavaScript's Date object to calculate these ranges dynamically rather than hardcoding dates.
Build a TeamHoursDashboard React component that fetches from /api/everhour/time-records. Show three summary cards: Total Hours, Active Projects, Active Members. Render a horizontal bar chart using Recharts showing hours by project name (top 10 by hours). Below, show a team member table with columns: Name, Hours, and a mini progress bar showing percentage of max hours. Add This Week / Last Week / This Month buttons that update the date range and trigger a refetch. Show loading skeletons for all three sections while fetching.
Paste this in Bolt.new chat
Pro tip: For the date range quick buttons, calculate dates using JavaScript to always generate correct ranges: for 'This Week', find the Monday of the current week by subtracting (dayOfWeek - 1) days from today. Use toISOString().split('T')[0] to format as YYYY-MM-DD strings for the API params.
Expected result: The dashboard renders with real Everhour data showing team hour totals, a project breakdown bar chart, and a team member table. Clicking the date range buttons updates all three sections with data for the selected period.
Create Time Entries from Your Bolt App
Create Time Entries from Your Bolt App
Writing time entries back to Everhour requires a task ID to associate the time with. Unlike pure time tracking tools where you can log time without a task, Everhour's core model is task-based — every time record belongs to a task (which belongs to a project). This reflects Everhour's role as an overlay on existing PM tools where tasks already exist. To create a time record, POST to /time-records with the body containing: time (integer seconds), date (YYYY-MM-DD string), task (object with id field), and optionally comment. The task ID must be a valid Everhour task ID — either a provider-specific ID from an integrated PM tool (format: 'as:1234567' for Asana) or a Everhour-native task ID. For the best user experience, build a task selector that lets users pick from their assigned tasks. Fetch tasks for a project using GET /projects/{projectId}/tasks, which returns task names and IDs. Populate a dropdown with these tasks so users select the task first, then enter hours and an optional comment. Time input from users should accept hours and minutes in a friendly format (e.g., '1h 30m' or '1.5') and convert to seconds before submission. A simple parser: if the input contains 'h', split on 'h' and 'm'; if it is a plain number, treat as hours and multiply by 3600. After successful creation, invalidate the time records cache for today's date range so the dashboard reflects the new entry immediately. Consider returning the full created record in the API response so the UI can update optimistically without a full refetch. Note: Everhour does not support incoming webhook callbacks during Bolt development — the WebContainer cannot receive POST requests from external services. For webhook-driven real-time sync, deploy to Netlify or Bolt Cloud and register the webhook URL in your Everhour account settings.
Create a time entry form component and API route. Build /api/everhour/time-records/create/route.ts that accepts POST with { taskId, date, hours, comment } and creates a time record via POST https://api.everhour.com/time-records. Convert hours to seconds (multiply by 3600). Build a React TimeEntryForm with: a date picker (default today), a task ID input, a hours input accepting decimal values, a comment textarea, and a submit button. Show a success toast with the logged hours after creation. Add a note in the code that webhooks for real-time sync require deployment to Netlify or Bolt Cloud.
Paste this in Bolt.new chat
1// app/api/everhour/time-records/create/route.ts2// NOTE: Everhour webhook callbacks require a deployed URL.3// For real-time sync, deploy to Netlify or Bolt Cloud and register4// your webhook URL in Everhour Settings → Integrations → Webhooks.5import { NextResponse } from 'next/server';6import { everhourPost } from '@/lib/everhour';78interface CreateTimeRecordBody {9 taskId: string;10 date: string;11 hours: number;12 comment?: string;13}1415interface EverhourTimeRecord {16 id: number;17 time: number;18 date: string;19 task: { id: string; name: string };20 user: { id: number; name: string };21}2223export async function POST(request: Request) {24 const { taskId, date, hours, comment } = await request.json() as CreateTimeRecordBody;2526 if (!taskId?.trim()) {27 return NextResponse.json({ error: 'taskId is required' }, { status: 400 });28 }29 if (!date || !/^\d{4}-\d{2}-\d{2}$/.test(date)) {30 return NextResponse.json({ error: 'date must be in YYYY-MM-DD format' }, { status: 400 });31 }32 if (!hours || hours <= 0 || hours > 24) {33 return NextResponse.json({ error: 'hours must be a positive number up to 24' }, { status: 400 });34 }3536 const timeInSeconds = Math.round(hours * 3600);3738 try {39 const record = await everhourPost<EverhourTimeRecord>('/time-records', {40 task: { id: taskId },41 time: timeInSeconds,42 date,43 ...(comment?.trim() ? { comment: comment.trim() } : {}),44 });4546 return NextResponse.json({47 success: true,48 record: {49 id: record.id,50 date: record.date,51 hours: record.time / 3600,52 taskName: record.task.name,53 userName: record.user.name,54 },55 });56 } catch (err) {57 const message = err instanceof Error ? err.message : 'Failed to create time record';58 return NextResponse.json({ error: message }, { status: 500 });59 }60}Pro tip: Everhour validates that task IDs exist in your account. If a task ID from an integrated PM tool has been deleted or is no longer synced, the create call returns a 404. Build error handling that shows a clear 'Task not found' message so users know to update the task ID in the form.
Expected result: Submitting the time entry form creates a new record in Everhour. Open Everhour and navigate to the Reports section or check the project's time log — the new entry should appear with the correct date, hours, and task association.
Common use cases
Team Hours Dashboard by Project
Build a weekly or monthly dashboard that shows how many hours each team member tracked across different projects. Filter time records by a date range, group by project and user, and display the breakdown as a sortable table with totals. This replaces manual report generation from Everhour's native reports section with a custom, always-current view.
Build a team time tracking dashboard using Everhour. Create /api/everhour/time-records that accepts from and to query params (YYYY-MM-DD format) and fetches time records from GET https://api.everhour.com/time-records with date range filtering. Return records grouped by project name and user name with hour totals. Build a React dashboard with a date range selector (This Week / This Month / Last Month quick buttons), a summary showing total team hours, a bar chart (Recharts) of hours per project, and a table of hours per team member. Store EVERHOUR_API_KEY in process.env, use X-Api-Key header.
Copy this prompt to try it in Bolt.new
Project Budget Tracker
Create a project budget tracking tool that compares estimated hours against tracked hours for each Everhour project. Fetch project data with budget estimates and compare against actual time records to show percentage utilization, remaining hours, and a warning when projects are over 80% of their budget. Display as a card grid sorted by utilization percentage.
Create a project budget tracker using the Everhour API. Build /api/everhour/projects that fetches projects from GET https://api.everhour.com/projects including budget and tracked time totals. Return each project's name, totalBudgetSeconds, totalTimeSeconds, team members, and status. Build a React card grid where each card shows: project name, a progress bar from 0-100% (tracked/budget), hours tracked vs budget (converted from seconds to hours), remaining hours, and a color-coded status badge (Green=Under 70%, Yellow=70-90%, Red=Over 90%). Sort cards by utilization percentage descending.
Copy this prompt to try it in Bolt.new
Personal Timesheet View
Build a personal timesheet that shows a specific team member's time entries for the current week, organized by day and project. Allow the user to add new time entries for today's work directly from the interface. This provides a quick daily time tracking workflow without opening Everhour's full interface.
Build a personal timesheet view using Everhour. Create /api/everhour/my-time that fetches time records for a specific user ID (from EVERHOUR_USER_ID env var) for the current week using GET /time-records with date filtering. Create /api/everhour/time-records/create that accepts POST with { taskId, date, time, comment } and calls POST https://api.everhour.com/time-records. Build a React weekly timesheet with rows for Mon-Sun, columns for projects, showing hours per day per project. Add a quick entry form: task ID input, hours input, optional comment, submit button. Show a running weekly total in the header.
Copy this prompt to try it in Bolt.new
Troubleshooting
401 Unauthorized on every API request even though the API key looks correct
Cause: The X-Api-Key header is missing, misspelled, or the environment variable has the NEXT_PUBLIC_ prefix. Everhour requires the header to be exactly 'X-Api-Key' with this capitalization. If the key is in a client-side variable, it may be empty in server-side API route context.
Solution: Verify the header name is exactly 'X-Api-Key' (capital X, capital A, capital K). Check that EVERHOUR_API_KEY is in your .env file without the NEXT_PUBLIC_ prefix. Log the value of process.env.EVERHOUR_API_KEY in your API route to confirm it is being read. Regenerate the token in Everhour Profile settings if the existing one stopped working.
1// Correct header format:2const headers = {3 'X-Api-Key': process.env.EVERHOUR_API_KEY, // Exact capitalization required4 'Content-Type': 'application/json',5};Time records endpoint returns an empty array even though there are entries in Everhour
Cause: Missing or incorrect date range parameters. Without explicit from and to parameters, Everhour defaults to only today's records. If no time was tracked today, the response is an empty array.
Solution: Always provide explicit from and to parameters in YYYY-MM-DD format. For a monthly report, pass from=2025-04-01 and to=2025-04-30. For the current week, calculate the Monday and Sunday dates dynamically. Verify the dates are in YYYY-MM-DD format, not ISO timestamp format.
1// Calculate current week range:2const now = new Date();3const dayOfWeek = now.getDay() || 7; // 1=Mon, 7=Sun4const monday = new Date(now);5monday.setDate(now.getDate() - dayOfWeek + 1);6const sunday = new Date(monday);7sunday.setDate(monday.getDate() + 6);8const from = monday.toISOString().split('T')[0];9const to = sunday.toISOString().split('T')[0];Creating a time record returns 404 with 'Task not found'
Cause: The task ID provided does not exist in Everhour or has been deleted from the connected PM tool. Task IDs for integrated tools (Asana, Jira, Trello) use a compound format with a provider prefix.
Solution: Fetch valid task IDs from GET /projects/{projectId}/tasks or from the time records returned by the records endpoint (the task.id field on any existing record shows the correct format). Confirm the task still exists in both Everhour and the connected PM tool. For Asana tasks, the ID format is 'as:{numericId}'; for Jira, 'jira:{issueKey}'.
1// Fetch tasks for a project to get valid task IDs:2const tasks = await everhourFetch(`/projects/${projectId}/tasks`);3// Returns: [{ id: 'as:1234567890', name: 'Task Name', ... }, ...]4// Use the id field from this response for time record creationEverhour webhook events are not reaching the API route
Cause: Everhour sends webhook POST requests to your server URL. The Bolt WebContainer preview is a browser-tab runtime that cannot receive incoming HTTP requests from Everhour's servers.
Solution: Deploy your Bolt app to Netlify or Bolt Cloud to get a stable public URL. Register that deployed URL in Everhour Settings → Integrations → Webhooks (if available on your plan). For development, use polling from the API route instead of webhooks — check for new records every 30 seconds using setInterval in a useEffect hook.
Best practices
- Store EVERHOUR_API_KEY without the NEXT_PUBLIC_ prefix — the API key grants full account access and must never appear in client-side JavaScript bundles.
- Always provide explicit from and to date range parameters when fetching time records — the default behavior (today only) is rarely what dashboard queries need.
- Cache time record responses for 30-60 seconds — Everhour's API is generally fast, but caching prevents redundant calls when multiple team members view the dashboard simultaneously.
- Convert time values from Everhour's seconds format to hours immediately in your API route before returning to the client — this keeps all time conversion logic in one place and prevents calculation errors in React components.
- Use Everhour's server-side aggregation by fetching and grouping records in the API route, not in React components — sending 500 individual time records to the browser and aggregating them client-side is wasteful when the API route can return pre-grouped summaries.
- Handle the paginated time records endpoint carefully — the 50-record limit per request means a busy team in a month-long date range may require multiple fetches to get all records.
- When creating time entries, validate hours server-side before submitting — Everhour accepts time as seconds with no upper bound validation, so a user accidentally entering '800' hours instead of '8' would be silently accepted without server-side validation.
- Register Everhour webhooks only after deploying to a stable URL — WebContainer preview URLs change per session and cannot receive incoming HTTP connections from Everhour's servers.
Alternatives
Harvest includes invoicing and expense tracking built into the same platform; Everhour is better for teams that track time against tasks in existing Asana, Jira, or Trello projects and want time to appear alongside tasks in those tools.
Clockify is completely free with no team member limits and has a generous API; Everhour is better when deep PM tool integration (tasks appearing in Asana, Jira, Trello directly) is more important than cost.
Toggl Track has a cleaner API with more generous rate limits and broad third-party integrations; Everhour is better for teams whose primary workflow is inside Asana or Jira and who want time tracking to appear directly inside those tools.
Time Doctor includes employee monitoring features like screenshots and app activity tracking; Everhour is better for teams that track time against project tasks without monitoring individual user activity.
Frequently asked questions
Can I use the Everhour API in Bolt's WebContainer preview without deploying?
Yes — all outbound Everhour API calls work in Bolt's WebContainer preview. You can fetch time records, projects, and tasks, and create new time entries during development without deploying. The only Everhour feature that requires a deployed URL is webhook callbacks, since those are incoming HTTP requests that the WebContainer cannot receive.
Does Bolt.new have a native Everhour integration?
No — Bolt.new does not include a built-in Everhour connector. The integration uses Everhour's REST API directly from Next.js API routes with your API token. Bolt's AI can generate the integration code from a description of what you need, making setup fast even without a native connector.
What Everhour plan do I need to access the API?
Everhour's API is available on all plans including the free plan for teams of up to 5 members. The API token appears in Profile settings regardless of plan. Paid plans (Team at $8.50/user/month) remove the 5-member limit and add features like invoicing and detailed reports, but API access itself is not gated to paid plans.
How does Everhour connect to Asana or Jira tasks?
Everhour connects to Asana, Jira, Trello, GitHub, and other PM tools via OAuth in your Everhour account settings. Once connected, tasks from those tools sync to Everhour and appear in the Everhour timer interface alongside native tasks. Through the API, task IDs for integrated tools use a provider prefix format: 'as:{asanaTaskId}' for Asana, 'jira:{issueKey}' for Jira. When you fetch time records, each record includes the task object with both the ID and name.
Can I fetch time records for all team members, not just myself?
Yes — the GET /time-records endpoint returns all team members' time records by default when called with an account-level API key. To filter to a specific team member, pass the userId query parameter. Fetch all users from GET /team/users to get the list of user IDs and names for building a user filter dropdown in your dashboard.
How do I handle the pagination in the time records endpoint?
Everhour returns a maximum of 50 time records per request. If the response array has exactly 50 records, there may be more — increase the offset by 50 and make another request. Continue until a response returns fewer than 50 records. For large date ranges with busy teams, this can require multiple API calls. The example API route in this guide handles pagination automatically by looping until the full dataset is fetched.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation