Skip to content

Instantly share code, notes, and snippets.

@blessingk
Last active July 17, 2025 14:26
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
{}
```
## Error Format
All errors follow this 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
schemas:
Country:
type: object
properties:
code:
type: string
description: Country code (e.g., 'ZA')
name:
type: string
description: Country name (e.g., 'South Africa')
Payment:
type: object
properties:
method:
type: string
description: Payment method name
SessionBrandResponse:
type: object
properties:
name:
type: string
version:
type: string
isActive:
type: boolean
brand:
type: object
theme:
type: object
steps:
type: array
items:
type: object
featureFlags:
type: object
formSchema:
type: array
items:
type: object
session:
type: object
Brand:
type: object
properties:
id:
type: string
format: uuid
description: Unique identifier for the brand config
name:
type: string
description: Brand name
domain:
type: string
description: Brand domain
logo:
type: object
properties:
url:
type: string
format: uri
description: URL to the brand logo
alt:
type: string
description: Alt text for the logo
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
BrandResponse:
type: object
properties:
id:
type: integer
version:
type: string
isActive:
type: boolean
brand:
$ref: '#/components/schemas/Brand'
theme:
type: object
featureFlags:
type: object
steps:
type: array
items:
type: object
formSchema:
type: array
items:
type: object
orderSuccess:
type: object
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
createdBy:
type: string
updatedBy:
type: string
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
Product:
type: object
description: Product details to be added to the cart for the session
properties:
id:
type: string
format: uuid
description: Unique identifier for the product
code:
type: string
description: Product code
feature:
type: object
properties:
icon:
type: string
format: uri
text:
type: string
tooltipText:
type: string
discounts:
type: array
items:
type: object
properties:
amount:
type: number
format: float
code:
type: string
id:
type: string
maxValue:
type: number
format: float
name:
type: string
type:
type: string
enum: [absolute, percentage]
optionalExtras:
type: array
items:
type: object
properties:
icon:
type: string
format: uri
imageUrl:
type: string
format: uri
maxQuantity:
type: integer
minQuantity:
type: integer
name:
type: string
price:
type: object
properties:
amount:
type: number
format: float
description:
type: string
discountedAmount:
type: number
format: float
quantity:
type: integer
tooltipText:
type: string
total:
type: number
format: float
unitMeasure:
type: object
properties:
plural:
type: string
singular:
type: string
Session:
type: object
required:
- code
- brandId
- brandVersion
- status
- country
- currency
- timer
- payment
- cart
- createdAt
- updatedAt
properties:
uuid:
type: string
code:
type: string
brandId:
type: integer
brandVersion:
type: string
status:
type: string
enum: [active, completed, cancelled, expired]
country:
$ref: '#/components/schemas/Country'
currency:
$ref: '#/components/schemas/Currency'
timer:
$ref: '#/components/schemas/Timer'
payment:
$ref: '#/components/schemas/Payment'
cart:
$ref: '#/components/schemas/Cart'
formsData:
type: object
expiresAt:
type: string
format: date-time
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
sessionHistory:
type: array
items:
$ref: '#/components/schemas/SessionHistoryEntry'
RecalculatePricesRequest:
type: object
required:
- sessionId
- cart
properties:
sessionId:
type: string
format: uuid
description: Session identifier
cart:
$ref: '#/components/schemas/Cart'
RecalculatePricesResponse:
type: object
properties:
data:
type: object
properties:
cart:
$ref: '#/components/schemas/Cart'
totals:
type: object
properties:
subtotal:
type: number
format: float
discount:
type: number
format: float
total:
type: number
format: float
meta:
type: object
properties:
message:
type: string
timestamp:
type: string
format: date-time
requestId:
type: string
format: uuid
Currency:
type: object
required:
- name
- code
- symbol
properties:
name:
type: string
example: "United States Dollar"
code:
type: string
example: "USD"
symbol:
type: string
example: "$"
Timer:
type: object
required:
- timeLimitInSeconds
- sessionUpdateUrl
- maximumRetries
- remainingTimeInSeconds
- warningThresholdInSeconds
- extendable
- extensionTimeInSeconds
properties:
timeLimitInSeconds:
type: integer
example: 1800
sessionUpdateUrl:
type: string
format: uri
example: "https://api.brandname.com/sessions/update"
maximumRetries:
type: integer
example: 0
remainingTimeInSeconds:
type: integer
example: 1800
warningThresholdInSeconds:
type: integer
example: 300
extendable:
type: boolean
example: false
extensionTimeInSeconds:
type: integer
example: 0
Cart:
type: object
required:
- products
- priceBreakdown
properties:
products:
type: array
items:
$ref: '#/components/schemas/CartProduct'
promoCode:
$ref: '#/components/schemas/PromoCode'
priceBreakdown:
$ref: '#/components/schemas/PriceBreakdown'
CartProduct:
type: object
required:
- id
- name
- quantity
- unitMeasure
- total
- discounts
- optionalExtras
- productImage
- features
- additionalInformation
properties:
id:
type: integer
name:
type: string
quantity:
type: integer
iconName:
type: string
maxQuantity:
type: integer
minQuantity:
type: integer
unitMeasure:
$ref: '#/components/schemas/UnitMeasure'
url:
type: string
productId:
type: string
optionId:
type: string
total:
type: object
properties:
price:
$ref: '#/components/schemas/CartProductTotal'
totals:
$ref: '#/components/schemas/CartProductTotal'
discounts:
type: array
items:
$ref: '#/components/schemas/ProductDiscount'
optionalExtras:
type: array
items:
$ref: '#/components/schemas/OptionalExtra'
productImage:
$ref: '#/components/schemas/Image'
features:
type: array
items:
$ref: '#/components/schemas/ProductFeature'
additionalInformation:
type: array
items:
$ref: '#/components/schemas/AdditionalInformation'
UnitMeasure:
type: object
properties:
quantitySelection:
$ref: '#/components/schemas/UnitMeasureItem'
priceBreakdown:
$ref: '#/components/schemas/UnitMeasureItem'
UnitMeasureItem:
type: object
properties:
singular:
type: string
plural:
type: string
ProductTotal:
type: object
required:
- price
- totals
properties:
price:
$ref: '#/components/schemas/Price'
totals:
$ref: '#/components/schemas/Price'
Price:
type: object
required:
- amount
- discountedAmount
- description
properties:
amount:
type: integer
example: 99999
discountedAmount:
type: integer
example: 79999
description:
type: string
example: "Price per person in cents"
OptionalExtra:
type: object
required:
- id
- name
- quantity
- unitMeasure
- price
- image
- isAdjustable
- total
properties:
id:
type: integer
name:
type: string
quantity:
type: integer
unitMeasure:
$ref: '#/components/schemas/UnitMeasure'
price:
$ref: '#/components/schemas/CartProductTotal'
image:
$ref: '#/components/schemas/Image'
tooltipText:
type: string
showInPriceBreakdown:
type: boolean
isAdjustable:
type: boolean
total:
type: number
PromoCode:
type: object
required:
- code
properties:
code:
type: string
example: "SUMMER20"
PriceBreakdown:
type: object
properties:
totalSavings:
$ref: '#/components/schemas/PriceBreakdownDetail'
totalDue:
$ref: '#/components/schemas/PriceBreakdownDetail'
totalDueNow:
$ref: '#/components/schemas/PriceBreakdownDetail'
PriceBreakdownDetail:
type: object
properties:
amount:
type: number
title:
type: object
properties:
text:
type: string
mobileOnlyText:
type: string
description:
type: string
tooltipText:
type: string
displayInBreakdown:
type: boolean
SessionHistoryEntry:
type: object
properties:
createAt:
type: string
action:
type: string
details:
type: object
properties:
reason:
type: string
userAgent:
type: string
ipAddress:
type: string
CartProductTotal:
type: object
properties:
amount:
type: number
discountedAmount:
type: number
description:
type: string
ProductDiscount:
type: object
properties:
id:
type: string
code:
type: string
name:
type: string
amount:
type: number
iconName:
type: string
Image:
type: object
properties:
alt:
type: string
url:
type: string
ProductFeature:
type: object
properties:
iconName:
type: string
text:
type: string
tooltipText:
type: string
AdditionalInformation:
type: object
properties:
iconName:
type: string
title:
type: string
text:
type: string
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)
tags:
- name: Brand
description: Operations for managing brand configurations
- name: Health
description: Health check and system status endpoints
- name: Sessions
description: Operations for managing checkout sessions
paths:
/internal/sessions/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: number
description: Session ID
get:
tags:
- Sessions
security: []
summary: Get a session by ID
description: Retrieve session details by ID
responses:
200:
description: Session details
content:
application/json:
schema:
$ref: '#/components/schemas/Session'
404:
$ref: '#/components/responses/NotFoundError'
put:
tags:
- Sessions
security: []
summary: Update a session
description: Update session details
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Session'
responses:
200:
description: Session updated
content:
application/json:
schema:
$ref: '#/components/schemas/Session'
400:
$ref: '#/components/responses/ValidationError'
404:
$ref: '#/components/responses/NotFoundError'
/internal/sessions/{id}/expire:
post:
tags:
- Sessions
security: []
summary: Expire session
description: Expire a session and optionally extend it
parameters:
- name: id
in: path
required: true
description: Session ID
schema:
type: integer
format: number
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 expired successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Session'
headers:
X-RateLimit-Limit:
schema:
type: integer
X-RateLimit-Remaining:
schema:
type: integer
X-RateLimit-Reset:
schema:
type: integer
400:
description: Session could not be expired
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
404:
$ref: '#/components/responses/NotFoundError'
429:
$ref: '#/components/responses/RateLimitError'
/sessions:
post:
tags:
- Sessions
security:
- ApiKeyAuth: []
summary: Create a new session
description: Create a new checkout session with product details and brand configuration.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- brandId
- brandVersion
- country
- currency
- timer
- payment
- cart
properties:
brandId:
type: integer
description: ID of the brand configuration to use for the session
brandVersion:
type: string
description: Version of the brand configuration
country:
$ref: '#/components/schemas/Country'
currency:
$ref: '#/components/schemas/Currency'
timer:
$ref: '#/components/schemas/Timer'
payment:
$ref: '#/components/schemas/Payment'
cart:
$ref: '#/components/schemas/Cart'
formsData:
type: object
description: Arbitrary form data for the session
expiresAt:
type: string
format: date-time
description: Expiry date/time for the session
responses:
201:
description: Session created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/SessionBrandResponse'
400:
$ref: '#/components/responses/ValidationError'
401:
$ref: '#/components/responses/UnauthorizedError'
/internal/brands/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: integer
description: Brand configuration ID
get:
tags:
- Brand
security: []
summary: Get a brand configuration by ID
description: Retrieve brand configuration details
responses:
200:
description: Brand configuration details
content:
application/json:
schema:
$ref: '#/components/schemas/BrandResponse'
404:
$ref: '#/components/responses/NotFoundError'
/internal/health:
get:
tags:
- Health
security: []
summary: Health check endpoint
description: Check the health status of the API and its dependencies
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
/recalculate-prices:
post:
tags:
- Sessions
summary: Recalculate prices when user modifies quantities or optional extras
description: Recalculate cart totals based on updated quantities and optional extras
operationId: recalculatePrices
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- currency
- cart
properties:
sessionId:
type: string
description: Session code (optional)
brandId:
type: integer
description: Brand ID (optional)
currency:
type: string
description: Currency code (e.g., 'USD')
cart:
type: object
required:
- products
properties:
products:
type: array
items:
type: object
properties:
productId:
type: string
description: Product identifier
optionId:
type: string
description: Option identifier (if applicable)
quantity:
type: integer
description: Quantity of the product
optionalExtras:
type: array
items:
type: object
properties:
id:
type: string
description: Optional extra identifier
quantity:
type: integer
description: Quantity of the optional extra
promoCode:
type: string
description: Promo code (optional)
responses:
200:
description: Prices recalculated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/RecalculatePricesResponse'
400:
$ref: '#/components/responses/ValidationError'
404:
$ref: '#/components/responses/NotFoundError'
500:
description: Server error during price recalculation
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment