API endpoint: api.calorily.com
All authenticated endpoints require a JWT token in the Authorization header:
Authorization: Bearer <jwt_token>
Creates an authenticated session using Apple Sign In.
Endpoint: /auth/apple
Method: POST
Request Body:
{
"identity_token": "apple_identity_token"
}
Response:
{
"jwt": "string",
"user_id": "string"
}
Creates an authenticated session for testing (dev enabled in config only).
Endpoint: /auth/dev
Method: POST
Request Body:
{
"user_id": "string"
}
Response:
{
"jwt": "string",
"user_id": "string"
}
Registers a new meal and starts an asynchronous analysis. The analysis results will be sent through the WebSocket connection.
Endpoint: /meals
Method: POST
Authentication: Required
Request Body:
{
"meal_id": "uuid", // Optional, will be generated if not provided
"b64_img": "base64_encoded_image_string"
}
Response:
{
"meal_id": "uuid",
"status": "processing" // Analysis will be sent through WebSocket
}
Submits feedback for a meal and triggers a new analysis. The new analysis results will be sent through the WebSocket connection.
Endpoint: /meals/feedback
Method: POST
Authentication: Required
Request Body:
{
"meal_id": "uuid",
"feedback": "string"
}
Response:
{
"meal_id": "uuid",
"status": "processing" // New analysis will be sent through WebSocket
}
Get detailed information about a specific meal and its latest analysis.
Endpoint: /meals/{meal_id}
Method: GET
Authentication: Not Required
Response:
{
"meal_id": "uuid",
"meal_name": "string",
"ingredients": [
{
"name": "string",
"amount": "number",
"carbs": "number",
"proteins": "number",
"fats": "number"
}
],
"timestamp": "datetime"
}
Get the image associated with a specific meal.
Endpoint: /meals/{meal_id}/image
Method: GET
Authentication: Not Required
Query Parameters:
size
(optional): Maximum width/height in pixels. Image will be scaled proportionally.quality
(optional): JPEG compression quality (1-100). Default: 85. Ignored for PNGs.
Response:
- Content-Type: image/jpeg or image/png (depending on original image)
- Binary image data
- Cache-Control headers for optimal caching
Error Response (404):
{
"error": "meal not found"
}
Get the latest analysis for each meal that has been updated since a given timestamp.
Endpoint: /meals/sync
Method: GET
Authentication: Required
Query Parameters:
since=2024-01-20T15:30:45.123Z // ISO 8601 timestamp
Response:
{
"analyses": [
{
"meal_id": "uuid",
"meal_name": "string",
"ingredients": [
{
"name": "string",
"amount": "number",
"carbs": "number",
"proteins": "number",
"fats": "number"
}
],
"timestamp": "datetime"
}
]
}
Connects to WebSocket to receive real-time updates for meal analyses.
Endpoint: /ws
Protocol: WSS
Authentication: Required (JWT as query parameter)
Connection URL:
wss://api.calorily.com/ws?token=<jwt_token>
Message Format (Server → Client):
{
"meal_id": "uuid",
"event": "analysis_complete",
"data": {
"meal_name": "string",
"ingredients": [
{
"name": "string",
"amount": "number",
"carbs": "number",
"proteins": "number",
"fats": "number"
}
],
"timestamp": "datetime"
}
}
{
"meal_id": "uuid",
"event": "analysis_failed",
"error": "string" // Human-readable error message
}
An example WebSocket subscriber script is provided to help test the real-time meal analysis updates during development.
- First, get a JWT token by creating a dev session:
curl -X POST http://localhost:8080/auth/dev \
-H "Content-Type: application/json" \
-d '{"user_id": "test-user-123"}'
- Run the example subscriber with your JWT token:
python subscriber.py <your-jwt-token>
The subscriber will:
- Connect to your local WebSocket server
- Listen for meal analysis updates
- Print received messages in a formatted way
- Handle connection errors gracefully
- Exit cleanly with Ctrl+C
Example output:
Connected to WebSocket server
Waiting for messages...
Received message at 2024-01-20 15:30:45
{
"meal_id": "123e4567-e89b-12d3-a456-426614174000",
"event": "analysis_complete",
"data": {
"meal_name": "Chocolate Cake",
"ingredients": [
{
"name": "mock ingredient",
"amount": 100,
"carbs": 20,
"proteins": 10,
"fats": 5
}
],
"timestamp": "2024-01-20T15:30:45.123456"
}
}
- To test the full flow:
- Keep the subscriber running
- Submit a meal using the
/meals
endpoint - Watch the analysis results arrive in real-time
- Submit feedback using
/meals/feedback
to see updated analysis
The API supports Cross-Origin Resource Sharing (CORS) with all origins (*) allowed.
- All images must be base64 encoded
- The API uses GPT Vision for analysis
- Analysis results are delivered asynchronously through WebSocket
- Each feedback submission triggers a new analysis
- WebSocket connections will automatically close after 24 hours of inactivity
- All timestamps are in ISO 8601 format
The application uses MongoDB with the following collections:
{
"meal_id": "uuid",
"user_id": "string",
"b64_img": "string",
"created_at": "datetime"
}
{
"meal_id": "uuid",
"meal_name": "string",
"ingredients": [
{
"name": "string",
"amount": "number",
"carbs": "number",
"proteins": "number",
"fats": "number"
}
],
"timestamp": "datetime"
}
{
"meal_id": "uuid",
"feedback": "string",
"timestamp": "datetime"
}