Skip to content

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.

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-Admin now also proxies Market directory routes under /api/v1/admin/artists-directory/*
  • 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
  • /api/v1/admin/companies is reserved for Core tenant-company control-plane operations.
  • /api/v1/admin/artists-directory/companies is the Market directory-company namespace.
  • The same split applies conceptually to related people/contact directory endpoints.

All protected requests:

Authorization: Bearer <access_token>
Content-Type: application/json

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"
}
}

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

Packages are commercial catalog entities. Admin provides the staff-facing management surface, but Core stores the truth.

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:

  • hasBasic
  • basePackage
  • items
  • entitlementVersion

items contains one row per active commercial assignment:

  • one package row when a base package is active
  • one addon row per active add-on

Each item includes:

  • id
  • key
  • name
  • description
  • status
  • startsAt
  • endsAt
  • priceMinor
  • currency
  • billingInterval
  • taxCode
  • taxInclusive
  • trialDays
  • regionPricing

Important:

  • priceMinor is stored as a decimal amount
  • example: 199.00 USD is sent/stored as 199.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
}
}

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
  • currency
    • 3-letter currency code
  • billingInterval
    • one of monthly, quarterly, yearly, one_time
  • 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 moduleKeys is omitted, package-module mappings should remain unchanged
  • if moduleKeys is 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

Modules represent commercial features/products in the platform catalog.

Purpose

List the module catalog.

Target

  • read module definitions from Core

Request body

  • no body

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

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

Add-ons are commercial catalog entities sold or assigned on top of packages.

Purpose

List add-ons available in the platform catalog.

Request body

  • no body

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 type is addon

Purpose

Get one add-on in detail.

Request body

  • no body

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"]
}

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

Company operations are initiated by Admin but stored in Core.

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

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"
}

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 subscription items[] row
  • Admin resolves that id to the Core addonKey before 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

These endpoints are staff-facing wrappers around Auth-side access governance.

Purpose

List the current delegation rules used by Auth.

Target

  • read from Auth delegation policy state

Request body

  • no body

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
}

These routes should exist in Admin as the platform-staff control surface, even when the underlying source of truth is Auth.

This distinction must be understood before implementing any Admin user-access screen.

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:

  • id
  • email
  • fullName
  • isActive
  • globalRole
  • approvalStatus

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 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:

  • userId
  • companyId
  • optional businessUnitId
  • role
  • isActive
  • moduleGrants
  • permissionGrants
  • delegation

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: MEMBER

This is still one user, but multiple scoped memberships.

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-users
  • GET /api/v1/admin/users
  • GET /api/v1/admin/platform-users/{userId}
  • GET /api/v1/admin/platform-users/{userId}/context

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}/memberships
  • POST /api/v1/admin/companies/{companyId}/memberships
  • GET /api/v1/admin/companies/{companyId}/business-units/{businessUnitId}/memberships
  • POST /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 representation
  • memberships = access-oriented representation

Use this rule during implementation:

  • user = who the person/account is
  • membership = what access assignment that person has in a specific scope

Purpose

List users visible to platform staff.

Target

  • read through Auth user-administration APIs

Request body

  • no body

Typical query parameters

  • approvalStatus
  • globalRole
  • limit
  • offset

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.

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

  • approvalStatus
  • limit
  • offset

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

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-Key using AUTH_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-Key using AUTH_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.

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

  • approvalStatus
  • globalRole
  • userId
  • companyId
  • limit
  • offset

Query behavior

  • approvalStatus
    • optional
    • when omitted, no approval-status filtering is applied
    • when provided, must match the Auth approval-status enum exactly
  • globalRole
    • optional
    • true means platform users only
    • false means 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
  • offset
    • default 0

Definition

A session is considered active when all of the following are true:

  • is_revoked = false
  • expires_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-Key using AUTH_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

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

  • approvalStatus
  • globalRole
  • userId
  • companyId

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-Key using AUTH_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 globalRole is one of the platform roles
  • tenantUsersConnected
    • distinct connected users whose globalRole is NONE

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

  • limit
  • offset

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-Key using AUTH_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-Key using CORE_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-Key using CORE_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-Key using CORE_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-Key using CORE_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-Key using CORE_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-Key using AUTH_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>

These are privileged operational endpoints. Their persistence details must be explicitly defined during implementation.

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.

Purpose

List pending approvals.

Request body

  • no body

Purpose

Get one approval.

Request body

  • no body

Purpose

Approve an approval request.

Body

{
"approvalId": "approval_123"
}

Purpose

Reject an approval request.

Body

{
"approvalId": "approval_123",
"rejectionReason": "Insufficient documentation"
}

Artist management remains an Admin responsibility.

Purpose

List artists.

Request body

  • no body

Typical query parameters

  • active
  • iso2
  • limit
  • page
  • search
  • sort_by
  • sort_order

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"
}
}

Purpose

Get one artist.

Request body

  • no body

Purpose

Update an artist.

Body

{
"name": "Updated Artist Name",
"bio": "Updated bio",
"website": "https://artist.example"
}

Purpose

Delete many artists.

Body

{
"ids": ["artist_1", "artist_2"]
}

Purpose

Get all artist genres.

Request body

  • no body

Purpose

Get latest artist counters.

Request body

  • no body

Purpose

Get artist platform information from platform integrations.

Body

{
"platform": "viberate",
"name": "Artist Name",
"spotify_id": "spotify-artist-id",
"iso2": "SG",
"type": "solo"
}

Purpose

Search artists.

Request body

  • no body

Purpose

Look up artist information from Spotify.

Request body

  • no body

These routes proxy the current Backend-Kisum-Artists surface for non-artist artists-directory entities. Admin returns the Artists contract unchanged.

  • /api/v1/admin/artists-directory/*
  • GET /api/v1/admin/artists-directory/companies
  • POST /api/v1/admin/artists-directory/companies
  • GET /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/people
  • POST /api/v1/admin/artists-directory/people
  • GET /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/genres
  • POST /api/v1/admin/artists-directory/genres
  • GET /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/subgenres
  • POST /api/v1/admin/artists-directory/subgenres
  • GET /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/platforms
  • POST /api/v1/admin/artists-directory/platforms
  • GET /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-sources
  • POST /api/v1/admin/artists-directory/provider-sources
  • GET /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/regions
  • GET /api/v1/admin/artists-directory/regions/{id}
  • GET /api/v1/admin/artists-directory/subregions
  • GET /api/v1/admin/artists-directory/subregions/{id}
  • GET /api/v1/admin/artists-directory/countries
  • GET /api/v1/admin/artists-directory/countries/{id}
  • GET /api/v1/admin/artists-directory/states
  • GET /api/v1/admin/artists-directory/states/{id}
  • GET /api/v1/admin/artists-directory/cities
  • GET /api/v1/admin/artists-directory/cities/{id}
  • GET /api/v1/admin/artists-directory/companies/{id}/people
  • PUT /api/v1/admin/artists-directory/companies/{id}/people
  • GET /api/v1/admin/artists-directory/companies/{id}/locations
  • PUT /api/v1/admin/artists-directory/companies/{id}/locations
  • GET /api/v1/admin/artists-directory/companies/{id}/genres
  • PUT /api/v1/admin/artists-directory/companies/{id}/genres
  • GET /api/v1/admin/artists-directory/companies/{id}/roster
  • PUT /api/v1/admin/artists-directory/companies/{id}/roster
  • GET /api/v1/admin/artists-directory/companies/{id}/social-metrics
  • PUT /api/v1/admin/artists-directory/companies/{id}/social-metrics
  • GET /api/v1/admin/artists-directory/people/{id}/companies
  • PUT /api/v1/admin/artists-directory/people/{id}/companies
  • GET /api/v1/admin/artists-directory/people/{id}/platform-accounts
  • PUT /api/v1/admin/artists-directory/people/{id}/platform-accounts
  • GET /api/v1/admin/artists-directory/regions/{id}/subregions
  • GET /api/v1/admin/artists-directory/regions/{id}/countries
  • GET /api/v1/admin/artists-directory/subregions/{id}/countries
  • GET /api/v1/admin/artists-directory/countries/{id}/states
  • GET /api/v1/admin/artists-directory/countries/{id}/cities
  • GET /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

Venue management remains an Admin control-plane responsibility, but runtime venue truth now belongs to Backend-Kisum-Venues.

Current enforced integration path:

  1. browser -> Frontend-Kisum-Admin
  2. browser -> Backend-Kisum-Admin
  3. Backend-Kisum-Admin -> Backend-Kisum-Venues internal admin routes

Important rules:

  • Admin must not query Venue Postgres directly
  • numeric venue_id is the Admin-facing venue identity
  • external venue enrichment/search may still stay in Admin, but persisted truth is written through Venue backend

Purpose

List venues.

Runtime truth

  • read from Backend-Kisum-Venues
  • return both backend UUID id and numeric venue_id

Request body

  • no body

Typical query parameters

  • active
  • iso2
  • limit
  • page
  • search
  • sort_by
  • sort_order
  • type

Purpose

Create a venue.

Body

{
"name": "Kisum Arena",
"country": "Singapore",
"region": "Singapore",
"city": "Singapore",
"type": "arena",
"capacity": 12000,
"address": "120 Orchard Road"
}

Purpose

Get one venue.

{id} is the numeric venue_id.

Request body

  • no body

Purpose

Update a venue.

{id} is the numeric venue_id.

Body

{
"name": "Updated Kisum Arena",
"capacity": 15000,
"type": "arena"
}

Purpose

Delete many venues.

Body

{
"ids": ["1001", "1002"]
}

Purpose

Get all venue types.

Runtime truth:

  • read from Venue venue_type

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.

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’s decision_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 (with error.details carrying per-table counts for spaces, 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 in ownership_status='active'.
  • 409 VENUE_ALREADY_SLEEPING — venue already belongs to the sleeping holding company.
  • 404 — venue not found.

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.

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).

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

  • 404 when 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.

Purpose

Search venues from Bandsintown.

Request body

  • no body

Purpose

Search venues from Viberate.

Request body

  • no body

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 of viberate, bandsintown, gemini, musicbrainz.
  • page, limit: pagination.
  • type, country, region, city: optional refinements. For platform=gemini, type, country, and region are required (see handler validation). For platform=musicbrainz, only name is strictly required; the server maps musicbrainz to MusicBrainz Places (GET /ws/2/place) and may pass city / country as optional Lucene area filters. city is forwarded for all platforms when present.

Notes

  • musicbrainz: responses include platform_ids with type=musicbrainz and the place MBID, and url pointing at https://musicbrainz.org/place/<mbid>. The Admin BFF should send a descriptive User-Agent (config: MUSICBRAINZ_USER_AGENT) per MusicBrainz API policy.

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

Purpose

Staff-only AI helper route.

Body

{
"prompt": "Summarize this admin review case"
}

If implementing the new Admin system, the recommended order is:

  1. package/module/add-on management
  2. company create/update and company lifecycle orchestration
  3. subscription/add-on assignment and entitlement inspection
  4. delegation-rule management through Auth
  5. payment-provider configuration
  6. cleanup or deprecation of legacy company proxy flows

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.