
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
node-intervals-icu
Advanced tools
A lightweight TypeScript client library for the Intervals.icu API. Supports all major endpoints including athletes, events, wellness, workouts, and activities.
npm install node-intervals-icu
import { IntervalsClient } from 'node-intervals-icu';
// Initialize the client
const client = new IntervalsClient({
apiKey: 'your-api-key-here',
athleteId: 'i12345' // optional, defaults to 'me'
});
// Get athlete information
const athlete = await client.getAthlete();
console.log(`Athlete: ${athlete.name}, FTP: ${athlete.ftp}`);
// Get events
const events = await client.getEvents({
oldest: '2024-01-01',
newest: '2024-12-31'
});
// Create a wellness entry
await client.createWellness({
date: '2024-01-15',
weight: 70,
restingHR: 50,
sleepSecs: 28800
});
interface IntervalsConfig {
apiKey: string; // Required: Your Intervals.icu API key
athleteId?: string; // Optional: Athlete ID (defaults to 'me')
baseURL?: string; // Optional: API base URL
timeout?: number; // Optional: Request timeout in ms (default: 10000)
}
getAthlete(athleteId?: string): Promise<Athlete>Get athlete information.
const athlete = await client.getAthlete();
console.log(athlete.name, athlete.ftp, athlete.weight);
updateAthlete(data: Partial<Athlete>, athleteId?: string): Promise<Athlete>Update athlete information.
const updated = await client.updateAthlete({
ftp: 250,
weight: 70
});
getEvents(options?: PaginationOptions, athleteId?: string): Promise<Event[]>Get calendar events.
const events = await client.getEvents({
oldest: '2024-01-01',
newest: '2024-12-31'
});
getEvent(eventId: number, athleteId?: string): Promise<Event>Get a specific event by ID.
const event = await client.getEvent(12345);
createEvent(data: EventInput, athleteId?: string): Promise<Event>Create a new calendar event.
const event = await client.createEvent({
start_date_local: '2024-01-15',
name: 'Race Day',
category: 'RACE',
description: 'Important race'
});
updateEvent(eventId: number, data: Partial<EventInput>, athleteId?: string): Promise<Event>Update an existing event.
await client.updateEvent(12345, {
name: 'Updated Race Day'
});
deleteEvent(eventId: number, athleteId?: string): Promise<void>Delete an event.
await client.deleteEvent(12345);
getWellness(options?: PaginationOptions, athleteId?: string): Promise<Wellness[]>Get wellness data.
const wellness = await client.getWellness({
oldest: '2024-01-01',
newest: '2024-01-31'
});
createWellness(data: WellnessInput, athleteId?: string): Promise<Wellness>Create a new wellness entry.
const wellness = await client.createWellness({
date: '2024-01-15',
weight: 70,
restingHR: 50,
hrv: 65,
sleepSecs: 28800,
sleepQuality: 8
});
updateWellness(date: string, data: Partial<WellnessInput>, athleteId?: string): Promise<Wellness>Update a wellness entry for a specific date.
await client.updateWellness('2024-01-15', {
weight: 69.5,
mood: 8
});
deleteWellness(date: string, athleteId?: string): Promise<void>Delete a wellness entry.
await client.deleteWellness('2024-01-15');
getWorkouts(options?: PaginationOptions, athleteId?: string): Promise<Workout[]>Get planned workouts.
const workouts = await client.getWorkouts({
oldest: '2024-01-01',
newest: '2024-01-31'
});
getWorkout(workoutId: number, athleteId?: string): Promise<Workout>Get a specific workout by ID.
const workout = await client.getWorkout(12345);
createWorkout(data: WorkoutInput, athleteId?: string): Promise<Workout>Create a new workout.
const workout = await client.createWorkout({
start_date_local: '2024-01-15',
name: 'Tempo Run',
description: '45 min tempo at threshold',
duration_secs: 2700,
tss: 65
});
updateWorkout(workoutId: number, data: Partial<WorkoutInput>, athleteId?: string): Promise<Workout>Update an existing workout.
await client.updateWorkout(12345, {
name: 'Updated Tempo Run',
tss: 70
});
deleteWorkout(workoutId: number, athleteId?: string): Promise<void>Delete a workout.
await client.deleteWorkout(12345);
getActivities(options?: PaginationOptions, athleteId?: string): Promise<Activity[]>Get recorded activities.
const activities = await client.getActivities({
oldest: '2024-01-01',
newest: '2024-01-31'
});
getActivity(activityId: number, athleteId?: string): Promise<Activity>Get a specific activity by ID.
const activity = await client.getActivity(12345);
updateActivity(activityId: number, data: ActivityInput, athleteId?: string): Promise<Activity>Update an existing activity.
await client.updateActivity(12345, {
name: 'Morning Run',
description: 'Easy recovery run',
feel: 8
});
deleteActivity(activityId: number, athleteId?: string): Promise<void>Delete an activity.
await client.deleteActivity(12345);
The client automatically tracks rate limit information from the API responses:
// Make some API calls
await client.getAthlete();
// Check rate limit status
const remaining = client.getRateLimitRemaining();
const resetTime = client.getRateLimitReset();
console.log(`Remaining: ${remaining}, Resets at: ${resetTime}`);
The client throws IntervalsAPIError for all API-related errors:
import { IntervalsClient, IntervalsAPIError } from 'node-intervals-icu';
try {
const athlete = await client.getAthlete();
} catch (error) {
if (error instanceof IntervalsAPIError) {
console.error(`API Error: ${error.message}`);
console.error(`Status: ${error.status}`);
console.error(`Code: ${error.code}`);
// Handle specific error types
if (error.code === 'RATE_LIMIT_EXCEEDED') {
console.error('Rate limit exceeded, try again later');
} else if (error.code === 'AUTH_FAILED') {
console.error('Invalid API key');
}
}
}
All methods and responses are fully typed. Import types as needed:
import type {
Athlete,
Event,
Wellness,
Workout,
Activity,
PaginationOptions,
IntervalsConfig
} from 'node-intervals-icu';
To get your API key:
Your athlete ID can be found in the URL when viewing your profile (e.g., i12345), or you can use 'me' to refer to the authenticated athlete.
MIT License - Copyright (c) 2025 Fernando Paladini
See the LICENSE file for details.
Special thanks to Filipe Ronzani for the inspiration and the initial idea that led to the creation of this library. Your project was the spark that made this happen! 🙏
Contributions are welcome! Please read our Contributing Guide to learn how you can help make this project better.
For maintainers: See the Publishing Guide for detailed instructions on publishing this library to NPM.
FAQs
Lightweight TypeScript client library for Intervals.icu API
We found that node-intervals-icu demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.