API Documentation
Integrate Latimer into your applications
Base URL
https://latimer.traqr.co.uk/api/v1
Authentication
All API requests require authentication via Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN
You can find your API token in your profile settings.
Endpoints
Users
GET /users
List all users (limited to 50)
GET /api/v1/users
Response:
[
{
"id": 1,
"username": "johndoe",
"name": "John Doe",
"avatar_url": "https://avatars.githubusercontent.com/u/123",
"level": 5,
"xp": 250
}
]
GET /users/:id
Get user details by ID or username (GDPR compliant - no email)
GET /api/v1/users/:id
Response:
{
"id": 1,
"username": "johndoe",
"name": "John Doe",
"bio": "Software developer",
"avatar_url": "https://avatars.githubusercontent.com/u/123",
"level": 5,
"xp": 250,
"github_url": "https://github.com/johndoe"
}
GET /users/me
Get current authenticated user's info
GET /api/v1/users/me
Response:
{
"id": 1,
"username": "johndoe",
"name": "John Doe",
"bio": "Software developer",
"avatar_url": "https://avatars.githubusercontent.com/u/123",
"level": 5,
"xp": 250,
"github_url": "https://github.com/johndoe"
}
GET /users/friends
Get current user's friends list (mutual follows)
GET /api/v1/users/friends
Response:
[
{
"id": 2,
"username": "janedoe",
"name": "Jane Doe",
"avatar_url": "https://avatars.githubusercontent.com/u/456",
"level": 8,
"xp": 500,
"github_url": "https://github.com/janedoe"
}
]
Audio Rooms
GET /rooms
List public live audio rooms (limited to 50)
GET /api/v1/rooms
Response:
[
{
"id": 1,
"title": "Coding Session",
"description": "Let's code together!",
"slug": "coding-session",
"is_public": true,
"is_scheduled": false,
"scheduled_at": null,
"started_at": "2024-01-15T10:00:00Z",
"ended_at": null,
"status": "live",
"recording_url": null,
"recording_consent": false,
"max_participants": 50,
"created_at": "2024-01-15T09:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"host": {
"id": 1,
"username": "johndoe"
}
}
]
GET /rooms/:id
Get a specific audio room by ID
GET /api/v1/rooms/:id
Response:
{
"id": 1,
"title": "Coding Session",
"description": "Let's code together!",
"slug": "coding-session",
"is_public": true,
"is_scheduled": false,
"scheduled_at": null,
"started_at": "2024-01-15T10:00:00Z",
"ended_at": null,
"status": "live",
"recording_url": null,
"recording_consent": false,
"max_participants": 50,
"created_at": "2024-01-15T09:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"host": {
"id": 1,
"username": "johndoe"
}
}
POST /rooms
Create a new audio room
POST /api/v1/rooms
Request Body:
{
"room": {
"title": "My New Room",
"description": "Room description (optional)",
"is_public": true
}
}
Fields:
title(required): Room titledescription(optional): Room descriptionis_public(optional, default: true): Whether the room is public
Response (201 Created):
{
"id": 1,
"title": "My New Room",
"description": "Room description",
"slug": "my-new-room",
"is_public": true,
"status": "pending",
"host": {
"id": 1,
"username": "johndoe"
},
"created_at": "2024-01-15T10:00:00Z"
}
GET /rooms/my_rooms
Get current user's rooms (hosted and participated)
GET /api/v1/rooms/my_rooms
Response:
{
"hosted": [
{
"id": 1,
"title": "My Room",
"status": "live",
"host": { "id": 1, "username": "johndoe" }
}
],
"participated": [
{
"id": 2,
"title": "Another Room",
"status": "live",
"host": { "id": 2, "username": "janedoe" }
}
]
}
GET /rooms/live_count
Get count of currently live public rooms
GET /api/v1/rooms/live_count
Response:
{
"count": 5,
"status": "live"
}
Communities
GET /communities
List public communities (limited to 50)
GET /api/v1/communities
Response:
[
{
"id": 1,
"name": "Ruby Developers",
"slug": "ruby-developers",
"description": "A community for Ruby developers",
"is_public": true,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"owner": {
"id": 1,
"username": "johndoe"
}
}
]
Response Fields:
id: Community IDname: Community nameslug: URL-friendly identifierdescription: Community description (can be null)is_public: Whether the community is publiccreated_at: Creation timestampupdated_at: Last update timestampowner: Object with owner'sidandusername
GET /communities/:id
Get a specific community by ID or slug
GET /api/v1/communities/:id
You can use either the numeric ID or the slug (e.g., ruby-developers)
Response:
{
"id": 1,
"name": "Ruby Developers",
"slug": "ruby-developers",
"description": "A community for Ruby developers to share knowledge and collaborate",
"is_public": true,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"owner": {
"id": 1,
"username": "johndoe"
}
}
Code Snippets
GET /snippets
List public code snippets (limited to 50)
GET /api/v1/snippets
Response:
[
{
"id": 1,
"title": "Hello World in Ruby",
"content": "puts 'Hello, World!'",
"language": "ruby",
"slug": "hello-world-in-ruby",
"visibility": "public",
"is_fork": false,
"forked_from_id": null,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"user": {
"id": 1,
"username": "johndoe"
}
}
]
GET /snippets/:id
Get a specific code snippet by ID
GET /api/v1/snippets/:id
Response:
{
"id": 1,
"title": "Hello World in Ruby",
"content": "puts 'Hello, World!'",
"language": "ruby",
"slug": "hello-world-in-ruby",
"visibility": "public",
"is_fork": false,
"forked_from_id": null,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"user": {
"id": 1,
"username": "johndoe"
}
}
POST /snippets
Create a new code snippet
POST /api/v1/snippets
Request Body:
{
"snippet": {
"title": "My Code Snippet",
"content": "console.log('Hello World');",
"language": "javascript",
"visibility": "public"
}
}
Fields:
title(required): Snippet titlecontent(required): Code contentlanguage(optional): Programming languagevisibility(optional, default: "public"): One of "public", "private", or "shared"
Response (201 Created):
{
"id": 1,
"title": "My Code Snippet",
"content": "console.log('Hello World');",
"language": "javascript",
"slug": "my-code-snippet",
"visibility": "public",
"is_fork": false,
"forked_from_id": null,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:00:00Z",
"user": {
"id": 1,
"username": "johndoe"
}
}
Notifications
GET /notifications
Get current user's notifications (limited to 50)
GET /api/v1/notifications
Response:
[
{
"id": 1,
"notification_type": "room_invite",
"read_at": null,
"created_at": "2024-01-15T10:00:00Z",
"notifiable_type": "AudioRoom",
"notifiable_id": 1,
"notifiable": {
"id": 1,
"title": "Coding Session",
"host": {
"id": 1,
"username": "johndoe"
}
}
}
]
Notification Types:
follow: Someone followed youroom_invite: Invited to an audio roommention: Mentioned in a messagebadge: Earned a badge
PATCH /notifications/:id
Mark a notification as read
PATCH /api/v1/notifications/:id
Response:
{
"id": 1,
"notification_type": "room_invite",
"read_at": "2024-01-15T10:05:00Z",
"created_at": "2024-01-15T10:00:00Z",
"notifiable_type": "AudioRoom",
"notifiable_id": 1,
"notifiable": {
"id": 1,
"title": "Coding Session",
"host": {
"id": 1,
"username": "johndoe"
}
}
}
Response Format
All responses are in JSON format. Note: User emails are never included in API responses for GDPR compliance.
{
"id": 1,
"username": "example",
"name": "Example User",
"avatar_url": "https://...",
"level": 5,
"xp": 250,
"github_url": "https://github.com/example"
}
Error Responses
All errors are returned in JSON format with appropriate HTTP status codes.
401 Unauthorized
Missing or invalid API token
{
"error": "Unauthorized"
}
403 Forbidden
User account is banned
{
"error": "Your account has been banned. Please contact support if you believe this is an error."
}
404 Not Found
Resource not found
{
"error": "Not Found"
}
422 Unprocessable Entity
Validation errors (e.g., when creating a room or snippet)
{
"errors": [
"Title can't be blank",
"Description is too short"
]
}
GDPR Compliance
⚠️ Privacy Notice
User email addresses are never exposed through the API to ensure GDPR compliance. Only public profile information (username, name, avatar, level, XP, GitHub URL) is available via the API.
Rate Limiting
API requests are rate-limited to 1000 requests per hour per API token. Rate limit headers are included in all responses.
For full Swagger/OpenAPI documentation, visit /api/swagger