Skip to content

Backend Core API Contract (OpenAPI-Style)

Contract Specification for Platform Core Internal API

Section titled “Contract Specification for Platform Core Internal API”

Audience: backend engineers, platform-admin backend engineers, Auth backend engineers, QA, DevOps, integrators
Status: contract specification
Scope: this document defines the API contract for Platform Core. It focuses on:

  • exact endpoints
  • methods
  • required headers
  • auth model
  • request parameters
  • request bodies
  • response bodies
  • error responses
  • examples
  • integration rules

This is the API contract companion to:


Platform Core is an internal-only backend service.

It is not intended for direct browser/frontend access.

Its main responsibilities are:

  • returning company commercial entitlements
  • returning catalog definitions (modules/packages/add-ons)
  • storing and updating package/add-on/subscription state
  • bumping entitlement versions for Auth cache invalidation

Platform Core is the commercial entitlement backend.

It is positioned in the runtime architecture as follows:

  • Auth Backend = identity, memberships, grants, permissions, delegation
  • Platform Core Backend = packages, add-ons, subscriptions, company entitlements
  • Base / Module Backends = business logic and enforcement
  • Frontend = consumes resolved access for UX, but is not the source of truth

Platform Core does not compute final user access.

The main access rule remains:

effective_access = company_entitlements ∩ membership_grants

Where:

  • company_entitlements come from Platform Core
  • membership_grants come from Auth
  • final effective_access is computed by Auth

Platform Core must not be used by frontend or business backends as a replacement for Auth when making user-level access decisions.

Platform Core only answers:

What does this company commercially own right now?

It does not answer:

  • whether a specific user can use a module
  • whether a specific permission is granted
  • whether a specific actor can delegate access

Frontend should not call Platform Core directly

Section titled “Frontend should not call Platform Core directly”

Frontend should normally call:

  • Auth Backend
  • Base Backend
  • module backends
  • admin backend (where applicable)

Frontend should not call Platform Core directly to determine access.

The primary caller of Platform Core is:

  • Auth Backend

Especially for:

  • GET /auth/me/access
  • company-switch access refresh
  • access recomputation after entitlement changes

Allowed secondary callers:

  • Platform Admin Backend
  • approved internal jobs/services

Business backends such as Base / Finance / Market / Touring / Venue / AI should not call Platform Core to compute final user authorization.

If a business backend needs user-level authorization, it must use Auth-resolved access context, not Core entitlements directly.

Frontend
-> Auth
-> Auth DB
-> Platform Core
<- resolved access result

This keeps Auth as the access aggregation layer and keeps Core focused on commercial entitlement truth.


To avoid confusion across teams, use these terms consistently:

  • Basic Package → commercial product / subscription concept
  • Core App → the frontend/base application experience
  • Basic Backend → business backend for core platform features
  • Platform Core Backend → commercial entitlement backend

This avoids mixing:

  • Basic Package
  • Basic Backend
  • Platform Core Backend

which are not the same thing.


https://core.kisum.io

All routes in this spec are internal routes.

Allowed callers:

  • Auth Backend
  • Platform Admin Backend
  • approved internal jobs/services

Not allowed:

  • public frontend
  • public mobile apps
  • arbitrary public clients

Platform Core is an internal service in the middle of an access-resolution chain.

Typical runtime chain:

Frontend -> Auth -> Platform Core

or for admin changes:

Platform Admin UI -> Platform Admin Backend -> Platform Core

Business backends should not bypass Auth and use Core as a user-authorization oracle.


All request bodies use:

Content-Type: application/json

unless explicitly noted otherwise.

All successful responses return:

{
"success": true,
"data": {}
}

All error responses return:

{
"success": false,
"error": {
"code": "string_code",
"message": "Human readable message"
}
}

Common error codes used by Platform Core:

  • unauthorized
  • forbidden
  • validation_error
  • not_found
  • conflict
  • not_ready
  • internal_error
  • service_unavailable

All /internal/* routes must require internal service authentication.

Recommended first implementation:

X-Internal-API-Key: <secret>

Alternative future implementation:

Authorization: Bearer <internal-service-token>

If internal auth is missing or invalid:

  • return 401 unauthorized
  • do not expose data
  • do not leak internal routing details
{
"success": false,
"error": {
"code": "unauthorized",
"message": "missing or invalid internal credentials"
}
}

{
"id": "uuid",
"key": "finance",
"name": "Finance",
"type": "addon",
"description": "Finance module",
"isActive": true
}
  • id: UUID
  • key: canonical module key
  • name: display name
  • type: base or addon
  • description: optional description
  • isActive: boolean

{
"id": "uuid",
"key": "basic",
"name": "Basic",
"description": "Basic subscription that enables Core App",
"isActive": true,
"modules": ["basic"]
}
  • id
  • key
  • name
  • description
  • isActive
  • modules: array of module keys currently mapped to this package

{
"id": "uuid",
"key": "finance",
"name": "Finance",
"description": "Finance add-on",
"isActive": true,
"modules": ["finance"]
}

{
"key": "finance",
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z"
}

{
"companyId": "cmp_001",
"hasBasic": true,
"basePackage": "basic",
"addons": [
{
"key": "finance",
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z"
}
],
"enabledModules": ["basic", "finance"],
"entitlementVersion": 8,
"updatedAt": "2026-04-16T05:00:00Z"
}

{
"id": "uuid",
"changeType": "addon_activated",
"entityType": "addon",
"entityKey": "finance",
"previousStatus": "inactive",
"newStatus": "active",
"source": "platform_admin",
"changedBy": "admin_user_uuid",
"createdAt": "2026-04-16T05:00:00Z"
}

Simple liveness probe.

No internal auth required, unless your infra policy requires all routes behind private network anyway.

{
"success": true,
"data": {
"status": "ok"
}
}

Readiness probe.

Must verify:

  • Core DB reachable
  • required config loaded
  • service initialized
{
"success": true,
"data": {
"status": "ready"
}
}
{
"success": false,
"error": {
"code": "not_ready",
"message": "core database unavailable"
}
}

Return full module catalog.

Internal auth required.

  • Platform Admin Backend
  • Auth Backend (optional)
  • internal jobs

None.

{
"success": true,
"data": {
"modules": [
{
"id": "11111111-1111-1111-1111-111111111111",
"key": "basic",
"name": "Core App",
"type": "base",
"description": "Core App / Basic product module",
"isActive": true
},
{
"id": "22222222-2222-2222-2222-222222222222",
"key": "finance",
"name": "Finance",
"type": "addon",
"description": "Finance module",
"isActive": true
}
]
}
}
  • 401 unauthorized
  • 500 internal_error

Return full package catalog.

Internal auth required.

{
"success": true,
"data": {
"packages": [
{
"id": "33333333-3333-3333-3333-333333333333",
"key": "basic",
"name": "Basic",
"description": "Basic subscription that enables Core App",
"isActive": true,
"modules": ["basic"]
}
]
}
}
  • 401 unauthorized
  • 500 internal_error

Return full add-on catalog.

Internal auth required.

{
"success": true,
"data": {
"addons": [
{
"id": "44444444-4444-4444-4444-444444444444",
"key": "finance",
"name": "Finance",
"description": "Finance add-on",
"isActive": true,
"modules": ["finance"]
},
{
"id": "55555555-5555-5555-5555-555555555555",
"key": "market",
"name": "Market",
"description": "Market add-on",
"isActive": true,
"modules": ["market"]
}
]
}
}
  • 401 unauthorized
  • 500 internal_error

7.1 GET /internal/companies/{companyId}/entitlements

Section titled “7.1 GET /internal/companies/{companyId}/entitlements”

Return the current normalized commercial entitlement state for one company.

Auth Backend, during /auth/me/access.

This endpoint returns company commercial entitlement state only.

It is intentionally designed for Auth to consume and merge with membership grants.

It must not be treated as a user-access endpoint by callers.

Internal auth required.

  • Auth Backend
  • Platform Admin Backend
  • internal jobs
  • companyId — required UUID
  • companyId must be valid UUID
  • if company has no active Basic and no active add-ons, response still succeeds with empty entitlement state
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"hasBasic": false,
"basePackage": null,
"addons": [
{
"key": "finance",
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z"
},
{
"key": "market",
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z"
}
],
"enabledModules": ["finance", "market"],
"entitlementVersion": 7,
"updatedAt": "2026-04-16T05:00:00Z"
}
}
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"hasBasic": true,
"basePackage": "basic",
"addons": [
{
"key": "finance",
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z"
}
],
"enabledModules": ["basic", "finance"],
"entitlementVersion": 8,
"updatedAt": "2026-04-16T05:00:00Z"
}
}
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"hasBasic": false,
"basePackage": null,
"addons": [],
"enabledModules": [],
"entitlementVersion": 1,
"updatedAt": "2026-04-16T05:00:00Z"
}
}
{
"success": false,
"error": {
"code": "validation_error",
"message": "invalid companyId"
}
}
{
"success": false,
"error": {
"code": "unauthorized",
"message": "missing or invalid internal credentials"
}
}

Use only if your system requires company existence to be pre-validated in Core.

{
"success": false,
"error": {
"code": "not_found",
"message": "company not found"
}
}
{
"success": false,
"error": {
"code": "internal_error",
"message": "failed to load entitlements"
}
}

7.2 GET /internal/companies/{companyId}/subscription-summary

Section titled “7.2 GET /internal/companies/{companyId}/subscription-summary”

Return admin-friendly company subscription summary.

Internal auth required.

  • Platform Admin Backend
  • internal jobs
  • Auth Backend (optional)
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"hasBasic": true,
"basePackage": "basic",
"addons": ["finance", "market"],
"status": "active",
"entitlementVersion": 7
}
}
  • status here is summary-level, not intended to replace detailed addon/package statuses
  • useful for admin dashboards and company overview pages

7.3 GET /internal/companies/{companyId}/history

Section titled “7.3 GET /internal/companies/{companyId}/history”

Return entitlement history for a company.

Internal auth required.

  • Platform Admin Backend
  • internal audit/reporting jobs
  • limit
  • offset
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"history": [
{
"id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"changeType": "addon_activated",
"entityType": "addon",
"entityKey": "finance",
"previousStatus": "inactive",
"newStatus": "active",
"source": "platform_admin",
"changedBy": "admin_user_uuid",
"createdAt": "2026-04-16T05:00:00Z"
}
]
}
}

These are usually called by the Platform Admin Backend, not directly from UI.

Create a new module catalog entry.

Internal auth required.

  • Platform Admin Backend only
{
"key": "finance",
"name": "Finance",
"type": "addon",
"description": "Finance module",
"isActive": true
}
  • key required
  • key unique
  • key lowercase slug recommended
  • name required
  • type required and must be base or addon
{
"success": true,
"data": {
"id": "22222222-2222-2222-2222-222222222222",
"key": "finance",
"name": "Finance",
"type": "addon",
"description": "Finance module",
"isActive": true
}
}
{
"success": false,
"error": {
"code": "conflict",
"message": "module key already exists"
}
}

8.2 PATCH /internal/catalog/modules/{moduleId}

Section titled “8.2 PATCH /internal/catalog/modules/{moduleId}”

Update existing module metadata.

Internal auth required.

  • moduleId — required UUID

All fields optional, but at least one required:

{
"name": "Finance",
"description": "Finance module updated",
"isActive": true
}
  • key should be immutable after creation in first version
  • patch should update updated_at
{
"success": true,
"data": {
"id": "22222222-2222-2222-2222-222222222222",
"key": "finance",
"name": "Finance",
"type": "addon",
"description": "Finance module updated",
"isActive": true
}
}

Create a new package.

Internal auth required.

{
"key": "basic",
"name": "Basic",
"description": "Basic subscription that enables Core App",
"isActive": true,
"moduleKeys": ["basic"]
}
  • key unique
  • moduleKeys must all exist in modules
  • package may map to one or more modules
{
"success": true,
"data": {
"id": "33333333-3333-3333-3333-333333333333",
"key": "basic",
"name": "Basic",
"description": "Basic subscription that enables Core App",
"isActive": true,
"modules": ["basic"]
}
}

8.4 PATCH /internal/catalog/packages/{packageId}

Section titled “8.4 PATCH /internal/catalog/packages/{packageId}”

Update package metadata and/or mapping.

  • packageId — UUID
{
"name": "Basic",
"description": "Updated Basic description",
"isActive": true,
"moduleKeys": ["basic"]
}
  • if moduleKeys is present, replace package mapping set with provided keys
  • mapping updates may require entitlement-version impact handling for active companies
{
"success": true,
"data": {
"id": "33333333-3333-3333-3333-333333333333",
"key": "basic",
"name": "Basic",
"description": "Updated Basic description",
"isActive": true,
"modules": ["basic"]
}
}

Create a new add-on.

{
"key": "finance",
"name": "Finance",
"description": "Finance add-on",
"isActive": true,
"moduleKeys": ["finance"]
}
{
"success": true,
"data": {
"id": "44444444-4444-4444-4444-444444444444",
"key": "finance",
"name": "Finance",
"description": "Finance add-on",
"isActive": true,
"modules": ["finance"]
}
}

8.6 PATCH /internal/catalog/addons/{addonId}

Section titled “8.6 PATCH /internal/catalog/addons/{addonId}”

Update add-on metadata and/or mapping.

  • addonId — UUID
{
"name": "Finance",
"description": "Finance updated",
"isActive": true,
"moduleKeys": ["finance"]
}
{
"success": true,
"data": {
"id": "44444444-4444-4444-4444-444444444444",
"key": "finance",
"name": "Finance",
"description": "Finance updated",
"isActive": true,
"modules": ["finance"]
}
}

9.1 POST /internal/companies/{companyId}/basic

Section titled “9.1 POST /internal/companies/{companyId}/basic”

Create or update Basic subscription state for a company.

Internal auth required.

  • Platform Admin Backend
  • optional billing/reconciliation jobs
  • companyId — UUID
{
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z",
"source": "platform_admin",
"externalReference": "sub_123"
}
  • active
  • inactive
  • cancelled
  • expired
  • trial
  • paused
  • resolve package basic
  • upsert company_subscriptions
  • bump entitlementVersion
  • write entitlement history
  • return normalized summary
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"hasBasic": true,
"basePackage": "basic",
"entitlementVersion": 8
}
}
{
"status": "inactive",
"source": "platform_admin"
}

9.2 POST /internal/companies/{companyId}/addons

Section titled “9.2 POST /internal/companies/{companyId}/addons”

Create or update add-on state for one company/add-on pair.

Internal auth required.

  • Platform Admin Backend
  • optional billing/reconciliation jobs
  • companyId — UUID
{
"addonKey": "finance",
"status": "active",
"startsAt": "2026-04-16T00:00:00Z",
"endsAt": "2026-05-16T00:00:00Z",
"source": "platform_admin",
"externalReference": "addon_sub_123"
}
  • resolve addon by addonKey
  • upsert company_addons
  • bump entitlementVersion
  • write entitlement history
  • return normalized addon result
{
"success": true,
"data": {
"companyId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"addonKey": "finance",
"status": "active",
"entitlementVersion": 9
}
}
{
"addonKey": "finance",
"status": "inactive",
"source": "platform_admin"
}
{
"success": false,
"error": {
"code": "validation_error",
"message": "addonKey is required"
}
}
{
"success": false,
"error": {
"code": "not_found",
"message": "addon not found"
}
}

Core returns entitlementVersion in all company entitlement responses.

Core must bump entitlementVersion when:

  • Basic activated
  • Basic deactivated
  • Basic expired
  • add-on activated
  • add-on deactivated
  • add-on expired
  • package mapping changed in a way affecting active companies
  • add-on mapping changed in a way affecting active companies
  • manual entitlement repair

Auth will use:

access:{companyId}:{membershipId}:{accessVersion}:{entitlementVersion}

or equivalent cache strategy.

Core does not manage Auth cache directly via this API contract.
But Core must always return the correct current version.


All timestamps are ISO-8601 UTC strings, example:

2026-04-16T05:00:00Z
  • basePackage may be null
  • startsAt / endsAt may be null
  • arrays should be empty arrays, not null, unless there is a strong reason otherwise

Responses must be normalized and not leak DB implementation details.

{
"addons": [
{ "key": "finance", "status": "active" }
]
}
{
"addons": [
{ "addon_id": "uuid", "company_addon_status": "A" }
]
}

StatusMeaning
200Successful read/update
201Successful creation
400Validation error
401Missing/invalid internal auth
403Authenticated internal caller but not allowed
404Resource not found
409Conflict
500Internal server error
503Dependency not ready / service unavailable

  1. Frontend calls /auth/me/access
  2. Auth loads user grants from Auth DB
  3. Auth calls:
    • GET /internal/companies/{companyId}/entitlements
  4. Core returns normalized company entitlements
  5. Auth merges:
    • entitlements ∩ membership grants
  6. Auth returns effective access to frontend
  1. Platform Admin UI calls Admin Backend
  2. Admin Backend validates platform-admin access
  3. Admin Backend calls Core internal catalog write endpoint
  4. Core writes DB rows and mapping rows
  5. Core returns normalized object
  1. Platform Admin UI calls Admin Backend
  2. Admin Backend validates admin rights
  3. Admin Backend calls POST /internal/companies/{companyId}/basic or /addons
  4. Core updates state
  5. Core bumps version
  6. Auth cache becomes stale and must rebuild on next access resolution

QA should validate at minimum:

  • GET /health
  • GET /ready
  • unauthorized internal call returns 401
  • module/package/addon reads return normalized arrays
  • company with no Basic but active addon returns valid entitlements
  • company with Basic + addon returns both in enabled modules
  • activating/deactivating Basic bumps entitlementVersion
  • activating/deactivating addon bumps entitlementVersion
  • patching catalog records preserves immutable keys
  • invalid UUID returns validation error
  • unknown addon/module/package returns not found where appropriate

This contract defines how internal services interact with Platform Core.
Core exposes catalog APIs and company entitlement APIs.
Auth reads company entitlements from Core.
Platform Admin writes company commercial state into Core.
Core returns normalized enabled modules and entitlementVersion.
Core does not return user permissions, roles, or grants.
Frontend should not call Core directly for access decisions.
Business backends should not use Core as a user-authorization service.

16. Access model layers (REFERENCE — DO NOT IMPLEMENT HERE)

Section titled “16. Access model layers (REFERENCE — DO NOT IMPLEMENT HERE)”

Platform Core participates in a 3-layer access model but only owns Level 1.

Level 1 — Company entitlements (OWNED BY CORE)

Section titled “Level 1 — Company entitlements (OWNED BY CORE)”

Defines what the company has purchased:

  • Basic
  • Finance
  • Market
  • Touring
  • Venue
  • AI

Source of truth: Platform Core DB


Level 2 — Membership module grants (OWNED BY AUTH)

Section titled “Level 2 — Membership module grants (OWNED BY AUTH)”

Defines which modules a user can access. Core MUST NOT store or evaluate this.


Defines actions inside modules. Core MUST NOT store or evaluate this.


Core returns entitlements ONLY
Core never computes user access

Platform Core is a dependency of Auth.

Auth → Core → Auth → Frontend

Core:

  • returns company entitlements
  • returns enabled modules
  • returns entitlementVersion

Auth:

  • merges entitlements with user grants
  • computes effective access
  • returns final access model

Core must NEVER:

  • return user-level access
  • validate permissions
  • validate roles
  • decide if a request is allowed

Core MUST NOT implement:

effective_access = entitlements ∩ grants

This logic belongs ONLY to Auth.


19. Delegation awareness (READ-ONLY CONTEXT)

Section titled “19. Delegation awareness (READ-ONLY CONTEXT)”

Core is aware that delegation exists, but:

  • does not enforce delegation
  • does not validate delegation
  • does not store delegation rules

Delegation is owned by Auth.


Frontend must NOT call Platform Core directly for access.

Allowed frontend calls:

  • Auth
  • Base backend
  • module backends
  • admin backend

Business backends must NOT:

  • call Core for user access decisions
  • use Core as authorization service

They must rely on:

Auth → /auth/me/access

Core = commercial truth
Auth = access truth
Backend = enforcement
Frontend = UX only