SaaS Builder

Create and publish SaaS packages — define pricing plans, branding, custom domains, marketing pages, seed data, screen definitions, app configs, feature flags, AI model overrides, data bundles, promotions, connector configs, and integrations for packages built on the Backbuild platform.

159 endpoints. Generated from the OpenAPI 3.1 specification.

GET /v1/app/builds

List build jobs

Returns a paginated list of build jobs for the caller's organization. Requires `build_job.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package.
platform query string (enum) no Filter by platform.
status query string (enum) no Filter by build status.
build_system query string (enum) no Filter by build system.
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of build jobs.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/app/builds

Create build job

Creates a new build job for a native app platform (iOS, Android, Windows, macOS, or Linux — web is not a valid build target). The referenced app config must exist and belong to the same package. Requires `build_job.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
app_config_id string<uuid> no
platform string (enum) iosandroidwindowsmacoslinux yes
build_system string (enum) cloudflare_containercodemagiceas_buildself_hosted_mac yes
build_type string (enum) developmentpreviewproduction yes
build_config object no

Responses

StatusDescription
201 Build job queued.
400 `INVALID_JSON` or `VALIDATION_ERROR` (e.g. web platform, invalid build-system/platform combination).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — referenced app config or SaaS package not found.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
build_id string<uuid>
saas_package_id string<uuid>
app_config_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinux
build_system string (enum) cloudflare_containercodemagiceas_buildself_hosted_mac
build_type string (enum) developmentpreviewproduction
status string (enum) pendingqueuedin_progresssuccessfailedcancelled
error_message string
artifact_url string<uri>
started_at string<date-time>
completed_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
GET /v1/app/builds/{buildId}

Get build job

Returns a single build job by id. Requires `build_job.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
buildId path string<uuid> yes Build job identifier (UUIDv7).

Responses

StatusDescription
200 The build job.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
build_id string<uuid>
saas_package_id string<uuid>
app_config_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinux
build_system string (enum) cloudflare_containercodemagiceas_buildself_hosted_mac
build_type string (enum) developmentpreviewproduction
status string (enum) pendingqueuedin_progresssuccessfailedcancelled
error_message string
artifact_url string<uri>
started_at string<date-time>
completed_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
POST /v1/app/builds/{buildId}/cancel

Cancel build job

Cancels a queued or in-progress build job. Returns `409 BUILD_JOB_NOT_CANCELLABLE` if the job is already in a terminal state (success, failed, or cancelled). Requires `build_job.cancel` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
buildId path string<uuid> yes Build job identifier (UUIDv7).

Responses

StatusDescription
200 Build job cancelled.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
409 `BUILD_JOB_NOT_CANCELLABLE` — the job is already in a terminal state.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
cancelled boolean
PUT /v1/app/builds/{buildId}/status

Update build status

Updates the execution status of a build job, called by the build system (Cloudflare Container, Codemagic, EAS Build, or self-hosted Mac builder) as the job progresses. Requires `build_job.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
buildId path string<uuid> yes Build job identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
status string (enum) pendingqueuedin_progresssuccessfailedcancelled yes
error_message string no
artifact_url string<uri> no

Responses

StatusDescription
200 Build status updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
422 `INVALID_STATUS_TRANSITION` — the requested status change is not permitted from the current state.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
build_id string<uuid>
saas_package_id string<uuid>
app_config_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinux
build_system string (enum) cloudflare_containercodemagiceas_buildself_hosted_mac
build_type string (enum) developmentpreviewproduction
status string (enum) pendingqueuedin_progresssuccessfailedcancelled
error_message string
artifact_url string<uri>
started_at string<date-time>
completed_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
GET /v1/app/bundles

List data bundles

Returns a paginated list of data bundles for the caller's organization. Requires `data_bundle.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package (UUIDv7).
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of data bundles.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/app/bundles

Create data bundle

Creates a new versioned data bundle (seed data, configuration, or content payload) for a SaaS package. Requires `data_bundle.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
version string yes
description string no
bundle_url string<uri> no

Responses

StatusDescription
201 Data bundle created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — referenced SaaS package not found.
409 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
bundle_id string<uuid>
saas_package_id string<uuid>
version string Semver-formatted bundle version.
description string
status string (enum) draftpublishedsuperseded
bundle_url string<uri> Download URL for the bundle payload.
published_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
GET /v1/app/bundles/{bundleId}

Get data bundle

Returns a single data bundle by id. Requires `data_bundle.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
bundleId path string<uuid> yes Data bundle identifier (UUIDv7).

Responses

StatusDescription
200 The data bundle.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
bundle_id string<uuid>
saas_package_id string<uuid>
version string Semver-formatted bundle version.
description string
status string (enum) draftpublishedsuperseded
bundle_url string<uri> Download URL for the bundle payload.
published_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
POST /v1/app/bundles/{bundleId}/publish

Publish data bundle

Marks a data bundle as the current published version for the package. The previously published bundle is demoted. Requires `data_bundle.publish` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
bundleId path string<uuid> yes Data bundle identifier (UUIDv7).

Responses

StatusDescription
200 Bundle published.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
published boolean
POST /v1/app/bundles/{bundleId}/rollback

Rollback to data bundle

Rolls back the current published bundle to the specified previous bundle. Requires `data_bundle.publish` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
bundleId path string<uuid> yes Data bundle identifier to roll back to (UUIDv7).

Responses

StatusDescription
200 Rollback performed.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
rolled_back boolean
GET /v1/app/bundles/current

Get current data bundle

Returns the currently published (active) data bundle for the specified SaaS package. Returns `404 NO_CURRENT_BUNDLE` when no bundle has been published yet. Requires `data_bundle.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> yes SaaS package identifier (UUIDv7).

Responses

StatusDescription
200 The current published data bundle.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` (`NO_CURRENT_BUNDLE`) — no published bundle exists for this package.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
bundle_id string<uuid>
saas_package_id string<uuid>
version string Semver-formatted bundle version.
description string
status string (enum) draftpublishedsuperseded
bundle_url string<uri> Download URL for the bundle payload.
published_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
GET /v1/app/configs

List app configs

Returns a paginated list of app configs for the caller's organization. Requires `app_config.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package (UUIDv7).
platform query string (enum) no Filter by platform.
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of app configs.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/app/configs

Create app config

Creates a platform-specific app configuration record for a SaaS package. One config per package per platform is enforced. Requires `app_config.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
platform string (enum) iosandroidwindowsmacoslinuxweb yes
bundle_id string no
version_name string no
version_code integer no
config_data object no

Responses

StatusDescription
201 App config created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — referenced SaaS package not found.
409 `APP_CONFIG_DUPLICATE_PLATFORM` — a config for this platform already exists for the package.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
config_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinuxweb
bundle_id string App bundle/package identifier for the platform.
version_name string
version_code integer
config_data object Platform-specific configuration fields.
created_at string<date-time>
updated_at string<date-time>
GET /v1/app/configs/{configId}

Get app config

Returns a single app config by id. Requires `app_config.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
configId path string<uuid> yes App config identifier (UUIDv7).

Responses

StatusDescription
200 The app config.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
config_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinuxweb
bundle_id string App bundle/package identifier for the platform.
version_name string
version_code integer
config_data object Platform-specific configuration fields.
created_at string<date-time>
updated_at string<date-time>
PUT /v1/app/configs/{configId}

Update app config

Updates an existing app config. At least one field must be supplied. Requires `app_config.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
configId path string<uuid> yes App config identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
bundle_id string no
version_name string no
version_code integer no
config_data object no

Responses

StatusDescription
200 App config updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
config_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinuxweb
bundle_id string App bundle/package identifier for the platform.
version_name string
version_code integer
config_data object Platform-specific configuration fields.
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/app/configs/{configId}

Delete app config

Deletes an app config. Requires `app_config.delete` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
configId path string<uuid> yes App config identifier (UUIDv7).

Responses

StatusDescription
200 App config deleted.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean
GET /v1/app/screens

List screen definitions

Returns a paginated list of screen definitions for the caller's organization. Requires `screen_definition.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package.
screen_type query string (enum) no Filter by screen type.
is_active query string (enum) no Filter by active status.
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of screen definitions.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/app/screens

Create screen definition

Creates a screen definition describing the layout and component configuration of a screen in the generated app. `screen_key` must be unique per package. Requires `screen_definition.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
screen_key string yes
screen_type string (enum) corecustomview_based yes
display_name string no
layout_config object no
is_active boolean no

Responses

StatusDescription
201 Screen definition created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — referenced SaaS package not found.
409 `SCREEN_KEY_EXISTS` — a screen with this key already exists for the package.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
screen_id string<uuid>
saas_package_id string<uuid>
screen_key string Unique key for the screen within the package.
screen_type string (enum) corecustomview_based
display_name string
layout_config object Screen layout and component configuration.
is_active boolean
created_at string<date-time>
updated_at string<date-time>
GET /v1/app/screens/{screenId}

Get screen definition

Returns a single screen definition by id. Requires `screen_definition.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
screenId path string<uuid> yes Screen definition identifier (UUIDv7).

Responses

StatusDescription
200 The screen definition.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
screen_id string<uuid>
saas_package_id string<uuid>
screen_key string Unique key for the screen within the package.
screen_type string (enum) corecustomview_based
display_name string
layout_config object Screen layout and component configuration.
is_active boolean
created_at string<date-time>
updated_at string<date-time>
PUT /v1/app/screens/{screenId}

Update screen definition

Updates a screen definition. At least one field must be supplied. Requires `screen_definition.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
screenId path string<uuid> yes Screen definition identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
display_name string no
layout_config object no
is_active boolean no

Responses

StatusDescription
200 Screen definition updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
screen_id string<uuid>
saas_package_id string<uuid>
screen_key string Unique key for the screen within the package.
screen_type string (enum) corecustomview_based
display_name string
layout_config object Screen layout and component configuration.
is_active boolean
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/app/screens/{screenId}

Delete screen definition

Deletes a screen definition. Requires `screen_definition.delete` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
screenId path string<uuid> yes Screen definition identifier (UUIDv7).

Responses

StatusDescription
200 Screen definition deleted.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean
POST /v1/marketing/events

Ingest marketing events

Accepts a batch of up to 25 marketing analytics events for asynchronous processing. The endpoint returns 202 immediately — all processing is fire-and-forget; delivery is best-effort. This endpoint requires service authorization; calls that fail service authorization return 403. Rate limited to 100 requests per 60 seconds per IP. Content-Length must not exceed 100 KB. Events missing required UUID fields or malformed events within an otherwise valid batch are silently dropped (reflected in `eventsDropped`).

Public Public: no authentication

Request Body

FieldTypeRequiredDescription
events array of object yes

Responses

StatusDescription
202 Events accepted for async processing. Returns counts of received and dropped events.
400 `INVALID_JSON` — unparseable body; or `MISSING_EVENTS` — the `events` array is absent or not an array.
403 `FORBIDDEN` — the request did not pass service authorization.
413 `PAYLOAD_TOO_LARGE` — request body exceeds the 100 KB limit.
415 `UNSUPPORTED_MEDIA_TYPE` — Content-Type must be `application/json`.
422 `BATCH_TOO_LARGE` — batch exceeds 25 events.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
503 `SERVICE_UNAVAILABLE` — marketing event ingestion is not configured for this environment.
GET /v1/marketplace/addons

Get marketplace add-ons

Returns available add-ons for a SaaS package. `saas_package_id` is required. Public endpoint — no authentication required. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> yes SaaS package identifier (UUIDv7).
plan_slug query string no Filter add-ons to those compatible with the specified plan slug.
page query integer no Page number (1-based).
page_size query integer no Records per page.

Responses

StatusDescription
200 List of add-ons for the package.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
404 `NOT_FOUND` — referenced SaaS package not found.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/marketplace/app-config

Get app configuration

Returns the app configuration for a SaaS package, resolved by domain or package ID. Public by default. Passing `subscriber_org_id` or `draft=true` requires a valid bearer token whose session org_id matches `subscriber_org_id`. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
domain query string no The verified domain for the SaaS package. One of `domain` or `package_id` is required.
package_id query string<uuid> no SaaS package identifier (UUIDv7). One of `domain` or `package_id` is required.
subscriber_org_id query string<uuid> no Subscriber organization identifier for subscriber-context config. Requires bearer authentication with matching org.
draft query string (enum) no Return draft config. Requires bearer authentication.

Responses

StatusDescription
200 App configuration.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 `UNAUTHORIZED` — bearer token required when `subscriber_org_id` or `draft=true` is supplied.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
saas_package_id string<uuid>
domain string
platform_configs object Keyed by platform name. Each value is the platform-specific configuration object.
GET /v1/marketplace/build-config

Get build configuration

Returns the build configuration for a SaaS package for the specified platform. Resolved by domain. Public endpoint — no authentication required. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
domain query string yes The verified domain for the SaaS package.
platform query string (enum) yes Target platform.

Responses

StatusDescription
200 Build configuration.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/marketplace/build-targets

Get build targets

Returns available build targets (platform + environment combinations) for a SaaS package. All parameters are optional. Public endpoint — no authentication required. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
domain query string no The verified domain for the SaaS package.
platform query string (enum) no Filter by platform.
org_id query string<uuid> no Filter by organization.
environment query string (enum) no Filter by environment.

Responses

StatusDescription
200 Available build targets.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/marketplace/listings

Browse marketplace listings

Returns a paginated list of published marketplace listings. Public endpoint — no authentication required. Rate limited to 60 requests per minute per IP.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
search query string no Full-text search query (max 100 characters, trimmed).
category query string no Filter by category (max 120 characters, trimmed).
sort query string (enum) no Sort order.

Responses

StatusDescription
200 List of public marketplace listings.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/marketplace/listings

Create marketplace listing

Creates a new marketplace listing. Requires `marketplace.create` permission. Unknown body keys are rejected with 400 (`additionalProperties: false`).

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
template_id string<uuid> no
title string yes
description string no
category string yes
tags array of string no
pricing_type string (enum) freeone_timesubscription yes
price_cents integer no
currency string no
screenshots array of string no

Responses

StatusDescription
201 Marketplace listing created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
listing_id string<uuid>
title string
description string
category string
tags array of string
pricing_type string (enum) freeone_timesubscription
price_cents integer
currency string
rating number
download_count integer
screenshots array of string
created_at string<date-time>
status string (enum) draftpending_reviewpublishedsuspended
publisher_org_id string<uuid>
template_id string<uuid>
updated_at string<date-time>
GET /v1/marketplace/listings/{id}

Get marketplace listing (management)

Returns full management-level detail for a single marketplace listing. `publisher_org_id` is required to scope the lookup. Any authenticated organization member may call this endpoint.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
id path string<uuid> yes Marketplace listing identifier (UUIDv7).
publisher_org_id query string<uuid> yes Publisher organization identifier (UUIDv7). Used to scope the lookup.

Responses

StatusDescription
200 The marketplace listing.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
listing_id string<uuid>
title string
description string
category string
tags array of string
pricing_type string (enum) freeone_timesubscription
price_cents integer
currency string
rating number
download_count integer
screenshots array of string
created_at string<date-time>
status string (enum) draftpending_reviewpublishedsuspended
publisher_org_id string<uuid>
template_id string<uuid>
updated_at string<date-time>
PATCH /v1/marketplace/listings/{id}

Update marketplace listing

Partially updates a marketplace listing. Requires `marketplace.update` permission. Unknown body keys are rejected with 400 (`additionalProperties: false`).

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
id path string<uuid> yes Marketplace listing identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
title string no
description string no
category string no
tags array of string no
pricing_type string (enum) freeone_timesubscription no
price_cents integer no
currency string no
screenshots array of string no
status string (enum) draftpending_reviewpublishedsuspended no

Responses

StatusDescription
200 Listing updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
listing_id string<uuid>
title string
description string
category string
tags array of string
pricing_type string (enum) freeone_timesubscription
price_cents integer
currency string
rating number
download_count integer
screenshots array of string
created_at string<date-time>
status string (enum) draftpending_reviewpublishedsuspended
publisher_org_id string<uuid>
template_id string<uuid>
updated_at string<date-time>
DELETE /v1/marketplace/listings/{id}

Delete marketplace listing

Deletes a marketplace listing. Requires `marketplace.delete` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
id path string<uuid> yes Marketplace listing identifier (UUIDv7).

Responses

StatusDescription
200 Listing deleted.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean
GET /v1/marketplace/listings/manage

Manage marketplace listings

Returns a paginated list of marketplace listings for the caller's organization, with management-level fields. Unlike the public browse endpoint, this returns draft and suspended listings. Any authenticated organization member may call this endpoint. Unknown query parameters are rejected with 400. NOTE: this route is registered before `GET /v1/marketplace/listings/{id}` to prevent path shadowing.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
mine_only query string (enum) no When `true`, returns only listings owned by the caller's organization.
search query string no Full-text search query.
category query string no Filter by category.
status query string (enum) no Filter by listing status.
pricing_type query string (enum) no Filter by pricing type.
page query integer no Page number (1-based).
page_size query integer no Records per page.

Responses

StatusDescription
200 Paginated list of managed listings.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/marketplace/packages

Browse marketplace packages

Returns available SaaS packages from the marketplace. Supports two modes: signup discovery (pass `visibility=signup` with either `org_id` or `domain`) and general browse. Public endpoint — no authentication required. Rate limited to 60 requests per minute per IP. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
visibility query string (enum) no Set to `signup` to fetch packages relevant for a specific organization or domain at signup. When `signup`, either `org_id` or `domain` is required.
org_id query string<uuid> no Organization identifier for signup-mode lookup (UUIDv7). One of `org_id` or `domain` required when `visibility=signup`.
domain query string no Verified domain for signup-mode lookup (max 253 chars, valid domain format). One of `org_id` or `domain` required when `visibility=signup`.
search query string no Full-text search query for general browse (max 100 characters).
sort query string (enum) no Sort order for general browse.

Responses

StatusDescription
200 List of marketplace packages.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/marketplace/plans

Get marketplace plans

Returns pricing plans for a SaaS package. Accepts either a UUID (`saas_package_id`) or a slug. UUID-based lookups are fully anonymous. Slug-based lookups apply a tighter per-IP rate limit and accept an optional bearer token to resolve subscriber-context pricing. Public endpoint — no authentication required by default; authentication is optional for subscriber-context slug resolution. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
saas_package_id query string no SaaS package identifier (UUID or URL slug). Exactly one of `saas_package_id` (UUID) or a slug equivalent must be supplied.
visibility query string (enum) no Plan visibility filter.
page query integer no Page number (1-based).
page_size query integer no Records per page.

Responses

StatusDescription
200 List of plans for the package.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/marketplace/resolve

Resolve domain to SaaS package (legacy alias)

Legacy alias for `GET /v1/marketplace/resolve-domain`. Identical behavior. Prefer `resolve-domain` for new integrations. Public endpoint — no authentication required.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
domain query string yes The domain to resolve.

Responses

StatusDescription
200 Resolved package metadata.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
domain string
saas_package_id string<uuid>
package_name string
slug string
logo_url string<uri>
GET /v1/marketplace/resolve-domain

Resolve domain to SaaS package

Resolves a verified custom domain to its associated SaaS package metadata. Used by app clients at startup to discover the correct package configuration. Public endpoint — no authentication required. Unknown query parameters are rejected with 400.

Public Public: no authentication

Parameters

NameInTypeRequiredDescription
domain query string yes The domain to resolve (must be a valid domain name).

Responses

StatusDescription
200 Resolved package metadata.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
domain string
saas_package_id string<uuid>
package_name string
slug string
logo_url string<uri>
GET /v1/marketplace/reviews

List marketplace reviews

Returns a paginated list of reviews. Optionally filter by `listing_id`. Any authenticated organization member may call this endpoint. Unknown query parameters are rejected with 400.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
listing_id query string<uuid> no Filter reviews by listing (UUIDv7).
page query integer no Page number (1-based).
page_size query integer no Records per page.

Responses

StatusDescription
200 Paginated list of reviews.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/marketplace/reviews

Create marketplace review

Creates a review for a marketplace listing. Requires `marketplace.review` permission. Rating must be an integer from 1 to 5. Unknown body keys are rejected with 400.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
listing_id string<uuid> yes
publisher_org_id string<uuid> no
rating integer yes
review_text string no

Responses

StatusDescription
201 Review created.
400 `INVALID_JSON` or `VALIDATION_ERROR` (e.g. rating out of range 1–5).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
review_id string<uuid>
listing_id string<uuid>
publisher_org_id string<uuid>
rating integer
review_text string
created_at string<date-time>
POST /v1/marketplace/subscriptions

Create marketplace subscription

Creates a subscription to a marketplace listing. Requires `marketplace.subscribe` permission. Unknown body keys are rejected with 400.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
listing_id string<uuid> yes
publisher_org_id string<uuid> no
expires_at string<date-time> no

Responses

StatusDescription
201 Subscription created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
409 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
subscription_id string<uuid>
listing_id string<uuid>
publisher_org_id string<uuid>
subscriber_org_id string<uuid>
expires_at string<date-time>
created_at string<date-time>
DELETE /v1/marketplace/subscriptions/{id}

Delete marketplace subscription

Cancels and removes a marketplace subscription. Requires `marketplace.subscribe` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
id path string<uuid> yes Marketplace subscription identifier (UUIDv7).

Responses

StatusDescription
200 Subscription removed.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean
GET /v1/saas-packages

List SaaS packages

List all SaaS packages for the authenticated caller's organization. Supports optional full-text search and page/page_size pagination. Requires `package.view` permission. Gated behind the `saas-builder` system feature flag.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
search query string no Optional full-text search term (max 255 chars).
page query integer no Page number (1-based, default 1).
page_size query integer no Page size (1–100, default varies by SP).

Responses

StatusDescription
200 Paginated list of packages.
400 `INVALID_PARAMETER` — invalid query parameter values.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages

Create a SaaS package

Create a new SaaS package in draft status for the caller's organization. The `slug` must match the canonical package slug grammar (lowercase alphanumeric, single internal hyphens, 3–63 characters, not UUID-shaped) and is globally unique across all organizations via a reference-table registry. Returns `409 PACKAGE_SLUG_EXISTS` if the slug is already registered. Requires `package.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
name string yes Display name.
slug string no Unique URL slug (lowercase alphanumeric + hyphens). When omitted the API derives one from `name`.
description string no
app_name string no Application display name (shown in the packaged app shell).
subdomain string no Subdomain slug (lowercase alphanumeric + hyphens).

Responses

StatusDescription
201 Package created.
400 `VALIDATION_ERROR` — field validation failed. `INVALID_JSON` — malformed request body.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
409 `PACKAGE_SLUG_EXISTS` — the requested slug is already registered globally.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}

Get a SaaS package

Retrieve a single SaaS package by UUID. Requires `package.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Responses

StatusDescription
200 Package record.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SAAS_PACKAGE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}

Update a SaaS package

Update package properties. At least one field (other than `id`) must be provided. Setting `slug` to `null` clears the slug and releases the globally-registered slug registry entry. Setting `logo_url` or `favicon_url` to `null` clears those fields. Changes to `app_name`, `logo_url`, `favicon_url`, `theme_config`, `org_config`, `login_screen_config`, `plan_group_config`, `billing_interval_config`, or `subdomain` invalidate the per-package app-config KV cache. Requires `package.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Request Body

FieldTypeRequiredDescription
id string<uuid> no URL-mirrored package UUID. Accepted for convenience but the path parameter takes precedence.
name string no
slug string | null no Canonical URL slug. Pass `null` to clear the slug and release the slug registry row.
description string | null no
app_name string no
subdomain string no
logo_url string | null no
favicon_url string | null no
theme_config object | null no Theme/branding JSON config.
org_config object | null no
login_screen_config object | null no
plan_group_config object | null no Config defining the plan group keys (used as valid `category` values on pricing plans).
billing_interval_config object | null no

Responses

StatusDescription
200 Updated package record.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `PACKAGE_SLUG_EXISTS` — the new slug is already globally registered.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
PATCH /v1/saas-packages/{packageId}

Curation-only update for a SaaS package

Update signup roll-up curation fields only. Intentionally distinct from `PUT /:packageId` so operators with `saas_package.curate` can manage the signup roll-up card without holding the broader `package.update` permission. The strict schema rejects all non-curation keys so a leaked curate token cannot piggyback a price or theme edit. `signup_card_config.icon_url` must be HTTPS and hosted on the Backbuild CDN allowlist.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Request Body

FieldTypeRequiredDescription
show_on_org_signup boolean no Whether this package appears on the org signup screen.
signup_rollup_sort_order integer no Display order on the signup rollup.
signup_card_config any no
academic_verification_purpose string | null no Purpose statement shown during academic verification.
project_ids array of string no Full-replace set of project UUIDs whose entity types/entities this package carries.
expected_version integer | null no Optimistic concurrency version. When provided, the SP rejects the update if the current version differs.

Responses

StatusDescription
200 Curation fields updated.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}

Delete a SaaS package

Soft-delete (archive) a SaaS package. Requires `package.delete` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `SAAS_PACKAGE_HAS_SUBSCRIBERS` — cannot delete while active subscriber tenants exist.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
GET /v1/saas-packages/{packageId}/ai-models

List AI models available to a package

Returns a model-centric list of AI models with their package-level enable/disable override state. Each entry includes the model's display name, model string, whether it is a system model or an org-owned model, and whether it is enabled for this package. Supports `page`/`page_size` pagination (default 50, max 200). Authorization is SP-enforced.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
page query integer no
page_size query integer no

Responses

StatusDescription
200 AI model list for the package.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
models array of object
pagination object Page/page_size pagination metadata.
PUT /v1/saas-packages/{packageId}/ai-models

Batch-update AI model overrides for a package

Batch-upsert package-level enable/disable overrides for AI models. Each entry must specify exactly one of `system_model_id` or `org_model_id` and a boolean `is_enabled`. Array must contain 1–200 items.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
overrides array of object yes

Responses

StatusDescription
200 Overrides applied.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/ai-models/override

Upsert a single AI model override for a package

Create or update the package-level enable/disable override for a single AI model. Exactly one of `system_model_id` or `org_model_id` must be provided. `PUT /ai-models/override` on the same path is a verb alias for this operation.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
system_model_id string<uuid> no System model UUID. Mutually exclusive with `org_model_id`.
org_model_id string<uuid> no Org-owned model UUID. Mutually exclusive with `system_model_id`.
is_enabled boolean yes

Responses

StatusDescription
200 Override upserted.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
PUT /v1/saas-packages/{packageId}/ai-models/override

Upsert a single AI model override for a package (PUT alias)

Identical to `POST /ai-models/override`. Both HTTP verbs map to the same upsert handler.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
system_model_id string<uuid> no System model UUID. Mutually exclusive with `org_model_id`.
org_model_id string<uuid> no Org-owned model UUID. Mutually exclusive with `system_model_id`.
is_enabled boolean yes

Responses

StatusDescription
200 Override upserted.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/saas-packages/{packageId}/app-configs

List app configs

List app configs for the package with optional `platform` filter and page/page_size pagination. Requires `app_config.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
platform query string (enum) no Filter by platform.
page query integer no
page_size query integer no

Responses

StatusDescription
200 App configs.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/app-configs

Create an app config

Create a platform-specific app config. Only one config per `platform` per package is allowed (`APP_CONFIG_DUPLICATE_PLATFORM`). `splash_background_color` must be a hex color like `#FFFFFF`. Requires `app_config.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
platform string (enum) iosandroidwindowsmacoslinuxweb yes
app_name string yes
bundle_identifier string no
version_name string no
version_code integer no
icon_url string<uri> no
splash_screen_url string<uri> no
splash_background_color string no Hex color like `#FFFFFF`.
signing_config_ref string no
platform_config object no
eas_project_id string no

Responses

StatusDescription
201 App config created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `APP_CONFIG_DUPLICATE_PLATFORM`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinuxweb
app_name string
bundle_identifier string | null
version_name string | null
version_code integer | null
icon_url string | null
splash_screen_url string | null
splash_background_color string | null
signing_config_ref string | null
platform_config object | null
eas_project_id string | null
status string (enum) draftbuildingpublishedsuspended
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/app-configs/{configId}

Get an app config

Retrieve an app config by ID. Requires `app_config.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
configId path string<uuid> yes

Responses

StatusDescription
200 App config.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `APP_CONFIG_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinuxweb
app_name string
bundle_identifier string | null
version_name string | null
version_code integer | null
icon_url string | null
splash_screen_url string | null
splash_background_color string | null
signing_config_ref string | null
platform_config object | null
eas_project_id string | null
status string (enum) draftbuildingpublishedsuspended
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/app-configs/{configId}

Update an app config

Update app config fields. `platform` is immutable after creation. At least one field (other than `id`) must be provided. `null` values clear optional URL/ref fields. Requires `app_config.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
configId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no
app_name string no
bundle_identifier string | null no
version_name string | null no
version_code integer | null no
icon_url string | null no
splash_screen_url string | null no
splash_background_color string | null no
signing_config_ref string | null no
platform_config object | null no
eas_project_id string | null no
status string (enum) draftbuildingpublishedsuspended no

Responses

StatusDescription
200 Updated app config.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `APP_CONFIG_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
platform string (enum) iosandroidwindowsmacoslinuxweb
app_name string
bundle_identifier string | null
version_name string | null
version_code integer | null
icon_url string | null
splash_screen_url string | null
splash_background_color string | null
signing_config_ref string | null
platform_config object | null
eas_project_id string | null
status string (enum) draftbuildingpublishedsuspended
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/app-configs/{configId}

Delete an app config

Delete an app config. Requires `app_config.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
configId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `APP_CONFIG_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
POST /v1/saas-packages/{packageId}/archive

Archive a suspended package

Permanently archive a suspended (unpublished) package. The package must first be suspended via `POST /unpublish`. Requires `package.publish` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Responses

StatusDescription
200 Package archived.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `CONFLICT` — precondition unmet (package must be suspended first).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
POST /v1/saas-packages/{packageId}/clone

Deep-clone a SaaS package

Create a deep copy of an existing package into a new draft. The clone inherits all pricing plans, screen definitions, marketing pages, seed data, connectors, and app configs from the source. The source package must belong to the caller's org. Requires `package.create` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Source package UUID.

Request Body

FieldTypeRequiredDescription
name string yes Name for the cloned package.
description string no

Responses

StatusDescription
201 Cloned package (new draft).
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SAAS_PACKAGE_NOT_FOUND` — source package not found.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/connectors

List connector configs

List connector configs for the package with optional limit/offset pagination. Requires `connector_config.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
limit query integer no Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100).
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Connector configs.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/connectors

Create a connector config

Create a connector configuration for the package. Requires `connector_config.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
name string yes
connector_type string yes
description string no
config object yes Connector configuration JSON. Required.
is_required boolean no
sort_order integer no
metadata object no

Responses

StatusDescription
201 Connector created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
connector_type string
description string | null
config object | null Connector configuration JSON.
is_required boolean | null
sort_order integer | null
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/connectors/{connectorId}

Get a connector config

Retrieve a connector config by ID. Requires `connector_config.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
connectorId path string<uuid> yes

Responses

StatusDescription
200 Connector config.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `CONNECTOR_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
connector_type string
description string | null
config object | null Connector configuration JSON.
is_required boolean | null
sort_order integer | null
metadata object | null
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/connectors/{connectorId}

Update a connector config

Update connector config fields. At least one field (other than `id`) must be provided. Requires `connector_config.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
connectorId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no
name string no
connector_type string no
description string | null no
config object | null no
is_required boolean no
sort_order integer | null no
metadata object | null no

Responses

StatusDescription
200 Updated connector config.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `CONNECTOR_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
connector_type string
description string | null
config object | null Connector configuration JSON.
is_required boolean | null
sort_order integer | null
metadata object | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/connectors/{connectorId}

Delete a connector config

Delete a connector config. Requires `connector_config.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
connectorId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `CONNECTOR_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
GET /v1/saas-packages/{packageId}/data-bundles

List data bundles

List data bundles for the package with limit/offset pagination (max 200 per page). Requires `data_bundle.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
limit query integer no
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Data bundles.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/data-bundles

Create a data bundle

Create a data bundle (snapshot of package config/seed data for distribution). `bundle_hash` is a content-addressed hash. Requires `data_bundle.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
bundle_hash string yes Content hash for the bundle.
content any yes Bundle content (any JSON).
bundle_url string<uri> no
bundle_size_bytes integer no

Responses

StatusDescription
201 Data bundle created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
bundle_hash string Content hash for integrity verification.
content any Bundle content (any JSON).
bundle_url string | null
bundle_size_bytes integer | null
status string (enum) draftpublishedrollback
created_at string<date-time>
published_at string | null
GET /v1/saas-packages/{packageId}/data-bundles/{bundleId}

Get a data bundle

Retrieve a data bundle by UUID. Requires `data_bundle.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
bundleId path string<uuid> yes

Responses

StatusDescription
200 Data bundle.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `DATA_BUNDLE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
bundle_hash string Content hash for integrity verification.
content any Bundle content (any JSON).
bundle_url string | null
bundle_size_bytes integer | null
status string (enum) draftpublishedrollback
created_at string<date-time>
published_at string | null
POST /v1/saas-packages/{packageId}/data-bundles/{bundleId}/publish

Publish a data bundle

Mark a data bundle as the current live bundle. Requires `data_bundle.publish`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
bundleId path string<uuid> yes

Responses

StatusDescription
200 Published data bundle.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `DATA_BUNDLE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
bundle_hash string Content hash for integrity verification.
content any Bundle content (any JSON).
bundle_url string | null
bundle_size_bytes integer | null
status string (enum) draftpublishedrollback
created_at string<date-time>
published_at string | null
POST /v1/saas-packages/{packageId}/data-bundles/{bundleId}/rollback

Rollback to a data bundle

Re-publish a previous data bundle, making it the current live bundle. Requires `data_bundle.publish`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
bundleId path string<uuid> yes

Responses

StatusDescription
200 Rolled-back data bundle.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `DATA_BUNDLE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
bundle_hash string Content hash for integrity verification.
content any Bundle content (any JSON).
bundle_url string | null
bundle_size_bytes integer | null
status string (enum) draftpublishedrollback
created_at string<date-time>
published_at string | null
GET /v1/saas-packages/{packageId}/data-bundles/current

Get the current (published) data bundle

Retrieve the currently published data bundle. Returns `404 NO_CURRENT_BUNDLE` if no bundle has been published. Registered before `/:bundleId` so the literal `current` segment wins. Requires `data_bundle.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Responses

StatusDescription
200 Current data bundle.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NO_CURRENT_BUNDLE` — no bundle has been published.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
bundle_hash string Content hash for integrity verification.
content any Bundle content (any JSON).
bundle_url string | null
bundle_size_bytes integer | null
status string (enum) draftpublishedrollback
created_at string<date-time>
published_at string | null
GET /v1/saas-packages/{packageId}/domains

List custom domains

List custom domains for the package. Supports optional `status` filter and limit/offset pagination. Requires `custom_domain.view`. The path `/v1/saas-packages/{packageId}/custom-domains` is a deprecated alias with identical behaviour.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
status query string no Filter by domain status.
limit query integer no Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100).
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Custom domains.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/domains

Create a custom domain

Add a custom domain to the package. `domain_type` defaults to `alias`. `environment` defaults to `production`. `api_base_url` must be HTTPS; defaults to the standard Backbuild API URL for the chosen environment. Returns `409 DOMAIN_ALREADY_EXISTS` on duplicate. Requires `custom_domain.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
domain string yes Fully-qualified domain name to add (e.g. `app.example.com`).
domain_type string (enum) primaryaliassubdomain no
is_default boolean no
environment string (enum) developmentstagingpreprodproduction no
api_base_url string<uri> no HTTPS base URL of the API for this domain. Must use `https://` scheme.

Responses

StatusDescription
201 Domain created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `DOMAIN_ALREADY_EXISTS`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
domain string<hostname> The fully-qualified domain name.
verified boolean Whether the domain has passed DNS verification.
verified_at string | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/domains/{domainId}

Get a custom domain

Retrieve a custom domain by ID. Returns `404` if the domain does not belong to the specified package. Requires `custom_domain.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
domainId path string<uuid> yes

Responses

StatusDescription
200 Custom domain.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
domain string<hostname> The fully-qualified domain name.
verified boolean Whether the domain has passed DNS verification.
verified_at string | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/domains/{domainId}

Delete a custom domain

Remove a custom domain. Returns `404` if the domain does not belong to the specified package. Requires `custom_domain.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
domainId path string<uuid> yes

Responses

StatusDescription
200 Deleted domain record.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
domain string<hostname> The fully-qualified domain name.
verified boolean Whether the domain has passed DNS verification.
verified_at string | null
created_at string<date-time>
updated_at string<date-time>
POST /v1/saas-packages/{packageId}/domains/{domainId}/verify

Verify custom domain DNS

Trigger a DNS verification check for the domain. The SP validates the expected TXT or CNAME record in DNS and updates `verification_status`. Returns `409 DOMAIN_VERIFICATION_FAILED` if DNS has not propagated. Requires `custom_domain.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
domainId path string<uuid> yes

Responses

StatusDescription
200 Domain with updated verification status.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `DOMAIN_VERIFICATION_FAILED` — DNS not yet propagated.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
domain string<hostname> The fully-qualified domain name.
verified boolean Whether the domain has passed DNS verification.
verified_at string | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/feature-flags

List custom feature flags for a package

List all custom feature flags defined for the package. Authorization is enforced entirely by the stored procedure. All routes in the feature-flags module require `bearerAuth` via the inherited `authMiddleware`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Responses

StatusDescription
200 Feature flags.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/feature-flags

Create a custom feature flag

Create a custom feature flag for the package. `slug` must be lowercase alphanumeric with hyphens. Returns `409 CONFLICT` if the slug is already used. Authorization is SP-enforced.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
slug string yes Lowercase alphanumeric + hyphens. Must be unique within the package.
name string yes
description string no
is_enabled boolean no Package-level default enable state.
metadata object no

Responses

StatusDescription
201 Feature flag created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `CONFLICT` — slug already in use.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string Unique slug identifier within the package.
name string
description string | null
is_enabled boolean Package-level default value.
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/feature-flags/{flagId}

Get a custom feature flag

Retrieve a custom feature flag by ID.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
flagId path string<uuid> yes

Responses

StatusDescription
200 Feature flag.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string Unique slug identifier within the package.
name string
description string | null
is_enabled boolean Package-level default value.
metadata object | null
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/feature-flags/{flagId}

Update a custom feature flag

Update a custom feature flag. At least one field must be provided.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
flagId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
name string no
description string | null no
is_enabled boolean no
metadata object | null no

Responses

StatusDescription
200 Updated feature flag.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string Unique slug identifier within the package.
name string
description string | null
is_enabled boolean Package-level default value.
metadata object | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/feature-flags/{flagId}

Delete a custom feature flag

Delete a custom feature flag from the package.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
flagId path string<uuid> yes

Responses

StatusDescription
200 Deleted.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/saas-packages/{packageId}/marketing-pages

List marketing pages

List marketing pages for the package with optional status filter and limit/offset pagination. Requires `marketing_page.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
status query string no Filter by page status.
limit query integer no Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100).
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Marketing pages.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/marketing-pages

Create a marketing page

Create a marketing page for the package. `og_image_url` must be HTTPS. Requires `marketing_page.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
title string yes
slug string no
page_type string (enum) landingfeaturepricingaboutcustom no
content object no Page content as a bounded JSON structure.
seo_title string no
seo_description string no
og_image_url string<uri> no Open Graph image URL. Must use `https://` scheme.
sort_order integer no
metadata object no

Responses

StatusDescription
201 Marketing page created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string | null
title string
page_type string (enum) landingfeaturepricingaboutcustom
content object | null Page content as a bounded JSON structure.
seo_title string | null
seo_description string | null
og_image_url string | null
sort_order integer | null
status string (enum) draftpublished
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/marketing-pages/{pageId}

Get a marketing page

Retrieve a marketing page by ID. Requires `marketing_page.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
pageId path string<uuid> yes

Responses

StatusDescription
200 Marketing page.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string | null
title string
page_type string (enum) landingfeaturepricingaboutcustom
content object | null Page content as a bounded JSON structure.
seo_title string | null
seo_description string | null
og_image_url string | null
sort_order integer | null
status string (enum) draftpublished
metadata object | null
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/marketing-pages/{pageId}

Update a marketing page

Update marketing page fields. At least one field (other than `id`) must be provided. Requires `marketing_page.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
pageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no
title string no
slug string no
page_type string (enum) landingfeaturepricingaboutcustom no
content object | null no
seo_title string | null no
seo_description string | null no
og_image_url string | null no
sort_order integer | null no
metadata object | null no

Responses

StatusDescription
200 Updated marketing page.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `MARKETING_PAGE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string | null
title string
page_type string (enum) landingfeaturepricingaboutcustom
content object | null Page content as a bounded JSON structure.
seo_title string | null
seo_description string | null
og_image_url string | null
sort_order integer | null
status string (enum) draftpublished
metadata object | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/marketing-pages/{pageId}

Delete a marketing page

Delete a marketing page. Requires `marketing_page.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
pageId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `MARKETING_PAGE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
POST /v1/saas-packages/{packageId}/marketing-pages/{pageId}/publish

Publish a marketing page

Transition a marketing page to `published` status. Requires `marketing_page.publish`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
pageId path string<uuid> yes

Responses

StatusDescription
200 Marketing page published.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `MARKETING_PAGE_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
slug string | null
title string
page_type string (enum) landingfeaturepricingaboutcustom
content object | null Page content as a bounded JSON structure.
seo_title string | null
seo_description string | null
og_image_url string | null
sort_order integer | null
status string (enum) draftpublished
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/pricing-plans

List pricing plans for a package

List pricing plans belonging to a package with optional active/inactive filter and limit/offset pagination. Requires `saas_pricing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
status query string (enum) no Filter by status: `active` or `inactive`. Omit for all.
limit query integer no Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100).
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Paginated pricing plans.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — package not found.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/pricing-plans

Create a pricing plan

Create a new pricing plan for the package. `plan_type` defaults to `recurring`; recurring plans require a `billing_interval`; free plans must have `price_cents: 0`. `plan_tier` is required and must be one of the platform canonical tiers. `category` is a builder-defined group key validated by the SP against the package's `plan_group_config`. Per-timeframe `prices` rows may be provided in addition to the legacy `price_cents`/`price_cents_yearly` fields. Requires `saas_pricing.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
name string yes
slug string no
plan_tier string (enum) academic_freeproteambusinessenterprise yes
category string yes Builder-defined group key. Must match a key in the package's `plan_group_config.groups`. The reserved value `system` is not permitted.
plan_type string (enum) freeone_timerecurring no
billing_interval string (enum) monthlyyearlyquarterly no Required when `plan_type` is `recurring`.
interval string (enum) monthyearquarter no Legacy alias for `billing_interval`. Prefer `billing_interval`.
price_cents integer yes
price_cents_yearly integer no
currency string no ISO 4217 currency code (default `USD`).
description string no
trial_days integer no
grace_period_days integer no
credits_monthly integer no
credit_cost_microcents integer no
max_projects integer no
max_members integer no
storage_bytes integer no
db_storage_bytes integer no
is_per_seat boolean no
min_seats integer no
max_seats integer no
features any no Plan feature list. Either an array of feature-string labels or a JSON feature map.
limits object no Arbitrary limits JSON.
sort_order integer no
is_active boolean no
is_highlighted boolean no
usage_billing object no
metadata object no
prices array of object no Per-timeframe price rows. When present, the SP upserts one row per entry.

Responses

StatusDescription
201 Pricing plan created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — package not found.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
slug string
plan_tier string (enum) academic_freeproteambusinessenterprise
description string | null
prices object Price definition for a billing interval.
is_active boolean
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/pricing-plans/{planId}

Get a pricing plan

Retrieve a single pricing plan. Returns `404` if the plan does not belong to the specified package. Requires `saas_pricing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
planId path string<uuid> yes

Responses

StatusDescription
200 Pricing plan.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
slug string
plan_tier string (enum) academic_freeproteambusinessenterprise
description string | null
prices object Price definition for a billing interval.
is_active boolean
metadata object | null
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/pricing-plans/{planId}

Update a pricing plan

Update pricing plan fields. At least one field (other than `id`) must be provided. Returns `404` if the plan does not belong to the specified package. Requires `saas_pricing.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
planId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no URL-mirrored. Accepted for convenience but ignored in favour of the path parameter.
name string no
slug string no
plan_tier string (enum) academic_freeproteambusinessenterprise no
category string no
plan_type string (enum) freeone_timerecurring no
billing_interval string (enum) monthlyyearlyquarterly no
interval string (enum) monthyearquarter no
price_cents integer no
price_cents_yearly integer no
currency string no
description string no
trial_days integer no
grace_period_days integer no
credits_monthly integer no
credit_cost_microcents integer no
max_projects integer no
max_members integer no
storage_bytes integer no
db_storage_bytes integer no
is_per_seat boolean no
min_seats integer no
max_seats integer no
is_highlighted boolean no
features any no Plan feature list.
limits object | null no
sort_order integer no
is_active boolean no
usage_billing object | null no
metadata object | null no
prices array of object no

Responses

StatusDescription
200 Updated pricing plan.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
slug string
plan_tier string (enum) academic_freeproteambusinessenterprise
description string | null
prices object Price definition for a billing interval.
is_active boolean
metadata object | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/pricing-plans/{planId}

Delete a pricing plan

Delete a pricing plan. Returns `409` if the plan has active subscribers. Returns `404` if the plan does not belong to the specified package. Requires `saas_pricing.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
planId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `PRICING_PLAN_HAS_SUBSCRIBERS`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
PATCH /v1/saas-packages/{packageId}/pricing-plans/{planId}/curation

Curation-only update for a pricing plan

Update signup-eligibility curation fields on a pricing plan. Distinct from `PUT` so operators with `saas_package.curate` can manage sign-up visibility without holding the broader `saas_pricing.update` permission. The strict schema rejects non-curation keys. Returns `404` if the plan does not belong to the specified package. Requires `saas_package.curate`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
planId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
show_on_signup boolean no
signup_tier_slug string | null no
eligibility_check string (enum) noneacademicemployee no
requires_any_plan_ids array | null no
fallback_plan_id string | null no
expected_version integer | null no

Responses

StatusDescription
200 Updated pricing plan.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
slug string
plan_tier string (enum) academic_freeproteambusinessenterprise
description string | null
prices object Price definition for a billing interval.
is_active boolean
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/pricing-plans/{planId}/feature-flags

Get feature flag assignments for a pricing plan

Retrieve the feature flag assignments (both system and custom) for a specific pricing plan.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
planId path string<uuid> yes

Responses

StatusDescription
200 Plan feature flag assignments.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
PUT /v1/saas-packages/{packageId}/pricing-plans/{planId}/feature-flags

Update feature flag assignments for a pricing plan

Batch-update feature flag assignments for a pricing plan. Each entry specifies `flag_source` (`system` or `custom`) and `feature_flag_id`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
planId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
assignments array of object yes

Responses

StatusDescription
200 Updated plan feature flag assignments.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/pricing-plans/sync

Mark pricing plans as pending Stripe sync

Mark one or all active pricing plans in the package as pending Stripe sync for the given deployment environment. An optional `plan_id` restricts the marking to a single plan. The actual Stripe synchronization is performed by a background worker; this endpoint only updates the sync-pending state. Requires `saas_pricing.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
environment string (enum) developmentstagingpreprodproduction yes Target billing environment to sync.
plan_id string no Optional — restrict sync to a single plan by its external provider ID.

Responses

StatusDescription
200 Plans marked as pending sync.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/saas-packages/{packageId}/promotions

List promotions for a package

List promotions with optional active filter and page/page_size pagination. Requires `saas_pricing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
is_active query string (enum) no Filter by active status.
page query integer no
page_size query integer no

Responses

StatusDescription
200 Paginated promotions.
400 `INVALID_ID_FORMAT`, `VALIDATION_ERROR`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/promotions

Create a promotion

Create a discount promotion for the package. `discount_type` is `percentage` or `fixed_amount`; `currency` is a 3-letter lowercase ISO 4217 code (default `usd`). `stripe_duration` controls Stripe coupon duration. Requires `saas_pricing.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
name string yes
description string no
internal_note string no
discount_type string (enum) percentagefixed_amount yes
discount_value number yes
currency string no
applies_to string (enum) allcategoriesplans no
applicable_categories array of string no
applicable_plan_ids array of string no
applies_to_intervals array of enum monthlyyearlyquarterly no
stripe_duration string (enum) onceforeverrepeating no
duration_months integer no
starts_at string<date-time> no
ends_at string | null no
max_redemptions integer | null no
badge_label string | null no
is_featured boolean no
sort_order integer no
is_active boolean no

Responses

StatusDescription
201 Promotion created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
description string | null
internal_note string | null
discount_type string (enum) percentagefixed_amount
discount_value number
currency string
applies_to string (enum) allcategoriesplans
applicable_categories array | null
applicable_plan_ids array | null
applies_to_intervals array | null
stripe_duration string (enum) onceforeverrepeating
duration_months integer | null
starts_at string | null
ends_at string | null
max_redemptions integer | null
badge_label string | null
is_featured boolean
sort_order integer
is_active boolean
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/promotions/{promotionId}

Get a promotion

Retrieve a single promotion by ID. Requires `saas_pricing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
promotionId path string<uuid> yes

Responses

StatusDescription
200 Promotion.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
description string | null
internal_note string | null
discount_type string (enum) percentagefixed_amount
discount_value number
currency string
applies_to string (enum) allcategoriesplans
applicable_categories array | null
applicable_plan_ids array | null
applies_to_intervals array | null
stripe_duration string (enum) onceforeverrepeating
duration_months integer | null
starts_at string | null
ends_at string | null
max_redemptions integer | null
badge_label string | null
is_featured boolean
sort_order integer
is_active boolean
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/promotions/{promotionId}

Update a promotion

Update promotion fields. At least one field (other than `id`) must be provided. Requires `saas_pricing.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
promotionId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no URL-mirrored. Ignored in favour of the path parameter.
name string no
description string no
internal_note string no
discount_type string (enum) percentagefixed_amount no
discount_value number no
currency string no
applies_to string (enum) allcategoriesplans no
applicable_categories array of string no
applicable_plan_ids array of string no
applies_to_intervals array of enum monthlyyearlyquarterly no
stripe_duration string (enum) onceforeverrepeating no
duration_months integer | null no
starts_at string<date-time> no
ends_at string | null no
max_redemptions integer | null no
badge_label string | null no
is_featured boolean no
sort_order integer no
is_active boolean no

Responses

StatusDescription
200 Updated promotion.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
description string | null
internal_note string | null
discount_type string (enum) percentagefixed_amount
discount_value number
currency string
applies_to string (enum) allcategoriesplans
applicable_categories array | null
applicable_plan_ids array | null
applies_to_intervals array | null
stripe_duration string (enum) onceforeverrepeating
duration_months integer | null
starts_at string | null
ends_at string | null
max_redemptions integer | null
badge_label string | null
is_featured boolean
sort_order integer
is_active boolean
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/promotions/{promotionId}

Soft-delete a promotion

Soft-delete (deactivate) a promotion. Requires `saas_pricing.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
promotionId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
POST /v1/saas-packages/{packageId}/promotions/sync

Trigger Stripe sync for promotions

Mark all active promotions in the package as pending Stripe sync for the given environment, then run the sync. Returns `503 SERVICE_UNAVAILABLE` if Stripe is not configured for this deployment. Requires `saas_pricing.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
environment string (enum) developmentstagingpreprodproduction yes

Responses

StatusDescription
200 Promotions sync result.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
503 `SERVICE_UNAVAILABLE` — Stripe is not configured.
200 response body: data fields
FieldTypeDescription
environment string
marked integer Number of promotions marked as pending sync.
total integer Total promotions processed by the sync worker.
synced integer Number successfully synced to Stripe.
errors array of string
POST /v1/saas-packages/{packageId}/publish

Publish a SaaS package

Transition a package from `draft` to `published`. The package must meet all SP-enforced preconditions (e.g. at least one active pricing plan); unmet conditions return `409 CONFLICT`. Requires `package.publish` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Responses

StatusDescription
200 Package published.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `CONFLICT` — publish precondition unmet (e.g. no active pricing plan). `SAAS_PACKAGE_NOT_PUBLISHABLE` — package state does not allow publishing.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/revenue/by-plan

Revenue breakdown by pricing plan

Retrieve revenue breakdown segmented by pricing plan. Requires `billing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Responses

StatusDescription
200 Revenue by plan.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
plans array of object
GET /v1/saas-packages/{packageId}/revenue/summary

Revenue summary (MRR, ARR, churn)

Retrieve revenue analytics summary including MRR, ARR, and churn metrics for the package. Requires `billing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Responses

StatusDescription
200 Revenue summary.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
mrr number Monthly Recurring Revenue in USD cents.
arr number Annual Recurring Revenue in USD cents.
churn_rate number Subscriber churn rate (0–1 fraction).
active_subscribers integer
trial_subscribers integer
total_revenue number Total lifetime revenue in USD cents.
as_of string<date-time> Snapshot timestamp for these metrics.
GET /v1/saas-packages/{packageId}/revenue/timeseries

Revenue timeseries

Retrieve revenue timeseries data by `interval` (`day`, `week`, or `month`) over `periods` data points (1–365). Requires `billing.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
interval query string (enum) no Aggregation interval.
periods query integer no Number of periods (1–365).

Responses

StatusDescription
200 Timeseries data.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
interval string (enum) dayweekmonth
periods integer
series array of object
GET /v1/saas-packages/{packageId}/screen-definitions

List screen definitions

List screen definitions for the package with optional `screen_type` / `is_active` filter and limit/offset pagination. Requires `screen_definition.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
screen_type query string (enum) no Filter by screen type.
is_active query string (enum) no Filter by active status.
limit query integer no
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Screen definitions.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/screen-definitions

Create a screen definition

Create a screen definition. `screen_key` must be alphanumeric with dots, underscores, or hyphens (max 200 chars). Returns `409 SCREEN_KEY_EXISTS` if the key is already used in the package. Requires `screen_definition.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
screen_key string yes Unique screen key within the package.
screen_type string (enum) corecustomview_based no
layout_config object no
component_config object no
visibility object no
sort_order integer no
is_active boolean no

Responses

StatusDescription
201 Screen definition created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
409 `SCREEN_KEY_EXISTS`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
screen_key string Unique key for this screen within the package (alphanumeric + dots + underscores + hyphens).
screen_type string (enum) corecustomview_based
layout_config object | null
component_config object | null
visibility object | null
sort_order integer | null
is_active boolean | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/screen-definitions/{screenDefId}

Get a screen definition

Retrieve a screen definition by ID. Requires `screen_definition.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
screenDefId path string<uuid> yes

Responses

StatusDescription
200 Screen definition.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SCREEN_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
screen_key string Unique key for this screen within the package (alphanumeric + dots + underscores + hyphens).
screen_type string (enum) corecustomview_based
layout_config object | null
component_config object | null
visibility object | null
sort_order integer | null
is_active boolean | null
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/screen-definitions/{screenDefId}

Update a screen definition

Update screen definition fields. At least one field (other than `id`) must be provided. `changelog` records a freeform description of what changed (max 4096 chars). Requires `screen_definition.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
screenDefId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no
screen_key string no
screen_type string (enum) corecustomview_based no
layout_config object | null no
component_config object | null no
visibility object | null no
sort_order integer | null no
is_active boolean no
changelog string no

Responses

StatusDescription
200 Updated screen definition.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SCREEN_NOT_FOUND`
409 `SCREEN_KEY_EXISTS`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
screen_key string Unique key for this screen within the package (alphanumeric + dots + underscores + hyphens).
screen_type string (enum) corecustomview_based
layout_config object | null
component_config object | null
visibility object | null
sort_order integer | null
is_active boolean | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/screen-definitions/{screenDefId}

Delete a screen definition

Delete a screen definition. Requires `screen_definition.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
screenDefId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SCREEN_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
GET /v1/saas-packages/{packageId}/seed-data

List seed data entries

List seed data for the package with optional limit/offset pagination. Requires `seed_data.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
limit query integer no Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100).
offset query integer no Number of records to skip for offset pagination.

Responses

StatusDescription
200 Seed data entries.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/seed-data

Create a seed data entry

Create a seed data record. `entity_type` is a free-form type discriminator (max 128 chars). `data` is the JSON payload. Requires `seed_data.create`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
name string yes
description string no
entity_type string yes
data any yes Seed data payload (any JSON value).
sort_order integer no
is_required boolean no
metadata object no

Responses

StatusDescription
201 Seed data created.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
description string | null
entity_type string
data any Arbitrary seed data payload (any JSON).
sort_order integer | null
is_required boolean | null
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/{packageId}/seed-data/{seedId}

Get a seed data entry

Retrieve a seed data entry by ID. Requires `seed_data.view`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
seedId path string<uuid> yes

Responses

StatusDescription
200 Seed data entry.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SEED_DATA_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
description string | null
entity_type string
data any Arbitrary seed data payload (any JSON).
sort_order integer | null
is_required boolean | null
metadata object | null
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-packages/{packageId}/seed-data/{seedId}

Update a seed data entry

Update seed data fields. At least one field (other than `id`) must be provided. Requires `seed_data.update`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
seedId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
id string<uuid> no
name string no
description string | null no
entity_type string no
data any no Seed data payload.
sort_order integer | null no
is_required boolean no
metadata object | null no

Responses

StatusDescription
200 Updated seed data.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SEED_DATA_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
description string | null
entity_type string
data any Arbitrary seed data payload (any JSON).
sort_order integer | null
is_required boolean | null
metadata object | null
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/saas-packages/{packageId}/seed-data/{seedId}

Delete a seed data entry

Delete a seed data entry. Requires `seed_data.delete`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
seedId path string<uuid> yes

Responses

StatusDescription
200 `deleted: true`
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `SEED_DATA_NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
GET /v1/saas-packages/{packageId}/signup-card-events

List signup card dropped events

Returns the most recent signup-card-dropped audit events for a package (default limit 10, max 50). Powers the curation UI warning banner. Requires `saas_package.curate` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.
limit query integer no Maximum events to return (1–50, default 10).

Responses

StatusDescription
200 Signup card events.
400 `INVALID_ID_FORMAT`, `INVALID_PARAMETER`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
items array of object
total integer
GET /v1/saas-packages/{packageId}/system-feature-flags

Get system feature flag assignments for a package

Retrieve the system-level feature flag assignments for the package.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Responses

StatusDescription
200 System feature flag assignments.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
PUT /v1/saas-packages/{packageId}/system-feature-flags

Update system feature flag assignments for a package

Batch-update the system-level feature flag assignments for the package. Each entry targets a system flag by `feature_flag_id` UUID.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes

Request Body

FieldTypeRequiredDescription
assignments array of object yes

Responses

StatusDescription
200 Updated system assignments.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/saas-packages/{packageId}/tenants/{tenantOrgId}/feature-flags

Get tenant feature flag overrides

Retrieve the feature flag overrides set for a specific subscriber tenant organization.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
tenantOrgId path string<uuid> yes Tenant organization UUID.

Responses

StatusDescription
200 Tenant feature flag overrides.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
PUT /v1/saas-packages/{packageId}/tenants/{tenantOrgId}/feature-flags

Update tenant feature flag overrides

Batch-update feature flag overrides for a specific subscriber tenant. Each entry specifies `flag_source` and `feature_flag_id`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
tenantOrgId path string<uuid> yes Tenant organization UUID.

Request Body

FieldTypeRequiredDescription
assignments array of object yes

Responses

StatusDescription
200 Updated tenant feature flag overrides.
400 `VALIDATION_ERROR`, `INVALID_ID_FORMAT`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/saas-packages/{packageId}/tenants/{tenantOrgId}/feature-flags/effective

Get effective feature flags for a tenant

Retrieve the computed (merged) effective feature flag state for a subscriber tenant, combining package defaults, plan-level overrides, and tenant-specific overrides. Registered before `/:tenantOrgId/feature-flags` so `effective` wins the path match.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes
tenantOrgId path string<uuid> yes Tenant organization UUID.

Responses

StatusDescription
200 Effective feature flag state.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-packages/{packageId}/unpublish

Unpublish / suspend a SaaS package

Transition a published package to `suspended`, preventing new subscriber sign-ups while retaining existing subscribers. Requires `package.publish` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes Package UUID.

Responses

StatusDescription
200 Package suspended.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
org_id string<uuid>
name string
slug string
description string | null
status string (enum) draftpublishedarchived Publication state.
metadata object | null Arbitrary JSON metadata.
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/by/{idOrSlug}

Resolve a package by slug or UUID (path form)

Identical resolution logic to `GET /v1/saas-packages/resolve` but accepts the identifier as a path segment rather than a query parameter. Useful for deep-link patterns. Same anti-enumeration, rate-limiting, and RFC 8594 deprecation-hint behaviour as the query-param form.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
idOrSlug path string yes Package slug or UUID (max 256 characters).

Responses

StatusDescription
200 Resolved package identity.
400 `INVALID_PARAMETER` — identifier empty or longer than 256 chars.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
404 `NOT_FOUND` — same anti-enumeration contract as `/resolve`.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid> Canonical package UUID.
slug string Canonical URL slug for the package.
org_id string<uuid> Owning organization UUID.
redirect boolean True when the lookup input was a UUID rather than the canonical slug. A client shell MAY update its URL to the slug form; no HTTP redirect is issued.
GET /v1/saas-packages/plans/refs

List cross-package pricing plan refs

Returns a picker-safe projection of every pricing plan across all packages in the caller's org (up to 500). Intended for the `requires_any_plan_ids` prerequisite multi-select in the curation UI — only `plan_id`, `plan_slug`, `plan_name`, `package_id`, `package_slug`, `package_name`, and `is_active` are returned; pricing amounts and features are never included. Requires `saas_package.curate` permission. Registered before `/:packageId` routes so the literal `plans` segment wins the Hono path match.

Auth Session JWT (Bearer)

Responses

StatusDescription
200 List of pricing plan refs across all packages in the org.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
items array of object
POST /v1/saas-packages/pricing-plans/{planId}/rename-slug

Atomically rename a pricing plan slug

Atomically rename the URL slug for a pricing plan. Direct slug edits via `PUT /:packageId/pricing-plans/:planId` are rejected by the stored procedure; this is the only supported rename path. Requires `saas_package.curate` permission. The `planId` is resolved cross-package within the caller's org. Returns `400 VALIDATION_ERROR` if the new slug is reserved or fails canonical-grammar validation server-side.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
planId path string<uuid> yes Pricing plan UUID.

Request Body

FieldTypeRequiredDescription
new_slug string yes New URL slug (lowercase alphanumeric + hyphens).

Responses

StatusDescription
200 Slug renamed successfully. Returns the updated pricing plan.
400 `VALIDATION_ERROR` — slug fails canonical-grammar or is a reserved word. `INVALID_ID_FORMAT` — planId is not a UUID.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — pricing plan not found in caller's org.
409 `CONFLICT` or `PACKAGE_SLUG_EXISTS` — slug already in use.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid>
package_id string<uuid>
name string
slug string
plan_tier string (enum) academic_freeproteambusinessenterprise
description string | null
prices object Price definition for a billing interval.
is_active boolean
metadata object | null
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-packages/resolve

Resolve a package slug or UUID

Resolve a slug (or UUID) to its canonical package identity. Authenticated callers who are members of the owning org see all packages scoped to their membership; non-members only see published packages (anti-enumeration: all not-found/non-published/cross-scope conditions collapse to 404). When the input is a UUID, RFC 8594 `Sunset`/`Deprecation` headers and a `Link: rel=alternate` pointing to the canonical slug URL are added to hint migration — the response is still HTTP 200. Rate-limited per IP (public slug lookup budget) and per authenticated session.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
slug query string yes Package slug or UUID (max 256 characters).

Responses

StatusDescription
200 Resolved package identity. `redirect` is a client-shell hint only — no HTTP redirect is emitted.
400 `INVALID_PARAMETER` — slug query param missing or longer than 256 chars.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
404 `NOT_FOUND` — package not found, not published (for non-members), or cross-scope. All conditions return identical shape for anti-enumeration.
429 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
id string<uuid> Canonical package UUID.
slug string Canonical URL slug for the package.
org_id string<uuid> Owning organization UUID.
redirect boolean True when the lookup input was a UUID rather than the canonical slug. A client shell MAY update its URL to the slug form; no HTTP redirect is issued.
GET /v1/saas-tenants

List tenant provisions

Returns a paginated list of tenant provisions for packages owned by the caller's organization. Requires the `saas_tenant.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package (UUIDv7).
status query string no Filter by provision status (e.g. `active`, `deprovisioned`).
limit query integer no Maximum records to return (1–100, default 50).
offset query integer no Number of records to skip.

Responses

StatusDescription
200 Paginated list of tenant provisions.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-tenants

Provision a new tenant

Creates a new tenant (end-customer environment) for a published SaaS package owned by the caller's organization. Requires the `saas_tenant.provision` permission. The package must be published and owned by the caller's org.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
tenant_name string yes
tenant_slug string yes
admin_user_id string<uuid> no
admin_email string<email> no
admin_display_name string no
tenant_settings object no

Responses

StatusDescription
201 Tenant provisioned. The provision record is returned under `data`.
400 `INVALID_JSON` (unparseable body), `VALIDATION_ERROR` (field validation failure or the referenced package is not valid for this operation).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` — caller lacks `saas_tenant.provision` permission or does not own the package.
404 `NOT_FOUND` — the referenced SaaS package or admin user does not exist.
409 `CONFLICT` — a tenant with this slug already exists (`TENANT_SLUG_EXISTS`) or the tenant is already provisioned (`TENANT_ALREADY_PROVISIONED`).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
provision_id string<uuid>
saas_package_id string<uuid>
tenant_name string
tenant_slug string
admin_user_id string<uuid>
admin_email string<email>
admin_display_name string
tenant_settings object Package-specific tenant configuration.
status string (enum) provisioningactivedeprovisioningdeprovisionedfailed
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-tenants/{packageId}/subscriptions

List customer subscriptions

Returns a paginated list of subscriptions for the specified SaaS package, scoped to the caller's organization. Requires `subscription.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes SaaS package identifier (UUIDv7).
status query string no Filter by subscription status.
subscriber_org_id query string<uuid> no Filter by subscriber organization (UUIDv7).
limit query integer no Maximum records to return (1–100, default 50).
offset query integer no Number of records to skip.

Responses

StatusDescription
200 Paginated list of subscriptions.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/saas-tenants/{packageId}/subscriptions

Create customer subscription

Creates a subscription record for a subscriber organization purchasing a pricing plan from the specified SaaS package. The caller must be the package owner and have the `subscription.create` permission. A subscriber cannot subscribe to their own package.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes SaaS package identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
pricing_plan_id string<uuid> yes
subscriber_org_id string<uuid> yes
stripe_subscription_id string no
quantity integer no

Responses

StatusDescription
201 Subscription created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — the package or pricing plan was not found.
409 `CONFLICT` or `DUPLICATE_SUBSCRIPTION` — an active subscription already exists for this subscriber and package.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
subscription_id string<uuid>
saas_package_id string<uuid>
subscriber_org_id string<uuid>
pricing_plan_id string<uuid>
stripe_subscription_id string
quantity integer
status string (enum) activepausedcancelledpast_duetrialing
created_at string<date-time>
updated_at string<date-time>
GET /v1/saas-tenants/{packageId}/subscriptions/{subscriptionId}

Get customer subscription

Returns a single customer subscription by id. Requires `subscription.view` permission. A subscription outside the caller's org scope is reported as 404.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes SaaS package identifier (UUIDv7).
subscriptionId path string<uuid> yes Subscription identifier (UUIDv7).

Responses

StatusDescription
200 The subscription record.
400 `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
subscription_id string<uuid>
saas_package_id string<uuid>
subscriber_org_id string<uuid>
pricing_plan_id string<uuid>
stripe_subscription_id string
quantity integer
status string (enum) activepausedcancelledpast_duetrialing
created_at string<date-time>
updated_at string<date-time>
PUT /v1/saas-tenants/{packageId}/subscriptions/{subscriptionId}

Update customer subscription

Updates a customer subscription (pricing plan, quantity, or metadata). At least one field must be provided. Requires `subscription.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes SaaS package identifier (UUIDv7).
subscriptionId path string<uuid> yes Subscription identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
pricing_plan_id string<uuid> no New pricing plan for the subscription.
quantity integer no
stripe_subscription_id string no
metadata object no Arbitrary JSON metadata for the subscription.

Responses

StatusDescription
200 Subscription updated.
400 `INVALID_JSON`, `INVALID_ID_FORMAT`, or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
subscription_id string<uuid>
saas_package_id string<uuid>
subscriber_org_id string<uuid>
pricing_plan_id string<uuid>
stripe_subscription_id string
quantity integer
status string (enum) activepausedcancelledpast_duetrialing
created_at string<date-time>
updated_at string<date-time>
POST /v1/saas-tenants/{packageId}/subscriptions/{subscriptionId}/cancel

Cancel customer subscription

Cancels an active customer subscription. Requires `subscription.cancel` permission. Returns `409 CONFLICT` if the subscription is already cancelled.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
packageId path string<uuid> yes SaaS package identifier (UUIDv7).
subscriptionId path string<uuid> yes Subscription identifier (UUIDv7).

Responses

StatusDescription
200 Subscription cancelled.
400 `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND` — the subscription does not exist.
409 `CONFLICT` — the subscription is already cancelled.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
cancelled boolean
GET /v1/saas-tenants/{provisionId}

Get tenant provision

Returns a single tenant provision record by id. Requires `saas_tenant.view` permission. A provision outside the caller's org scope is reported as 404.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
provisionId path string<uuid> yes Tenant provision identifier (UUIDv7).

Responses

StatusDescription
200 The tenant provision record.
400 `INVALID_ID_FORMAT` — provisionId is not a valid UUID.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
provision_id string<uuid>
saas_package_id string<uuid>
tenant_name string
tenant_slug string
admin_user_id string<uuid>
admin_email string<email>
admin_display_name string
tenant_settings object Package-specific tenant configuration.
status string (enum) provisioningactivedeprovisioningdeprovisionedfailed
created_at string<date-time>
updated_at string<date-time>
POST /v1/saas-tenants/{provisionId}/deprovision

Deprovision a tenant

Deprovisions an active tenant, removing access and cleaning up resources. Requires the `saas_tenant.deprovision` permission. An optional `reason` string is recorded in the audit log.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
provisionId path string<uuid> yes Tenant provision identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
reason string no Human-readable reason for deprovisioning, recorded in the audit log.

Responses

StatusDescription
200 Tenant deprovisioned.
400 `INVALID_ID_FORMAT` — provisionId is not a valid UUID.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` — caller lacks `saas_tenant.deprovision` permission.
404 `NOT_FOUND` — the tenant provision does not exist.
409 `CONFLICT` — the tenant is already deprovisioned.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/saas/customer/paused-subscriptions

List paused customer subscriptions

Returns the calling organization's SaaS subscriptions that are currently paused because the seller's payment account has been disabled. Used to render a 'Payments temporarily unavailable' banner in the subscriber UI. Returns an empty list when no subscriptions are paused. The organization is derived from the authenticated session — no org_id parameter is accepted. NOTE: this route is declared in saas-customer.ts and documented at its declared path /v1/saas/customer/paused-subscriptions; verify against the active router mount when consuming.

Auth Session JWT (Bearer)

Responses

StatusDescription
200 List of paused subscriptions for the caller's organization.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` — the caller is not a member of the organization.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
subscriptions array of object
total integer Total count of paused subscriptions.
GET /v1/saas/integrations

List configured SaaS integrations for an org

List the integrations configured for the calling user's organization. Requires an authenticated session (`bearerAuth`). Authorization is verified inline: unauthenticated requests receive `401 AUTH_REQUIRED`. Secret values are never returned — config objects strip `_secret_ref` fields. Supports `limit`/`offset` pagination (default `limit` 20, max 100; default `offset` 0).

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
limit query integer no
offset query integer no

Responses

StatusDescription
200 Integration list.
401 `AUTH_REQUIRED` — session not present.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
integrations array of object
total integer Total number of integrations for this org.
DELETE /v1/saas/integrations/{integrationId}

Delete a SaaS integration

Delete an integration and clean up its encrypted secrets. Requires `integration.delete` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
integrationId path string<uuid> yes

Responses

StatusDescription
200 Integration deleted.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
id string<uuid>
POST /v1/saas/integrations/{integrationId}/test

Test a SaaS integration connection

Test the live connectivity of a configured integration by exercising a provider-specific connectivity probe. Requires `integration.view` permission. Returns `503 SERVICE_UNAVAILABLE` if the encryption service is not available.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
integrationId path string<uuid> yes

Responses

StatusDescription
200 Test result.
400 `INVALID_ID_FORMAT`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 `NOT_FOUND`
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
503 `SERVICE_UNAVAILABLE` — encryption service is not configured.
200 response body: data fields
FieldTypeDescription
success boolean Whether the provider connectivity test passed.
message string Human-readable detail about the test outcome (may be absent on success).
POST /v1/saas/integrations/configure

Configure a SaaS integration provider

Create or replace the configuration for a third-party integration provider. Requires `integration.create` permission. Secret values are encrypted at rest; they are never returned in subsequent reads. Returns `503 SERVICE_UNAVAILABLE` if the encryption service is not available.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
provider string (enum) striperesendsendgridsestwiliosignalwire yes Integration provider to configure.
config object yes Non-secret provider configuration key/value pairs.
secrets object yes Secret provider key/value pairs. At least one entry required. Values are encrypted at rest and never returned.

Responses

StatusDescription
201 Integration configured.
400 `VALIDATION_ERROR`, `INVALID_JSON`
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
503 `SERVICE_UNAVAILABLE` — encryption service is not configured.
201 response body: data fields
FieldTypeDescription
integration object A third-party integration configured for an organization. Secret values are never included in responses.
GET /v1/store/accounts

List store accounts

Returns a paginated list of store accounts for the caller's organization. Requires `store_account.view` permission. Credential fields are masked.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package.
platform query string (enum) no Filter by platform.
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of store accounts.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/store/accounts

Create store account

Creates a store account credential for submitting apps to a supported app store. Requires `store_account.create` permission. Credentials are encrypted at rest and never returned in plaintext.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
platform string (enum) iosandroidwindowsmacos yes
account_type string (enum) apple_app_store_connectgoogle_play_consolemicrosoft_partner_center yes
account_name string yes
credentials object no Platform-specific credential fields. Encrypted at rest.

Responses

StatusDescription
201 Store account created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
409 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
account_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacos
account_type string (enum) apple_app_store_connectgoogle_play_consolemicrosoft_partner_center
account_name string
is_active boolean
last_validated_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
GET /v1/store/accounts/{accountId}

Get store account

Returns a single store account by id. Credential fields are masked. Requires `store_account.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
accountId path string<uuid> yes Store account identifier (UUIDv7).

Responses

StatusDescription
200 The store account.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
account_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacos
account_type string (enum) apple_app_store_connectgoogle_play_consolemicrosoft_partner_center
account_name string
is_active boolean
last_validated_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
PUT /v1/store/accounts/{accountId}

Update store account

Updates a store account. Requires `store_account.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
accountId path string<uuid> yes Store account identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
account_name string no
credentials object no Platform-specific credential fields. Encrypted at rest.
is_active boolean no

Responses

StatusDescription
200 Store account updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
account_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacos
account_type string (enum) apple_app_store_connectgoogle_play_consolemicrosoft_partner_center
account_name string
is_active boolean
last_validated_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
DELETE /v1/store/accounts/{accountId}

Delete store account

Deletes a store account and its encrypted credentials. Requires `store_account.delete` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
accountId path string<uuid> yes Store account identifier (UUIDv7).

Responses

StatusDescription
200 Store account deleted.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
deleted boolean
POST /v1/store/accounts/{accountId}/validate

Validate store account credentials

Triggers a live connectivity check against the target store API to validate the stored credentials. Returns validation result and any error detail. Requires `store_account.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
accountId path string<uuid> yes Store account identifier (UUIDv7).

Responses

StatusDescription
200 Validation result (may indicate failure via `valid: false` — this is not an HTTP error).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
valid boolean
error string Human-readable validation error, present when `valid` is false.
GET /v1/store/age-ratings

List age ratings

Returns age rating records. Both `saas_package_id` and `platform` are required query parameters. Requires `age_rating.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> yes SaaS package identifier (UUIDv7).
platform query string (enum) yes Target store platform.

Responses

StatusDescription
200 List of age ratings for the specified package and platform.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/store/age-ratings

Create age rating

Creates an age rating record for a SaaS package on a specific store platform. Both `saas_package_id` and `platform` are required. Requires `age_rating.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
platform string (enum) iosandroidwindowsmacos yes
rating_category string yes
content_descriptors array of string no
questionnaire_answers object no

Responses

StatusDescription
201 Age rating created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
409 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
rating_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacos
rating_category string Platform-specific age rating category (e.g. `4+`, `E`, `USK 0`).
content_descriptors array of string
questionnaire_answers object
created_at string<date-time>
updated_at string<date-time>
PUT /v1/store/age-ratings/{ratingId}

Update age rating

Updates an existing age rating record. Requires `age_rating.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
ratingId path string<uuid> yes Age rating identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
rating_category string no
content_descriptors array of string no
questionnaire_answers object no

Responses

StatusDescription
200 Age rating updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
rating_id string<uuid>
saas_package_id string<uuid>
platform string (enum) iosandroidwindowsmacos
rating_category string Platform-specific age rating category (e.g. `4+`, `E`, `USK 0`).
content_descriptors array of string
questionnaire_answers object
created_at string<date-time>
updated_at string<date-time>
POST /v1/store/compliance/check

Database-backed compliance check

Runs a database-backed compliance evaluation for a SaaS package and returns structured compliance findings. Distinct from `POST /v1/store/submissions/compliance-check` which uses the local service. Requires `store_submission.view` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
platform string (enum) iosandroidwindowsmacos no

Responses

StatusDescription
200 Compliance check result.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
422 `VALIDATION_ERROR`.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
passed boolean Whether all compliance checks passed.
issues array of object
GET /v1/store/kyc/requirements

Get KYC requirements

Returns the list of KYC requirements for a SaaS package (required documents, fields, supported regions). Requires `kyc.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> yes SaaS package identifier (UUIDv7).

Responses

StatusDescription
200 KYC requirements.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
saas_package_id string<uuid>
requirements array of object
supported_regions array of string
POST /v1/store/kyc/sessions

Create KYC session

Initiates a KYC (Know Your Customer) verification session for the caller's organization in the context of a SaaS package. Returns a session token and redirect URL to the KYC provider. Requires `kyc.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
return_url string<uri> no URL to redirect to after KYC completion.

Responses

StatusDescription
201 KYC session created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
session_id string<uuid>
saas_package_id string<uuid>
status string (enum) pendingin_progresscompletedexpiredfailed
redirect_url string<uri> URL to redirect the user to the KYC provider.
expires_at string<date-time>
created_at string<date-time>
GET /v1/store/kyc/status

Get KYC verification status

Returns the current KYC verification status for the caller's organization on a SaaS package. Requires `kyc.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> yes SaaS package identifier (UUIDv7).

Responses

StatusDescription
200 KYC status for the organization.
400 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
status string (enum) not_startedpendingin_reviewapprovedrejected
submitted_at string<date-time>
reviewed_at string<date-time>
GET /v1/store/listings

List store listings

Returns a paginated list of store listings for the caller's organization. Requires `store_listing.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package.
platform query string (enum) no Filter by target platform.
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of store listings.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/store/listings

Create store listing

Creates a store listing for a SaaS package. Listing content (title, description, keywords, screenshots) is evaluated against the platform content policy before storage; requests that violate the policy are rejected with `CONTENT_POLICY_VIOLATION`. Requires `store_listing.create` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
saas_package_id string<uuid> yes
platform string (enum) iosandroidwindowsmacos yes
app_title string yes
short_description string no
full_description string no
keywords array of string no
screenshots array of string no
icon_url string<uri> no

Responses

StatusDescription
201 Store listing created.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
422 `CONTENT_POLICY_VIOLATION` — the listing content failed the platform content-safety evaluation.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
201 response body: data fields
FieldTypeDescription
listing_id string<uuid>
saas_package_id string<uuid>
app_title string
short_description string
full_description string
keywords array of string
screenshots array of string
icon_url string<uri>
platform string (enum) iosandroidwindowsmacos
status string (enum) draftpending_reviewin_reviewapprovedrejectedpublished
created_at string<date-time>
updated_at string<date-time>
GET /v1/store/listings/{listingId}

Get store listing

Returns a single store listing by id. Requires `store_listing.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
listingId path string<uuid> yes Store listing identifier (UUIDv7).

Responses

StatusDescription
200 The store listing.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
listing_id string<uuid>
saas_package_id string<uuid>
app_title string
short_description string
full_description string
keywords array of string
screenshots array of string
icon_url string<uri>
platform string (enum) iosandroidwindowsmacos
status string (enum) draftpending_reviewin_reviewapprovedrejectedpublished
created_at string<date-time>
updated_at string<date-time>
PUT /v1/store/listings/{listingId}

Update store listing

Updates a store listing. Content fields are re-evaluated against the platform content policy; rejected content returns `CONTENT_POLICY_VIOLATION`. Requires `store_listing.update` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
listingId path string<uuid> yes Store listing identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
app_title string no
short_description string no
full_description string no
keywords array of string no
screenshots array of string no
icon_url string<uri> no

Responses

StatusDescription
200 Store listing updated.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
422 `CONTENT_POLICY_VIOLATION` — updated content failed the platform content-safety evaluation.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
listing_id string<uuid>
saas_package_id string<uuid>
app_title string
short_description string
full_description string
keywords array of string
screenshots array of string
icon_url string<uri>
platform string (enum) iosandroidwindowsmacos
status string (enum) draftpending_reviewin_reviewapprovedrejectedpublished
created_at string<date-time>
updated_at string<date-time>
GET /v1/store/submissions

List store submissions

Returns a paginated list of store submissions for the caller's organization. Requires `store_submission.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
saas_package_id query string<uuid> no Filter by SaaS package.
status query string (enum) no Filter by submission status.
limit query integer no Maximum records (1–100, default 50).
offset query integer no Records to skip.

Responses

StatusDescription
200 Paginated list of submissions.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/store/submissions/{submissionId}

Get store submission

Returns a single store submission by id. Requires `store_submission.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
submissionId path string<uuid> yes Store submission identifier (UUIDv7).

Responses

StatusDescription
200 The store submission.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
submission_id string<uuid>
saas_package_id string<uuid>
listing_id string<uuid>
build_id string<uuid>
status string (enum) draftpending_reviewin_reviewapprovedrejectedpublished
reviewer_notes string
submitted_at string<date-time>
created_at string<date-time>
updated_at string<date-time>
GET /v1/store/submissions/{submissionId}/status

Get store submission status

Returns the current status details for a store submission including any reviewer notes. Requires `store_submission.view` permission.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
submissionId path string<uuid> yes Store submission identifier (UUIDv7).

Responses

StatusDescription
200 Submission status details.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
404 404 Not Found — the requested resource does not exist or is not visible to the caller.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
submission_id string<uuid>
status string (enum) draftpending_reviewin_reviewapprovedrejectedpublished
reviewer_notes string
updated_at string<date-time>
POST /v1/store/submissions/compliance-check

Run submission compliance check

Triggers a compliance pre-check for a submission using the local compliance evaluation service (distinct from `POST /v1/store/compliance/check` which is database-backed). Returns a list of compliance issues and a pass/fail result. Requires `store_submission.view` permission.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
submission_id string<uuid> yes

Responses

StatusDescription
200 Compliance check completed. `passed` indicates whether all checks passed.
400 `INVALID_JSON` or `VALIDATION_ERROR`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement.
422 `VALIDATION_ERROR` — submission is missing required prerequisites for compliance evaluation.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
passed boolean Whether all compliance checks passed.
issues array of object