Base URL: http://localhost:8000 (API Gateway)
Authentication: Bearer Token (JWT)
Content-Type: application/json
Login with username and password to receive a JWT token.
Request:
POST /api/v1/auth/login
Content-Type: application/x-www-form-urlencoded
username=admin&password=adminResponse (200 OK):
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}Response (401 Unauthorized):
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid credentials"
}
}Retrieve the public key for JWT verification.
Response (200 OK):
{
"public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
}List all characteristics.
Headers:
Authorization: Bearer <token>(USER or ADMIN role)
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
skip |
integer | 0 | Number of items to skip |
limit |
integer | 100 | Maximum items to return |
Response (200 OK):
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Internet Speed",
"value": "100",
"unit_of_measure": "MBPS",
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z"
}
]Create a new characteristic.
Headers:
Authorization: Bearer <token>(ADMIN role required)
Request Body:
{
"name": "Internet Speed",
"value": "100",
"unit_of_measure": "MBPS"
}Valid Units: MBPS, GBPS, GB, TB, GHZ, VOLT, WATT, METER, NONE, PERCENT, SECONDS, MINUTES, HOURS, DAYS, MONTHS, YEARS, UNIT
Response (201 Created):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Internet Speed",
"value": "100",
"unit_of_measure": "MBPS",
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z"
}Get a characteristic by ID.
Response (200 OK):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Internet Speed",
"value": "100",
"unit_of_measure": "MBPS",
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z"
}Update an existing characteristic.
Headers:
Authorization: Bearer <token>(ADMIN role required)
Request Body:
{
"name": "Internet Speed",
"value": "200",
"unit_of_measure": "MBPS"
}Delete a characteristic.
Headers:
Authorization: Bearer <token>(ADMIN role required)
Response (204 No Content)
Error (409 Conflict): Cannot delete if referenced by specifications.
List all specifications.
Headers:
Authorization: Bearer <token>(USER or ADMIN role)
Response (200 OK):
[
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Fiber Optic Spec",
"characteristic_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z"
}
]Create a new specification.
Headers:
Authorization: Bearer <token>(ADMIN role required)
Request Body:
{
"name": "Fiber Optic Spec",
"characteristic_ids": [
"550e8400-e29b-41d4-a716-446655440000"
]
}Validation:
- At least 1 characteristic ID required
- All characteristic IDs must exist
Response (201 Created):
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Fiber Optic Spec",
"characteristic_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z"
}Get a specification by ID with expanded characteristics.
Update an existing specification.
Delete a specification.
Error (409 Conflict): Cannot delete if referenced by offerings.
List all prices.
Response (200 OK):
[
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Monthly Fee",
"value": 50.00,
"unit": "per month",
"currency": "USD",
"locked": false,
"locked_by_saga_id": null,
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z"
}
]Create a new price.
Request Body:
{
"name": "Monthly Fee",
"value": 50.00,
"unit": "per month",
"currency": "USD"
}Valid Currencies: USD, EUR, TRY
Get a price by ID.
Update an existing price.
Error (423 Locked): Cannot modify a locked price.
Delete a price.
Error (423 Locked): Cannot delete a locked price.
Lock a price (used by Saga workflow).
Request Body:
{
"saga_id": "550e8400-e29b-41d4-a716-446655440003"
}Response (200 OK):
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"locked": true,
"locked_by_saga_id": "550e8400-e29b-41d4-a716-446655440003"
}Unlock a price (compensation transaction).
List all offerings.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by lifecycle status |
Response (200 OK):
[
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"name": "Premium Internet",
"description": "High-speed fiber optic internet",
"specification_ids": ["550e8400-e29b-41d4-a716-446655440001"],
"pricing_ids": ["550e8400-e29b-41d4-a716-446655440002"],
"sales_channels": ["online", "retail"],
"lifecycle_status": "DRAFT",
"created_at": "2026-01-18T00:00:00Z",
"updated_at": "2026-01-18T00:00:00Z",
"published_at": null,
"retired_at": null
}
]Create a new offering (starts in DRAFT status).
Request Body:
{
"name": "Premium Internet",
"description": "High-speed fiber optic internet",
"specification_ids": ["550e8400-e29b-41d4-a716-446655440001"],
"pricing_ids": ["550e8400-e29b-41d4-a716-446655440002"],
"sales_channels": ["online", "retail"]
}Validation:
- At least 1 specification ID
- At least 1 pricing ID
- At least 1 sales channel
Get an offering by ID.
Update an offering.
Error (400 Bad Request): Can only update offerings in DRAFT status.
Delete an offering.
Error (400 Bad Request): Can only delete offerings in DRAFT status.
Publish an offering (triggers Saga workflow).
Preconditions:
- Offering must be in DRAFT status
- Must have at least 1 spec, 1 price, 1 sales channel
Response (202 Accepted):
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"lifecycle_status": "PUBLISHING",
"message": "Publication saga started"
}Saga Steps:
- Lock all referenced prices
- Validate all specifications exist
- Create store entry (MongoDB + Elasticsearch)
- Confirm publication
On Success: Status → PUBLISHED
On Failure: Compensation runs, status → DRAFT
Retire a published offering.
Precondition: Offering must be in PUBLISHED status.
Response (200 OK):
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"lifecycle_status": "RETIRED",
"retired_at": "2026-01-18T00:00:00Z"
}Note: Store endpoints are PUBLIC (no authentication required).
Search published offerings.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
query |
string | Full-text search |
min_price |
number | Minimum price filter |
max_price |
number | Maximum price filter |
skip |
integer | Pagination offset |
limit |
integer | Maximum results |
Example:
GET /api/v1/store/offerings?query=internet&min_price=20&max_price=100Response (200 OK):
[
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"name": "Premium Internet",
"description": "High-speed fiber optic internet",
"specifications": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Fiber Optic Spec",
"characteristics": [
{
"name": "Internet Speed",
"value": "100",
"unit": "MBPS"
}
]
}
],
"pricing": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Monthly Fee",
"value": 50.00,
"currency": "USD"
}
],
"sales_channels": ["online", "retail"],
"published_at": "2026-01-18T00:00:00Z"
}
]Get a published offering by ID with full details.
Basic health check.
Response (200 OK):
{
"status": "healthy",
"service": "api-gateway"
}Check all downstream service dependencies.
Response (200 OK):
{
"status": "healthy",
"dependencies": {
"identity": "healthy",
"characteristic": "healthy",
"specification": "healthy",
"pricing": "healthy",
"offering": "healthy",
"store": "healthy"
}
}All errors follow a consistent format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": {},
"correlation_id": "uuid"
}
}| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Request validation failed |
UNAUTHORIZED |
401 | Missing or invalid token |
FORBIDDEN |
403 | Insufficient permissions |
NOT_FOUND |
404 | Resource not found |
CONFLICT |
409 | Resource conflict (e.g., duplicate name) |
LOCKED |
423 | Resource is locked |
SERVICE_UNAVAILABLE |
503 | Downstream service unavailable |
Each service provides interactive Swagger documentation:
| Service | Swagger UI |
|---|---|
| API Gateway | http://localhost:8000/docs |
| Identity | http://localhost:8001/docs |
| Characteristic | http://localhost:8002/docs |
| Specification | http://localhost:8003/docs |
| Pricing | http://localhost:8004/docs |
| Offering | http://localhost:8005/docs |
| Store | http://localhost:8006/docs |
Generated from FastAPI OpenAPI specifications
January 2026