Installing a Marketplace App
This tutorial covers finding an app in the marketplace, installing it into your org, polling until it is active, and accessing the provisioned endpoint.
Prerequisites
- An authenticated ButtrBase session with an active org
- Org admin rights (required to initiate an install)
---
Step 1 — Browse the Marketplace
~~~http
GET /api/marketplace
Authorization: Bearer
Or search by name:
~~~http GET /api/marketplace?q=datasync ~~~
Find the slug of the app you want to install (e.g. datasync-pro).
---
Step 2 — View App Details
~~~http GET /api/marketplace/datasync-pro ~~~
Check the available deployment_modes, pricing_model, and base_price_cents
before committing.
---
Step 3 — Install
~~~http
POST /api/marketplace/datasync-pro/install
Authorization: Bearer
{ "deployment_mode": "single_tenant", "plan_id": "pro", "quantity": 1 } ~~~
~~~jsonc // 202 Accepted { "install_id": "inst_01def...", "status": "provisioning" } ~~~
ButtrBase immediately calls the publisher's provision webhook. The install is
active once the publisher's webhook responds with an endpoint URL.
---
Step 4 — Poll Until Active
~~~typescript
async function waitForInstall(installId: string, token: string) {
for (let i = 0; i < 20; i++) {
const res = await fetch(/api/installs/${installId}, {
headers: { Authorization: Bearer ${token} },
});
const install = await res.json();
if (install.status === 'active') return install; if (install.status === 'provisioning_failed') throw new Error('Provisioning failed');
await new Promise(r => setTimeout(r, 3000)); } throw new Error('Timed out waiting for install'); }
const install = await waitForInstall(installId, token); console.log('Ready at:', install.endpoint_url); ~~~
---
Step 5 — Access the Install
Once active, the install record contains the endpoint_url of your running instance:
~~~jsonc { "install_id": "inst_01def...", "app": { "name": "DataSync Pro", "slug": "datasync-pro" }, "status": "active", "endpoint_url": "https://acme.datasync.example", "deployment_mode": "single_tenant", "payment_source": "direct", "current_period_end": "2026-06-17T00:00:00Z" } ~~~
Direct your users to endpoint_url. The app knows which org it is serving
because ButtrBase issued scoped credentials during provisioning.
---
Checking Access from the App's Frontend
After navigating to the app, its frontend can call:
~~~http
GET /api/marketplace/apps/:app_id/access
Authorization: Bearer
To confirm the install is active and whether the current user has admin rights within the app's own context:
~~~jsonc { "is_app_admin": false, "is_org_owner": true, "install_status": "active", "install_id": "inst_01def..." } ~~~
---
Deprovisioning
To cancel and remove the install:
~~~http
DELETE /api/installs/inst_01def...
Authorization: Bearer
Status transitions to deprovisioning, then deprovisioned once the publisher
tears down the tenant. Billing stops at the end of the current period.