openapi: 3.0.3
info:
title: smokesignal API
description: |
Event and RSVP management system with comprehensive internationalization support.
## I18n Features
smokesignal provides full internationalization support with automatic language detection
and locale-aware responses. All endpoints support multiple languages through:
- **Accept-Language headers**: Standard HTTP language negotiation
- **URL parameters**: `?lang=fr-ca` for explicit language selection
- **Locale-aware caching**: Optimized performance with language-specific cache keys
- **Translated content**: All user-facing content available in supported locales
## Supported Locales
- `en-US`: English (United States) - Default
- `fr-CA`: French (Canada) with gender-aware content
## Language Detection Priority
1. URL `lang` parameter
2. Accept-Language header
3. Session preference
4. Default locale (en-US)
version: 1.0.0
contact:
name: smokesignal Support
url: https://github.com/yourusername/smokesignal
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.smokesignal.example.com
description: Production server
- url: http://localhost:3000
description: Development server
paths:
/events:
get:
summary: Filter and search events
description: |
Retrieve events based on filter criteria with full internationalization support.
Facets and event metadata are automatically translated based on the user's
language preference. Cache keys include locale information for optimal performance.
## I18n Behavior
- Event status and format facets are translated
- Date range facets use locale-appropriate formatting
- Facet counts include proper pluralization
- Error messages are localized
parameters:
- name: Accept-Language
in: header
description: |
Language preference using standard HTTP Accept-Language header.
Examples:
- `en-US,en;q=0.9` - English preferred
- `fr-CA,fr;q=0.9,en;q=0.8` - French Canadian preferred, French secondary, English fallback
- `fr-CA` - French Canadian only
schema:
type: string
example: "fr-CA,fr;q=0.9,en;q=0.8"
- name: lang
in: query
description: |
Explicit language override. Takes priority over Accept-Language header.
Supported values:
- `en-us`: English (United States)
- `fr-ca`: French (Canada)
schema:
type: string
enum: [en-us, fr-ca]
example: "fr-ca"
- name: q
in: query
description: Search term for event title and description
schema:
type: string
example: "music festival"
- name: start_date
in: query
description: Filter events starting after this date (ISO 8601)
schema:
type: string
format: date
example: "2025-06-01"
- name: end_date
in: query
description: Filter events ending before this date (ISO 8601)
schema:
type: string
format: date
example: "2025-12-31"
- name: lat
in: query
description: Latitude for location-based filtering
schema:
type: number
format: float
example: 45.5017
- name: lng
in: query
description: Longitude for location-based filtering
schema:
type: number
format: float
example: -73.5673
- name: radius
in: query
description: Search radius in kilometers (requires lat/lng)
schema:
type: number
format: float
minimum: 0
maximum: 1000
example: 25
- name: modes
in: query
description: Filter by event format/mode
schema:
type: array
items:
type: string
enum: [in_person, virtual, hybrid]
example: ["in_person", "hybrid"]
- name: statuses
in: query
description: Filter by event status
schema:
type: array
items:
type: string
enum: [active, draft, cancelled]
example: ["active"]
- name: sort
in: query
description: Sort order for results
schema:
type: string
enum: [start_time, created_at, updated_at, relevance]
default: start_time
example: "start_time"
- name: limit
in: query
description: Maximum number of events to return
schema:
type: integer
minimum: 1
maximum: 100
default: 20
example: 20
- name: offset
in: query
description: Number of events to skip (for pagination)
schema:
type: integer
minimum: 0
default: 0
example: 0
responses:
'200':
description: Successful response with filtered events and facets
headers:
Content-Language:
description: Language of the returned content
schema:
type: string
example: "fr-CA"
X-Cache-Key:
description: Cache key used (includes locale)
schema:
type: string
example: "filter:abc123:fr-ca"
content:
application/json:
schema:
$ref: '#/components/schemas/FilterResults'
examples:
english_results:
summary: English response
value:
events:
- id: "evt_123"
title: "Summer Music Festival"
description: "Annual outdoor music festival"
start_date: "2025-07-15T19:00:00Z"
mode: "in_person"
status: "active"
facets:
modes:
- value: "in_person"
count: 25
i18n_key: "event-mode-in-person"
display_name: "In Person"
statuses:
- value: "active"
count: 25
i18n_key: "event-status-active"
display_name: "Active"
total_count: 25
french_results:
summary: French Canadian response
value:
events:
- id: "evt_123"
title: "Summer Music Festival"
description: "Annual outdoor music festival"
start_date: "2025-07-15T19:00:00Z"
mode: "in_person"
status: "active"
facets:
modes:
- value: "in_person"
count: 25
i18n_key: "event-mode-in-person"
display_name: "En personne"
statuses:
- value: "active"
count: 25
i18n_key: "event-status-active"
display_name: "Actif"
total_count: 25
text/html:
schema:
type: string
description: Rendered HTML template with translated content
examples:
htmx_fragment:
summary: HTMX partial response
value: |
25 événements trouvés
'400':
description: Bad request - Invalid parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
invalid_locale:
summary: Invalid locale parameter
value:
error: "invalid_locale"
message: "Unsupported locale 'es-ES'. Supported locales: en-us, fr-ca"
details:
supported_locales: ["en-us", "fr-ca"]
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/events/{id}:
get:
summary: Get event details
description: |
Retrieve detailed information for a specific event with localized content.
## I18n Features
- Event metadata translated based on user language
- Date/time formatting according to locale conventions
- RSVP status and form labels localized
parameters:
- name: id
in: path
required: true
description: Event ID
schema:
type: string
example: "evt_123"
- name: Accept-Language
in: header
description: Language preference
schema:
type: string
example: "fr-CA,fr;q=0.9,en;q=0.8"
- name: lang
in: query
description: Explicit language override
schema:
type: string
enum: [en-us, fr-ca]
responses:
'200':
description: Event details
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
text/html:
schema:
type: string
description: Rendered event detail page
'404':
description: Event not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/facets:
get:
summary: Get available facets for filtering
description: |
Retrieve facet counts for the current filter context with translated display names.
This endpoint is optimized for autocomplete and filter UI updates. Facets include
pre-calculated display names in the user's preferred language.
parameters:
- name: Accept-Language
in: header
description: Language preference for facet translations
schema:
type: string
example: "fr-CA"
- name: context
in: query
description: Current filter context to calculate facets against
schema:
type: string
example: "search=music&location=montreal"
responses:
'200':
description: Available facets with counts and translations
content:
application/json:
schema:
$ref: '#/components/schemas/EventFacets'
/health/translations:
get:
summary: Health check for translation system
description: |
Verify that translation system is working correctly for all supported locales.
Returns status of translation loading, cache connectivity, and sample translations.
responses:
'200':
description: Translation system healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: "healthy"
locales:
type: array
items:
type: object
properties:
locale:
type: string
loaded:
type: boolean
translation_count:
type: integer
example:
- locale: "en-us"
loaded: true
translation_count: 245
- locale: "fr-ca"
loaded: true
translation_count: 243
cache:
type: object
properties:
connected:
type: boolean
hit_rate:
type: number
components:
schemas:
FilterResults:
type: object
properties:
events:
type: array
items:
$ref: '#/components/schemas/Event'
facets:
$ref: '#/components/schemas/EventFacets'
total_count:
type: integer
description: Total number of events matching criteria
Event:
type: object
properties:
id:
type: string
description: Unique event identifier
title:
type: string
description: Event title
description:
type: string
description: Event description
start_date:
type: string
format: date-time
description: Event start date and time (ISO 8601)
end_date:
type: string
format: date-time
description: Event end date and time (ISO 8601)
mode:
type: string
enum: [in_person, virtual, hybrid]
description: Event format/mode
status:
type: string
enum: [active, draft, cancelled]
description: Event status
location:
$ref: '#/components/schemas/Location'
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
EventFacets:
type: object
description: Available facets for filtering with translated display names
properties:
modes:
type: array
items:
$ref: '#/components/schemas/FacetValue'
description: Event format facets
statuses:
type: array
items:
$ref: '#/components/schemas/FacetValue'
description: Event status facets
date_ranges:
type: array
items:
$ref: '#/components/schemas/FacetValue'
description: Date range facets (Today, This Week, etc.)
creators:
type: array
items:
$ref: '#/components/schemas/FacetValue'
description: Event creator facets
total_count:
type: integer
description: Total events matching current criteria
FacetValue:
type: object
description: A single facet value with count and i18n support
properties:
value:
type: string
description: The actual filter value (e.g., "in_person")
example: "in_person"
count:
type: integer
description: Number of events matching this facet
example: 15
i18n_key:
type: string
description: Translation key for the display name
example: "event-mode-in-person"
display_name:
type: string
description: Pre-calculated display name in user's locale
example: "En personne"
Location:
type: object
properties:
latitude:
type: number
format: float
longitude:
type: number
format: float
address:
type: string
city:
type: string
country:
type: string
Error:
type: object
properties:
error:
type: string
description: Error code
message:
type: string
description: Human-readable error message (localized)
details:
type: object
description: Additional error context
required:
- error
- message
securitySchemes:
BearerAuth:
type: http
scheme: bearer
description: JWT token authentication
security:
- BearerAuth: []
tags:
- name: Events
description: Event management and filtering
- name: I18n
description: Internationalization and localization
- name: Health
description: System health and status checks