Skip to content

Instantly share code, notes, and snippets.

@blessingk
Last active May 30, 2025 12:15
Show Gist options
  • Save blessingk/491e9b4a55890d8396a5813dff2168db to your computer and use it in GitHub Desktop.
Save blessingk/491e9b4a55890d8396a5813dff2168db to your computer and use it in GitHub Desktop.
COP API
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