Last active
May 30, 2025 12:15
-
-
Save blessingk/491e9b4a55890d8396a5813dff2168db to your computer and use it in GitHub Desktop.
COP API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
openapi: 3.0.0 | |
info: | |
title: Checkout API | |
version: 1.0.0 | |
description: | | |
API for managing checkout brand configurations and sessions. | |
## Authentication | |
This API uses two authentication methods: | |
- Bearer token authentication for user sessions | |
- API key authentication for service-to-service communication | |
## Rate Limiting | |
- Standard rate limit: 100 requests per minute | |
- Burst rate limit: 200 requests per minute | |
- Rate limit headers are included in all responses | |
## Versioning | |
- Current version: v0.9 | |
- Version deprecation policy: 6 months notice | |
- Version in URL: /api | |
- Version in header: X-API-Version | |
## Response Format | |
All responses follow a standard format: | |
```json | |
{ | |
"data": {}, // Response data | |
"meta": { | |
"message": "Success message", | |
"timestamp": "2024-03-20T10:00:00Z", | |
"requestId": "req_123456789" | |
} | |
} | |
``` | |
## Error Format | |
All errors follow a standard format: | |
```json | |
{ | |
"statusCode": 404, | |
"message": "Human readable error message", | |
"timestamp": "2024-03-20T10:00:00Z", | |
"path": "/api/resource", | |
"requestId": "req_123456789", | |
"details": {}, // Optional additional error details | |
"trace": [] // Optional stack trace (only in non-production environments) | |
} | |
``` | |
servers: | |
- url: /api | |
description: API v0.9 (Current) | |
components: | |
securitySchemes: | |
BearerAuth: | |
type: http | |
scheme: bearer | |
bearerFormat: JWT | |
description: JWT token for user authentication | |
ApiKeyAuth: | |
type: apiKey | |
in: header | |
name: X-API-Key | |
description: API key for service-to-service communication | |
security: | |
- BearerAuth: [] | |
- ApiKeyAuth: [] | |
parameters: | |
page: | |
name: page | |
in: query | |
description: Page number for pagination | |
required: false | |
schema: | |
type: integer | |
minimum: 1 | |
default: 1 | |
perPage: | |
name: perPage | |
in: query | |
description: Number of items per page | |
required: false | |
schema: | |
type: integer | |
minimum: 1 | |
maximum: 100 | |
default: 20 | |
sort: | |
name: sort | |
in: query | |
description: Sort field and direction (e.g., createdAt:desc) | |
required: false | |
schema: | |
type: string | |
filter: | |
name: filter | |
in: query | |
description: Filter criteria (e.g., status:active) | |
required: false | |
schema: | |
type: string | |
responses: | |
UnauthorizedError: | |
description: Authentication credentials are missing or invalid | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Error' | |
ForbiddenError: | |
description: The authenticated user doesn't have permission to access the resource | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Error' | |
NotFoundError: | |
description: The requested resource was not found | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Error' | |
ValidationError: | |
description: The request payload is invalid | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Error' | |
RateLimitError: | |
description: Too many requests | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Error' | |
headers: | |
X-RateLimit-Limit: | |
schema: | |
type: integer | |
description: The maximum number of requests allowed per time window | |
X-RateLimit-Remaining: | |
schema: | |
type: integer | |
description: The number of requests remaining in the current time window | |
X-RateLimit-Reset: | |
schema: | |
type: integer | |
description: The time at which the current rate limit window resets (Unix timestamp) | |
schemas: | |
Error: | |
type: object | |
properties: | |
statusCode: | |
type: integer | |
description: HTTP status code | |
message: | |
type: string | |
description: Human readable error message | |
timestamp: | |
type: string | |
format: date-time | |
description: When the error occurred | |
path: | |
type: string | |
description: The request path that caused the error | |
requestId: | |
type: string | |
format: uuid | |
description: Unique request identifier | |
details: | |
type: object | |
description: Additional error details | |
trace: | |
type: array | |
items: | |
type: string | |
description: Stack trace (only in non-production environments) | |
PaginatedResponse: | |
type: object | |
properties: | |
data: | |
type: array | |
items: | |
type: object | |
meta: | |
type: object | |
properties: | |
total: | |
type: integer | |
description: Total number of items | |
page: | |
type: integer | |
description: Current page number | |
perPage: | |
type: integer | |
description: Number of items per page | |
totalPages: | |
type: integer | |
description: Total number of pages | |
hasMore: | |
type: boolean | |
description: Whether there are more pages | |
requestId: | |
type: string | |
format: uuid | |
timestamp: | |
type: string | |
format: date-time | |
Brand: | |
type: object | |
properties: | |
id: | |
type: string | |
format: uuid | |
description: Unique identifier for the brand config | |
brand: | |
type: object | |
properties: | |
id: | |
type: string | |
description: Brand identifier (e.g., expatexplore) | |
logo: | |
type: object | |
properties: | |
url: | |
type: string | |
format: uri | |
description: URL to the brand logo | |
alt: | |
type: string | |
description: Alt text for the logo | |
name: | |
type: string | |
description: Brand name | |
domain: | |
type: string | |
description: Brand domain | |
meta: | |
type: object | |
properties: | |
title: | |
type: string | |
description: Page title | |
description: | |
type: string | |
description: Page description | |
links: | |
type: object | |
properties: | |
privacyPolicy: | |
type: string | |
format: uri | |
description: Privacy policy URL | |
termsAndConditions: | |
type: string | |
format: uri | |
description: Terms and conditions URL | |
copyrightStartYear: | |
type: string | |
description: Copyright start year | |
paymentProvider: | |
type: object | |
properties: | |
name: | |
type: string | |
description: Payment provider name | |
currencyCode: | |
type: string | |
description: Currency code (e.g., ZAR) | |
logo: | |
type: object | |
properties: | |
url: | |
type: string | |
format: uri | |
description: Payment provider logo URL | |
alt: | |
type: string | |
description: Alt text for the payment provider logo | |
acceptedPaymentMethodLogos: | |
type: array | |
items: | |
type: object | |
properties: | |
url: | |
type: string | |
format: uri | |
description: Payment method logo URL | |
alt: | |
type: string | |
description: Alt text for the payment method logo | |
support: | |
type: object | |
properties: | |
phoneNumber: | |
type: string | |
description: Support phone number | |
theme: | |
type: object | |
properties: | |
font: | |
type: string | |
description: Font family | |
colors: | |
type: object | |
properties: | |
primary: | |
type: string | |
description: Primary color | |
accent: | |
type: string | |
description: Accent color | |
borderRadius: | |
type: string | |
description: Border radius value | |
iconLibrary: | |
type: string | |
description: Icon library name | |
ui: | |
type: object | |
properties: | |
header: | |
type: object | |
properties: | |
mdc: | |
type: string | |
description: Header component MDC | |
footer: | |
type: object | |
properties: | |
componentName: | |
type: string | |
description: Footer component name | |
createdAt: | |
type: string | |
format: date-time | |
updatedAt: | |
type: string | |
format: date-time | |
createdBy: | |
type: string | |
format: uuid | |
updatedBy: | |
type: string | |
format: uuid | |
Session: | |
type: object | |
properties: | |
id: | |
type: string | |
format: uuid | |
brandConfigId: | |
type: string | |
format: uuid | |
brandConfigVersion: | |
type: string | |
status: | |
type: string | |
enum: [active, completed, expired, cancelled] | |
user: | |
type: object | |
properties: | |
email: | |
type: string | |
format: email | |
phoneNumber: | |
type: string | |
timer: | |
type: object | |
properties: | |
timeLimit: | |
type: integer | |
sessionUpdateUrl: | |
type: string | |
format: uri | |
maximumRetries: | |
type: integer | |
paymentData: | |
type: object | |
properties: | |
methods: | |
type: array | |
items: | |
type: object | |
properties: | |
name: | |
type: string | |
icon: | |
type: string | |
format: uri | |
description: | |
type: string | |
preferredMethod: | |
type: boolean | |
type: | |
type: string | |
enum: [instalments, full, deposit] | |
structure: | |
type: object | |
properties: | |
startDate: | |
type: string | |
format: date-time | |
lastAvailableDate: | |
type: string | |
format: date-time | |
paymentBreakdown: | |
type: object | |
properties: | |
numberOfMonths: | |
type: integer | |
selected: | |
type: boolean | |
totals: | |
type: object | |
properties: | |
monthlyTotal: | |
type: number | |
format: float | |
totalDue: | |
type: number | |
format: float | |
selectedMethod: | |
type: string | |
totals: | |
type: object | |
properties: | |
monthlyTotal: | |
type: number | |
format: float | |
totalDue: | |
type: number | |
format: float | |
cart: | |
type: object | |
properties: | |
products: | |
type: array | |
items: | |
type: object | |
properties: | |
id: | |
type: string | |
name: | |
type: string | |
quantity: | |
type: integer | |
icon: | |
type: string | |
format: uri | |
maxQuantity: | |
type: integer | |
minQuantity: | |
type: integer | |
unitMeasure: | |
type: object | |
properties: | |
singular: | |
type: string | |
plural: | |
type: string | |
total: | |
type: object | |
properties: | |
price: | |
type: object | |
properties: | |
amount: | |
type: number | |
format: float | |
discountedAmount: | |
type: number | |
format: float | |
totals: | |
type: object | |
properties: | |
originalTotal: | |
type: number | |
format: float | |
discountedTotal: | |
type: number | |
format: float | |
discounts: | |
type: array | |
items: | |
type: object | |
properties: | |
id: | |
type: string | |
code: | |
type: string | |
name: | |
type: string | |
type: | |
type: string | |
enum: [absolute, percentage] | |
amount: | |
type: number | |
format: float | |
maxValue: | |
type: number | |
format: float | |
optionalExtras: | |
type: array | |
items: | |
type: object | |
properties: | |
name: | |
type: string | |
tooltipText: | |
type: string | |
price: | |
type: object | |
properties: | |
amount: | |
type: number | |
format: float | |
discountedAmount: | |
type: number | |
format: float | |
imageUrl: | |
type: string | |
format: uri | |
quantity: | |
type: integer | |
icon: | |
type: string | |
format: uri | |
maxQuantity: | |
type: integer | |
minQuantity: | |
type: integer | |
total: | |
type: number | |
format: float | |
unitMeasure: | |
type: object | |
properties: | |
singular: | |
type: string | |
plural: | |
type: string | |
productImageUrl: | |
type: string | |
format: uri | |
features: | |
type: array | |
items: | |
type: object | |
properties: | |
icon: | |
type: string | |
text: | |
type: string | |
tooltipText: | |
type: string | |
promoCode: | |
type: object | |
properties: | |
id: | |
type: string | |
code: | |
type: string | |
name: | |
type: string | |
type: | |
type: string | |
enum: [absolute, percentage] | |
amount: | |
type: number | |
format: float | |
maxValue: | |
type: number | |
format: float | |
priceBreakdown: | |
type: object | |
properties: | |
totalSavings: | |
type: object | |
properties: | |
amount: | |
type: number | |
format: float | |
title: | |
type: string | |
description: | |
type: string | |
tooltip: | |
type: string | |
subTotal: | |
type: object | |
properties: | |
amount: | |
type: number | |
format: float | |
title: | |
type: string | |
description: | |
type: string | |
tooltip: | |
type: string | |
totalDue: | |
type: object | |
properties: | |
amount: | |
type: number | |
format: float | |
title: | |
type: string | |
description: | |
type: string | |
tooltip: | |
type: string | |
sessionHistory: | |
type: array | |
items: | |
type: object | |
properties: | |
timestamp: | |
type: integer | |
format: int64 | |
action: | |
type: string | |
enum: [created, updated, completed, expired, cancelled] | |
details: | |
type: object | |
properties: | |
previousState: | |
type: object | |
newState: | |
type: object | |
reason: | |
type: string | |
userAgent: | |
type: string | |
ipAddress: | |
type: string | |
createdAt: | |
type: string | |
format: date-time | |
updatedAt: | |
type: string | |
format: date-time | |
expiresAt: | |
type: string | |
format: date-time | |
tags: | |
- name: Brand | |
description: Operations for managing brand configurations | |
- name: Sessions | |
description: Operations for managing checkout sessions | |
- name: Health | |
description: Health check and system status endpoints | |
- name: Cart | |
description: Operations for managing session cart | |
- name: Payment | |
description: Operations for managing session payments | |
paths: | |
/sessions: | |
get: | |
tags: | |
- Sessions | |
summary: List sessions | |
description: Retrieve a paginated list of sessions with optional filtering | |
parameters: | |
- $ref: '#/components/parameters/page' | |
- $ref: '#/components/parameters/perPage' | |
- $ref: '#/components/parameters/sort' | |
- $ref: '#/components/parameters/filter' | |
- name: status | |
in: query | |
description: Filter by session status | |
schema: | |
type: string | |
enum: [active, completed, expired, cancelled] | |
- name: brandConfigId | |
in: query | |
description: Filter by brand configuration ID | |
schema: | |
type: string | |
format: uuid | |
responses: | |
200: | |
description: List of sessions | |
content: | |
application/json: | |
schema: | |
allOf: | |
- $ref: '#/components/schemas/PaginatedResponse' | |
- type: object | |
properties: | |
data: | |
type: array | |
items: | |
$ref: '#/components/schemas/Session' | |
headers: | |
X-RateLimit-Limit: | |
schema: | |
type: integer | |
X-RateLimit-Remaining: | |
schema: | |
type: integer | |
X-RateLimit-Reset: | |
schema: | |
type: integer | |
401: | |
$ref: '#/components/responses/UnauthorizedError' | |
403: | |
$ref: '#/components/responses/ForbiddenError' | |
429: | |
$ref: '#/components/responses/RateLimitError' | |
post: | |
tags: | |
- Sessions | |
summary: Create a new session | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Session' | |
responses: | |
201: | |
description: Session created | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Session' | |
/sessions/{id}: | |
parameters: | |
- name: id | |
in: path | |
required: true | |
schema: | |
type: string | |
format: uuid | |
get: | |
tags: | |
- Sessions | |
summary: Get a session by ID | |
responses: | |
200: | |
description: Session details | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Session' | |
put: | |
tags: | |
- Sessions | |
summary: Update a session | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Session' | |
responses: | |
200: | |
description: Session updated | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Session' | |
delete: | |
tags: | |
- Sessions | |
summary: Delete a session | |
responses: | |
204: | |
description: Session deleted | |
/sessions/{id}/cart: | |
parameters: | |
- name: id | |
in: path | |
required: true | |
schema: | |
type: string | |
format: uuid | |
get: | |
tags: | |
- Cart | |
summary: Get session cart | |
responses: | |
200: | |
description: Session cart details | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
cartData: | |
$ref: '#/components/schemas/Session/properties/cart' | |
put: | |
tags: | |
- Cart | |
summary: Update session cart | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
cartData: | |
$ref: '#/components/schemas/Session/properties/cart' | |
responses: | |
200: | |
description: Session cart updated | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
cartData: | |
$ref: '#/components/schemas/Session/properties/cart' | |
/sessions/{id}/payment: | |
parameters: | |
- name: id | |
in: path | |
required: true | |
schema: | |
type: string | |
format: uuid | |
get: | |
tags: | |
- Payment | |
summary: Get session payment data | |
responses: | |
200: | |
description: Session payment details | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
paymentData: | |
$ref: '#/components/schemas/Session/properties/paymentData' | |
put: | |
tags: | |
- Payment | |
summary: Update session payment data | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
paymentData: | |
$ref: '#/components/schemas/Session/properties/paymentData' | |
responses: | |
200: | |
description: Session payment data updated | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
paymentData: | |
$ref: '#/components/schemas/Session/properties/paymentData' | |
/sessions/{id}/validate: | |
get: | |
tags: | |
- Sessions | |
summary: Validate session status | |
description: Check if a session is valid and get its current status | |
parameters: | |
- name: id | |
in: path | |
required: true | |
description: Session ID | |
schema: | |
type: string | |
format: uuid | |
responses: | |
200: | |
description: Session validation result | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
data: | |
type: object | |
properties: | |
isValid: | |
type: boolean | |
description: Whether the session is valid | |
status: | |
type: string | |
enum: [active, completed, expired, cancelled] | |
description: Current session status | |
reason: | |
type: string | |
description: Reason for invalid status if applicable | |
expiresIn: | |
type: integer | |
description: Seconds until session expires | |
remainingTime: | |
type: integer | |
description: Remaining time in seconds for active sessions | |
meta: | |
type: object | |
properties: | |
timestamp: | |
type: string | |
format: date-time | |
requestId: | |
type: string | |
format: uuid | |
headers: | |
X-RateLimit-Limit: | |
schema: | |
type: integer | |
X-RateLimit-Remaining: | |
schema: | |
type: integer | |
404: | |
$ref: '#/components/responses/NotFoundError' | |
429: | |
$ref: '#/components/responses/RateLimitError' | |
/sessions/{id}/extend: | |
post: | |
tags: | |
- Sessions | |
summary: Extend session timer | |
description: Extend the session timer if allowed by the configuration | |
parameters: | |
- name: id | |
in: path | |
required: true | |
description: Session ID | |
schema: | |
type: string | |
format: uuid | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
extensionTime: | |
type: integer | |
description: Time to extend in seconds | |
minimum: 60 | |
maximum: 1800 | |
responses: | |
200: | |
description: Session extended successfully | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
data: | |
type: object | |
properties: | |
remainingTime: | |
type: integer | |
description: New remaining time in seconds | |
extensionsRemaining: | |
type: integer | |
description: Number of extensions remaining | |
maxExtensions: | |
type: integer | |
description: Maximum number of allowed extensions | |
meta: | |
type: object | |
properties: | |
message: | |
type: string | |
timestamp: | |
type: string | |
format: date-time | |
requestId: | |
type: string | |
format: uuid | |
headers: | |
X-RateLimit-Limit: | |
schema: | |
type: integer | |
X-RateLimit-Remaining: | |
schema: | |
type: integer | |
X-RateLimit-Reset: | |
schema: | |
type: integer | |
400: | |
description: Extension not allowed | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Error' | |
404: | |
$ref: '#/components/responses/NotFoundError' | |
429: | |
$ref: '#/components/responses/RateLimitError' | |
/brands: | |
get: | |
tags: | |
- Brand | |
summary: List brand configurations | |
description: Retrieve a paginated list of brand configurations with optional filtering | |
parameters: | |
- $ref: '#/components/parameters/page' | |
- $ref: '#/components/parameters/perPage' | |
- $ref: '#/components/parameters/sort' | |
- $ref: '#/components/parameters/filter' | |
- name: isActive | |
in: query | |
description: Filter by active status | |
schema: | |
type: boolean | |
- name: version | |
in: query | |
description: Filter by version | |
schema: | |
type: string | |
responses: | |
200: | |
description: List of brand configurations | |
content: | |
application/json: | |
schema: | |
allOf: | |
- $ref: '#/components/schemas/PaginatedResponse' | |
- type: object | |
properties: | |
data: | |
type: array | |
items: | |
$ref: '#/components/schemas/Brand' | |
headers: | |
X-RateLimit-Limit: | |
schema: | |
type: integer | |
X-RateLimit-Remaining: | |
schema: | |
type: integer | |
X-RateLimit-Reset: | |
schema: | |
type: integer | |
401: | |
$ref: '#/components/responses/UnauthorizedError' | |
403: | |
$ref: '#/components/responses/ForbiddenError' | |
429: | |
$ref: '#/components/responses/RateLimitError' | |
post: | |
tags: | |
- Brand | |
summary: Create a new brand configuration | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Brand' | |
responses: | |
201: | |
description: Brand configuration created | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Brand' | |
/brands/{id}: | |
parameters: | |
- name: id | |
in: path | |
required: true | |
schema: | |
type: string | |
format: uuid | |
get: | |
tags: | |
- Brand | |
summary: Get a brand configuration by ID | |
responses: | |
200: | |
description: Brand configuration details | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Brand' | |
put: | |
tags: | |
- Brand | |
summary: Update a brand configuration | |
requestBody: | |
required: true | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Brand' | |
responses: | |
'200': | |
description: Brand configuration updated | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Brand' | |
delete: | |
tags: | |
- Brand | |
summary: Delete a brand configuration | |
responses: | |
'204': | |
description: Brand configuration deleted | |
/health: | |
get: | |
tags: | |
- Health | |
summary: Health check endpoint | |
description: Check the health status of the API and its dependencies | |
security: [] # No authentication required | |
responses: | |
200: | |
description: System is healthy | |
content: | |
application/json: | |
schema: | |
type: object | |
properties: | |
status: | |
type: string | |
enum: [healthy, degraded] | |
description: Current system health status | |
version: | |
type: string | |
description: Current API version | |
timestamp: | |
type: string | |
format: date-time | |
description: Current server time | |
dependencies: | |
type: object | |
properties: | |
database: | |
type: string | |
enum: [up, down] | |
cache: | |
type: string | |
enum: [up, down] | |
paymentGateway: | |
type: string | |
enum: [up, down] | |
headers: | |
X-RateLimit-Limit: | |
schema: | |
type: integer | |
description: Rate limit for health checks | |
X-RateLimit-Remaining: | |
schema: | |
type: integer | |
description: Remaining health check requests |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment