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

ParameterTypeDescription
searchstringFilter packages by name or slug
pageintegerPage number (1-based)
page_sizeintegerResults 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

StatusMeaning
201 CreatedPackage created; the full record is returned
400 Bad RequestMalformed JSON or request body validation failure (e.g. missing name, or an invalid/reserved slug)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to create packages
409 ConflictA package with this slug already exists (slugs are globally unique)
500 Internal Server ErrorUnexpected 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

StatusMeaning
201 CreatedPricing plan created; the full record is returned
400 Bad RequestMalformed JSON or request body validation failure (e.g. missing required field, or an invalid plan tier)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage pricing plans
404 Not FoundThe package does not exist in your organization
409 ConflictA plan with this slug already exists for the package
500 Internal Server ErrorUnexpected 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

StatusMeaning
201 CreatedDomain registered; the full record is returned
400 Bad RequestMalformed JSON, invalid package ID, or request body validation failure (e.g. missing or malformed domain)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to add domains
404 Not FoundThe package does not exist in your organization
500 Internal Server ErrorUnexpected 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

StatusMeaning
201 CreatedMarketing page created in draft status; the full record is returned
400 Bad RequestMalformed JSON, invalid package ID, or request body validation failure (e.g. missing title, or an invalid slug)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage marketing pages
404 Not FoundThe package does not exist in your organization
409 ConflictA page with this slug already exists for the package
500 Internal Server ErrorUnexpected 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

StatusMeaning
201 CreatedScreen definition created; the full record is returned
400 Bad RequestMalformed JSON, invalid package ID, or request body validation failure
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage screen definitions
404 Not FoundThe package does not exist in your organization
409 ConflictA screen definition with this key already exists for the package
500 Internal Server ErrorUnexpected 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

StatusMeaning
201 CreatedApp config created in draft status; the full record is returned
400 Bad RequestMalformed JSON, invalid package ID, or request body validation failure
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage app configs
404 Not FoundThe package does not exist in your organization
409 ConflictAn app config already exists for this platform on the package
500 Internal Server ErrorUnexpected 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

StatusMeaning
201 CreatedData bundle created; the full record is returned
400 Bad RequestMalformed JSON, invalid package ID, or request body validation failure
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage data bundles
404 Not FoundThe package does not exist in your organization
500 Internal Server ErrorUnexpected 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

ParameterTypeDescription
start_dateISO 8601Start of the time range
end_dateISO 8601End of the time range
intervalstringday, 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.