Generate the Service Broker Feature

The service broker feature defines three new record types: the Service, Plan, and ServiceInstance. If you're familiar with Heroku, CloudFoundry, or the Open Service Broker spec then you already know how these work.

  • Services and Plans are typically managed through an admin-facing service or a corresponding Admin CLI.
  • Services and Plans can typically be displayed as read-only through an end user-facing service or corresponding User CLI.
  • Plan records are typically synchronized with a payment provider. For example, if you use Stripe, you would create a Stripe Product record for every SaaS RS Plan record. SaaS RS provides this synchronization code.
  • ServiceInstance records are typically maintained by a Stripe Callback endpoint that you would build and use to detect certain Stripe events such as:
    • when a purchase is completed, create a ServiceInstance record to track it
    • when a subscription is canceled, soft-delete the corresponding ServiceInstance record
    • update your user service endpoint to check the active ServiceInstance records before deciding to allow certain operations

Generate the Service Broker feature like this:

$ saas-rs generate feature --name service-broker --service user --version 1

The following content is added or changed in your Rust workspace:

crates/
├── config_store/
│   ├── src/
│   │   └── bucket.rs
└── user_server/
│   └── src/
│       └── v1/
│           ├── controllers/
│           │   ├── mod.rs
│           │   ├── plan.rs
│           │   ├── service.rs
│           │   └── service_instance.rs
│           └── mod.rs
metadata/
└── service_broker/
│   ├── service_1.yaml
│   └── service_2.yaml
proto/
└── acme/
    └── user/
        └── v1/
            ├── plan.proto
            ├── plan_resource.proto
            ├── service.proto
            ├── service_resource.proto
            ├── service_instance.proto
            ├── service_instance_resource.proto
            └── user_service.proto

Bootstrapping ConfigStore Services and Plans with YAML files

The metadata/service_broker/ folder shows two example service definitions and their corresponding plans, defined in YAML.

The first might be used if you want to charge a one-time membership fee when someone subscribes to it.

kind: Service
id: d1ui8n71t0s84oaqjc30
name: my-service-1
description: My Service 1
visible: true
planUpdateable: false
metadata:
  displayName: My Service 1
---
kind: Plan
id: d1ui8n71t0s84oaqjc3g
serviceId: d1ui8n71t0s84oaqjc30
name: default
description: Monthly subscription
metadata:
  displayName: Default
  costs:
    - id: d1ui8n71t0s84oaqjc40
      unit: initiation fee
      amount:
        usd: 100

The second might be used if you wanted to offer the service as a subscription, using variously priced plans:

kind: Service
id: d1ui8n71t0s84oaqjc4g
name: my-service-2
description: My Service 2
visible: true
planUpdateable: true
metadata:
  displayName: My Service 2
---
kind: Plan
id: d1ui8n71t0s84oaqjc50
serviceId: d1ui8n71t0s84oaqjc4g
name: basic
description: Basic
metadata:
  displayName: Basic
  bullets:
    - first feature
  costs:
    - id: d1ui8n71t0s84oaqjc60
      unit: per month
      recurringInterval: month
      amount:
        usd: 20
---
kind: Plan
id: d1ui8n71t0s84oaqjc5g
serviceId: d1ui8n71t0s84oaqjc4g
name: professional
description: Professional
metadata:
  displayName: Professional
  bullets:
    - first feature
    - second feature
  costs:
    - id: d1ui8n71t0s84oaqjc6g
      unit: per month
      recurringInterval: month
      amount:
        usd: 50

Notice that records are given pre-allocated static XIDs, which are committed to Git. These IDs would also occur as consts in your Rust code. Keep in mind that once you've created at least one service instance for a given plan, you can no longer make changes to the plan, and your only path forward is to discontinue the plan and completely replace it with a new plan that has different parameters. It's up to you to decide how long to service your customers on an old plan. I've seen some managed service providers offer customers 6 months to get off of a plan that is being retired.

A bootstrap mechanism is required to upload these YAML files into corresponding Service and Plan buckets in your ConfigStore. An Admin CLI is typically perfect for this.

Synchronizing Services and Plans with Stripe

Once Service and Plan records are defined in your ConfigStore, they need to be synchronized with Stripe. For every Plan record, you will want to create a Stripe Product record, and corresponding Stripe Price records.

SaaS RS can provide pre-built code that performs this synchronization, but it is not published in open source yet because it is based on a feature branch of async-stripe, and the saas-rs-sdk crate cannot reference any non-tagged feature branches of its dependencies (a restriction imposed by crates.io).

Once your Stripe Product records exist, you can log into the Stripe console and test by generating a new invoice or subscription that contains one or more products. Then your web front-end team may decide to offer end users a self-service way to do this, to automate it. This is only suitable in situations where you're willing to disclose your pricing. This would typically not be the case for professional services oriented service offerings.


©2025 SaaS RS | Website | GitHub | GitLab | Contact