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.
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/app/builds/{buildId} Get build job
Returns a single build job by id. Requires `build_job.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
buildId | path | string<uuid> | yes | Build job identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
buildId | path | string<uuid> | yes | Build job identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
cancelled | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
buildId | path | string<uuid> | yes | Build job identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
status | string (enum) pendingqueuedin_progresssuccessfailedcancelled | yes | |
error_message | string | no | |
artifact_url | string<uri> | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
saas_package_id | string<uuid> | yes | |
version | string | yes | |
description | string | no | |
bundle_url | string<uri> | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/app/bundles/{bundleId} Get data bundle
Returns a single data bundle by id. Requires `data_bundle.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
bundleId | path | string<uuid> | yes | Data bundle identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
bundleId | path | string<uuid> | yes | Data bundle identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
published | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
bundleId | path | string<uuid> | yes | Data bundle identifier to roll back to (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
rolled_back | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
saas_package_id | query | string<uuid> | yes | SaaS package identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/app/configs/{configId} Get app config
Returns a single app config by id. Requires `app_config.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
configId | path | string<uuid> | yes | App config identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
configId | path | string<uuid> | yes | App config identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
bundle_id | string | no | |
version_name | string | no | |
version_code | integer | no | |
config_data | object | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/app/configs/{configId} Delete app config
Deletes an app config. Requires `app_config.delete` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
configId | path | string<uuid> | yes | App config identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/app/screens/{screenId} Get screen definition
Returns a single screen definition by id. Requires `screen_definition.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
screenId | path | string<uuid> | yes | Screen definition identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
screenId | path | string<uuid> | yes | Screen definition identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
display_name | string | no | |
layout_config | object | no | |
is_active | boolean | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/app/screens/{screenId} Delete screen definition
Deletes a screen definition. Requires `screen_definition.delete` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
screenId | path | string<uuid> | yes | Screen definition identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean |
/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
| Field | Type | Required | Description |
|---|---|---|---|
events | array of object | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
saas_package_id | string<uuid> | |
domain | string | |
platform_configs | object | Keyed by platform name. Each value is the platform-specific configuration object. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | query | string | yes | The verified domain for the SaaS package. |
platform | query | string (enum) | yes | Target platform. |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string<uuid> | yes | Marketplace listing identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/marketplace/listings/{id} Delete marketplace listing
Deletes a marketplace listing. Requires `marketplace.delete` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string<uuid> | yes | Marketplace listing identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | query | string | yes | The domain to resolve. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
domain | string | |
saas_package_id | string<uuid> | |
package_name | string | |
slug | string | |
logo_url | string<uri> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | query | string | yes | The domain to resolve (must be a valid domain name). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
domain | string | |
saas_package_id | string<uuid> | |
package_name | string | |
slug | string | |
logo_url | string<uri> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
listing_id | string<uuid> | yes | |
publisher_org_id | string<uuid> | no | |
rating | integer | yes | |
review_text | string | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
review_id | string<uuid> | |
listing_id | string<uuid> | |
publisher_org_id | string<uuid> | |
rating | integer | |
review_text | string | |
created_at | string<date-time> |
/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
| Field | Type | Required | Description |
|---|---|---|---|
listing_id | string<uuid> | yes | |
publisher_org_id | string<uuid> | no | |
expires_at | string<date-time> | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/marketplace/subscriptions/{id} Delete marketplace subscription
Cancels and removes a marketplace subscription. Requires `marketplace.subscribe` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string<uuid> | yes | Marketplace subscription identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId} Get a SaaS package
Retrieve a single SaaS package by UUID. Requires `package.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId} Delete a SaaS package
Soft-delete (archive) a SaaS package. Requires `package.delete` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
page | query | integer | no | |
page_size | query | integer | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
models | array of object | |
pagination | object | Page/page_size pagination metadata. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
overrides | array of object | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
platform | query | string (enum) | no | Filter by platform. |
page | query | integer | no | |
page_size | query | integer | no |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
configId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
configId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/app-configs/{configId} Delete an app config
Delete an app config. Requires `app_config.delete`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
configId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Source package UUID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Name for the cloned package. |
description | string | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
connectorId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
connectorId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/connectors/{connectorId} Delete a connector config
Delete a connector config. Requires `connector_config.delete`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
connectorId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
limit | query | integer | no | |
offset | query | integer | no | Number of records to skip for offset pagination. |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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 |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
bundleId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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 |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
bundleId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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 |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
bundleId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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 |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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 |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
domainId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
domainId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
domainId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/feature-flags/{flagId} Get a custom feature flag
Retrieve a custom feature flag by ID.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
flagId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
flagId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | |
description | string | null | no | |
is_enabled | boolean | no | |
metadata | object | null | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
flagId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
pageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
pageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/marketing-pages/{pageId} Delete a marketing page
Delete a marketing page. Requires `marketing_page.delete`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
pageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
pageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
planId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
planId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
planId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
planId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
planId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
planId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
assignments | array of object | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/promotions/{promotionId} Get a promotion
Retrieve a single promotion by ID. Requires `saas_pricing.view`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
promotionId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
promotionId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/promotions/{promotionId} Soft-delete a promotion
Soft-delete (deactivate) a promotion. Requires `saas_pricing.delete`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
promotionId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
environment | string (enum) developmentstagingpreprodproduction | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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 |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
plans | array of object |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
interval | query | string (enum) | no | Aggregation interval. |
periods | query | integer | no | Number of periods (1–365). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
interval | string (enum) dayweekmonth | |
periods | integer | |
series | array of object |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
screenDefId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
screenDefId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/saas-packages/{packageId}/screen-definitions/{screenDefId} Delete a screen definition
Delete a screen definition. Requires `screen_definition.delete`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
screenDefId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
seedId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
seedId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
seedId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
limit | query | integer | no | Maximum events to return (1–50, default 10). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
items | array of object | |
total | integer |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
assignments | array of object | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
tenantOrgId | path | string<uuid> | yes | Tenant organization UUID. |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
tenantOrgId | path | string<uuid> | yes | Tenant organization UUID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
assignments | array of object | yes |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | |
tenantOrgId | path | string<uuid> | yes | Tenant organization UUID. |
Responses
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | Package UUID. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
idOrSlug | path | string | yes | Package slug or UUID (max 256 characters). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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. |
/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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
items | array of object |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
planId | path | string<uuid> | yes | Pricing plan UUID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
new_slug | string | yes | New URL slug (lowercase alphanumeric + hyphens). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
slug | query | string | yes | Package slug or UUID (max 256 characters). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | SaaS package identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
pricing_plan_id | string<uuid> | yes | |
subscriber_org_id | string<uuid> | yes | |
stripe_subscription_id | string | no | |
quantity | integer | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | SaaS package identifier (UUIDv7). |
subscriptionId | path | string<uuid> | yes | Subscription identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | SaaS package identifier (UUIDv7). |
subscriptionId | path | string<uuid> | yes | Subscription identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
packageId | path | string<uuid> | yes | SaaS package identifier (UUIDv7). |
subscriptionId | path | string<uuid> | yes | Subscription identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
cancelled | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
provisionId | path | string<uuid> | yes | Tenant provision identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
provisionId | path | string<uuid> | yes | Tenant provision identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | no | Human-readable reason for deprovisioning, recorded in the audit log. |
Responses
| Status | Description |
|---|---|
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. |
/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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
subscriptions | array of object | |
total | integer | Total count of paused subscriptions. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | no | |
offset | query | integer | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
integrations | array of object | |
total | integer | Total number of integrations for this org. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
integrationId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean (enum) true | |
id | string<uuid> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
integrationId | path | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the provider connectivity test passed. |
message | string | Human-readable detail about the test outcome (may be absent on success). |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
integration | object | A third-party integration configured for an organization. Secret values are never included in responses. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
accountId | path | string<uuid> | yes | Store account identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/store/accounts/{accountId} Update store account
Updates a store account. Requires `store_account.update` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
accountId | path | string<uuid> | yes | Store account identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
account_name | string | no | |
credentials | object | no | Platform-specific credential fields. Encrypted at rest. |
is_active | boolean | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
accountId | path | string<uuid> | yes | Store account identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
deleted | boolean |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
accountId | path | string<uuid> | yes | Store account identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
valid | boolean | |
error | string | Human-readable validation error, present when `valid` is false. |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
saas_package_id | query | string<uuid> | yes | SaaS package identifier (UUIDv7). |
platform | query | string (enum) | yes | Target store platform. |
Responses
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/store/age-ratings/{ratingId} Update age rating
Updates an existing age rating record. Requires `age_rating.update` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
ratingId | path | string<uuid> | yes | Age rating identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
rating_category | string | no | |
content_descriptors | array of string | no | |
questionnaire_answers | object | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Field | Type | Required | Description |
|---|---|---|---|
saas_package_id | string<uuid> | yes | |
platform | string (enum) iosandroidwindowsmacos | no |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
passed | boolean | Whether all compliance checks passed. |
issues | array of object |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
saas_package_id | query | string<uuid> | yes | SaaS package identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
saas_package_id | string<uuid> | |
requirements | array of object | |
supported_regions | array of string |
/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
| Field | Type | Required | Description |
|---|---|---|---|
saas_package_id | string<uuid> | yes | |
return_url | string<uri> | no | URL to redirect to after KYC completion. |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
saas_package_id | query | string<uuid> | yes | SaaS package identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
status | string (enum) not_startedpendingin_reviewapprovedrejected | |
submitted_at | string<date-time> | |
reviewed_at | string<date-time> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/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
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/v1/store/listings/{listingId} Get store listing
Returns a single store listing by id. Requires `store_listing.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
listingId | path | string<uuid> | yes | Store listing identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
listingId | path | string<uuid> | yes | Store listing identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
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
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
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
| Status | Description |
|---|---|
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. |
/v1/store/submissions/{submissionId} Get store submission
Returns a single store submission by id. Requires `store_submission.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
submissionId | path | string<uuid> | yes | Store submission identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
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> |
/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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
submissionId | path | string<uuid> | yes | Store submission identifier (UUIDv7). |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
submission_id | string<uuid> | |
status | string (enum) draftpending_reviewin_reviewapprovedrejectedpublished | |
reviewer_notes | string | |
updated_at | string<date-time> |
/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
| Field | Type | Required | Description |
|---|---|---|---|
submission_id | string<uuid> | yes |
Responses
| Status | Description |
|---|---|
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
| Field | Type | Description |
|---|---|---|
passed | boolean | Whether all compliance checks passed. |
issues | array of object |