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 title
  • description (optional): Room description
  • is_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 ID
  • name: Community name
  • slug: URL-friendly identifier
  • description: Community description (can be null)
  • is_public: Whether the community is public
  • created_at: Creation timestamp
  • updated_at: Last update timestamp
  • owner: Object with owner's id and username

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 title
  • content (required): Code content
  • language (optional): Programming language
  • visibility (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 you
  • room_invite: Invited to an audio room
  • mention: Mentioned in a message
  • badge: 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