API Documentation
Overview
PhotoFlow exposes RESTful APIs through the AppGateway for frontend applications and external integrations.
Base URLs
Environment | URL |
|---|
Development | https://dev.api.photoflow.vn
|
UAT | https://uat.api.photoflow.vn
|
Production | https://api.photoflow.vn
|
Authentication
All authenticated endpoints require a JWT Bearer token:
Authorization: Bearer <access_token>
Token Acquisition
Tokens are obtained through the OAuth2 flow with Google:
POST /api/v1/auth/login
Content-Type: application/json
{
"provider": "Google",
"code": "<oauth_authorization_code>",
"redirectUri": "https://app.photoflow.vn/callback"
}
Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 3600
}
Token Refresh
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refreshToken": "<refresh_token>"
}
API Categories
Album APIs
Endpoint | Method | Auth | Description |
|---|
/api/v1/albums
| GET | Photographer | List albums |
/api/v1/albums
| POST | Photographer | Create album |
/api/v1/albums/{id}
| GET | Photographer | Get album detail |
/api/v1/albums/{id}
| PUT | Photographer | Update album |
/api/v1/albums/{id}
| DELETE | Photographer | Delete album |
/api/v1/albums/{id}/transitions
| GET | PhotographerOrAnonymous | Get available transitions |
/api/v1/albums/{id}/state
| PUT | PhotographerOrAnonymous | Trigger state change |
Album Tag APIs
Endpoint | Method | Auth | Description |
|---|
/api/v1/albums/{albumId}/tags
| GET | Photographer | List album tags |
/api/v1/albums/{albumId}/tags/{tagId}
| GET | Photographer | Get tag detail |
/api/v1/albums/{albumId}/tags/{tagId}/url
| PUT | Photographer | Update tag URL |
Photo APIs
Endpoint | Method | Auth | Description |
|---|
/api/v1/albums/{albumId}/tags/{tagId}/photos
| GET | PhotographerOrAnonymous | List photos |
/api/v1/albums/{albumId}/photos/{photoId}
| GET | PhotographerOrAnonymous | Get photo detail |
/api/v1/albums/{albumId}/photos/{photoId}/vote
| POST | PhotographerOrAnonymous | Vote photo |
/api/v1/albums/{albumId}/photos/{photoId}/comments
| GET | PhotographerOrAnonymous | Get comments |
/api/v1/albums/{albumId}/photos/{photoId}/comments
| POST | PhotographerOrAnonymous | Add comment |
Public APIs (Anonymous)
Endpoint | Method | Auth | Description |
|---|
/api/v1/public/albums/{publicUrl}
| GET | Anonymous | Get album by public URL |
/api/v1/public/albums/{publicUrl}/photos
| GET | Anonymous | Get photos |
/api/v1/public/albums/{publicUrl}/feedback
| POST | Anonymous | Submit feedback |
Storage APIs
Endpoint | Method | Auth | Description |
|---|
/api/v1/storage/folders
| GET | Photographer | List folders |
/api/v1/storage/folders/{id}
| GET | Photographer | Get folder detail |
/api/v1/storage/folders/{id}/sync
| POST | Photographer | Sync folder |
/api/v1/storage/folders/{id}/photos
| GET | Photographer | Get photos in folder |
List Albums Request
GET /api/v1/albums?searchTerm=wedding&states=Raw,Stock&page=1&pageSize=20
Authorization: Bearer <token>
List Albums Response
{
"data": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Wedding Album 2024",
"assignee": "John Doe",
"assigneeId": "user-123",
"albumState": "Stock",
"albumStateDisplay": "Ready for Rating",
"createdAt": 1703001600000,
"currentStateEnteredAt": 1703088000000,
"lastUpdatedByUserName": "admin"
}
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalCount": 45,
"totalPages": 3
}
}
Get Transitions Response
{
"transitions": [
{
"event": "Rate",
"fromState": "Stock",
"toState": "Rate",
"isRetry": false,
"retryReason": null,
"disable": false,
"disableReason": null
},
{
"event": "Close",
"fromState": "Stock",
"toState": "Closed",
"isRetry": false,
"retryReason": null,
"disable": false,
"disableReason": null
}
]
}
Trigger State Change Request
PUT /api/v1/albums/{id}/state
Authorization: Bearer <token>
Content-Type: application/json
{
"trigger": "Rate",
"url": "https://drive.google.com/drive/folders/abc123"
}
Vote Photo Request
POST /api/v1/albums/{albumId}/photos/{photoId}/vote
Authorization: Bearer <token>
Content-Type: application/json
{
"voted": true
}
Error Responses
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "Invalid album state transition",
"instance": "/api/v1/albums/123/state",
"errors": {
"trigger": ["Cannot transition from 'Init' to 'Stock' directly"]
}
}
Common Error Codes
Status | Description |
|---|
400 | Bad Request - Invalid input data |
401 | Unauthorized - Missing or invalid token |
403 | Forbidden - Insufficient permissions |
404 | Not Found - Resource doesn't exist |
409 | Conflict - State transition not allowed |
500 | Internal Server Error |
Rate Limiting
API requests are rate-limited per user:
Tier | Requests/min | Burst |
|---|
Standard | 100 | 200 |
Premium | 500 | 1000 |
Rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1703001660
List endpoints support pagination:
Parameter | Type | Default | Description |
|---|
page
| int | 1 | Page number |
pageSize
| int | 20 | Items per page (max: 100) |
Filtering & Sorting
Filter Parameters
GET /api/v1/albums?states=Raw,Stock&createdFrom=2024-01-01&createdTo=2024-12-31
Sort Parameters
GET /api/v1/albums?sortBy=createdAt&sortOrder=desc
Swagger/OpenAPI
Interactive API documentation is available at:
Last modified: 25 February 2026