Bỏ qua

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-booking realm per README).

Roles (RBAC)

  • ADMIN
  • OWNER (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