The system provides multiple API endpoints across different services, following RESTful principles and supporting both authenticated and public access patterns.
| Service | Base URL | Authentication | Purpose |
|---|---|---|---|
| Public API | http://localhost:8080/api |
None | Public read-only endpoints |
| Write Layer | http://localhost:8080/write |
JWT Required | Write operations |
| Coupon Service | http://localhost:8080/coupons |
JWT Required | Coupon management |
Most endpoints require JWT authentication via the Authorization header:
Authorization: Bearer <jwt-token>- Frontend Authentication: Login via React app at
http://localhost:3000 - Direct Keycloak: Use Keycloak API for programmatic access
- Token Endpoint:
POST http://localhost:8080/realms/event-system/protocol/openid-connect/token
# Example token request
curl -X POST \
http://localhost:8080/realms/event-system/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password&client_id=event-system-client&username=user&password=password'Check service health and status.
Endpoint: GET /api/health
Authentication: None
Response:
{
"status": "healthy",
"timestamp": "2024-01-01T12:00:00Z",
"services": {
"database": "up",
"cache": "up",
"auth": "up"
}
}Example:
curl http://localhost:8080/api/healthRetrieve publicly available coupons.
Endpoint: GET /api/v1/coupons
Authentication: None
Query Parameters:
limit(optional): Number of coupons to return (default: 10, max: 100)offset(optional): Pagination offset (default: 0)category(optional): Filter by coupon categoryactive(optional): Filter by active status (true/false)
Response:
{
"coupons": [
{
"id": "coupon_123",
"title": "20% Off Electronics",
"description": "Save 20% on all electronic items",
"discount_percent": 20,
"category": "electronics",
"valid_until": "2024-12-31T23:59:59Z",
"active": true,
"usage_limit": 1000,
"usage_count": 245
}
],
"total": 50,
"limit": 10,
"offset": 0
}Example:
# Get all active coupons
curl "http://localhost:8080/api/v1/coupons?active=true&limit=20"
# Get electronics coupons
curl "http://localhost:8080/api/v1/coupons?category=electronics"Retrieve specific coupon details.
Endpoint: GET /api/v1/coupons/{id}
Authentication: None
Path Parameters:
id: Coupon identifier
Response:
{
"id": "coupon_123",
"title": "20% Off Electronics",
"description": "Save 20% on all electronic items",
"discount_percent": 20,
"category": "electronics",
"valid_until": "2024-12-31T23:59:59Z",
"active": true,
"usage_limit": 1000,
"usage_count": 245,
"terms_conditions": "Valid for one-time use only",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}Example:
curl http://localhost:8080/api/v1/coupons/coupon_123Get current user profile information.
Endpoint: GET /api/v1/users/profile
Authentication: JWT Required
Response:
{
"id": "user_456",
"username": "john.doe",
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"roles": ["user"],
"created_at": "2024-01-01T00:00:00Z",
"last_login": "2024-01-15T09:15:00Z"
}Example:
curl -H "Authorization: Bearer <jwt-token>" \
http://localhost:8080/api/v1/users/profileCreate a new coupon (Admin only).
Endpoint: POST /write/v1/coupons
Authentication: JWT Required (Admin role)
Request Body:
{
"title": "Summer Sale",
"description": "Special summer discount",
"discount_percent": 25,
"category": "clothing",
"valid_until": "2024-08-31T23:59:59Z",
"usage_limit": 500,
"terms_conditions": "Cannot be combined with other offers"
}Response:
{
"id": "coupon_789",
"title": "Summer Sale",
"description": "Special summer discount",
"discount_percent": 25,
"category": "clothing",
"valid_until": "2024-08-31T23:59:59Z",
"active": true,
"usage_limit": 500,
"usage_count": 0,
"terms_conditions": "Cannot be combined with other offers",
"created_at": "2024-01-15T12:00:00Z",
"created_by": "admin_user"
}Example:
curl -X POST \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"title": "Summer Sale",
"description": "Special summer discount",
"discount_percent": 25,
"category": "clothing",
"valid_until": "2024-08-31T23:59:59Z",
"usage_limit": 500
}' \
http://localhost:8080/write/v1/couponsUpdate an existing coupon.
Endpoint: PUT /write/v1/coupons/{id}
Authentication: JWT Required (Admin role)
Path Parameters:
id: Coupon identifier
Request Body:
{
"title": "Updated Summer Sale",
"description": "Updated special summer discount",
"discount_percent": 30,
"active": true
}Response:
{
"id": "coupon_789",
"title": "Updated Summer Sale",
"description": "Updated special summer discount",
"discount_percent": 30,
"category": "clothing",
"valid_until": "2024-08-31T23:59:59Z",
"active": true,
"usage_limit": 500,
"usage_count": 0,
"updated_at": "2024-01-15T14:30:00Z",
"updated_by": "admin_user"
}Example:
curl -X PUT \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Summer Sale",
"discount_percent": 30
}' \
http://localhost:8080/write/v1/coupons/coupon_789Soft delete a coupon (marks as inactive).
Endpoint: DELETE /write/v1/coupons/{id}
Authentication: JWT Required (Admin role)
Path Parameters:
id: Coupon identifier
Response:
{
"message": "Coupon successfully deleted",
"id": "coupon_789",
"deleted_at": "2024-01-15T15:00:00Z"
}Example:
curl -X DELETE \
-H "Authorization: Bearer <jwt-token>" \
http://localhost:8080/write/v1/coupons/coupon_789Redeem a coupon for the authenticated user.
Endpoint: POST /coupons/v1/redeem
Authentication: JWT Required
Request Body:
{
"coupon_id": "coupon_123",
"order_id": "order_456"
}Response:
{
"success": true,
"message": "Coupon successfully redeemed",
"coupon_id": "coupon_123",
"order_id": "order_456",
"discount_amount": 25.00,
"redeemed_at": "2024-01-15T16:00:00Z",
"redemption_id": "redemption_789"
}Example:
curl -X POST \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"coupon_id": "coupon_123",
"order_id": "order_456"
}' \
http://localhost:8080/coupons/v1/redeemGet coupons redeemed by the authenticated user.
Endpoint: GET /coupons/v1/user/coupons
Authentication: JWT Required
Query Parameters:
limit(optional): Number of coupons to return (default: 10)offset(optional): Pagination offset (default: 0)status(optional): Filter by redemption status (active, used, expired)
Response:
{
"coupons": [
{
"coupon_id": "coupon_123",
"title": "20% Off Electronics",
"discount_amount": 25.00,
"redeemed_at": "2024-01-15T16:00:00Z",
"status": "used",
"order_id": "order_456"
}
],
"total": 5,
"limit": 10,
"offset": 0
}Example:
curl -H "Authorization: Bearer <jwt-token>" \
"http://localhost:8080/coupons/v1/user/coupons?limit=20"All API endpoints return errors in a consistent format:
{
"error": {
"code": "INVALID_REQUEST",
"message": "The request is invalid",
"details": "Missing required field: title",
"timestamp": "2024-01-15T12:00:00Z",
"request_id": "req_123456"
}
}| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST |
Request validation failed |
| 401 | UNAUTHORIZED |
Authentication required |
| 403 | FORBIDDEN |
Insufficient permissions |
| 404 | NOT_FOUND |
Resource not found |
| 409 | CONFLICT |
Resource conflict (duplicate) |
| 429 | RATE_LIMITED |
Too many requests |
| 500 | INTERNAL_ERROR |
Server error |
| 503 | SERVICE_UNAVAILABLE |
Service temporarily unavailable |
{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"details": "JWT token is missing or invalid"
}
}{
"error": {
"code": "INVALID_REQUEST",
"message": "Validation failed",
"details": {
"title": "Title is required",
"discount_percent": "Must be between 1 and 100"
}
}
}API responses include rate limiting information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1642262400| Endpoint Category | Rate Limit | Window |
|---|---|---|
| Public Read | 1000 req/hour | 1 hour |
| Authenticated Read | 2000 req/hour | 1 hour |
| Write Operations | 100 req/hour | 1 hour |
| Admin Operations | 500 req/hour | 1 hour |
limit: Number of items per page (default: 10, max: 100)offset: Number of items to skip (default: 0)
{
"data": [...],
"pagination": {
"total": 500,
"limit": 10,
"offset": 0,
"has_more": true
}
}Link: <http://localhost:8080/api/v1/coupons?offset=10&limit=10>; rel="next",
<http://localhost:8080/api/v1/coupons?offset=490&limit=10>; rel="last"Connect to WebSocket for real-time coupon updates:
Endpoint: ws://localhost:8080/ws/coupons
Authentication: JWT via query parameter or header
Message Format:
{
"type": "coupon_created",
"data": {
"id": "coupon_123",
"title": "New Flash Sale",
"discount_percent": 50
},
"timestamp": "2024-01-15T12:00:00Z"
}Event Types:
coupon_created: New coupon availablecoupon_updated: Coupon details changedcoupon_expired: Coupon no longer validusage_updated: Coupon usage count changed
const ApiClient = require('@company/api-client');
const client = new ApiClient({
baseUrl: 'http://localhost:8080',
token: 'your-jwt-token'
});
// Get coupons
const coupons = await client.coupons.list({ limit: 20 });
// Create coupon
const newCoupon = await client.coupons.create({
title: 'Holiday Sale',
discount_percent: 25
});from api_client import ApiClient
client = ApiClient(
base_url='http://localhost:8080',
token='your-jwt-token'
)
# Get coupons
coupons = client.coupons.list(limit=20)
# Create coupon
new_coupon = client.coupons.create({
'title': 'Holiday Sale',
'discount_percent': 25
})# Set base URL and token
BASE_URL="http://localhost:8080"
TOKEN="your-jwt-token"
# Get public coupons
curl "$BASE_URL/api/v1/coupons"
# Get user profile
curl -H "Authorization: Bearer $TOKEN" \
"$BASE_URL/api/v1/users/profile"
# Create coupon
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Test Coupon","discount_percent":15}' \
"$BASE_URL/write/v1/coupons"