Download OpenAPI specification:
Unified API documentation for all booking system services
Main orchestration service that coordinates authentication, bookings, and course management
Initiates the OAuth authentication flow by redirecting the user's browser to the OAuth adapter service.
Authentication Flow Entry Point: This is the starting point for user authentication. The browser is redirected to the OAuth adapter, which handles the actual OAuth flow with the external provider (Google).
Provider Validation: Currently only 'google' is supported as a provider. Any other provider value returns 400 Bad Request.
Redirect Target:
The user is redirected to: {OAUTH_ADAPTER_SERVICE_URL}/api/v1/oauth/{provider}/login
Next Steps:
After successful authentication with the provider, the OAuth adapter will redirect the user back to the /api/v1/auth/complete endpoint with a nonce parameter.
| provider required | string Value: "google" OAuth provider name (currently only 'google' is supported) |
{- "error": {
- "code": "INVALID_REQUEST",
- "message": "courseId and slotIds are required."
}
}Finalizes the OAuth authentication flow after the OAuth adapter redirects the user back with a verified assertion.
Completion Flow:
Token Details:
Security: The nonce serves as a one-time use token that links the OAuth callback to the original login request. Once used, the pending assertion is removed from storage.
Cookie Configuration:
Error Scenarios:
| nonce required | string Unique nonce from the OAuth flow |
{- "error": {
- "code": "INVALID_REQUEST",
- "message": "courseId and slotIds are required."
}
}Logs out the user by revoking their refresh token and clearing authentication cookies.
Logout Process:
Token Revocation: Revoking the refresh token JTI prevents it from being used to obtain new access tokens, effectively invalidating the user's session across all clients using that refresh token.
Cookie Clearing: Both cookies are cleared from the client's browser, ensuring the access token cannot be used for subsequent requests.
Graceful Handling: If the refresh token is invalid or missing, the endpoint still clears the cookies and returns success. This ensures logout always succeeds from the user's perspective.
Response: Returns 204 No Content with cleared cookies in Set-Cookie headers.
Exchanges a valid refresh token for a new access token and refresh token pair, implementing token rotation for enhanced security.
Token Rotation Flow:
Security - Token Rotation: Each refresh operation invalidates the old refresh token and issues a new one. This limits the window of vulnerability if a refresh token is compromised.
Allowlist Validation: The refresh token's JTI must be in the allowlist and associated with the correct user. This enables immediate revocation (e.g., on logout) and prevents use of old or stolen tokens.
Cookie Updates: Both access_token and refresh_token cookies are updated with new values and reset expiration times.
Error Scenarios:
{- "error": {
- "code": "UNAUTHENTICATED",
- "message": "Access Denied."
}
}Returns basic profile information for the currently authenticated user extracted from the access token.
Authentication Required: Requires valid access_token cookie. The authentication middleware validates the token and populates req.user.
Response Data:
authenticated: Always true (endpoint only accessible with valid token)userId: Unique user identifier from OAuth provider (format: 'provider:subject')picture: User's profile picture URL from OAuth providerToken Source: All data is extracted from the JWT access token claims, no additional service calls required.
Use Cases:
Error Scenarios:
{- "authenticated": true,
- "userId": "google:123456789",
}Internal service-to-service endpoint used by OAuth adapters to submit verified user assertions after successful OAuth authentication. Not intended for direct client use.
Architecture Role: This endpoint is called by the OAuth adapter service after it successfully authenticates a user with an external OAuth provider (Google). It bridges the OAuth adapter and the main orchestrator.
Assertion Validation:
Assertion Storage:
Stores the validated assertion temporarily in-memory with the nonce as key, allowing the /api/v1/auth/complete endpoint to retrieve it when the user's browser is redirected back.
Security:
Error Scenarios:
Response: 204 No Content on successful assertion storage.
| provider required | string |
| sub required | string |
| iat | integer |
| nonce required | string |
| signature required | string |
| picture | string |
| frontendRedirectUrl | string |
{- "provider": "string",
- "sub": "string",
- "iat": 0,
- "nonce": "string",
- "signature": "string",
- "picture": "string",
- "frontendRedirectUrl": "string"
}{- "error": {
- "code": "INVALID_REQUEST",
- "message": "courseId and slotIds are required."
}
}Orchestrator endpoint that delegates to the booking-data service to retrieve the complete course catalog.
Orchestration Pattern: This endpoint acts as a simple proxy, forwarding the request to the data layer service and returning the response. No business logic or multi-service coordination occurs at this level.
Service Delegation:
Error Handling Strategy:
Response Structure:
Standardized wrapper format: { data: { courses: [...] } }
Use Cases:
{- "data": {
- "courses": [
- {
- "_id": "string",
- "name": "string",
- "description": "string",
- "slots": [
- {
- "_id": "string",
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z",
- "capacity": 0,
- "available": 0
}
], - "open": true,
- "priceOptions": [
- {
- "_id": "string",
- "numberSlots": 0,
- "price": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
]
}
}Orchestrator endpoint that validates input and delegates to booking-data service for single course retrieval.
Orchestration Responsibilities:
Service Delegation:
Error Handling Strategy:
Response Structure:
Wrapped format: { data: { course: {...} } }
Use Cases:
| id required | string Course ID |
{- "data": {
- "course": {
- "_id": "string",
- "name": "string",
- "description": "string",
- "slots": [
- {
- "_id": "string",
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z",
- "capacity": 0,
- "available": 0
}
], - "open": true,
- "priceOptions": [
- {
- "_id": "string",
- "numberSlots": 0,
- "price": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
}
}Orchestrator endpoint that extracts authenticated user context and delegates to booking-logic service for booking retrieval.
Authentication Layer (Orchestrator Responsibility): Access token validation performed by middleware before delegation. User ID extracted from JWT claims and passed to downstream service.
Service Delegation:
Orchestration Flow:
Error Translation:
Use Cases:
{- "data": {
- "bookings": [
- {
- "id": "string",
- "courseId": "string",
- "userId": "string",
- "slots": [
- "string"
], - "status": "confirmed",
- "transactionId": "string",
- "price": "string",
- "createdAt": "2019-08-24T14:15:22Z"
}
]
}
}Multi-service orchestration endpoint that coordinates reservation creation with payment order initialization.
Orchestration Pattern: Sequential service coordination with conditional logic for reservation creation vs. retrieval.
Service Choreography:
reservationId provided → retrieve existing reservationDownstream Services:
Error Handling Strategy:
Aggregated Response: Combines data from both services:
reservationId (from booking-logic)priceToPay (from booking-logic)orderID (from paypal-adapter)Continuation:
Client proceeds to /api/v1/bookings/confirm after PayPal payment approval.
| courseId required | string |
| slotIds required | Array of strings |
| reservationId | string Optional existing reservation id to reuse instead of creating a new one |
{- "courseId": "695ba111b2e63b75bee66279",
- "slotIds": [
- "695ba111b2e63b75bee6627b"
], - "reservationId": "696prev1234567890abcdef"
}{- "data": {
- "reservationId": "6969808214d2f13caa1e5f16",
- "priceToPay": "49.00",
- "orderID": "8VX12345AB6789012"
}
}Complex orchestration endpoint implementing a distributed saga pattern with compensation logic for payment capture and booking confirmation.
Saga Orchestration Pattern: Coordinates a two-phase distributed transaction across payment and booking services with automatic rollback on failure.
Service Choreography:
Downstream Services:
Saga Compensation Logic:
Orchestrator Error Handling:
Critical State Management: This orchestrator manages critical financial state transitions. Compensation ensures payment refunds occur when booking creation fails, preventing user charges without service delivery.
Response: Successfully created booking in serialized format (transformed by booking-logic service).
| orderID required | string |
| reservationId required | string |
{- "orderID": "8VX12345AB6789012",
- "reservationId": "6969808214d2f13caa1e5f16"
}{- "data": {
- "booking": {
- "id": "string",
- "courseId": "string",
- "userId": "string",
- "slots": [
- "string"
], - "status": "confirmed",
- "transactionId": "string",
- "price": "string",
- "createdAt": "2019-08-24T14:15:22Z"
}
}
}Orchestrator endpoint that injects authenticated user context and delegates to booking-logic for pending reservation query.
Orchestration Responsibilities:
Service Delegation:
Orchestration Flow:
Error Handling Strategy:
Use Cases:
| courseId required | string |
{- "courseId": "string"
}{- "data": {
- "reservation": {
- "id": "string",
- "courseId": "string",
- "userId": "string",
- "slots": [
- "string"
], - "status": "held",
- "expiration": "2019-08-24T14:15:22Z"
}
}
}Orchestrator endpoint that enforces authentication and delegates reservation cancellation with authorization to booking-logic service.
Orchestration Responsibilities:
Service Delegation Chain:
Orchestration Flow:
Authorization (Delegated to Business Layer): Ownership validation performed by booking-logic service - ensures users can only cancel their own reservations. Orchestrator passes userId for authorization context.
Error Handling Strategy:
Success Response: 204 No Content - cancellation completed, no response body.
| reservationId required | string Reservation ID to cancel |
{- "error": {
- "code": "INVALID_REQUEST",
- "message": "courseId and slotIds are required."
}
}Retrieves confirmed bookings from the booking-data service with optional user filtering. Results are serialized to expose only client-relevant fields.
Behavior:
userId is provided: Returns only bookings for that specific useruserId is provided: Returns all bookings in the system (typically admin use)Data Transformation: Bookings are serialized before being returned, transforming MongoDB fields to cleaner client-facing format:
_id → idcourse → courseIduser → userId__v, updatedAt, and reservation are excludedUse cases:
| userId | string Example: userId=648a1f4e2f8fb814c8d6f9b1 ID of the user to filter bookings |
{- "data": {
- "bookings": [
- {
- "id": "69642e1f21d2db02c99b9aec",
- "courseId": "695ba111b2e63b75bee66279",
- "userId": "648a1f4e2f8fb814c8d6f9b1",
- "slots": [
- "695ba111b2e63b75bee6627b"
], - "status": "confirmed",
- "transactionId": "6KT41896LL345210G",
- "price": "49.00",
- "createdAt": "2026-01-11T23:11:27.530Z"
}, - {
- "id": "6969609fe8d3650f299ea570",
- "courseId": "695ba111b2e63b75bee66279",
- "userId": "648a1f4e2f8fb814c8d6f9b1",
- "slots": [
- "695ba111b2e63b75bee6627b",
- "695ba111b2e63b75bee6627a"
], - "status": "confirmed",
- "transactionId": "6MC33684BA3458225",
- "price": "89.00",
- "createdAt": "2026-01-15T21:48:15.941Z"
}
]
}
}Converts a held reservation into a confirmed booking after successful payment. Performs comprehensive validation before delegating to the booking-data service for atomic transaction execution.
Validation Flow:
held status (409 if not)Transaction Safety: The actual booking creation and reservation completion happen atomically in the booking-data service's transaction, ensuring consistency.
Response: Returns the newly created booking in serialized format with clean field names and only client-relevant data.
Error Scenarios:
| userId required | string |
| reservationId required | string |
| transactionId required | string |
| price required | string |
{- "userId": "TEST_USER_12345",
- "reservationId": "696b690186faaabbfded290e",
- "transactionId": "52V73452E9342521J",
- "price": "79.00"
}{- "data": {
- "booking": {
- "id": "696b695386faaabbfded2912",
- "courseId": "695ba111b2e63b75bee66284",
- "userId": "TEST_USER_12345",
- "slots": [
- "695ba111b2e63b75bee66286"
], - "status": "confirmed",
- "transactionId": "52V73452E9342521J",
- "price": "79.00",
- "createdAt": "2026-01-17T10:49:55.591Z"
}
}
}Creates a new slot reservation with comprehensive validation before delegating to the booking-data service for atomic slot holding.
Validation Flow:
Reservation Expiration: The reservation is created with a configurable expiration time (default from bookingSettings). After expiration, a cleanup job will cancel the reservation and restore slot availability.
Response: Returns a simplified response containing:
reservationId: The unique identifier for the created reservationpriceToPay: The price based on the matching pricing optionAtomicity: Slot availability is decremented atomically with reservation creation in the booking-data service's transaction.
Error Scenarios:
| userId required | string |
| courseId required | string |
| slotIds required | Array of strings |
{- "userId": "TEST_USER_12345",
- "courseId": "695ba111b2e63b75bee66284",
- "slotIds": [
- "695ba111b2e63b75bee66286"
]
}{- "data": {
- "reservationId": "6969808214d2f13caa1e5f16",
- "priceToPay": "49.00"
}
}Retrieves reservation details with pricing information, enforcing user authorization checks.
Authorization:
The endpoint requires the userId query parameter and validates that the reservation belongs to the requesting user. Returns 403 if there's a mismatch.
Processing Flow:
Response: Returns a simplified response with:
reservationId: The reservation identifierpriceToPay: Price calculated from course's pricing options based on slot countUse cases:
Error Scenarios:
| id required | string Example: 6969808214d2f13caa1e5f16 Reservation ID |
| userId required | string Example: userId=TEST_USER_12345 ID of the user requesting the reservation |
{- "data": {
- "reservationId": "6969808214d2f13caa1e5f16",
- "priceToPay": "49.00"
}
}Retrieves the most recent active reservation for a specific user and course, filtering by status and expiration.
Query Requirements:
Both userId and courseId query parameters are required. Returns 400 if either is missing.
Active Reservation Criteria: A reservation is considered active if:
held (not completed, cancelled, or expired)Filtering Logic:
Response: Returns the full reservation object in serialized format with clean field names:
_id → idcourse → courseIduser → userIdUse cases:
Error Scenarios:
| userId required | string Example: userId=TEST_USER_12345 ID of the user |
| courseId required | string Example: courseId=695ba111b2e63b75bee66284 ID of the course |
{- "data": {
- "reservation": {
- "id": "696b69fd86faaabbfded291e",
- "courseId": "695ba111b2e63b75bee66284",
- "userId": "TEST_USER_12345",
- "slots": [
- "695ba111b2e63b75bee66286"
], - "status": "held",
- "expiration": "2026-01-17T11:07:45.157Z"
}
}
}Cancels a held reservation with authorization and status validation, delegating to booking-data service for atomic slot restoration.
Validation Flow:
held status (409 if not)Authorization: Strict ownership validation ensures users can only cancel their own reservations. Returns 403 if the reservation's user ID doesn't match the requesting userId.
Status Validation:
Only reservations in held status can be cancelled. Attempting to cancel completed, already-cancelled, or expired reservations returns 409 conflict.
Atomicity: The booking-data service handles the actual cancellation in a transaction that:
cancelledSuccess Response: Returns 204 No Content upon successful cancellation.
Use cases:
Error Scenarios:
| id required | string Example: 696b69fd86faaabbfded291e The unique identifier of the reservation to cancel |
| userId required | string |
{- "userId": "string"
}{- "error": {
- "code": "INVALID_BOOKING_DATA",
- "message": "Missing required booking data."
}
}Retrieves all booking records from the database, with optional filtering by user ID.
This endpoint performs a read-only query against the bookings collection. When no filters are provided, all confirmed bookings across all users are returned. Results are returned as raw MongoDB documents including all internal fields.
Filtering:
userId: Returns only bookings associated with the specified user ID. When provided, the query filters by the user field in the booking document.Use cases:
| userId | string ID of the user holding the bookings |
{- "data": {
- "bookings": [
- {
- "_id": "69642e1f21d2db02c99b9aec",
- "course": "695ba111b2e63b75bee66279",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "reservation": "69642e1921d2db02c99b9ae8",
- "slots": [
- "695ba111b2e63b75bee6627b"
], - "status": "confirmed",
- "transactionId": "6KT41896LL345210G",
- "price": "49.00",
- "createdAt": "2026-01-11T23:11:27.530Z",
- "updatedAt": "2026-01-11T23:11:27.530Z",
- "__v": 0
}, - {
- "_id": "6969609fe8d3650f299ea570",
- "course": "695ba111b2e63b75bee66279",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "reservation": "69696094e8d3650f299ea56c",
- "slots": [
- "695ba111b2e63b75bee6627b",
- "695ba111b2e63b75bee6627a"
], - "status": "confirmed",
- "transactionId": "6MC33684BA3458225",
- "price": "89.00",
- "createdAt": "2026-01-15T21:48:15.941Z",
- "updatedAt": "2026-01-15T21:48:15.941Z",
- "__v": 0
}
]
}
}Atomically creates a new confirmed booking and finalizes the associated reservation in a single database transaction.
Transaction Flow:
confirmed statuscompletedAtomicity Guarantee: All database operations are executed within a MongoDB transaction. If any step fails, all changes are rolled back to maintain data consistency. This ensures that a booking is never created without properly completing its reservation.
Important:
| courseId required | string |
| userId required | string |
| reservationId required | string |
| slots required | string |
| transactionId required | string |
| price required | string |
{- "courseId": "695ba111b2e63b75bee6627e",
- "userId": "648a1f4e2f8fb814c8d6f9b1",
- "reservationId": "69696655989dec9e8a6e9fed",
- "slots": [
- "695ba111b2e63b75bee6627f"
], - "transactionId": "05V54435V6286635A",
- "price": "99.00"
}{- "data": {
- "booking": {
- "_id": "69642e1f21d2db02c99b9aec",
- "course": "695ba111b2e63b75bee66279",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "reservation": "69642e1921d2db02c99b9ae8",
- "slots": [
- "695ba111b2e63b75bee6627b"
], - "status": "confirmed",
- "transactionId": "6KT41896LL345210G",
- "price": "49.00",
- "createdAt": "2026-01-11T23:11:27.530Z",
- "updatedAt": "2026-01-11T23:11:27.530Z",
- "__v": 0
}
}
}Retrieves all course records stored in the database without any filtering or pagination.
Response Details: Returns complete course documents including:
Slot Availability:
The available field in each slot reflects real-time availability. This value is decremented when reservations are created and incremented when reservations are cancelled or expire.
Use cases:
{- "data": {
- "courses": [
- {
- "_id": "695ba111b2e63b75bee66279",
- "name": "Introduction to Web Development",
- "description": "Learn the basics of HTML, CSS, and JavaScript to build modern web pages.",
- "slots": [
- {
- "start": "2026-03-10T09:00:00.000Z",
- "end": "2026-03-10T13:00:00.000Z",
- "capacity": 20,
- "available": 20,
- "_id": "695ba111b2e63b75bee6627a"
}, - {
- "start": "2026-03-12T14:00:00.000Z",
- "end": "2026-03-12T18:00:00.000Z",
- "capacity": 20,
- "available": 14,
- "_id": "695ba111b2e63b75bee6627b"
}, - {
- "start": "2026-03-15T14:00:00.000Z",
- "end": "2026-03-15T18:00:00.000Z",
- "capacity": 20,
- "available": 20,
- "_id": "695ee7f30b5f48720cad5c81"
}
], - "open": true,
- "priceOptions": [
- {
- "numberSlots": 1,
- "price": "49.00",
- "_id": "695ba111b2e63b75bee6627c"
}, - {
- "numberSlots": 2,
- "price": "89.00",
- "_id": "695ba111b2e63b75bee6627d"
}
], - "__v": 0,
- "createdAt": "2026-01-05T11:31:29.809Z",
- "updatedAt": "2026-01-15T22:10:00.827Z"
}, - {
- "_id": "695ba111b2e63b75bee6627e",
- "name": "Advanced Node.js and Backend APIs",
- "description": "Deep dive into Node.js, Express, and REST API design with real-world patterns.",
- "slots": [
- {
- "start": "2026-03-18T09:00:00.000Z",
- "end": "2026-03-18T17:00:00.000Z",
- "capacity": 15,
- "available": 9,
- "_id": "695ba111b2e63b75bee6627f"
}, - {
- "start": "2026-03-22T09:00:00.000Z",
- "end": "2026-03-25T17:00:00.000Z",
- "capacity": 15,
- "available": 15,
- "_id": "695ba111b2e63b75bee66280"
}
], - "open": true,
- "priceOptions": [
- {
- "numberSlots": 1,
- "price": "99.00",
- "_id": "695ba111b2e63b75bee66281"
}, - {
- "numberSlots": 2,
- "price": "179.00",
- "_id": "695ba111b2e63b75bee66282"
}, - {
- "numberSlots": 3,
- "price": "249.00",
- "_id": "695ba111b2e63b75bee66283"
}
], - "__v": 0,
- "createdAt": "2026-01-05T11:31:29.810Z",
- "updatedAt": "2026-01-15T22:30:00.867Z"
}
]
}
}Retrieves detailed information for a single course identified by its MongoDB ObjectId.
Validation:
Response Details: Returns the complete course document including:
Real-time Availability: The slot availability counts reflect the current state and are updated atomically when reservations are created or cancelled.
| id | string Examples:
ID of the course to retrieve. |
{- "data": {
- "course": {
- "_id": "695ba111b2e63b75bee66279",
- "name": "Introduction to Web Development",
- "description": "Learn the basics of HTML, CSS, and JavaScript to build modern web pages.",
- "slots": [
- {
- "start": "2026-03-10T09:00:00.000Z",
- "end": "2026-03-10T13:00:00.000Z",
- "capacity": 20,
- "available": 20,
- "_id": "695ba111b2e63b75bee6627a"
}, - {
- "start": "2026-03-12T14:00:00.000Z",
- "end": "2026-03-12T18:00:00.000Z",
- "capacity": 20,
- "available": 14,
- "_id": "695ba111b2e63b75bee6627b"
}, - {
- "start": "2026-03-15T14:00:00.000Z",
- "end": "2026-03-15T18:00:00.000Z",
- "capacity": 20,
- "available": 20,
- "_id": "695ee7f30b5f48720cad5c81"
}
], - "open": true,
- "priceOptions": [
- {
- "numberSlots": 1,
- "price": "49.00",
- "_id": "695ba111b2e63b75bee6627c"
}, - {
- "numberSlots": 2,
- "price": "89.00",
- "_id": "695ba111b2e63b75bee6627d"
}
], - "__v": 0,
- "createdAt": "2026-01-05T11:31:29.809Z",
- "updatedAt": "2026-01-15T22:10:00.827Z"
}
}
}Retrieves reservation records from the database with optional filtering by user ID and/or course ID.
Filtering Options:
userId: Returns only reservations for the specified usercourseId: Returns only reservations for the specified course (validates ObjectId format)Reservation Statuses: Results may include reservations in any status:
held: Active reservation with slot availability temporarily heldcompleted: Reservation successfully converted to a confirmed bookingcancelled: Manually cancelled reservation with slots releasedexpired: Reservation that expired before being confirmed (may be cleaned up by cron job)Use cases:
| userId | string Examples:
ID of the user holding the reservations |
| courseId | string Examples:
ID of the course associated with the reservations |
{- "data": {
- "reservations": [
- {
- "_id": "695d651ad97543f2ef9b5231",
- "course": "695ba111b2e63b75bee6627e",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "slots": [
- "695ba111b2e63b75bee6627f",
- "695ba111b2e63b75bee66280"
], - "status": "cancelled",
- "expiration": "2026-01-06T19:55:10.345Z",
- "createdAt": "2026-01-06T19:40:10.351Z",
- "updatedAt": "2026-01-07T18:30:01.202Z",
- "__v": 0
}, - {
- "_id": "695d656ed97543f2ef9b523c",
- "course": "695ba111b2e63b75bee6627e",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "slots": [
- "695ba111b2e63b75bee6627f",
- "695ba111b2e63b75bee66280"
], - "status": "confirmed",
- "expiration": "2026-01-06T19:56:34.674Z",
- "createdAt": "2026-01-06T19:41:34.675Z",
- "updatedAt": "2026-01-07T17:07:00.497Z",
- "__v": 0
}
]
}
}Atomically creates a new reservation and holds the specified slot availability within a single database transaction.
Transaction Flow:
available count for each selected slot by 1held status with calculated expiration timeAtomicity Guarantee: All operations are wrapped in a MongoDB transaction. If any validation fails or if slots become unavailable between checks, the entire transaction is rolled back and no changes are persisted. This prevents race conditions and ensures data consistency.
Expiration:
The reservation is created with an expiration timestamp calculated as now + expiresInMinutes. After this time, the reservation may be automatically cancelled by the cleanup cron job, which will restore the held slot availability.
Conflict Handling:
| test | string |
| userId required | string |
| courseId required | string |
| slotIds required | Array of strings |
| expiresInMinutes required | number |
{- "userId": "648a1f4e2f8fb814c8d6f9b1",
- "courseId": "695ba111b2e63b75bee66279",
- "slotIds": [
- "695ee7f30b5f48720cad5c81"
], - "expiresInMinutes": 15
}{- "data": {
- "reservation": {
- "course": "695ba111b2e63b75bee66279",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "slots": [
- "695ee7f30b5f48720cad5c81"
], - "status": "held",
- "expiration": "2026-01-16T00:19:18.552Z",
- "_id": "6969808214d2f13caa1e5f16",
- "createdAt": "2026-01-16T00:04:18.557Z",
- "updatedAt": "2026-01-16T00:04:18.557Z",
- "__v": 0
}
}
}Retrieves complete details for a single reservation identified by its MongoDB ObjectId.
Validation:
Response: Returns the full reservation document including:
Use cases:
| id required | string Examples:
The unique identifier of the reservation to retrieve. |
{- "data": {
- "reservation": {
- "_id": "695d651ad97543f2ef9b5231",
- "course": "695ba111b2e63b75bee6627e",
- "user": "648a1f4e2f8fb814c8d6f9b1",
- "slots": [
- "695ba111b2e63b75bee6627f",
- "695ba111b2e63b75bee66280"
], - "status": "held",
- "expiration": "2026-01-06T19:55:10.345Z",
- "createdAt": "2026-01-06T19:40:10.351Z",
- "updatedAt": "2026-01-07T18:30:01.202Z",
- "__v": 0
}
}
}Atomically cancels an existing reservation and restores slot availability within a single database transaction.
Transaction Flow:
available count for each reserved slot by 1cancelledAtomicity Guarantee: All database operations are executed within a MongoDB transaction. If any step fails (e.g., course not found, slot mismatch), the entire transaction is rolled back and no changes are persisted.
Idempotency:
This endpoint can be called on already-cancelled reservations. The operation will still validate data integrity but may not modify any documents if the status is already cancelled.
Use cases:
Success Response: Returns 204 No Content with no response body upon successful cancellation.
| id required | string Examples:
The unique identifier of the reservation to cancel. |
nullBatch cleanup job that identifies and cancels expired reservations in held status, restoring their slot availability.
Cleanup Process:
held and expiration timestamp < current timecancelledTransaction Isolation: Each reservation is cancelled in its own separate transaction. If one reservation fails to clean up, others in the batch continue processing. This prevents a single failure from blocking the entire cleanup job.
Error Handling:
Errors during individual reservation cleanup are caught and logged, with the reservation counted as failed. The endpoint continues processing remaining reservations in the batch.
Response: Returns statistics about the cleanup operation:
processed: Total number of expired reservations found and attemptedcleaned: Number successfully cancelled with slots restored failed: Number that encountered errors during cancellationIntended Usage: This endpoint should be called periodically by a cron job or scheduled task to ensure expired reservations don't permanently hold slot availability.
{- "data": {
- "processed": 10,
- "cleaned": 8,
- "failed": 2
}
}Adapter entry point that initiates the OAuth 2.0 authorization code flow by redirecting the user's browser to Google's consent screen.
Adapter Pattern Role: Adapts internal authentication request to Google's OAuth 2.0 protocol requirements.
External Service Integration:
Adapter Responsibilities:
OAuth Parameters:
Flow Continuation:
After user consent, Google redirects back to /api/v1/oauth/google/callback with authorization code.
Adapter callback endpoint that translates Google's OAuth 2.0 response into an internal authentication assertion for the orchestrator service.
Adapter Pattern Role: Protocol translation layer that converts external OAuth provider response into internal authentication format, isolating the orchestrator from Google-specific OAuth implementation details.
External Service Integration:
Adapter Processing Flow:
/api/v1/auth/internal/assert endpoint/api/v1/auth/complete?nonce={nonce}Assertion Structure (Internal Protocol):
Error Handling:
Security: Signature verification ensures assertion authenticity when orchestrator retrieves it. The adapter acts as a trusted intermediary between Google and the internal system.
| code required | string Authorization code from Google OAuth |
| state | string State parameter for CSRF protection |
{- "error": {
- "code": "CREDENTIAL_ASSERTION_FAILED",
- "message": "Failed to notify authentication manager"
}
}Adapter endpoint that translates internal reservation payment request into PayPal Orders API v2 format.
Adapter Pattern Role: Data model translation layer that converts internal reservation and pricing representation to PayPal-specific order structure, isolating orchestrator from PayPal API changes.
External Service Integration:
Adapter Translation:
PayPal Order Configuration:
Error Handling:
Use Case: Called by orchestrator during booking initiation to prepare payment infrastructure before user payment approval.
| reservationId required | string The reservation ID to associate with this payment |
| priceToPay required | string The amount to charge in EUR (must be a string with 2 decimals) |
{- "reservationId": "6969808214d2f13caa1e5f16",
- "priceToPay": "49.00"
}{- "data": {
- "orderID": "8VX12345AB6789012"
}
}Adapter endpoint that executes payment capture via PayPal API and translates capture response to internal format.
Adapter Pattern Role: Operation translation layer that adapts PayPal's capture operation and response structure to internal payment confirmation model.
External Service Integration:
Adapter Translation Flow:
PayPal Response Extraction:
Navigates complex PayPal response: order.purchase_units[0].payments.captures[0] → extracts id, status, amount.value
Status Translation:
Error Handling:
Critical Operation: This endpoint executes the financial transaction. Called by orchestrator after user approves payment in frontend PayPal UI.
| orderID required | string The PayPal order ID to capture |
{- "orderID": "8VX12345AB6789012"
}{- "data": {
- "status": "COMPLETED",
- "captureId": "6KT41896LL345210G",
- "pricePaid": "49.00"
}
}Adapter endpoint that executes payment refund via PayPal API as part of distributed saga compensation logic.
Adapter Pattern Role: Compensation operation adapter that translates internal refund request to PayPal Payments API refund operation.
External Service Integration:
Adapter Translation Flow:
Refund Type: Full refund (no amount specified) - returns entire captured amount to customer.
Saga Compensation Context: Primarily used by orchestrator's saga compensation logic when booking creation fails after payment capture. Adapter isolates orchestrator from PayPal-specific refund API details.
Error Handling:
Idempotency: PayPal API handles duplicate refund attempts - adapter passes through PayPal's error response if refund already exists.
Critical Financial Operation: Failure of this operation in saga compensation requires manual intervention to ensure customer receives refund.
| captureId required | string The PayPal capture ID to refund |
| reservationId required | string The reservation ID associated with this refund |
{- "captureId": "6KT41896LL345210G",
- "reservationId": "6969808214d2f13caa1e5f16"
}{- "data": {
- "refundId": "3L428953E3355840R",
- "status": "COMPLETED"
}
}