SaaS Builder
Build and manage SaaS products on Backbuild. Configure packages, pricing plans, custom domains, marketing pages, application screens, and monitor revenue.
SaaS Packages
List Packages
GET /v1/saas-packages The organization is resolved from the authenticated session.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
search | string | Filter packages by name or slug |
page | integer | Page number (1-based) |
page_size | integer | Results per page |
Create Package
POST /v1/saas-packages The package is created under the authenticated user’s organization.
Request Body
{
"name": "My SaaS Product",
"slug": "my-saas-product",
"description": "A construction management platform",
"app_name": "My SaaS",
"subdomain": "my-saas-product"
}
Do not send id, org_id, created_at, or
updated_at; these are assigned by the server, and the
organization is resolved from the authenticated session.
Response
On success the complete created package is returned.
{
"success": true,
"data": {
"id": "...",
"name": "My SaaS Product",
"slug": "my-saas-product",
"description": "A construction management platform",
"template_id": null,
"theme_config": {},
"org_config": {},
"listing_id": null,
"created_by": "...",
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Package created; the full record is returned |
400 Bad Request | Malformed JSON or request body validation failure (e.g. missing name, or an invalid/reserved slug) |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to create packages |
409 Conflict | A package with this slug already exists (slugs are globally unique) |
500 Internal Server Error | Unexpected server error |
Get Package
GET /v1/saas-packages/:id Update Package
PUT /v1/saas-packages/:id Delete Package
DELETE /v1/saas-packages/:id Publish Package
POST /v1/saas-packages/:id/publish Make the package publicly available on the marketplace.
Unpublish Package
POST /v1/saas-packages/:id/unpublish Remove the package from the public marketplace. Existing subscribers are not affected.
Pricing Plans
List Pricing Plans
GET /v1/saas-packages/:id/pricing-plans Create Pricing Plan
POST /v1/saas-packages/:id/pricing-plans Request Body
{
"name": "Business Gold",
"slug": "business-gold",
"category": "business",
"plan_tier": "business",
"plan_type": "recurring",
"billing_interval": "monthly",
"price_cents": 9900,
"price_cents_yearly": 99900,
"currency": "USD",
"max_projects": 50,
"max_members": 25,
"credits_monthly": 5000
} category (required) is your own builder-defined plan group key.
plan_tier (required) is the platform-canonical entitlement
bucket (academic_free, pro, team,
business, or enterprise). Prices are in the
smallest currency unit (cents). These are values you define for
your SaaS product’s plans.
Do not send id, org_id, created_at, or
updated_at; these are assigned by the server, and the
organization is resolved from the authenticated session. The package is taken
from the path.
Response
On success the complete created pricing plan is returned, including any
per-timeframe price rows under prices (an array, empty when none
were supplied) and default values for fields you did not set.
{
"success": true,
"data": {
"id": "...",
"saas_package_id": "...",
"name": "Business Gold",
"slug": "business-gold",
"description": null,
"category": "business",
"plan_tier": "business",
"plan_type": "recurring",
"billing_interval": "monthly",
"price_cents": 9900,
"price_cents_yearly": 99900,
"currency": "USD",
"max_projects": 50,
"max_members": 25,
"credits_monthly": 5000,
"features": {},
"limits": {},
"stripe_price_id": null,
"stripe_product_id": null,
"stripe_sync_status": "pending",
"sort_order": 0,
"is_active": true,
"is_highlighted": false,
"version": 1,
"prices": [],
"created_by": "...",
"updated_by": null,
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Pricing plan created; the full record is returned |
400 Bad Request | Malformed JSON or request body validation failure (e.g. missing required field, or an invalid plan tier) |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to manage pricing plans |
404 Not Found | The package does not exist in your organization |
409 Conflict | A plan with this slug already exists for the package |
500 Internal Server Error | Unexpected server error |
Get Pricing Plan
GET /v1/saas-packages/:id/pricing-plans/:planId Update Pricing Plan
PUT /v1/saas-packages/:id/pricing-plans/:planId Delete Pricing Plan
DELETE /v1/saas-packages/:id/pricing-plans/:planId Sync Pricing Plans to Stripe
POST /v1/saas-packages/:id/pricing-plans/sync Synchronize all pricing plans for the package with Stripe. Creates or updates Stripe Products and Prices to match the platform definitions. Published plans are served from Stripe as the source of truth for pricing.
Custom Domains
List Domains
GET /v1/saas-packages/:id/domains Add Domain
POST /v1/saas-packages/:id/domains Request Body
{
"domain": "app.example.com"
}
Do not send id, org_id, status,
created_at, or updated_at; these are assigned
by the server, and the organization is resolved from the authenticated session.
The package is taken from the path.
Response
On success the complete created domain is returned. A new domain starts in
pending_verification status with a DNS verification token to add to
your DNS records.
{
"success": true,
"data": {
"id": "...",
"domain": "app.example.com",
"domain_type": "alias",
"saas_package_id": "...",
"ssl_status": "pending",
"dns_verification_token": "...",
"dns_verified_at": null,
"status": "pending_verification",
"is_default": false,
"environment": "production",
"api_base_url": "...",
"created_by": "...",
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Domain registered; the full record is returned |
400 Bad Request | Malformed JSON, invalid package ID, or request body validation failure (e.g. missing or malformed domain) |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to add domains |
404 Not Found | The package does not exist in your organization |
500 Internal Server Error | Unexpected server error (a domain that is already registered is rejected here) |
Get Domain
GET /v1/saas-packages/:id/domains/:domainId Remove Domain
DELETE /v1/saas-packages/:id/domains/:domainId Verify DNS
POST /v1/saas-packages/:id/domains/:domainId/verify Verify that the required DNS records are configured for the custom domain. DNS verification must pass before the domain becomes active.
Marketing Pages
List Marketing Pages
GET /v1/saas-packages/:id/marketing-pages Create Marketing Page
POST /v1/saas-packages/:id/marketing-pages Request Body
{
"title": "Features",
"slug": "features",
"page_type": "feature",
"content": { ... },
"seo_title": "Features",
"seo_description": "Explore the features of our platform"
}
Do not send id, org_id, status,
created_at, or updated_at; these are assigned
by the server (a new page starts in draft status), and the
organization is resolved from the authenticated session. The package is taken
from the path.
Response
On success the complete created marketing page is returned.
{
"success": true,
"data": {
"id": "...",
"saas_package_id": "...",
"slug": "features",
"title": "Features",
"meta_description": "Explore the features of our platform",
"og_image_url": null,
"page_content": { ... },
"custom_css": null,
"status": "draft",
"published_at": null,
"created_by": "...",
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Marketing page created in draft status; the full record is returned |
400 Bad Request | Malformed JSON, invalid package ID, or request body validation failure (e.g. missing title, or an invalid slug) |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to manage marketing pages |
404 Not Found | The package does not exist in your organization |
409 Conflict | A page with this slug already exists for the package |
500 Internal Server Error | Unexpected server error |
Get Marketing Page
GET /v1/saas-packages/:id/marketing-pages/:pageId Update Marketing Page
PUT /v1/saas-packages/:id/marketing-pages/:pageId Delete Marketing Page
DELETE /v1/saas-packages/:id/marketing-pages/:pageId Publish Marketing Page
POST /v1/saas-packages/:id/marketing-pages/:pageId/publish Screen Definitions
List Screen Definitions
GET /v1/saas-packages/:id/screen-definitions Create Screen Definition
POST /v1/saas-packages/:id/screen-definitions Request Body
{
"screen_key": "dashboard",
"screen_type": "custom",
"layout_config": { ... },
"component_config": { ... },
"sort_order": 0,
"is_active": true
}
Do not send id, org_id, created_at, or
updated_at; these are assigned by the server, and the
organization is resolved from the authenticated session. The package is taken
from the path.
Response
On success the complete created screen definition is returned.
{
"success": true,
"data": {
"id": "...",
"saas_package_id": "...",
"screen_key": "dashboard",
"screen_type": "custom",
"layout_config": { ... },
"component_config": { ... },
"visibility": "default",
"sort_order": 0,
"is_active": true,
"created_by": "...",
"updated_by": null,
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Screen definition created; the full record is returned |
400 Bad Request | Malformed JSON, invalid package ID, or request body validation failure |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to manage screen definitions |
404 Not Found | The package does not exist in your organization |
409 Conflict | A screen definition with this key already exists for the package |
500 Internal Server Error | Unexpected server error |
Get Screen Definition
GET /v1/saas-packages/:id/screen-definitions/:screenDefId Update Screen Definition
PUT /v1/saas-packages/:id/screen-definitions/:screenDefId Delete Screen Definition
DELETE /v1/saas-packages/:id/screen-definitions/:screenDefId App Configs
List App Configs
GET /v1/saas-packages/:id/app-configs Create App Config
POST /v1/saas-packages/:id/app-configs Request Body
{
"platform": "web",
"app_name": "My SaaS",
"bundle_identifier": "com.example.mysaas",
"version_name": "1.0.0",
"platform_config": {
"theme_id": "...",
"navigation": [...]
}
}
Do not send id, org_id, status,
created_at, or updated_at; these are assigned
by the server (a new config starts in draft status), and the
organization is resolved from the authenticated session. The package is taken
from the path.
Response
On success the complete created app config is returned.
{
"success": true,
"data": {
"id": "...",
"saas_package_id": "...",
"platform": "web",
"app_name": "My SaaS",
"bundle_identifier": "com.example.mysaas",
"version_name": "1.0.0",
"version_code": null,
"icon_url": null,
"splash_screen_url": null,
"splash_background_color": null,
"signing_config_ref": null,
"platform_config": { "theme_id": "...", "navigation": [...] },
"eas_project_id": null,
"status": "draft",
"created_by": "...",
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | App config created in draft status; the full record is returned |
400 Bad Request | Malformed JSON, invalid package ID, or request body validation failure |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to manage app configs |
404 Not Found | The package does not exist in your organization |
409 Conflict | An app config already exists for this platform on the package |
500 Internal Server Error | Unexpected server error |
Get App Config
GET /v1/saas-packages/:id/app-configs/:configId Update App Config
PUT /v1/saas-packages/:id/app-configs/:configId Delete App Config
DELETE /v1/saas-packages/:id/app-configs/:configId Data Bundles
Create Data Bundle
POST /v1/saas-packages/:id/data-bundles Create a new data bundle snapshot. Bundles capture the complete state of a package’s configuration for versioned deployment.
Request Body
{
"bundle_hash": "sha256:...",
"content": { ... },
"bundle_url": "https://...",
"bundle_size_bytes": 1048576
}
Do not send id, org_id, bundle_version,
is_current, created_at, or updated_at;
these are assigned by the server (bundle_version is
auto-incremented per package, and a new bundle is not current until published),
and the organization is resolved from the authenticated session. The package is
taken from the path.
Response
On success the complete created data bundle is returned.
{
"success": true,
"data": {
"id": "...",
"saas_package_id": "...",
"bundle_version": 1,
"bundle_hash": "sha256:...",
"bundle_url": "https://...",
"bundle_size_bytes": 1048576,
"content": { ... },
"is_current": false,
"published_at": null,
"created_by": "...",
"created_at": "2026-04-10T08:00:00Z",
"updated_at": "2026-04-10T08:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Data bundle created; the full record is returned |
400 Bad Request | Malformed JSON, invalid package ID, or request body validation failure |
401 Unauthorized | Missing or invalid access token |
403 Forbidden | Caller lacks permission to manage data bundles |
404 Not Found | The package does not exist in your organization |
500 Internal Server Error | Unexpected server error |
Get Current Bundle
GET /v1/saas-packages/:id/data-bundles/current Publish Bundle
POST /v1/saas-packages/:id/data-bundles/:bundleId/publish Promote a data bundle to the live version. The previous bundle is retained for rollback.
Rollback Bundle
POST /v1/saas-packages/:id/data-bundles/:bundleId/rollback Revert to the previously published data bundle.
Revenue Analytics
Revenue Summary
GET /v1/saas-packages/:id/revenue/summary Aggregate revenue metrics for the package: MRR, ARR, churn rate, active subscribers, and average revenue per user.
Response
{
"data": {
"mrr": 125000,
"arr": 1500000,
"churn_rate": 0.032,
"active_subscribers": 142,
"arpu": 880,
"currency": "usd"
}
} Revenue Timeseries
GET /v1/saas-packages/:id/revenue/timeseries Query Parameters
| Parameter | Type | Description |
|---|---|---|
start_date | ISO 8601 | Start of the time range |
end_date | ISO 8601 | End of the time range |
interval | string | day, week, or month |
Revenue by Plan
GET /v1/saas-packages/:id/revenue/by-plan Revenue breakdown by pricing plan, showing subscriber counts and revenue contribution per plan.