API Documentation
Integrate Timekeeper into your applications with our tiered REST API. Choose the tier that fits your needs.
API access requires generating an API key. Contact support for tier upgrades beyond Supporter.
Overview
The Timekeeper API provides programmatic access to time tracking data, analytics, and server management features. All endpoints use RESTful conventions and return JSON responses.
Base URL: https://api.timekeeper.404connernotfound.dev/api/v1
API Tiers
| Tier | Rate Limit | Permissions | Price |
|---|---|---|---|
| Supporter | 20 req/min | Read-only basic data | $1/month or $10/year |
| Premium | 60 req/min | Full read + admin write | $2.50/month or $25/year |
| Enterprise | 120 req/min | Full access + sub-keys | $5/month or $50/year |
| Admin | Unlimited | Unrestricted | Internal only |
Authentication
Generating an API Key
API keys are generated server-side. Contact an administrator or use the following endpoint with master key:
POST /api/v1/auth/generate
Content-Type: application/json
{
"guild_id": 123456789,
"admin_user_id": 987654321,
"master_key": "YOUR_MASTER_KEY",
"tier": "PREMIUM"
}
Using Your API Key
Include your API key in the X-API-Key header with every request:
GET /api/v1/guild/123456789/status
X-API-Key: tk_your_api_key_here
Rate Limiting
Rate limits are enforced per minute. Response headers indicate your usage:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 28
X-API-Tier: PREMIUM
Core Endpoints
Get Guild Status
GET /api/v1/guild/{guild_id}/status
Tier Required: Supporter+
GET /api/v1/guild/123456789/status
X-API-Key: tk_your_key
Response:
{
"guild_id": 123456789,
"total_time_seconds": 3600000,
"total_time_hours": 1000.0,
"total_users": 42,
"active_sessions": 5,
"categories": {
"Development": 1800000,
"Meetings": 900000
}
}
Clock In User
POST /api/v1/guild/{guild_id}/clockin
Tier Required: Premium+ (admin users only), Enterprise+ (all users)
POST /api/v1/guild/123456789/clockin
X-API-Key: tk_your_key
Content-Type: application/json
{
"user_id": 987654321,
"category": "Development",
"description": "Working on API integration"
}
Response:
{
"success": true,
"session_id": "api_abc123def456",
"category": "Development",
"start_time": "2025-10-10T14:30:00Z",
"user_id": 987654321
}
List Categories
GET /api/v1/guild/{guild_id}/categories
Tier Required: Supporter+
Get Leaderboard
GET /api/v1/guild/{guild_id}/leaderboard
Tier Required: Supporter+
Code Examples
Choose your preferred programming language and see how to integrate Timekeeper:
import requests
class TimekeeperAPI:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.timekeeper.404connernotfound.dev"
self.session = requests.Session()
self.session.headers.update({"X-API-Key": api_key})
def get_guild_status(self, guild_id: int):
"""Get guild status and statistics"""
response = self.session.get(
f"{self.base_url}/api/v1/guild/{guild_id}/status"
)
response.raise_for_status()
return response.json()
def clock_in(self, guild_id: int, user_id: int,
category: str, description: str = None):
"""Clock in a user"""
data = {"user_id": user_id, "category": category}
if description:
data["description"] = description
response = self.session.post(
f"{self.base_url}/api/v1/guild/{guild_id}/clockin",
json=data
)
response.raise_for_status()
return response.json()
def get_leaderboard(self, guild_id: int, category: str = None,
timeframe: str = "all"):
"""Get guild leaderboard"""
params = {"timeframe": timeframe}
if category:
params["category"] = category
response = self.session.get(
f"{self.base_url}/api/v1/guild/{guild_id}/leaderboard",
params=params
)
response.raise_for_status()
return response.json()
# Usage
api = TimekeeperAPI("tk_your_api_key_here")
# Get guild status
status = api.get_guild_status(123456789)
print(f"Total hours: {status['total_time_hours']}")
# Clock in a user
result = api.clock_in(
guild_id=123456789,
user_id=987654321,
category="Development",
description="API integration"
)
print(f"Session started: {result['session_id']}")
# Get leaderboard
leaderboard = api.get_leaderboard(123456789, timeframe="week")
for entry in leaderboard['leaderboard'][:5]:
print(f"{entry['rank']}. {entry['username']}: {entry['hours']}h")
const axios = require('axios');
class TimekeeperAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://api.timekeeper.404connernotfound.dev';
this.client = axios.create({
baseURL: this.baseURL,
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
});
}
async getGuildStatus(guildId) {
const response = await this.client.get(
`/api/v1/guild/${guildId}/status`
);
return response.data;
}
async clockIn(guildId, userId, category, description = null) {
const data = { user_id: userId, category };
if (description) data.description = description;
const response = await this.client.post(
`/api/v1/guild/${guildId}/clockin`,
data
);
return response.data;
}
async getLeaderboard(guildId, category = null, timeframe = 'all') {
const params = { timeframe };
if (category) params.category = category;
const response = await this.client.get(
`/api/v1/guild/${guildId}/leaderboard`,
{ params }
);
return response.data;
}
}
// Usage
(async () => {
const api = new TimekeeperAPI('tk_your_api_key_here');
// Get guild status
const status = await api.getGuildStatus(123456789);
console.log(`Total hours: ${status.total_time_hours}`);
// Clock in a user
const result = await api.clockIn(
123456789,
987654321,
'Development',
'API integration'
);
console.log(`Session started: ${result.session_id}`);
// Get leaderboard
const leaderboard = await api.getLeaderboard(123456789, null, 'week');
leaderboard.leaderboard.slice(0, 5).forEach(entry => {
console.log(`${entry.rank}. ${entry.username}: ${entry.hours}h`);
});
})();
import axios, { AxiosInstance } from 'axios';
interface GuildStatus {
guild_id: number;
total_time_seconds: number;
total_time_hours: number;
total_users: number;
active_sessions: number;
categories: Record;
}
interface ClockInResponse {
success: boolean;
session_id: string;
category: string;
start_time: string;
user_id: number;
}
class TimekeeperAPI {
private client: AxiosInstance;
constructor(private apiKey: string) {
this.client = axios.create({
baseURL: 'https://api.timekeeper.404connernotfound.dev',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
});
}
async getGuildStatus(guildId: number): Promise {
const response = await this.client.get(
`/api/v1/guild/${guildId}/status`
);
return response.data;
}
async clockIn(
guildId: number,
userId: number,
category: string,
description?: string
): Promise {
const data: any = { user_id: userId, category };
if (description) data.description = description;
const response = await this.client.post(
`/api/v1/guild/${guildId}/clockin`,
data
);
return response.data;
}
}
// Usage
(async () => {
const api = new TimekeeperAPI('tk_your_api_key_here');
const status = await api.getGuildStatus(123456789);
console.log(`Total hours: ${status.total_time_hours}`);
const result = await api.clockIn(
123456789,
987654321,
'Development',
'API integration'
);
console.log(`Session started: ${result.session_id}`);
})();
use reqwest;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Deserialize)]
struct GuildStatus {
guild_id: u64,
total_time_seconds: u64,
total_time_hours: f64,
total_users: u32,
active_sessions: u32,
categories: HashMap,
}
#[derive(Debug, Serialize)]
struct ClockInRequest {
user_id: u64,
category: String,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option,
}
struct TimekeeperAPI {
api_key: String,
client: reqwest::Client,
}
impl TimekeeperAPI {
fn new(api_key: String) -> Self {
Self {
api_key,
client: reqwest::Client::new(),
}
}
async fn get_guild_status(
&self,
guild_id: u64,
) -> Result {
let url = format!(
"https://api.timekeeper.404connernotfound.dev/api/v1/guild/{}/status",
guild_id
);
self.client
.get(&url)
.header("X-API-Key", &self.api_key)
.send()
.await?
.json::()
.await
}
async fn clock_in(
&self,
guild_id: u64,
user_id: u64,
category: String,
description: Option,
) -> Result<(), reqwest::Error> {
let url = format!(
"https://api.timekeeper.404connernotfound.dev/api/v1/guild/{}/clockin",
guild_id
);
let data = ClockInRequest {
user_id,
category,
description,
};
self.client
.post(&url)
.header("X-API-Key", &self.api_key)
.json(&data)
.send()
.await?;
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let api = TimekeeperAPI::new("tk_your_api_key_here".to_string());
let status = api.get_guild_status(123456789).await?;
println!("Total hours: {}", status.total_time_hours);
api.clock_in(
123456789,
987654321,
"Development".to_string(),
Some("API integration".to_string()),
).await?;
Ok(())
}
Error Handling
All API errors follow a consistent format:
{
"error": "Rate limit exceeded",
"message": "Limit: 60 requests/minute",
"remaining": 0,
"reset_in": 42,
"tier": "PREMIUM",
"code": "RATE_001"
}