Backend Admin API Contract
Related documentation: Backend Admin · Backend Core · Backend Core API · Backend Auth · Admin Platform Spec
Detailed Target Contract for Platform Admin API
Section titled “Detailed Target Contract for Platform Admin API”Audience: backend engineers, frontend engineers, QA, product, operations
Status: docs-first target contract with runtime notes
Scope: this page describes the intended Admin API surface for the new system. It is more important than the legacy runtime shape when the two differ, but implemented runtime route families are called out where they already exist.
Important reading rule
Section titled “Important reading rule”This page is the target Admin contract.
- some of these endpoints do not exist yet in the current
Backend-Kisum-Admin - some currently existing Admin endpoints are legacy and are not the final shape
- where an endpoint is described below, its job is to provide the staff-facing control-plane surface, while Core or Auth remains the source of truth underneath
- current runtime exception:
Backend-Kisum-Adminnow also proxies Market directory routes under/api/v1/admin/artists-directory/*
Base rules
Section titled “Base rules”- Base path:
/api/v1/admin - Auth:
Authorization: Bearer <access_token> - Caller must be platform staff
- Admin orchestrates
- Core stores company/commercial truth
- Auth stores identity/access truth
- Market stores artists-directory truth for artists, market companies, people, taxonomy, and related directory relations
Namespace boundary
Section titled “Namespace boundary”/api/v1/admin/companiesis reserved for Core tenant-company control-plane operations./api/v1/admin/artists-directory/companiesis the Market directory-company namespace.- The same split applies conceptually to related people/contact directory endpoints.
1. Common response and request rules
Section titled “1. Common response and request rules”1.1 Request headers
Section titled “1.1 Request headers”All protected requests:
Authorization: Bearer <access_token>Content-Type: application/json1.2 Response shape
Section titled “1.2 Response shape”Recommended Admin response envelope:
{ "success": true, "data": {}}For lists:
{ "success": true, "data": { "items": [], "total": 0, "page": 1, "limit": 20 }}For errors:
{ "success": false, "error": { "code": "validation_error", "message": "Human-readable error message" }}1.3 Admin orchestration rule
Section titled “1.3 Admin orchestration rule”Every endpoint below should document three things:
- what the endpoint does for platform staff
- what backend truth it writes to
- what downstream effect should happen
2. Packages
Section titled “2. Packages”Packages are commercial catalog entities. Admin provides the staff-facing management surface, but Core stores the truth.
2.1 GET /api/v1/admin/packages
Section titled “2.1 GET /api/v1/admin/packages”Purpose
List packages for platform administrators.
Target
- read from Core package catalog
- display package metadata and mapped modules
Request body
- no body
Response shape
Admin returns the Core subscription-summary payload unchanged.
The response contains:
hasBasicbasePackageitemsentitlementVersion
items contains one row per active commercial assignment:
- one
packagerow when a base package is active - one
addonrow per active add-on
Each item includes:
idkeynamedescriptionstatusstartsAtendsAtpriceMinorcurrencybillingIntervaltaxCodetaxInclusivetrialDaysregionPricing
Important:
priceMinoris stored as a decimal amount- example:
199.00 USDis sent/stored as199.00
Example:
{ "success": true, "data": { "companyId": "fb8163f2-587f-4c7b-b5bc-628e7b121520", "hasBasic": true, "basePackage": "basic", "items": [ { "kind": "package", "id": "255db6d9-c9bc-4fff-a08f-b97f4906507e", "key": "basic", "name": "Basic", "description": "Basic subscription that enables the core application", "isActive": true, "status": "active", "startsAt": "2026-04-16T00:00:00Z", "endsAt": "2026-05-16T00:00:00Z", "priceMinor": 99.00, "currency": "USD", "billingInterval": "monthly", "taxCode": "digital_services", "taxInclusive": false, "trialDays": 14, "regionPricing": [], "entitlementKind": "package", "entitlementLabel": "Package" }, { "kind": "addon", "id": "b8c37dfb-d154-408a-a7e8-fbfab9ff6a2c", "key": "finance", "name": "Finance", "description": "Finance add-on", "isActive": true, "status": "active", "startsAt": "2026-04-16T00:00:00Z", "endsAt": "2026-05-16T00:00:00Z", "priceMinor": 49.00, "currency": "USD", "billingInterval": "monthly", "taxCode": "digital_services", "taxInclusive": false, "trialDays": 7, "regionPricing": [], "entitlementKind": "addon", "entitlementLabel": "Add-on" } ], "entitlementVersion": 7 }}2.2 POST /api/v1/admin/packages
Section titled “2.2 POST /api/v1/admin/packages”Purpose
Create a new commercial package from the Admin control plane.
Target
- create package in Core
- optionally map modules during creation
Body
{ "key": "basic", "name": "Basic", "description": "Basic subscription that enables the core application", "isActive": true, "priceMinor": 99.00, "currency": "USD", "billingInterval": "monthly", "taxCode": "digital_services", "taxInclusive": false, "trialDays": 14, "regionPricing": [ { "region": "SG", "currency": "SGD", "priceMinor": 129.00 } ], "moduleKeys": ["basic"]}Field meaning
key- stable package identifier used across systems
name- display name shown in admin UI and potentially billing flows
description- internal or UI-facing commercial description
isActive- whether the package can be assigned to companies
priceMinor- commercial price as a decimal amount, for example
199.00
- commercial price as a decimal amount, for example
currency- 3-letter currency code
billingInterval- one of
monthly,quarterly,yearly,one_time
- one of
taxCode- optional tax classification
taxInclusive- whether the stored price already includes tax
trialDays- free-trial duration in days
regionPricing- optional region-specific price overrides
moduleKeys- modules bundled in the package
2.3 GET /api/v1/admin/packages/{packageId}
Section titled “2.3 GET /api/v1/admin/packages/{packageId}”Purpose
Read one package in detail.
Target
- fetch package metadata and its module mappings from Core
Request body
- no body
2.4 PATCH /api/v1/admin/packages/{packageId}
Section titled “2.4 PATCH /api/v1/admin/packages/{packageId}”Purpose
Update a package without recreating it.
Target
- patch package metadata in Core
- optionally replace mapped modules
Body
{ "name": "Basic Plan", "description": "Updated basic plan description", "isActive": true, "priceMinor": 119.00, "currency": "USD", "billingInterval": "yearly", "trialDays": 30, "moduleKeys": ["basic", "finance"]}Important rule
- if
moduleKeysis omitted, package-module mappings should remain unchanged - if
moduleKeysis provided, it should replace the package’s module mapping set
2.5 PUT /api/v1/admin/packages/{packageId}/modules
Section titled “2.5 PUT /api/v1/admin/packages/{packageId}/modules”Purpose
Replace the module mapping for a package explicitly.
Target
- update package-module relationships in Core
Body
{ "moduleKeys": ["basic", "finance", "venue"]}2.6 DELETE /api/v1/admin/packages/{packageId}
Section titled “2.6 DELETE /api/v1/admin/packages/{packageId}”Purpose
Delete a package from the platform catalog.
Target
- delete package in Core
Important rule
- delete must fail when the package is already assigned to companies
3. Modules
Section titled “3. Modules”Modules represent commercial features/products in the platform catalog.
3.1 GET /api/v1/admin/modules
Section titled “3.1 GET /api/v1/admin/modules”Purpose
List the module catalog.
Target
- read module definitions from Core
Request body
- no body
3.2 POST /api/v1/admin/modules
Section titled “3.2 POST /api/v1/admin/modules”Purpose
Create a new module in the commercial catalog.
Target
- create module in Core
Body
{ "key": "finance", "name": "Finance", "type": "addon", "description": "Finance module", "isActive": true}Field meaning
key- stable identifier
name- display name
type- commercial/module grouping type
description- human-readable explanation of the module
isActive- whether the module may be used in active catalog configurations
3.3 GET /api/v1/admin/modules/{moduleId}
Section titled “3.3 GET /api/v1/admin/modules/{moduleId}”Purpose
Get one module definition.
Request body
- no body
3.4 PATCH /api/v1/admin/modules/{moduleId}
Section titled “3.4 PATCH /api/v1/admin/modules/{moduleId}”Purpose
Update module metadata or lifecycle state.
Target
- patch module metadata in Core
Body
{ "name": "Finance Module", "description": "Updated finance module description", "isActive": true}3.5 DELETE /api/v1/admin/modules/{moduleId}
Section titled “3.5 DELETE /api/v1/admin/modules/{moduleId}”Purpose
Delete a module from the commercial catalog.
Target
- delete module in Core
Important rule
- delete must fail when the module is still linked to packages or add-ons
4. Add-ons
Section titled “4. Add-ons”Add-ons are commercial catalog entities sold or assigned on top of packages.
4.1 GET /api/v1/admin/addons
Section titled “4.1 GET /api/v1/admin/addons”Purpose
List add-ons available in the platform catalog.
Request body
- no body
4.2 POST /api/v1/admin/addons
Section titled “4.2 POST /api/v1/admin/addons”Purpose
Create an add-on.
Target
- create add-on in Core
- optionally map modules during creation
Body
{ "key": "finance", "name": "Finance", "description": "Finance add-on", "isActive": true, "priceMinor": 49.00, "currency": "USD", "billingInterval": "monthly", "taxCode": "digital_services", "taxInclusive": false, "trialDays": 7, "moduleKeys": ["finance"]}Important rule
- add-ons may only map modules whose module
typeisaddon
4.3 GET /api/v1/admin/addons/{addonId}
Section titled “4.3 GET /api/v1/admin/addons/{addonId}”Purpose
Get one add-on in detail.
Request body
- no body
4.4 PATCH /api/v1/admin/addons/{addonId}
Section titled “4.4 PATCH /api/v1/admin/addons/{addonId}”Purpose
Update add-on metadata and optionally its module mappings.
Body
{ "name": "Finance Add-on", "description": "Updated finance add-on description", "isActive": true, "priceMinor": 59.00, "currency": "USD", "billingInterval": "yearly", "moduleKeys": ["finance"]}4.5 PUT /api/v1/admin/addons/{addonId}/modules
Section titled “4.5 PUT /api/v1/admin/addons/{addonId}/modules”Purpose
Replace the mapped modules for an add-on.
Body
{ "moduleKeys": ["finance", "market"]}4.6 DELETE /api/v1/admin/addons/{addonId}
Section titled “4.6 DELETE /api/v1/admin/addons/{addonId}”Purpose
Delete an add-on from the platform catalog.
Target
- delete add-on in Core
Important rule
- delete must fail when the add-on is already assigned to companies
5. Companies
Section titled “5. Companies”Company operations are initiated by Admin but stored in Core.
5.1 GET /api/v1/admin/companies
Section titled “5.1 GET /api/v1/admin/companies”Purpose
List companies from the platform control plane.
Target
- list company records from Core
- may aggregate profile and address summaries for UI convenience
Request body
- no body
5.2 POST /api/v1/admin/companies
Section titled “5.2 POST /api/v1/admin/companies”Purpose
Create a company through the Admin control plane.
Target
- write company master/profile/address/social/document structure into Core
Body
{ "legalName": "Kisum Entertainment Group Pte Ltd", "displayName": "Kisum Entertainment Group", "status": "active", "createdSource": "admin", "metadata": { "region": "SG" }, "profile": { "website": "https://group.kisum.dev", "email": "group@kisum.dev", "phone": "+65 6999 8888", "timezone": "Asia/Singapore", "industry": "Entertainment", "description": "Regional artist management and touring group", "metadata": { "preferredLanguage": "en" } }, "addresses": [ { "type": "primary", "line1": "120 Orchard Road", "line2": "Level 15", "city": "Singapore", "state": "Singapore", "postalCode": "238888", "country": "Singapore", "isPrimary": true } ], "socialLinks": [ { "platform": "instagram", "label": "Official Instagram", "url": "https://instagram.com/kisumgroup" } ], "documents": [ { "type": "business_registration", "name": "Business Registration Certificate", "storageKey": "companies/company-id/business-registration.pdf", "url": "https://files.kisum.dev/companies/company-id/business-registration.pdf", "mimeType": "application/pdf", "sizeBytes": 251004, "metadata": { "version": 1 } } ]}Target system
Core
Important rule
- Admin should not persist this company locally as source of truth
5.3 GET /api/v1/admin/companies/{companyId}
Section titled “5.3 GET /api/v1/admin/companies/{companyId}”Purpose
Get one company in detail.
Target
- read company bundle from Core
Request body
- no body
5.4 PATCH /api/v1/admin/companies/{companyId}
Section titled “5.4 PATCH /api/v1/admin/companies/{companyId}”Purpose
Update a company from Admin.
Target
- patch company master and optional nested sections in Core
Body
{ "displayName": "Kisum Entertainment Group", "status": "active", "metadata": { "region": "SG", "tier": "enterprise" }, "profile": { "website": "https://group.kisum.dev", "email": "group@kisum.dev", "phone": "+65 6999 8888", "timezone": "Asia/Singapore", "industry": "Entertainment", "description": "Regional artist management and touring group", "metadata": { "preferredLanguage": "en" } }, "addresses": [ { "id": "0f4de9f7-6f87-4f8c-8209-7480ac8d2374", "type": "primary", "line1": "120 Orchard Road", "line2": "Level 15", "city": "Singapore", "state": "Singapore", "postalCode": "238888", "country": "Singapore", "isPrimary": true } ], "socialLinks": [ { "id": "2c2f57c9-cce0-4a6e-8dc9-cf2d2e4e86c7", "platform": "instagram", "label": "Official Instagram", "url": "https://instagram.com/kisumgroup" } ], "documents": [ { "id": "698c5ef5-1c93-4d8f-b644-80d7d3a75af0", "type": "business_registration", "name": "Updated Business Registration Certificate", "storageKey": "companies/company-id/business-registration-v2.pdf", "url": "https://files.kisum.dev/companies/company-id/business-registration-v2.pdf", "mimeType": "application/pdf", "sizeBytes": 251004, "metadata": { "version": 2 } } ]}Important partial-update rule
- omitted collection keys mean no change
- empty collection arrays mean replace with empty set
5.5 POST /api/v1/admin/companies/{companyId}/approve
Section titled “5.5 POST /api/v1/admin/companies/{companyId}/approve”Purpose
Approve company onboarding or company activation from an admin review workflow.
Target
- update company lifecycle status in Core
- optionally trigger follow-up flows such as invitation activation or onboarding continuation
Body
{ "reason": "Company review completed and approved", "activate": true}5.6 POST /api/v1/admin/companies/{companyId}/reject
Section titled “5.6 POST /api/v1/admin/companies/{companyId}/reject”Purpose
Reject company onboarding.
Target
- write rejection status and reason
- ensure downstream UI sees the company as rejected or blocked
Body
{ "reason": "Missing required registration documentation"}5.7 POST /api/v1/admin/companies/{companyId}/activate
Section titled “5.7 POST /api/v1/admin/companies/{companyId}/activate”Purpose
Activate a company that is already known to the platform.
Body
{ "reason": "Commercial account activated by platform admin"}5.8 POST /api/v1/admin/companies/{companyId}/deactivate
Section titled “5.8 POST /api/v1/admin/companies/{companyId}/deactivate”Purpose
Deactivate a company.
Body
{ "reason": "Compliance hold"}6. Company commercial management
Section titled “6. Company commercial management”These endpoints are staff-facing wrappers around Core commercial operations.
6.1 GET /api/v1/admin/companies/{companyId}/subscription
Section titled “6.1 GET /api/v1/admin/companies/{companyId}/subscription”Purpose
Read the current company subscription summary.
Target
- read from Core subscription-summary view
Request body
- no body
6.2 POST /api/v1/admin/companies/{companyId}/package
Section titled “6.2 POST /api/v1/admin/companies/{companyId}/package”Purpose
Assign or change the base package for a company.
Target
- write to Core package/subscription assignment flow
Body
{ "packageKey": "basic", "status": "active", "startsAt": "2026-04-19T00:00:00Z", "endsAt": "2026-05-19T00:00:00Z", "source": "platform_admin", "externalReference": "stripe_sub_123"}6.3 POST /api/v1/admin/companies/{companyId}/addons
Section titled “6.3 POST /api/v1/admin/companies/{companyId}/addons”Purpose
Add an add-on to a company.
Target
- write to Core company add-on assignment flow
Body
{ "addonKey": "finance", "status": "active", "startsAt": "2026-04-19T00:00:00Z", "endsAt": "2026-05-19T00:00:00Z", "source": "platform_admin", "externalReference": "stripe_addon_finance_123"}Admin also accepts:
{ "addonId": "b8c37dfb-d154-408a-a7e8-fbfab9ff6a2c", "status": "active"}When addonId is sent, Admin resolves the catalog add-on id to the Core addonKey before calling Core.
6.4 DELETE /api/v1/admin/companies/{companyId}/addons/{addonId}
Section titled “6.4 DELETE /api/v1/admin/companies/{companyId}/addons/{addonId}”Purpose
Remove an add-on from a company.
Request body
- no body
Important
{addonId}must be the catalog add-on id from the subscriptionitems[]row- Admin resolves that id to the Core
addonKeybefore deactivating the company add-on
6.5 GET /api/v1/admin/companies/{companyId}/entitlements
Section titled “6.5 GET /api/v1/admin/companies/{companyId}/entitlements”Purpose
Inspect the resulting company entitlements.
Target
- read entitlement result from Core
Request body
- no body
6.6 GET /api/v1/admin/companies/{companyId}/history
Section titled “6.6 GET /api/v1/admin/companies/{companyId}/history”Purpose
Inspect commercial history for audit, support, or troubleshooting.
Target
- read from Core entitlement/subscription history
Request body
- no body
7. Delegation rules and access governance
Section titled “7. Delegation rules and access governance”These endpoints are staff-facing wrappers around Auth-side access governance.
7.1 GET /api/v1/admin/delegation-rules
Section titled “7.1 GET /api/v1/admin/delegation-rules”Purpose
List the current delegation rules used by Auth.
Target
- read from Auth delegation policy state
Request body
- no body
7.2 POST /api/v1/admin/delegation-rules
Section titled “7.2 POST /api/v1/admin/delegation-rules”Purpose
Create a new delegation rule set.
Target
- write delegation policy into Auth
Body
{ "role": "ADMIN", "grantableModules": ["basic", "finance"], "grantablePermissions": [ "finance.read", "finance.write", "users.manage" ], "canManageUsers": true, "canBuyAddons": false}7.3 PATCH /api/v1/admin/delegation-rules/{ruleId}
Section titled “7.3 PATCH /api/v1/admin/delegation-rules/{ruleId}”Purpose
Update delegation limits.
Target
- patch Auth-side delegation policy
Body
{ "grantableModules": ["basic"], "grantablePermissions": [ "finance.read" ], "canManageUsers": false, "canBuyAddons": false}8. Platform staff, users, and memberships
Section titled “8. Platform staff, users, and memberships”These routes should exist in Admin as the platform-staff control surface, even when the underlying source of truth is Auth.
8.0 Users vs memberships
Section titled “8.0 Users vs memberships”This distinction must be understood before implementing any Admin user-access screen.
A user is an identity
Section titled “A user is an identity”A user is the person/account record stored in Auth.
It answers identity-level questions such as:
- who is this person
- what is their email
- what is their full name
- are they active
- do they have a platform global role
- what sessions do they currently have
Typical user fields:
idemailfullNameisActiveglobalRoleapprovalStatus
A user exists independently of any company or business unit.
One user can exist even if they are not assigned to any tenant scope yet.
A membership is a scoped assignment
Section titled “A membership is a scoped assignment”A membership is the relationship between a user and an organizational scope.
That scope can be:
- a company
- a business unit
A membership answers access-level questions such as:
- is this user assigned to this company
- is this user assigned to this business unit
- what role do they have in that scope
- is that scoped assignment active
- which module grants apply in that scope
- which permission grants apply in that scope
- which delegation limits apply in that scope
Typical membership fields:
userIdcompanyId- optional
businessUnitId roleisActivemoduleGrantspermissionGrantsdelegation
One user can have many memberships
Section titled “One user can have many memberships”This is the core reason the two endpoint groups are different.
Example:
User- id: U1- email: marco@kisum.io
Company membership- user_id: U1- company_id: C1- role: ADMIN
Business-unit membership- user_id: U1- company_id: C1- business_unit_id: BU7- role: APPROVER
Business-unit membership- user_id: U1- company_id: C1- business_unit_id: BU9- role: MEMBERThis is still one user, but multiple scoped memberships.
When to use /users
Section titled “When to use /users”Use users endpoints when the screen is identity-centered.
That means the main question is:
- who are the people/accounts in the system
Use users endpoints for:
- global user directories
- platform-user directories
- user detail pages
- user activation/deactivation
- user context inspection
- session inspection
Examples:
GET /api/v1/admin/platform-usersGET /api/v1/admin/usersGET /api/v1/admin/platform-users/{userId}GET /api/v1/admin/platform-users/{userId}/context
When to use /memberships
Section titled “When to use /memberships”Use memberships endpoints when the screen is scope-assignment-centered.
That means the main question is:
- who belongs to this company or business unit, and with what scoped role/access
Use memberships endpoints for:
- company access administration
- business-unit access administration
- role assignment in tenant scopes
- module grant editing
- permission grant editing
- delegation configuration in tenant scopes
Examples:
GET /api/v1/admin/companies/{companyId}/membershipsPOST /api/v1/admin/companies/{companyId}/membershipsGET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/membershipsPOST /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
Why both /users and /memberships may appear in one screen
Section titled “Why both /users and /memberships may appear in one screen”Some Admin screens need both views at the same time.
Example:
- a company page may show
users- human directory view
- useful for search, contact, status, and profile inspection
- the same company page may also show
memberships- access administration view
- useful for role changes, grants, and delegation settings
So:
users= identity-oriented representationmemberships= access-oriented representation
Short rule
Section titled “Short rule”Use this rule during implementation:
user= who the person/account ismembership= what access assignment that person has in a specific scope
8.1 GET /api/v1/admin/platform-users
Section titled “8.1 GET /api/v1/admin/platform-users”Purpose
List users visible to platform staff.
Target
- read through Auth user-administration APIs
Request body
- no body
Typical query parameters
approvalStatusglobalRolelimitoffset
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/platform-users - Auth upstream:
GET /internal/users?globalRole=true - Auth mode: forwarded
Authorization: Bearer <token>
This route is for the platform-staff directory only.
8.1A GET /api/v1/admin/users
Section titled “8.1A GET /api/v1/admin/users”Purpose
List all non-platform users across the system, not filtered by company.
Target
- read tenant/non-platform users through Auth
Request body
- no body
Typical query parameters
approvalStatuslimitoffset
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/users - Auth upstream:
GET /internal/users?globalRole=false - Auth mode: forwarded
Authorization: Bearer <token>
Important rule
- this is the global tenant-user directory
- this is not limited to one company
- company-specific user views must use the company-scoped routes below
8.2 POST /api/v1/admin/platform-users
Section titled “8.2 POST /api/v1/admin/platform-users”Purpose
Create a user from Admin.
Target
- create user in Auth
Body
{ "email": "ops-admin@kisum.dev", "fullName": "Ops Admin", "password": "TemporaryPassword123!", "globalRole": "PLATFORM_ADMIN", "approvalStatus": "APPROVED", "isActive": true}Admin backend mapping
- Admin endpoint:
POST /api/v1/admin/platform-users - Auth upstream:
POST /internal/users - Auth mode: forwarded
Authorization: Bearer <token>
8.3 GET /api/v1/admin/platform-users/{userId}
Section titled “8.3 GET /api/v1/admin/platform-users/{userId}”Purpose
Get one user from the platform-admin perspective.
Target
- read user detail from Auth
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/platform-users/{userId} - Auth upstream:
GET /internal/users/{id} - Auth mode: forwarded
Authorization: Bearer <token>
8.4 PATCH /api/v1/admin/platform-users/{userId}
Section titled “8.4 PATCH /api/v1/admin/platform-users/{userId}”Purpose
Update a user from Admin.
Target
- patch user in Auth
Body
{ "fullName": "Updated Ops Admin", "globalRole": "PLATFORM_SUPERADMIN", "approvalStatus": "APPROVED", "isActive": true}Admin backend mapping
- Admin endpoint:
PATCH /api/v1/admin/platform-users/{userId} - Auth upstream:
PATCH /internal/users/{id} - Auth mode: forwarded
Authorization: Bearer <token>
8.5 DELETE /api/v1/admin/platform-users/{userId}
Section titled “8.5 DELETE /api/v1/admin/platform-users/{userId}”Purpose
Deactivate a user from Admin.
Target
- deactivate user in Auth
Request body
- no body
Admin backend mapping
- Admin endpoint:
DELETE /api/v1/admin/platform-users/{userId} - Auth upstream:
DELETE /internal/users/{id} - Auth mode: forwarded
Authorization: Bearer <token>
8.6 GET /api/v1/admin/platform-users/{userId}/context
Section titled “8.6 GET /api/v1/admin/platform-users/{userId}/context”Purpose
Read the full admin-visible user context, including memberships.
Target
- read Auth user-context output
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/platform-users/{userId}/context - Auth machine endpoint:
GET /internal/admin/users/{id}/context - Auth mode:
X-Internal-API-KeyusingAUTH_INTERNAL_API_KEY
8.7 POST /api/v1/admin/platform-users/{userId}/revoke-all
Section titled “8.7 POST /api/v1/admin/platform-users/{userId}/revoke-all”Purpose
Revoke all sessions for a user.
Target
- revoke sessions in Auth
Body
{}Admin backend mapping
- Admin endpoint:
POST /api/v1/admin/platform-users/{userId}/revoke-all - Auth machine endpoint:
POST /internal/admin/users/{id}/revoke-all - Auth mode:
X-Internal-API-KeyusingAUTH_INTERNAL_API_KEY
8.8 POST /api/v1/admin/platform-users/invitations
Section titled “8.8 POST /api/v1/admin/platform-users/invitations”Purpose
Invite a new platform staff user.
Target
- create invitation in Auth
- optionally trigger invitation email flow
Body
{ "email": "ops-admin@kisum.dev", "globalRole": "PLATFORM_ADMIN", "name": "Ops Admin"}Current implementation note
Platform-user invitations still require a dedicated Auth-backed implementation contract. If that upstream invitation path is not present in the running Auth deployment, Admin must treat this action as unavailable rather than inventing a separate endpoint.
8.8A GET /api/v1/admin/sessions
Section titled “8.8A GET /api/v1/admin/sessions”Purpose
List active sessions across the platform-admin scope.
Target
- read active-session data from Auth
- support “who is currently connected” views in Admin
- support operational filtering by user, company, approval status, and platform-vs-tenant scope
Request body
- no body
Typical query parameters
approvalStatusglobalRoleuserIdcompanyIdlimitoffset
Query behavior
approvalStatus- optional
- when omitted, no approval-status filtering is applied
- when provided, must match the Auth approval-status enum exactly
globalRole- optional
truemeans platform users onlyfalsemeans tenant users only- a comma-separated role list can also be used for explicit role filtering
userId- optional UUID
- when provided, restricts the result to sessions for a single user
companyId- optional UUID
- when provided, returns sessions for users who currently have an active membership in that company
limit- default
50 - upper bounded by Auth validation
- default
offset- default
0
- default
Definition
A session is considered active when all of the following are true:
is_revoked = falseexpires_at > now()- the user row still exists
This route represents authenticated active-session presence, not websocket-style realtime presence.
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/sessions - Auth machine endpoint:
GET /internal/admin/sessions - Auth mode:
X-Internal-API-KeyusingAUTH_INTERNAL_API_KEY
Response shape
{ "success": true, "data": [ { "sessionId": "8b4d1c3a-1a9e-4e93-b71f-9d8d8d7a7e90", "userId": "9e280dc5-c1cf-4d62-bad9-0774e4a3b9e1", "email": "ops-admin@kisum.dev", "fullName": "Ops Admin", "globalRole": "PLATFORM_ADMIN", "approvalStatus": "APPROVED", "isUserActive": true, "ipAddress": "103.21.244.1", "userAgent": "Mozilla/5.0 ...", "deviceName": "Chrome on macOS", "createdAt": "2026-04-19T02:00:00Z", "lastUsedAt": "2026-04-19T08:41:00Z", "expiresAt": "2026-05-19T02:00:00Z" } ]}Operational use
This route should back:
- connected-user dashboards
- fraud or security review
- support diagnostics
- company-scoped activity checks
8.8B GET /api/v1/admin/session-stats
Section titled “8.8B GET /api/v1/admin/session-stats”Purpose
Return aggregate counts for active sessions and connected users.
Target
- power dashboard counters
- separate platform-user activity from tenant-user activity
Request body
- no body
Typical query parameters
approvalStatusglobalRoleuserIdcompanyId
These filters use the same semantics as GET /api/v1/admin/sessions, but return counts instead of individual session rows.
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/session-stats - Auth machine endpoint:
GET /internal/admin/session-stats - Auth mode:
X-Internal-API-KeyusingAUTH_INTERNAL_API_KEY
Response shape
{ "success": true, "data": { "activeSessions": 124, "connectedUsers": 87, "platformUsersConnected": 6, "tenantUsersConnected": 81 }}Meaning of each field
activeSessions- total number of active session records matching the filter
connectedUsers- distinct users with at least one active session
platformUsersConnected- distinct connected users whose
globalRoleis one of the platform roles
- distinct connected users whose
tenantUsersConnected- distinct connected users whose
globalRoleisNONE
- distinct connected users whose
8.8C GET /api/v1/admin/companies/{companyId}/sessions
Section titled “8.8C GET /api/v1/admin/companies/{companyId}/sessions”Purpose
List active sessions for users belonging to one company.
Target
- inspect company-scoped user activity
- support approval, security, and support operations for one tenant
Request body
- no body
Typical query parameters
limitoffset
Behavior
- this route is scoped by the company in the path
- Auth returns sessions for users who currently have an active membership in that company
- this is the company-scoped alternative to the global session list
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/companies/{companyId}/sessions - Auth machine endpoint:
GET /internal/admin/companies/{companyId}/sessions - Auth mode:
X-Internal-API-KeyusingAUTH_INTERNAL_API_KEY
Response shape
{ "success": true, "data": [ { "sessionId": "8b4d1c3a-1a9e-4e93-b71f-9d8d8d7a7e90", "userId": "9e280dc5-c1cf-4d62-bad9-0774e4a3b9e1", "email": "finance-user@kisum.dev", "fullName": "Finance User", "globalRole": "NONE", "approvalStatus": "APPROVED", "isUserActive": true, "ipAddress": "103.21.244.1", "userAgent": "Mozilla/5.0 ...", "deviceName": "Chrome on macOS", "createdAt": "2026-04-19T02:00:00Z", "lastUsedAt": "2026-04-19T08:41:00Z", "expiresAt": "2026-05-19T02:00:00Z" } ]}8.9 GET /api/v1/admin/companies/{companyId}/users
Section titled “8.9 GET /api/v1/admin/companies/{companyId}/users”Purpose
List company users from the platform-admin view.
Target
- read through Auth company memberships
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/companies/{companyId}/users - Auth upstream:
GET /internal/companies/{companyId}/users - Auth mode: forwarded
Authorization: Bearer <token>
8.10 POST /api/v1/admin/companies/{companyId}/memberships
Section titled “8.10 POST /api/v1/admin/companies/{companyId}/memberships”Purpose
Create or update a company membership from Admin.
Target
- write company membership in Auth
- write module grants in Auth
- write permission grants in Auth
- write delegation constraints in Auth
Body
{ "userId": "9e280dc5-c1cf-4d62-bad9-0774e4a3b9e1", "role": "ADMIN", "status": "ACTIVE", "moduleGrants": ["basic", "finance"], "permissionGrants": [ "finance.read", "finance.write", "users.manage" ], "delegation": { "grantableModules": ["basic"], "grantablePermissions": ["finance.read"], "canManageUsers": false, "canBuyAddons": false }}Admin backend mapping
- Admin endpoint:
POST /api/v1/admin/companies/{companyId}/memberships - Auth upstream:
POST /internal/companies/{companyId}/memberships - Auth mode: forwarded
Authorization: Bearer <token>
8.11 GET /api/v1/admin/companies/{companyId}/business-units
Section titled “8.11 GET /api/v1/admin/companies/{companyId}/business-units”Purpose
List Core-owned business-unit master rows for one company from the Admin control plane.
Target
- read business-unit master data from Core
- show company organizational structure owned by Core
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/companies/{companyId}/business-units - Core upstream:
GET /internal/companies/{companyId}/business-units - Core mode:
X-Internal-API-KeyusingCORE_INTERNAL_API_KEY
8.12 POST /api/v1/admin/companies/{companyId}/business-units
Section titled “8.12 POST /api/v1/admin/companies/{companyId}/business-units”Purpose
Create one Core-owned business-unit master row under a company.
Target
- write business-unit master data in Core
Body
{ "name": "Finance Operations", "code": "FINOPS", "slug": "finance-operations", "isActive": true, "metadata": { "description": "Finance team business unit" }}Admin backend mapping
- Admin endpoint:
POST /api/v1/admin/companies/{companyId}/business-units - Core upstream:
POST /internal/companies/{companyId}/business-units - Core mode:
X-Internal-API-KeyusingCORE_INTERNAL_API_KEY
8.13 GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}
Section titled “8.13 GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}”Purpose
Get one Core-owned business-unit master row in the scope of its parent company.
Target
- read one business-unit master row from Core
- keep business-unit reads explicitly scoped to the parent company
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId} - Core upstream target: company-scoped business-unit read
- Core mode:
X-Internal-API-KeyusingCORE_INTERNAL_API_KEY
Important rule:
- backend must verify the business unit belongs to the
{companyId}in the path
8.14 PATCH /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}
Section titled “8.14 PATCH /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}”Purpose
Update one Core-owned business-unit master row.
Target
- update business-unit master data in Core
Body
{ "name": "Finance & Procurement", "code": "FINPROC", "slug": "finance-procurement", "isActive": true, "metadata": { "description": "Updated business unit name" }}Admin backend mapping
- Admin endpoint:
PATCH /api/v1/admin/companies/{companyId}/business-units/{businessUnitId} - Core upstream target: company-scoped business-unit patch
- Core mode:
X-Internal-API-KeyusingCORE_INTERNAL_API_KEY
Important note:
- this route patches the Core business-unit master row
- it does not patch business-unit memberships
- memberships remain Auth-owned
- backend must verify the business unit belongs to the
{companyId}in the path
8.15 DELETE /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}
Section titled “8.15 DELETE /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}”Purpose
Delete or archive one Core-owned business-unit master row in the scope of its parent company.
Target
- remove a business-unit master row from Core, or mark it inactive depending on final implementation policy
Request body
- no body
Admin backend mapping
- Admin endpoint:
DELETE /api/v1/admin/companies/{companyId}/business-units/{businessUnitId} - Core upstream target: company-scoped business-unit delete
- Core mode:
X-Internal-API-KeyusingCORE_INTERNAL_API_KEY
Important rule:
- backend must verify the business unit belongs to the
{companyId}in the path - delete policy must be explicit:
- hard delete only if no dependent records exist, or
- soft delete / deactivate if business-unit history must be preserved
8.16 GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/users
Section titled “8.16 GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/users”Purpose
List users for one business unit.
Target
- read business-unit memberships from Auth
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/users - Auth upstream:
GET /internal/companies/{companyId}/business-units/{businessUnitId}/users - Auth mode: forwarded
Authorization: Bearer <token>
8.17 GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
Section titled “8.17 GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships”Purpose
List business-unit memberships for one business unit.
Target
- read business-unit memberships from Auth
Request body
- no body
Admin backend mapping
- Admin endpoint:
GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships - Auth upstream:
GET /internal/admin/companies/{companyId}/business-units/{businessUnitId}/memberships - Auth mode:
X-Internal-API-KeyusingAUTH_INTERNAL_API_KEY
8.18 POST /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
Section titled “8.18 POST /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships”Purpose
Create or update a business-unit membership from Admin.
Target
- write business-unit membership in Auth
Body
{ "userId": "9e280dc5-c1cf-4d62-bad9-0774e4a3b9e1", "role": "MEMBER", "status": "ACTIVE"}Admin backend mapping
- Admin endpoint:
POST /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships - Auth upstream:
POST /internal/companies/{companyId}/business-units/{businessUnitId}/memberships - Auth mode: forwarded
Authorization: Bearer <token>
9. Payment-provider configuration
Section titled “9. Payment-provider configuration”These are privileged operational endpoints. Their persistence details must be explicitly defined during implementation.
9.1 GET /api/v1/admin/payment-providers
Section titled “9.1 GET /api/v1/admin/payment-providers”Purpose
List payment-provider configuration visible to platform staff.
Request body
- no body
9.2 POST /api/v1/admin/payment-providers/stripe
Section titled “9.2 POST /api/v1/admin/payment-providers/stripe”Purpose
Configure Stripe for a deployment, country, or environment scope.
Body
{ "scopeType": "country", "scopeValue": "SG", "publishableKey": "pk_live_xxx", "secretReference": "secrets/stripe/sg/live", "webhookSecretReference": "secrets/stripe/sg/webhook", "isActive": true}9.3 POST /api/v1/admin/payment-providers/xendit
Section titled “9.3 POST /api/v1/admin/payment-providers/xendit”Purpose
Configure Xendit for a deployment, country, or environment scope.
Body
{ "scopeType": "country", "scopeValue": "ID", "apiKeyReference": "secrets/xendit/id/live", "callbackTokenReference": "secrets/xendit/id/callback", "isActive": true}10. Operational Admin surfaces that remain first-class
Section titled “10. Operational Admin surfaces that remain first-class”These routes are not secondary. Even in the new architecture, they remain valid Admin responsibilities and should stay fully documented.
10.1 Approvals
Section titled “10.1 Approvals”GET /api/v1/admin/approvals
Section titled “GET /api/v1/admin/approvals”Purpose
List pending approvals.
Request body
- no body
GET /api/v1/admin/approvals/{id}
Section titled “GET /api/v1/admin/approvals/{id}”Purpose
Get one approval.
Request body
- no body
POST /api/v1/admin/approvals/approve
Section titled “POST /api/v1/admin/approvals/approve”Purpose
Approve an approval request.
Body
{ "approvalId": "approval_123"}POST /api/v1/admin/approvals/reject
Section titled “POST /api/v1/admin/approvals/reject”Purpose
Reject an approval request.
Body
{ "approvalId": "approval_123", "rejectionReason": "Insufficient documentation"}10.2 Artists
Section titled “10.2 Artists”Artist management remains an Admin responsibility.
GET /api/v1/admin/artists
Section titled “GET /api/v1/admin/artists”Purpose
List artists.
Request body
- no body
Typical query parameters
activeiso2limitpagesearchsort_bysort_order
POST /api/v1/admin/artists
Section titled “POST /api/v1/admin/artists”Purpose
Create a new artist.
Body
{ "name": "Artist Name", "type": "solo", "country": { "name": "Singapore", "iso2": "SG" }, "genre": ["pop"], "website": "https://artist.example", "bio": "Artist biography", "socials": { "instagram": "https://instagram.com/artist", "youtube": "https://youtube.com/@artist" }}GET /api/v1/admin/artists/{id}
Section titled “GET /api/v1/admin/artists/{id}”Purpose
Get one artist.
Request body
- no body
PATCH /api/v1/admin/artists/{id}
Section titled “PATCH /api/v1/admin/artists/{id}”Purpose
Update an artist.
Body
{ "name": "Updated Artist Name", "bio": "Updated bio", "website": "https://artist.example"}DELETE /api/v1/admin/artists
Section titled “DELETE /api/v1/admin/artists”Purpose
Delete many artists.
Body
{ "ids": ["artist_1", "artist_2"]}GET /api/v1/admin/artists/genres
Section titled “GET /api/v1/admin/artists/genres”Purpose
Get all artist genres.
Request body
- no body
GET /api/v1/admin/artists/latest-counters
Section titled “GET /api/v1/admin/artists/latest-counters”Purpose
Get latest artist counters.
Request body
- no body
POST /api/v1/admin/artists/platforms
Section titled “POST /api/v1/admin/artists/platforms”Purpose
Get artist platform information from platform integrations.
Body
{ "platform": "viberate", "name": "Artist Name", "spotify_id": "spotify-artist-id", "iso2": "SG", "type": "solo"}GET /api/v1/admin/artists/search
Section titled “GET /api/v1/admin/artists/search”Purpose
Search artists.
Request body
- no body
GET /api/v1/admin/artists/spotify
Section titled “GET /api/v1/admin/artists/spotify”Purpose
Look up artist information from Spotify.
Request body
- no body
10.2A Market directory
Section titled “10.2A Market directory”These routes proxy the current Backend-Kisum-Artists surface for non-artist artists-directory entities. Admin returns the Artists contract unchanged.
Runtime namespace
Section titled “Runtime namespace”/api/v1/admin/artists-directory/*
Current entity routes
Section titled “Current entity routes”GET /api/v1/admin/artists-directory/companiesPOST /api/v1/admin/artists-directory/companiesGET /api/v1/admin/artists-directory/companies/{id}PATCH /api/v1/admin/artists-directory/companies/{id}DELETE /api/v1/admin/artists-directory/companies/{id}GET /api/v1/admin/artists-directory/peoplePOST /api/v1/admin/artists-directory/peopleGET /api/v1/admin/artists-directory/people/{id}PATCH /api/v1/admin/artists-directory/people/{id}DELETE /api/v1/admin/artists-directory/people/{id}GET /api/v1/admin/artists-directory/genresPOST /api/v1/admin/artists-directory/genresGET /api/v1/admin/artists-directory/genres/{id}PATCH /api/v1/admin/artists-directory/genres/{id}DELETE /api/v1/admin/artists-directory/genres/{id}GET /api/v1/admin/artists-directory/subgenresPOST /api/v1/admin/artists-directory/subgenresGET /api/v1/admin/artists-directory/subgenres/{id}PATCH /api/v1/admin/artists-directory/subgenres/{id}DELETE /api/v1/admin/artists-directory/subgenres/{id}GET /api/v1/admin/artists-directory/platformsPOST /api/v1/admin/artists-directory/platformsGET /api/v1/admin/artists-directory/platforms/{id}PATCH /api/v1/admin/artists-directory/platforms/{id}DELETE /api/v1/admin/artists-directory/platforms/{id}GET /api/v1/admin/artists-directory/provider-sourcesPOST /api/v1/admin/artists-directory/provider-sourcesGET /api/v1/admin/artists-directory/provider-sources/{id}PATCH /api/v1/admin/artists-directory/provider-sources/{id}DELETE /api/v1/admin/artists-directory/provider-sources/{id}GET /api/v1/admin/artists-directory/regionsGET /api/v1/admin/artists-directory/regions/{id}GET /api/v1/admin/artists-directory/subregionsGET /api/v1/admin/artists-directory/subregions/{id}GET /api/v1/admin/artists-directory/countriesGET /api/v1/admin/artists-directory/countries/{id}GET /api/v1/admin/artists-directory/statesGET /api/v1/admin/artists-directory/states/{id}GET /api/v1/admin/artists-directory/citiesGET /api/v1/admin/artists-directory/cities/{id}
Current relation routes
Section titled “Current relation routes”GET /api/v1/admin/artists-directory/companies/{id}/peoplePUT /api/v1/admin/artists-directory/companies/{id}/peopleGET /api/v1/admin/artists-directory/companies/{id}/locationsPUT /api/v1/admin/artists-directory/companies/{id}/locationsGET /api/v1/admin/artists-directory/companies/{id}/genresPUT /api/v1/admin/artists-directory/companies/{id}/genresGET /api/v1/admin/artists-directory/companies/{id}/rosterPUT /api/v1/admin/artists-directory/companies/{id}/rosterGET /api/v1/admin/artists-directory/companies/{id}/social-metricsPUT /api/v1/admin/artists-directory/companies/{id}/social-metricsGET /api/v1/admin/artists-directory/people/{id}/companiesPUT /api/v1/admin/artists-directory/people/{id}/companiesGET /api/v1/admin/artists-directory/people/{id}/platform-accountsPUT /api/v1/admin/artists-directory/people/{id}/platform-accounts
Current geo nested routes
Section titled “Current geo nested routes”GET /api/v1/admin/artists-directory/regions/{id}/subregionsGET /api/v1/admin/artists-directory/regions/{id}/countriesGET /api/v1/admin/artists-directory/subregions/{id}/countriesGET /api/v1/admin/artists-directory/countries/{id}/statesGET /api/v1/admin/artists-directory/countries/{id}/citiesGET /api/v1/admin/artists-directory/states/{id}/cities
- These routes are for the market directory only, not for Core tenant-company administration.
- Upstream source of truth:
Backend-Kisum-Artists. - Path IDs follow the upstream Market rules:
- UUIDs for market entities such as companies, people, genres, subgenres, platforms, and provider sources
- integers for geo/reference entities such as regions, subregions, countries, states, and cities
10.3 Venues
Section titled “10.3 Venues”Venue management remains an Admin control-plane responsibility, but runtime venue truth now belongs to Backend-Kisum-Venues.
Current enforced integration path:
- browser ->
Frontend-Kisum-Admin - browser ->
Backend-Kisum-Admin Backend-Kisum-Admin->Backend-Kisum-Venuesinternal admin routes
Important rules:
- Admin must not query Venue Postgres directly
- numeric
venue_idis the Admin-facing venue identity - external venue enrichment/search may still stay in Admin, but persisted truth is written through Venue backend
GET /api/v1/admin/venues
Section titled “GET /api/v1/admin/venues”Purpose
List venues.
Runtime truth
- read from
Backend-Kisum-Venues - return both backend UUID
idand numericvenue_id
Request body
- no body
Typical query parameters
activeiso2limitpagesearchsort_bysort_ordertype
POST /api/v1/admin/venues
Section titled “POST /api/v1/admin/venues”Purpose
Create a venue.
Body
{ "name": "Kisum Arena", "country": "Singapore", "region": "Singapore", "city": "Singapore", "type": "arena", "capacity": 12000, "address": "120 Orchard Road"}GET /api/v1/admin/venues/{id}
Section titled “GET /api/v1/admin/venues/{id}”Purpose
Get one venue.
{id} is the numeric venue_id.
Request body
- no body
PATCH /api/v1/admin/venues/{id}
Section titled “PATCH /api/v1/admin/venues/{id}”Purpose
Update a venue.
{id} is the numeric venue_id.
Body
{ "name": "Updated Kisum Arena", "capacity": 15000, "type": "arena"}DELETE /api/v1/admin/venues
Section titled “DELETE /api/v1/admin/venues”Purpose
Delete many venues.
Body
{ "ids": ["1001", "1002"]}GET /api/v1/admin/venues/types
Section titled “GET /api/v1/admin/venues/types”Purpose
Get all venue types.
Runtime truth:
- read from Venue
venue_type
GET /api/v1/admin/venues/sleeping
Section titled “GET /api/v1/admin/venues/sleeping”Purpose
List sleeping imported venues that are still held by the Kisum holding company.
POST /api/v1/admin/venues/{id}/takeover-approvals
Section titled “POST /api/v1/admin/venues/{id}/takeover-approvals”Purpose
Create a Venue-owned takeover approval record for a sleeping venue.
POST /api/v1/admin/venues/{id}/activate
Section titled “POST /api/v1/admin/venues/{id}/activate”Purpose
Move a sleeping venue out of the Kisum holding company into the approved tenant company and mark it active.
Request body
- no body
POST /api/v1/admin/venues/{id}/revert-takeover
Section titled “POST /api/v1/admin/venues/{id}/revert-takeover”Purpose
Undo a previously approved venue takeover. Moves the venue back to the sleeping holding company, marks the originating approved takeover request revoked (with decision_notes = reason), and writes reconciliation + audit rows. Use case: falsified proof of ownership, or a takeover approved by mistake.
Request body
reason(required, min 10 chars): explanation surfaced to the tenant in the revoked request’sdecision_notes.actor_user_id,actor_email,actor_name— stamped by the handler from the JWT, not trusted from the client.
Errors
409 VENUE_HAS_TENANT_DATA(witherror.detailscarrying per-table counts forspaces,bookings,deposits,contracts,events,availability_blocks,checklists) — refuses when the tenant has created data on the venue. Admins must coordinate cleanup first.409 VENUE_NOT_ACTIVE— venue is not inownership_status='active'.409 VENUE_ALREADY_SLEEPING— venue already belongs to the sleeping holding company.404— venue not found.
10.3a Venue Requests (queue)
Section titled “10.3a Venue Requests (queue)”Admin BFF queue for tenant-submitted venue requests. Proxies the /internal/admin/venue-requests* family on Backend-Kisum-Venues. Decision routes stamp the JWT actor (user_id / user_email / user_name) onto the payload before forwarding.
GET /api/v1/admin/venue-requests
Section titled “GET /api/v1/admin/venue-requests”Purpose
List venue takeover + creation requests across all companies for the admin queue.
Query parameters
status(optional):pending|approved|rejected.kind(optional):takeover|creation.requestedCompanyId(optional): scope to a single tenant company.page,limit: pagination (defaults from the validator).
GET /api/v1/admin/venue-requests/{id}
Section titled “GET /api/v1/admin/venue-requests/{id}”Purpose
Read a single venue request including the kind-specific payload, the proofOfOwnership descriptor (if any), and any decision metadata.
GET /api/v1/admin/venue-requests/{id}/proof-url
Section titled “GET /api/v1/admin/venue-requests/{id}/proof-url”Purpose
Return a short-lived presigned S3 GET URL for the proof-of-ownership file attached to the request, so the admin UI can open it in a new tab without making the bucket public.
Response shape
url: presigned GET URL.expiresAt: ISO-8601 expiry (5 minutes from issue).fileName,contentType,size: descriptor copied from the request row.
Errors
404when no proof was uploaded with the request.
POST /api/v1/admin/venue-requests/{id}/approve
Section titled “POST /api/v1/admin/venue-requests/{id}/approve”Purpose
Approve a venue request. The Venue backend dispatches to the existing ActivateVenue (for takeover) or CreateVenue (for creation) flow, then marks the request approved.
Request body
decisionNotes(optional): free-form notes shown to the tenant.
POST /api/v1/admin/venue-requests/{id}/reject
Section titled “POST /api/v1/admin/venue-requests/{id}/reject”Purpose
Reject a venue request. Persists decisionNotes and marks the request rejected.
Request body
decisionNotes(optional, but recommended): explanation surfaced to the tenant in/settings/venue.
GET /api/v1/admin/venues/bandsintown
Section titled “GET /api/v1/admin/venues/bandsintown”Purpose
Search venues from Bandsintown.
Request body
- no body
GET /api/v1/admin/venues/viberate
Section titled “GET /api/v1/admin/venues/viberate”Purpose
Search venues from Viberate.
Request body
- no body
GET /api/v1/admin/venues/gemini
Section titled “GET /api/v1/admin/venues/gemini”Purpose
Generate or enrich venue information using Gemini.
Request body
- no body
GET /api/v1/admin/venues/search-by-platform
Section titled “GET /api/v1/admin/venues/search-by-platform”Purpose
Search venue-like records from an external source for admin auto-fill.
Request body
- no body
Query parameters (representative)
name(required): search string (venue name).platform(required): one ofviberate,bandsintown,gemini,musicbrainz.page,limit: pagination.type,country,region,city: optional refinements. Forplatform=gemini,type,country, andregionare required (see handler validation). Forplatform=musicbrainz, onlynameis strictly required; the server mapsmusicbrainzto MusicBrainz Places (GET /ws/2/place) and may passcity/countryas optional Luceneareafilters.cityis forwarded for all platforms when present.
Notes
musicbrainz: responses includeplatform_idswithtype=musicbrainzand the place MBID, andurlpointing athttps://musicbrainz.org/place/<mbid>. The Admin BFF should send a descriptiveUser-Agent(config:MUSICBRAINZ_USER_AGENT) per MusicBrainz API policy.
10.4 Files
Section titled “10.4 Files”POST /api/v1/admin/files/upload
Section titled “POST /api/v1/admin/files/upload”Purpose
Upload file assets for admin workflows.
Target
- operational upload only
- not a replacement for Core company-document truth
Body
multipart/form-data
Required form field:
file
10.5 AI
Section titled “10.5 AI”POST /api/v1/admin/ai/gemini
Section titled “POST /api/v1/admin/ai/gemini”Purpose
Staff-only AI helper route.
Body
{ "prompt": "Summarize this admin review case"}11. Implementation priority
Section titled “11. Implementation priority”If implementing the new Admin system, the recommended order is:
- package/module/add-on management
- company create/update and company lifecycle orchestration
- subscription/add-on assignment and entitlement inspection
- delegation-rule management through Auth
- payment-provider configuration
- cleanup or deprecation of legacy company proxy flows
12. Final rule
Section titled “12. Final rule”Admin endpoints must always be documented with:
- what the admin action does
- which system stores the truth
- what request body is required
- what downstream effect should happen
If an Admin endpoint writes commercial truth, it should target Core.
If an Admin endpoint writes access truth, it should target Auth.