Many software developers build their product on Platform.sh. You can take several approaches, some of which are very straightforward. For instance, you can become a member of our Agency Partner Program. Or you can take advantage of our White-label offering to deliver a fully functional, fully-featured Platform.sh PaaS, branded with your organization’s logo.
But if your business model doesn't fit into either of the above scenarios, let's explore some other options that might work for you.
Scenario: sell limited-access, PaaS-based projects
Our Agency Partner Program and White-label offering won’t necessarily lend themselves to all possible circumstances. There are perfectly valid scenarios that you might want to consider. Something that was recently brought to our attention? The desire to use Platform.sh for hosting as a PaaS while, at the same time, being able to limit what customers can actually access—especially in terms of codebase and services. It’s likely easier to understand this with an example:
- You develop your own Drupal distribution.
- You’d like your users to purchase a PaaS-enabled hosting of your Drupal distribution, with an awesome development workflow.
- You’d like to restrict codebase access to just modules and themes.
If you opted for any of our standard avenues, you’d end up exposing your users to full project access. But that’s not something you’d want to do.
The user’s repository
We won’t cover this extensively because it’s not the main point of this article. But we would like to give you a few ideas about how the end-user’s repository with themes and modules could be brought into the Platform.sh project with the rest of the codebase you’ll be hiding from your users.
The easiest way to do this is to provide the user with a ready-to-use [.platform.app.yaml](https://docs.platform.sh/configuration/app.html)
file they’d save at the root of their own repository, together with their modules and themes directories. The .platform.app.yaml
would assume the presence of such folders and have all the instructions to bring them into the main project. With this setup, the user’s repository can be connected to the project on Platform.sh via one of our source integrations.
Of course, this approach would still expose too much of the platform that’s running the end-user’s project behind the scenes, with a very serious risk of them being able to compromise the project altogether. More generally, they’d have the ability to change things that you might not want them to change, e.g., the Drupal distribution itself, as in our example.
Another, more complex approach would be to use Git submodules and some CI workflows to tie the whole experience together. For example:
- The Platform.sh project’s main repository (that you own) has the Drupal distro and all the necessary Platform.sh config.
- Each of the user’s repositories is linked to one, and only one, Platform.sh project.
- Themes and modules can be brought in via submodules (and moved around via the build and deploy hooks, if necessary).
- When the user pushes up code to the production branch on their repo, we would want to trigger a push to the production branch in the project’s repo to be updated with the latest version, which, in turn, would trigger a deployment on Platform.sh.
- When a Pull Request is opened on the user’s repository, we’d like to trigger a new PR on the project’s repository, which updates the submodule to the user’s PR commit and, in turn, opens a PR environment on Platform.sh.
Points 4 and 5 will require setting up additional CI workflows of some sort, e.g., via GitHub actions, to provide an automagic experience.
Provisioning, selling, and billing Platform.sh projects via API
The other, perhaps, larger task you’d have to confront is setting up your own ecommerce website, where you can:
- Manage a stock of Platform.sh projects that ship with your Drupal distribution.
- Sell these kinds of projects as subscriptions.
- Bill customers.
- Provide customers with access and billing details for the subscription they purchased.
- Other (you name it).
Is this possible? Of course! We have a rich public API. And we have SDKs implementing it, too. In the remainder of this article, I’ll present an embryonic WooCommerce plugin I developed specifically for this blog post. 💪🏼
The (very few) features in the plugin are:
- Provision new projects when adding new stock for a product.
- View a summary of provisioned projects, their status, and orders they’re linked to.
- Provide customers with a summary of access details upon order completion.
Provisioning when adding stock
First things first, as this is a very rudimentary plugin (for now); I’m not supporting WooCommerce subscription products, which are paid add-ons. Instead, I’m using the standard product type (that comes out of the box) to showcase how to interact with the relevant APIs upon adding new stock to a product.
Here’s a screen capture of a new product I set up to map to a Platform.sh product. In this case, the GIF is showing a product that will map onto a Development Plan deployed in the DE-2 region. All you need to do is add two custom attributes as shown in the GIF animation: region and plan.
When this product is saved, the following will happen:
- For each newly added stock, a new Platform.sh project is created. This is done via POST /organizations/{organization_id}/subscriptions, implemented in the SDK as
PlatformClient()::createSubscription()
- Initial information about the newly created subscriptions (projects) is stored in the plugin’s table
The projects need time to be provisioned, so the subscriptions won’t be active to begin with. Their status can be viewed (and refreshed) at /wp-admin/admin.php?page=platform-sh
IMPORTANT: when you add new stock to an existing product, only the number of projects necessary to reach the overall new stock count will be provisioned. For instance, if you had created a product with a stock count of 10, then you come back and change the stock count to 15, only 5 new projects will be provisioned (assuming, of course, none got sold in the meantime)—not 15 new ones!
Summary of provisioned projects, with status and related orders
This is what the page mentioned above looks like:
The information about each subscription in this table is updated at each refresh (a better way of executing this would be to do it in the background). A newly created subscription, as seen in this table, would have a status of requested or provisioning, with no project or order listed against it.
In this instance, you can see that I have four products: 15, 19, 22, 24. Of these, product 15 has a stock of 2, with two subscriptions associated. The subscription ID represents a Platform.sh subscription to which a project is associated. In the table above, all projects have been fully provisioned. Only one has been initialized (codebase deployed, HTTP routes generated, and containers up and running) and sold with order 46.
Initializing projects
It’s important to note that when a new subscription is created via the API, it subsequently needs to be initialized with a codebase. You don’t want to sell uninitialized projects, first, because that isn’t the current scenario’s intent, and second, because it would be silly to sell an empty project that doesn’t even have functional HTTP routes leading to a holding page.
That said, I didn’t build this functionality into the plugin, so the project you see initialized in the table above was brought to that state using our official CLI (which—FYI—just also happens to be the best reference for how to use the PHP SDK and our public APIs).
Ideally, if we wanted to add the initialization feature to the plugin, we’d leverage a queue system to do this in the background. If you hosted your WooCommerce shop on Platform.sh, you could leverage our workers feature to do just that.
Purchasing and summary of access details
Since we leverage standard WooCommerce products, a customer can purchase these normally, and the stock count will automatically be reduced accordingly.
Additionally, our plugin will perform other operations (once the order is marked as completed, which is not done automatically upon purchase):
- A suitable subscription will be marked as sold by associating the new order with it in our plugin’s table.
- A new WordPress post will be created for the customer, where the access details are saved for them; given the current rudimentary nature of the plugin, all we’re now saving in that post is the primary project URL.
What about the functionality the plugin doesn’t cover?
Believe me, there is a lot this plugin should and could be doing and currently doesn’t. Let’s see some of the functionality you might want to support in the future.
Get billing information
At some point, you’ll need to get billing information for a user. In the most recent versions of Platform.sh, a user is an instance of an organization. Therefore, you need the API.
GET /organizations/{organization_id}
In the PHP SDK, this is implemented as PlatformClient::getOrganizationByName()
. Once you have your organization, you can get its billing profile and its billing address. For example:
$client = new PlatformClient();
$client->getConnector()->setApiToken( $_ENV['PLATFORMSH_TOKEN'], 'exchange' );
$org = $client->getOrganizationByName( 'username' );
$profile = $org->getProfile()->getProperties();
$address = $org->getAddress()->getProperties();
Backups
It might be that you want to sell backups as add-on packages. Which means you also want to trigger these backups yourself. Whether by user input or in a scheduled fashion, it doesn’t really matter. What matters is that you can do that via our API.
POST /projects/{projectId}/environments/{environmentId}/backup
With our PHP SDK, it would look something like this:
$client = new PlatformClient();
$client->getConnector()->setApiToken( $_ENV['PLATFORMSH_TOKEN'], 'exchange' );
$subId = 123435; // please, use an actual subscription id :)
$project = $client->getSubscription( $subId )->getProject();
$project->getEnvironment( $project->default_branch )->backup();
Of course, you can also delete backups.
Domains
Depending on the model you choose, you might want to have domain management as a paid add-on (or not). Again, it doesn’t matter. Once again, what matters is that you can handle all this via the API. To add a new domain, the API is:
POST /projects/{projectId}/domains}
Using the PHP SDK, it would look something like this:
$client = new PlatformClient();
$client->getConnector()->setApiToken( $_ENV['PLATFORMSH_TOKEN'], 'exchange' );
$subId = 123435; // please, use an actual subscription id :)
$project = $client->getSubscription( $subId )->getProject();
$domainName = '...';
$sslOptions = '...';
$project->addDomain( $domainName, $sslOptions);
FleetOps
Fleet management is something that Platform.sh makes very easy for you. This, too, can be done via our API. In fact, in the past, we’ve produced another reference implementation (built on Symfony) that uses the PHP SDK to do exactly that. It’s called Admiral. And there’s nothing stopping you from borrowing from Admiral to extend our WooCommerce plugin further!
Conclusions
The objective of this article was to prove that it’s entirely feasible to build your own ecommerce shop to resell Platform.sh projects in ways that aren’t accounted for by our standard offerings, like our Partner Program and White-label initiative.
We maintain SDKs for various languages, so you can talk to our rich API. In this article, I’ve shown you how easy it is to leverage the PHP SDK to develop a WooCommerce plugin. Of course, the plugin is just an exercise, a reference implementation, far from being a comprehensive solution. But it’s certainly a starting point for any of you considering the possibility.
Of course, we’re always here to help!