Skip to content

Stayblox CLI: apps

The stayblox app command group lets you author, publish, and debug apps from the terminal. It is part of the same @stayblox/cli package used for themes. Install once and both surfaces are available.

bash
npm install -g @stayblox/cli

Requires Node 20 or later.

Authenticate

App commands use an account personal access token (PAT) minted in the Account panel (Developer access tokens). Generate a token with the develop-apps ability. It is shown once on creation.

bash
stayblox login --token <your-account-pat>

This stores the token in ~/.config/stayblox/config.json. The account PAT is your authoring credential and is not the same as the runtime token your app server uses to call the GraphQL API. The runtime token is issued when you run app install.

Configuration: app.toml

All app configuration lives in app.toml in your app directory. Commands that need the app slug or manifest read this file automatically; pass --app <slug> to override.

toml
name = "Smart Lock Manager"
type = "remote"               # "remote" | "payment" | "channel" | "injection"
distribution = "private"      # "private" | "public"
# slug =                      # public: set manually; private: written back on first push

scopes = ["read_bookings", "read_contacts", "write_conversations"]
capabilities = []             # "act_as_assignment_provider" | "register_task_types"
webhooks = ["booking.confirmed", "booking.cancelled"]
webhook_url = "https://app.example.com/webhooks/stayblox"

# The following keys are for public apps only (not supported for private apps):

[oauth]
redirect_uris = ["https://app.example.com/auth/stayblox/callback"]

[app_page]
url = "https://app.example.com/stayblox"

[[settings_schema]]
key = "api_key"
type = "string"
label = "API key"
required = true

[[injections]]
slot = "head"
template = '<script src="https://cdn.example.com/widget.js?key={{ api_key }}"></script>'

[[metafields]]
owner = "booking"
key = "access_code"
type = "string"
visibility = "guest"

For the full key reference see Configuration (app.toml).

Private-app slug write-back: on the first push of a private app (no slug in app.toml), the server generates a slug and the CLI writes it back into app.toml. Commit the updated file.

Not in app.toml: the app icon, store listing, pricing, and gallery images for public apps are managed in the Account-panel Dashboard.


Account-scoped commands

These commands operate on your account and do not require --team.

app init [dir]

Scaffolds an app.toml, an icon.png placeholder, and a README.md in a new directory. Prompts for the app name.

bash
stayblox app init my-rate-sync

Edit app.toml before pushing.


app validate

Reads app.toml in the current directory and sends it to the server for a dry-run validation report. Exits non-zero on any error, making it a useful CI gate.

bash
stayblox app validate

Example output on success:

✔ Valid.

On failure:

✖ Custom apps support type: remote only in this version.
✖ Scope "read_invoices" is not a known scope.

app push [--no-release]

Pushes app.toml to create or update the app. Each push creates an immutable version. By default the new version is also released (made live). Pass --no-release to push a version without releasing it, then promote it manually with app release.

bash
stayblox app push
stayblox app push --no-release

app release [version]

Promotes the latest pending version to live. Pass a version number to re-release an older version (rollback).

bash
stayblox app release        # promote the latest pending version
stayblox app release 3      # roll back to version 3

app versions

Lists all versions for the app: id, status, and whether that version is currently live.

bash
stayblox app versions

app list

Lists all apps on your account.

bash
stayblox app list

app teams

Lists the teams your account can install apps on, with their slugs.

bash
stayblox app teams

app show

Shows the full details for the app. Reads the slug from app.toml; override with --app <slug>.

bash
stayblox app show
stayblox app show --app rate-sync

app installs

Lists all team installs for the app.

bash
stayblox app installs
stayblox app installs --app rate-sync

Team-scoped commands

These commands require --team <slug> to identify the team. Use stayblox app teams to find your team slugs.

app install --team <slug>

Installs the app on a team. On the first install, prints the per-install runtime token and webhook secret; both are shown only once.

bash
stayblox app install --team 8cs3o-qe

Output on first install:

Installed rate-sync on 8cs3o-qe.
Token: stayblox_app_...
Webhook secret: whsec_...
Saved once. Copy now.

Store the runtime token as STAYBLOX_APP_TOKEN (or similar) in your server's environment and pass it as Authorization: Bearer <token> on every GraphQL request. Store the webhook secret for HMAC verification. See Signing & security.


app uninstall --team <slug>

Removes the install from a team. The runtime token is revoked immediately.

bash
stayblox app uninstall --team 8cs3o-qe

app token --team <slug>

Rotates the install's runtime token. The old token stops working immediately. The new token is printed once.

bash
stayblox app token --team 8cs3o-qe

app logs --team <slug>

Shows recent webhook deliveries for the install: event id, topic, timestamp, status, and attempt count.

bash
stayblox app logs --team 8cs3o-qe

Output:

01J9A...  booking.confirmed  2026-06-28 12:00:01  delivered  attempts:1
01J9B...  booking.cancelled  2026-06-28 11:58:43  delivered  attempts:1

The first column is the event id (ULID). Pass it to app replay to re-POST that delivery to your local server.


app forward --team <slug> --to <host:port>

Routes live webhook deliveries from the platform to your local server. No tunnel or persistent server needed; it polls every second and re-POSTs signed deliveries to the local target. Press Ctrl-C to stop; normal delivery to your webhook_url resumes automatically about 30 seconds after the last poll.

bash
stayblox app forward --team 8cs3o-qe --to localhost:3000

Forwarded deliveries carry the same HMAC headers as production deliveries, so your verification code is exercised as-is. See the Signing & security guide for verification examples.


app replay <eventId> --team <slug> --to <host:port>

Re-POSTs a persisted delivery to your local server. Headers and body are identical to the original, including the HMAC signature.

bash
stayblox app replay 01J9XYZ... --team 8cs3o-qe --to localhost:3000

app dev --team <slug> [--to <host:port>]

Convenience command that ensures a dev install exists on the team, then starts forwarding. Use this to spin up a local development session in one step. (--to is optional; omit it to capture traffic in app logs without re-POSTing to a local server.)

bash
stayblox app dev --team 8cs3o-qe --to localhost:3000

Forwarding mechanics

  1. On start, the CLI polls GET /dev/apps/{slug}/forward. The server returns the current head cursor and no deliveries, so only events that arrive after you start the loop are forwarded.
  2. Every second the CLI polls with ?since=<cursor>, receiving any new deliveries and the updated cursor.
  3. For each delivery the CLI re-POSTs the body with headers verbatim to --to.
  4. Each poll resets the server's forwarding TTL (30 s). When you stop polling, the TTL expires and normal dispatch resumes.

No delivery is lost: the platform stores every delivery row regardless of whether forwarding is active. While the loop runs, the dispatch job is skipped and the row stays pending. app logs and app replay still see it.

Webhook headers on forwarded deliveries

HeaderDescription
X-Stayblox-Signaturesha256=<hex>: HMAC-SHA256 of {timestamp}.{body} keyed with the install's webhook_secret.
X-Stayblox-TimestampUnix seconds at delivery time. Reject if more than 5 minutes old.
X-Stayblox-Event-IdThe event id ULID, matching the envelope.
X-Stayblox-TopicThe topic string (e.g. booking.confirmed).
X-Stayblox-AppThe app slug (e.g. rate-sync). Use this to key verification when one server handles multiple apps.

Verify signatures exactly as you would in production; the algorithm and key are unchanged.

Webhook envelope shape

json
{
  "event_id": "01J9XYZ...",
  "topic": "booking.confirmed",
  "occurred_at": "2026-06-28T12:00:00Z",
  "api_version": "2026-01",
  "team": "8cs3o-qe",
  "resource": { "type": "booking", "id": 4821 }
}

The team field carries the team slug. Per-resource object ids inside resource (booking id, contact id, and so on) remain as integers; they are the handles your app uses to call back to the GraphQL API.

© Stayblox — Developer Platform