API Specifications - Football Field Booking System
Version: 1.0
Base URL: https://api.footballbooking.com/v1
Local Base URL (dev): http://localhost:3000/v1 (via API Gateway)
Authentication: Bearer Access Token (Keycloak OIDC)
Last Updated: 2026-01-13
API Design Principles
- RESTful design with JSON request/response bodies.
- Consistent error format and error codes.
- Pagination for list endpoints.
- Idempotency for payment-related endpoints.
- API versioning via prefix (
/v1,/v2). - Traceability: include requestId + traceId (OpenTelemetry).
Authentication & Authorization
All endpoints except /health and selected public endpoints (e.g., field search) require authentication.
Authorization Header
Authorization: Bearer <ACCESS_TOKEN>
Token Policy
- Access token expiry: 15 minutes
- Refresh token expiry: 7 days
- Tokens are issued by Keycloak (
football-bookingrealm per README).
Roles (RBAC)
ADMINOWNER(field owner)CUSTOMER
Common Response Formats
Success Response
{
"success": true,
"data": {},
"message": "Operation successful",
"timestamp": "2026-01-13T10:00:00Z",
"requestId": "req_123",
"traceId": "trace_abc"
}
Error Response
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
},
"timestamp": "2026-01-13T10:00:00Z",
"requestId": "req_123",
"traceId": "trace_abc"
}
Pagination Response
{
"success": true,
"data": [],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"totalPages": 8
},
"timestamp": "2026-01-13T10:00:00Z",
"requestId": "req_123",
"traceId": "trace_abc"
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
| VALIDATION_ERROR | 400 | Invalid input payload / query params |
| UNAUTHORIZED | 401 | Missing/invalid token |
| FORBIDDEN | 403 | Insufficient permissions |
| NOT_FOUND | 404 | Resource not found |
| CONFLICT | 409 | Resource conflict (e.g., double booking) |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests |
| INTERNAL_ERROR | 500 | Unexpected server error |
| SERVICE_UNAVAILABLE | 503 | Dependency unavailable |
Rate Limiting
Default rate limit policies (enforced at API Gateway):
- Default: 100 req/min/user
- Auth endpoints: 5 req/min (login/register/refresh)
- Payment endpoints: 10 req/min
- Search endpoints: 30 req/min
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1768300000
API Endpoints by Domain (via API Gateway)
Note: Backend services are reachable directly in dev (ports 3001–3005), but clients must use API Gateway (3000) in production.
1) Authentication API (Keycloak-backed)
POST /auth/register
Register a new user (optional if Keycloak handles registration directly).
Request
{
"email": "user@example.com",
"password": "SecurePass123!",
"name": "John Doe",
"phone": "+84901234567"
}
Response (201 Created)
{
"success": true,
"data": {
"userId": "uuid",
"email": "user@example.com",
"name": "John Doe",
"role": "CUSTOMER",
"emailVerified": false
},
"message": "Registration successful. Please verify your email.",
"timestamp": "2026-01-13T10:00:00Z"
}
POST /auth/login
User login (Keycloak token exchange).
Request
{
"email": "user@example.com",
"password": "SecurePass123!"
}
Response (200 OK)
{
"success": true,
"data": {
"accessToken": "eyJhbGciOi...",
"refreshToken": "eyJhbGciOi...",
"expiresIn": 900,
"user": {
"userId": "uuid",
"email": "user@example.com",
"name": "John Doe",
"role": "CUSTOMER"
}
},
"timestamp": "2026-01-13T10:00:00Z"
}
POST /auth/logout
Invalidate session / refresh token (implementation-dependent).
Headers: Authorization: Bearer <token>
Response (200 OK)
{
"success": true,
"message": "Logged out successfully",
"timestamp": "2026-01-13T10:00:00Z"
}
POST /auth/refresh
Refresh access token.
Request
{
"refreshToken": "eyJhbGciOi..."
}
Response (200 OK)
{
"success": true,
"data": {
"accessToken": "eyJhbGciOi...",
"expiresIn": 900
},
"timestamp": "2026-01-13T10:00:00Z"
}
POST /auth/forgot-password
Request password reset.
Request
{
"email": "user@example.com"
}
Response (200 OK)
{
"success": true,
"message": "Password reset link sent to your email",
"timestamp": "2026-01-13T10:00:00Z"
}
POST /auth/reset-password
Reset password with token.
Request
{
"token": "reset_token_here",
"newPassword": "NewSecurePass123!"
}
Response (200 OK)
{
"success": true,
"message": "Password reset successful",
"timestamp": "2026-01-13T10:00:00Z"
}
2) User API (user-service)
GET /users/me
Get current user profile.
Headers: Authorization: Bearer <token>
Response (200 OK)
{
"success": true,
"data": {
"userId": "uuid",
"email": "user@example.com",
"name": "John Doe",
"phone": "+84901234567",
"avatar": "https://cdn.example.com/avatars/uuid.jpg",
"role": "CUSTOMER",
"emailVerified": true,
"preferences": {
"emailNotifications": true,
"smsNotifications": false
},
"createdAt": "2026-01-01T00:00:00Z"
},
"timestamp": "2026-01-13T10:00:00Z"
}
PUT /users/me
Update current user profile.
Request
{
"name": "John Updated Doe",
"phone": "+84901234567",
"preferences": {
"emailNotifications": true,
"smsNotifications": true
}
}
Response (200 OK): standard success response.
POST /users/me/avatar
Upload user avatar.
Headers
Authorization: Bearer <token>Content-Type: multipart/form-data
Request
file: <image_file>
PUT /users/me/password
Change password (if local password managed by platform).
Request
{
"currentPassword": "OldPass123!",
"newPassword": "NewPass123!"
}
DELETE /users/me
Delete user account.
Request
{
"password": "CurrentPass123!",
"confirmDeletion": true
}
Response (200 OK)
{
"success": true,
"message": "Account deleted successfully. You can restore it within 30 days by contacting support.",
"timestamp": "2026-01-13T10:00:00Z"
}
3) Field API (field-service)
POST /fields
Create a new field (OWNER only).
Headers: Authorization: Bearer <token>
Request
{
"name": "Golden Field Arena",
"description": "Professional 7v7 football field with LED lighting",
"address": "123 Nguyen Hue, District 1, HCMC",
"latitude": 10.762622,
"longitude": 106.660172,
"sportType": "FOOTBALL_7",
"pricePerHour": 200000,
"amenities": ["PARKING", "SHOWER", "CHANGING_ROOM", "LIGHTING"],
"operatingHours": {
"monday": { "open": "06:00", "close": "22:00" },
"tuesday": { "open": "06:00", "close": "22:00" }
}
}
Response (201 Created)
{
"success": true,
"data": {
"fieldId": "uuid",
"name": "Golden Field Arena",
"status": "PENDING_APPROVAL"
},
"message": "Field created successfully. Awaiting admin approval.",
"timestamp": "2026-01-13T10:00:00Z"
}
GET /fields/search
Search for fields.
Query Parameters
?lat=10.762622
&lng=106.660172
&radius=5000
&sportType=FOOTBALL_7
&minPrice=50000
&maxPrice=500000
&date=2026-01-20
&startTime=10:00
&endTime=12:00
&amenities=PARKING,LIGHTING
&sortBy=distance
&sortOrder=asc
&page=1
&limit=20
Response (200 OK): paginated response.
GET /fields/:id
Get field details.
GET /fields/:id/availability
Get field availability for a date.
Query Parameters: ?date=2026-01-20
PUT /fields/:id
Update field (OWNER only).
PUT /fields/:id/status
Approve/disable field (ADMIN only).
4) Booking API (booking-service)
POST /bookings
Create a new booking.
Request
{
"fieldId": "uuid",
"startTime": "2026-01-20T10:00:00Z",
"endTime": "2026-01-20T12:00:00Z",
"notes": "Birthday party event"
}
Response (201 Created)
{
"success": true,
"data": {
"bookingId": "uuid",
"fieldId": "uuid",
"userId": "uuid",
"startTime": "2026-01-20T10:00:00Z",
"endTime": "2026-01-20T12:00:00Z",
"duration": 2,
"totalPrice": 400000,
"status": "PENDING",
"expiresAt": "2026-01-20T09:15:00Z",
"paymentUrl": "https://payment-gateway.com/checkout/xyz"
},
"message": "Booking created. Please complete payment within 15 minutes.",
"timestamp": "2026-01-13T10:00:00Z"
}
GET /bookings/me
Get current user's bookings.
Query Parameters
?status=CONFIRMED
&startDate=2026-01-01
&endDate=2026-01-31
&page=1
&limit=20
GET /bookings/:id
Get booking details.
PUT /bookings/:id/cancel
Cancel a booking.
Request
{
"reason": "Weather forecast shows heavy rain"
}
GET /bookings/:id/receipt
Download booking receipt (PDF).
Response
Content-Type: application/pdf- File download
5) Payment API (payment-service)
POST /payments/create
Create a payment intent.
Request
{
"bookingId": "uuid",
"method": "STRIPE",
"returnUrl": "https://footballbooking.com/bookings/uuid"
}
Response (201 Created)
{
"success": true,
"data": {
"paymentId": "uuid",
"bookingId": "uuid",
"amount": 400000,
"currency": "VND",
"method": "STRIPE",
"status": "PENDING",
"checkoutUrl": "https://payment-gateway.com/checkout/xyz",
"expiresAt": "2026-01-20T09:15:00Z"
},
"timestamp": "2026-01-13T10:00:00Z"
}
GET /payments/:id
Get payment status.
POST /webhooks/stripe
Stripe webhook handler (no auth required).
Headers: Stripe-Signature: <signature>
POST /webhooks/vnpay
VNPay webhook handler (no auth required).
API Documentation (Swagger)
Each service exposes Swagger docs:
- API Gateway:
http://localhost:3000/api/docs - User Service:
http://localhost:3001/api/docs - Field Service:
http://localhost:3002/api/docs - Booking Service:
http://localhost:3003/api/docs - Payment Service:
http://localhost:3004/api/docs - Notification Service:
http://localhost:3005/api/docs
Document Version: 1.0 Last Updated: 2026-01-13