Commands for platform operations
The commands of the internal szenera-ops tool that run only with an operator profile: device software, approvals, incidents, queues, organizations, operator accounts.
19 minute readCLIUpdated: 10/25/2026
On this page
Before you start
- For
- Anyone who operates the platform: releases device software, handles incidents, and manages queues and organizations
- Prerequisite
- the platform’s source tree, a profile with
audience: "operator", and theplatform.*permissions named in the “Route and permission” column. The “Key” column says whether an operator keyopk_…may carry the permission.
The commands of the szenera-ops tool that run only with a profile of the audience operator: an operator account or an operator key opk_…. They do not concern customers of the platform and are not part of the szenera command line. They are listed here because whoami, device, audit, player, playback, permission, api-key, and invoice serve both sides, depending on the profile.
The tool lives in the source tree under tools/ops-cli and is not shipped. It runs with pnpm -s szenera-ops <befehl> and carries all 230 commands of the platform. Profiles, environment variables, output, and exit codes are the same as for szenera. In addition, it knows the audience operator (profile field audience, environment variable SZENERA_AUDIENCE), its own profile file .secrets/szenera-profile.json in the source tree, and the fallback to the environments in .secrets/umgebungen.json. A command that serves only one side rejects the profile of the other before a call goes out.
The tables have the same form as under Commands for your organization: command, purpose, route and permission, whether a key may carry the permission, and whether the command changes something. Operator keys are valid for 1 to 365 days (default 90). Which permissions such a key may carry at all is shown by szenera-ops permission catalog --key-eligible under an operator profile. They are the read-only operations routes, the device software, and reading ad sales. Everything else stays reserved for people with two-factor sign-in. Of the 230 commands of the tool, 136 are listed under Commands for your organization, and they are the commands of szenera. The remaining 94 run only under an operator profile and are listed here. 21 of the 136 serve both sides: 14 of them take a route of their own under an operator profile (whoami, device list, device get, audit list, audit get, player get-program, playback timeline, permission catalog, the four api-key … commands, invoice list, and invoice get), and seven run unchanged (health, health public, and the five commands of the escape hatch api …).
Health
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
health deep |
A verdict from five sources, the command to run after a deployment. One red source makes the command red, a silent one appears as unknown |
GET /health/ready, GET /v1/platform/ops/platform-health, GET …/ops/jobs/health, GET …/ops/cache/health, GET …/ops/events/dispatcher/health, GET …/ops/audit/health · platform.ops.health.read, platform.jobs.health.read, platform.cache.stats.read, platform.events.dispatcher.read, platform.audit.health.read |
partly: cache and audit log only with an account | no |
With --json, the response carries the verdict under verdict (green or yellow) and, per source, the fields name, status, and hint under sources. A red verdict ends with exit 11 instead. The counter-check from outside is health public: the same information the status page shows, without a credential and without an operator profile. It answers “What do our customers see right now?” and not “How are things really?”. The command is listed under Commands for your organization.
Fleet devices
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
device list |
The devices of all organizations, including those without an organization. Plus --tenant=<tnt_…>, --all-tenants, --silent-only (silent for over a quarter of an hour) |
GET /v1/platform/ops/devices · platform.ops.device.read |
yes | no |
device get <dev_…> |
One device in the operations view: organization and serial number | GET /v1/platform/ops/devices/{deviceId} · platform.ops.device.read |
yes | no |
device lookup --serial=<text> |
Find a device by its hardware serial number | GET /v1/platform/ops/devices/lookup · platform.ops.device.read |
yes | no |
device get-command <dev_…> <cmd_…> |
What became of a command sent to a device. --wait waits until the end (exit 11 on failed/timeout, exit 12 on the time limit) |
GET /v1/platform/ops/devices/{id}/commands/{commandId} · platform.ops.device.command-read |
yes | no |
device release <dev_…> --reason=reconnect|factory|removed --yes |
Release a device. The reason is mandatory. reconnect and removed leave Wi-Fi and remote access in place. factory takes both along. All displays of the device go with it |
POST /v1/platform/ops/devices/{deviceId}/release · platform.ops.device.reset |
no | yes |
device block <dev_…> --reason=<text> --yes |
Block a device: it loses its organization, all displays go with it, every certificate is revoked, and the API rejects every sign-in with 409 Device.Blocked. The reason (1 to 500 characters) is mandatory |
POST /v1/platform/ops/devices/{deviceId}/block · platform.ops.device.reset |
no | yes |
device unblock <dev_…> |
Lift the block. The device is then unpaired and can be paired again | POST /v1/platform/ops/devices/{deviceId}/unblock · platform.ops.device.reset |
no | yes |
device check-ota <dev_…> |
Make a device look for a new OS version right away. Response 202, --wait additionally needs platform.ops.device.command-read |
POST /v1/platform/ops/devices/{id}/ota-check · platform.ops.device.ota-check |
yes | yes |
device channel --channel=beta|stable|canary --device=<dev_…> --yes |
Change the channel of several devices in one call, --device may be repeated up to 100 times. Each device gets its own result, and a device that fails does not hold up the others |
POST /v1/platform/ops/devices/channel · platform.ops.device.channel |
no | yes |
player get-program <ply_…> |
What is assigned to a display, across all organizations, logged | GET /v1/platform/ops/devices/{playerId}/program · platform.ops.device.playback-read |
yes | no |
playback timeline <ply_…> |
The resolved playback timeline of a display, across all organizations, logged | GET /v1/platform/ops/devices/{playerId}/timeline · platform.ops.device.playback-read |
yes | no |
Every call of device get-command appears in the audit log of the organization concerned. An operator profile cannot use device send-command or device screenshot: these routes require fleet.player.command.issue and reject an operator identity. The tool says so before the call.
Incidents and maintenance windows
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
incident list |
The incident reports, with --id=<inc_…> a single one including its history |
GET /v1/platform/ops/incidents · platform.ops.incident.list, with --id GET …/incidents/{id} · platform.ops.incident.read |
no | no |
incident create --title=… --severity=sev-1…sev-4 --scope=platform|tenant|device-fleet |
Open an incident. --public also puts it on the status page, and without the flag it stays internal |
POST /v1/platform/ops/incidents · platform.ops.incident.open |
no | yes |
incident update <inc_…> --message=… |
Add an entry to the history. --status advances the status at the same time, --public puts the incident on the status page, --internal takes it down |
PATCH /v1/platform/ops/incidents/{id} · platform.ops.incident.update |
no | yes |
incident resolve <inc_…> |
Close an incident, plus --postmortem=<url> |
POST /v1/platform/ops/incidents/{id}/resolve · platform.ops.incident.resolve |
no | yes |
maintenance-window list |
The planned maintenance windows, with --id=<mtw_…> a single one |
GET /v1/platform/ops/maintenance-windows · platform.ops.maintenance.list, with --id platform.ops.maintenance.read |
no | no |
maintenance-window create --title=… --start=… --end=… --scope=… |
Plan a maintenance window. --banner, --notify-days=<tage>, and --block-mutations, which halts the organizations’ write calls |
POST /v1/platform/ops/maintenance-windows · platform.ops.maintenance.create |
no | yes |
maintenance-window update <mtw_…> |
Move or rewrite a window | PATCH /v1/platform/ops/maintenance-windows/{id} · platform.ops.maintenance.update |
no | yes |
maintenance-window cancel <mtw_…> --reason=… |
Cancel a window. The reason goes into the notification | DELETE /v1/platform/ops/maintenance-windows/{id} · platform.ops.maintenance.cancel |
no | yes |
Queues, cache, events, and connections
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
job queues |
The queues with metrics and state, from three sources in one table | GET …/ops/jobs/queues, GET …/ops/jobs/metrics, GET …/ops/jobs/health · platform.jobs.queues.read, platform.jobs.metrics.read, platform.jobs.health.read |
yes | no |
job pause <name> |
Pause a queue. What is running finishes | POST /v1/platform/ops/jobs/queues/{queueName}/pause · platform.jobs.queues.pause |
no | yes |
job resume <name> |
Resume a paused queue | POST /v1/platform/ops/jobs/queues/{queueName}/resume · platform.jobs.queues.resume |
no | yes |
job failed |
The jobs that failed for good, with --not-replayed, --queue=<name>, --id=<kennung> |
GET /v1/platform/ops/jobs/dead-letter, GET …/dead-letter/{id} · platform.jobs.dead-letter.read |
yes | no |
job replay --id=<kennung>|--all --reason=… |
Enqueue a failed job, or many, again. --max (default 100) caps the number |
POST …/jobs/dead-letter/{id}/replay, POST …/jobs/dead-letter/bulk-replay · platform.jobs.replay |
no | yes |
job kill <jobId> --queue=<name> --reason=… --yes |
Abort a running job, response 202 | POST /v1/platform/ops/jobs/{queueName}/{jobId}/force-kill · platform.jobs.force-kill |
no | yes |
job cleanup --yes |
Clear out old dead-letter entries | POST /v1/platform/ops/jobs/cleanup/run · platform.jobs.cleanup |
no | yes |
cache stats |
State, hit rate, and the hot topics, plus --window=1m|5m|1h |
GET …/ops/cache/health, GET …/ops/cache/stats, GET …/ops/cache/topics · platform.cache.stats.read |
no | no |
cache invalidate --topic=<thema>|--pattern=<glob> --reason=… --yes |
Discard a topic or a pattern | POST …/ops/cache/invalidate, POST …/ops/cache/invalidate-pattern · platform.cache.invalidate |
no | yes |
event pending |
What has not been delivered yet. --metrics appends the numbers and health of the dispatcher |
GET /v1/platform/ops/events/outbox/pending · platform.events.outbox.read |
yes | no |
event failed |
What was not delivered for good | GET /v1/platform/ops/events/outbox/dead-letter · platform.events.outbox.read |
yes | no |
event get <evt_…> |
An event with its payload: exactly what was sent | GET /v1/platform/ops/events/outbox/{eventId} · platform.events.outbox.read |
yes | no |
event replay --id=<evt_…>|--all --reason=… |
Deliver an event, or many, again, plus --event-type, --since, --max |
POST …/events/outbox/{eventId}/replay, POST …/events/outbox/replay-bulk · platform.events.outbox.replay |
no | yes |
connection list |
The open real-time connections: display, portal session, or renderer | GET /v1/platform/realtime/connections · platform.realtime.read |
no | no |
connection disconnect <id> --yes |
Disconnect a connection. The client then reconnects | POST /v1/platform/realtime/connections/{id}/disconnect · platform.realtime.disconnect |
no | yes |
The reason for job replay, job kill, cache invalidate, and event replay is mandatory and at least ten characters long.
Error and permission catalog
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
error catalog |
All error codes of the API with HTTP status, plus --search=<text> |
GET /v1/platform/ops/errors/catalog · platform.errors.catalog.read |
no | no |
permission catalog |
The permission catalog. --key-eligible shows what an operator key may carry |
GET /v1/permission-catalog, sign-in only |
n/a | no |
permission drift |
What the inventory lacks compared with the catalog. Changes nothing | GET /v1/platform/ops/permissions/catalog-drift · platform.permissions.catalog.read |
no | no |
permission reload |
Reload the catalog, which is needed when app permissions are added | POST /v1/platform/ops/permissions/catalog/reload · platform.permissions.catalog.reload |
no | yes |
permission backfill |
Bring the roles of the organizations up to date with the catalog, plus --tenant=<tnt_…>. --dry-run only calculates, --reconcile also removes. Operator accounts do not need this: their permissions follow the role |
POST …/ops/permissions/roles/backfill · platform.permissions.role.backfill |
no | yes |
permission flush-cache --yes |
Discard the cache of effective permissions | POST /v1/platform/ops/permissions/cache/flush · platform.permissions.cache.flush |
no | yes |
Organizations
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
tenant list |
The organizations of the platform (active, frozen, suspended, deleted) |
GET /v1/platform/tenants · platform.tenant.list |
no | no |
tenant get <tnt_…> |
An organization in the operations view | GET /v1/platform/tenants/{id} · platform.tenant.read |
no | no |
tenant provision --slug=… --name=… --owner-email=… --address=… |
Organization, contract, owner, and invitation in one go, plus --licenses, --set=<k=v> |
POST /v1/platform/tenants/provision · platform.tenant.provision, with --set PATCH …/tenants/{tenantId}/feature-entitlements · platform.billing.override |
no | yes |
tenant overview <tnt_…> |
The operations record: fleet, content, contacts | GET /v1/platform/tenants/{tenantId}/overview · platform.tenant.read |
no | no |
tenant suspend <tnt_…> --reason=… --yes |
Suspend an organization, which cascades to its accounts | POST /v1/platform/tenants/{id}/suspend · platform.tenant.suspend |
no | yes |
tenant resume <tnt_…> |
Lift a suspension | POST /v1/platform/tenants/{id}/resume · platform.tenant.resume |
no | yes |
tenant delete <tnt_…> --slug=… --yes |
Delete an organization. This cannot be undone. The short name is the confirmation. Its devices are released and then show a pairing code | DELETE /v1/platform/tenants/{id} · platform.tenant.delete |
no | yes |
tenant entitlements <tnt_…> |
Read contractual capabilities and set them with --set=<k=v> (switch on or off) |
GET …/tenants/{tenantId}/feature-entitlements · platform.billing.invoice.read, PATCH … · platform.billing.override |
no | yes |
tenant licensing <tnt_…> |
Contract status: licenses, items, special terms | GET /v1/platform/tenants/{tenantId}/licensing · platform.billing.invoice.read |
no | no |
tenant price-override <tnt_…> --sku=<code> |
Set a special term (--price or --discount, never both) or withdraw it with --clear |
PUT …/tenants/{tenantId}/licensing/items/{skuCode}/override · platform.billing.override |
no | yes |
tenant sso-recovery <tnt_…> --email=… --reason=… --yes |
Issue SSO emergency access for an account | POST /v1/platform/tenants/{tenantId}/sso-recovery · platform.tenant.sso-recovery |
no | yes |
self-registration set |
Read self-registration, switch it with --on/--off --reason=… |
GET/PUT /v1/platform/self-registration · platform.self-registration.manage |
no | yes |
The invitation address from tenant provision appears in plain text in the output (--json: inviteUrl). It is the only place where this token leaves the API.
Operator accounts and operator keys
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
operator list |
The operator accounts, with --role=owner|manager|support|viewer, --status, --search, and --with-permission=<platform.…> (accounts whose role carries the permission) |
GET /v1/platform/operators · platform.operator.list |
no | no |
operator get <ops_…> |
An operator account with its role and the level of the role per bundle | GET /v1/platform/operators/{id} · platform.operator.list |
no | no |
operator create --email=… --name=… --role=manager|support|viewer |
Create an operator account. The role is required, owner is not available here. The two-factor setup appears exactly once |
POST /v1/platform/operators · platform.operator.create |
no | yes |
operator set-role <ops_…> --role=manager|support|viewer --yes |
Replace the role. Only the owner, never the own role, never the owner’s. The new permissions apply with the next request of the account | PATCH /v1/platform/operators/{id}/role · platform.operator.create |
no | yes |
operator transfer-owner <ops_…> --totp-code=<123456> |
Transfer the owner role, step 1: the owner makes the account an offer. The offer is valid for seven days, and a new one replaces the earlier one. --accept --totp-code=… (step 2, under the profile of the target) accepts, after which the target is owner and the former owner is manager. --status shows the open offer |
POST /v1/platform/operators/{id}/owner-transfer, POST …/operators/owner-transfer/accept, GET …/operators/owner-transfer · platform.operator.create, on acceptance and status platform.operator.list |
no | yes |
operator suspend <ops_…> --reason=… |
Suspend an operator account | POST /v1/platform/operators/{id}/suspend · platform.operator.suspend |
no | yes |
operator reactivate <ops_…> |
Lift the suspension | POST /v1/platform/operators/{id}/reactivate · platform.operator.suspend |
no | yes |
operator reset-mfa <ops_…> --reason=… --yes |
Set up two-factor again. The previous authenticator no longer applies | POST /v1/platform/operators/{id}/mfa-reset · platform.operator.mfa-reset |
no | yes |
operator resend-onboarding <ops_…> |
Send the setup email again. It is valid for 72 hours | POST /v1/platform/operators/{id}/onboarding-resend · platform.operator.mfa-reset |
no | yes |
api-key list |
The operator keys of the company | GET /v1/platform/api-keys · platform.operator.api-key.list |
no | no |
api-key issue --name=… --permissions=<a,b,c> |
Issue an operator key opk_…. --days=<1–365> (default 90), --list-allowed shows the permissions that are allowed |
POST /v1/platform/api-keys · platform.operator.api-key.create |
no | yes |
api-key rotate <oak_…> |
Renew an operator key, plus --grace-hours=<0–72>, --days |
POST /v1/platform/api-keys/{id}/rotate · platform.operator.api-key.create |
no | yes |
api-key revoke <oak_…> --yes |
Revoke an operator key, immediately and permanently | DELETE /v1/platform/api-keys/{id} · platform.operator.api-key.revoke |
no | yes |
Device software
The component is always the first word after the command: os, agent, renderer, host-webos, or host-tizen. A version is named by the command with the build identifier (twelve hex characters), and list shows it.
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
device-software list <component> |
The versions in storage, newest first: display name with world (0.6.1-prod), build, state, the channels in which it applies, the number of devices, and the size |
GET /v1/platform/ops/device-software/{component}/builds · platform.ops.device-software.read |
yes | no |
device-software releases <component> |
What applies in the channels, and the history of releases, with --limit and --cursor |
GET …/device-software/{component}/releases · platform.ops.device-software.read |
yes | no |
device-software devices <component> |
The devices that run the component, with channel, version, build, and state relative to the release (current, updating, rolled-back, outdated, no-release). Plus --channel, --build, --state |
GET …/device-software/{component}/devices · platform.ops.device-software.read |
yes | no |
device-software activity |
The history across all components: releases, imports, deletions, requests, and the rollbacks that devices reported. Plus --component=<component> |
GET …/device-software/activity · platform.ops.device-software.read |
yes | no |
device-software release <component> <build> --channel=… --yes |
Make a version apply in a channel. --pull-along=beta,canary pulls lower channels along in the same step, --note, --security. If the platform requires a second person (releaseApproval.deviceSoftware), a request is created for stable, and --reason=… is then required |
POST …/device-software/{component}/releases · platform.ops.device-software.release |
no | yes |
device-software promote <component> --from=… --to=… --yes |
Release the build that applies today in the lower channel in the higher one, otherwise like release |
GET and POST …/device-software/{component}/releases · platform.ops.device-software.release |
no | yes |
device-software delete <component> <build> --yes |
Delete the bytes of a version, the record stays as a tombstone. A version that applies in a channel or that a request points to is protected (DeviceSoftware.BuildInUse, exit 6) |
DELETE …/device-software/{component}/builds/{build} · platform.ops.device-software.delete |
no | yes |
device-software cleanup <component> --dry-run|--yes |
Delete the versions beyond the newest --keep-newest=<n> (without a value retention.deviceSoftware.keepNewest) that can be deleted. --dry-run only names what would be deleted |
POST …/device-software/{component}/builds/cleanup · platform.ops.device-software.delete |
no | yes |
device-software nudge <component> <dsr_…> |
Remind the devices of the channel immediately of the applying release | POST …/device-software/{component}/releases/{id}/nudge · platform.ops.device-software.release |
no | yes |
device-software image <build> |
The short-lived download address of the SD card image for a SzeneraOS version | GET …/device-software/os/builds/{build}/image · platform.ops.device-software.read |
yes | no |
The tool does not fetch a build: the environment syncs with the registry every ten minutes, and CI speeds it up with POST …/builds/import-from-registry (platform.ops.device-software.import, with an operator key). release and promote require --yes because a release reaches the devices of the channel.
Requests to a second person
The same for device software and apps. Whether a release to stable needs a second person is set by the owner with settings set releaseApproval.deviceSoftware|apps stable.
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
approval list |
The requests, without --state the open ones. Plus --state=open|approved|withdrawn|expired, --kind=device-software|app, --package=<component or app> |
GET /v1/platform/ops/approvals · platform.ops.device-software.read or platform.app-catalog.list |
yes | no |
approval approve <rap_…> |
Approve a request as the second person and thereby execute it. The person who made the request gets a one-line message and exit 4 (ReleaseApproval.SamePerson) |
POST /v1/platform/ops/approvals/{id}/approve · platform.ops.release.approve |
no | yes |
approval withdraw <rap_…> |
Withdraw a request, or reject it as another person. --reason=… is optional |
POST /v1/platform/ops/approvals/{id}/withdraw · platform.ops.release.approve or platform.ops.device-software.release or platform.app-catalog.promote |
no | yes |
Platform settings
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
settings get |
All platform settings in full, one that is not set with its default | GET /v1/platform/settings · platform.settings.read |
no | no |
settings set <setting> <value> --yes |
Change a setting, for example releaseApproval.apps stable or retention.deviceSoftware.keepNewest 3. The value is checked against the contract before anything goes out |
PATCH /v1/platform/settings · platform.settings.manage (owner only) |
no | yes |
The settings are releaseApproval.deviceSoftware and releaseApproval.apps (off or stable, default off) as well as retention.deviceSoftware.keepNewest (1 to 100, default 5) and retention.deviceSoftware.auto (default false). In addition there are retention.apps.keepNewest (1 to 100, default 5), retention.apps.unreferencedMonths (1 to 120, default 12), and retention.apps.auto (default false). Every change appears in the audit log with the old and the new value (platform.settings.changed).
App catalog
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
app-release list |
The releases of the app catalog, with --app=<app-id>, --channel=canary|beta|stable|deprecated|retired |
GET /v1/platform/app-catalog/apps, GET …/apps/{appId}/releases · platform.app-catalog.list |
no | no |
app-release set-notes <arl_…> --app=<app-id> --notes=… |
Change the release notes (up to 2000 characters) | PATCH …/apps/{appId}/releases/{id} · platform.app-catalog.update |
no | yes |
app-release promote <arl_…> --app=<app-id> --channel=beta|stable |
Promote to beta or stable, always one step at a time. To stable, the command promotes immediately if the platform does not require a second person (releaseApproval.apps = off), otherwise it creates a request, and --reason=… (10 to 500 characters) is then mandatory |
POST …/apps/{appId}/releases/{id}/promote · platform.app-catalog.promote |
no | yes |
app-release restore <arl_…> --app=<app-id> --reason=… |
Roll back an outdated or superseded version to stable. Immediately or, depending on the setting, as a request that a second person confirms with approval approve. The version that applied until then goes to deprecated |
POST …/apps/{appId}/releases/{id}/restore · platform.app-catalog.promote |
no | yes |
app-release demote <arl_…> --app=<app-id> --channel=deprecated |
Demote a release from stable to deprecated, the only step backward | POST …/apps/{appId}/releases/{id}/demote · platform.app-catalog.promote |
no | yes |
app-release retire <arl_…> --app=<app-id> --reason=… --grace=regular|security|immediate |
Take a release out of service. --grace chooses the retirement period and has no default: regular three months, security one month, in which case the security advisory --advisory=… is mandatory for the organizations, and immediate no period, so the platform switches at once to the next higher version in stable. For regular and immediate there is no advisory |
POST …/apps/{appId}/releases/{id}/retire · platform.app-catalog.retire |
no | yes |
app-release grace-period <arl_…> --app=<app-id> |
Extend the retirement period, by --months=<n> from its current end or to the end of a day with --until=<jjjj-mm-tt>, or end it at once with --immediately --reason=…. Exactly one choice |
POST …/releases/{id}/extend-grace, POST …/releases/{id}/force-retire · platform.app-catalog.retire |
no | yes |
app-release delete-artifact <arl_…> --app=<app-id> --yes |
Delete the bytes of a version, the row, manifest, and history remain. A version in a channel, with an installation, a scene, or an open request is protected (AppRelease.ArtifactInUse, exit 6) |
DELETE …/apps/{appId}/releases/{id}/artifact · platform.app-catalog.delete |
no | yes |
app-release cleanup --app=<app-id> --dry-run|--yes |
Delete the bytes of all versions beyond the newest --keep-newest=<n> (without a value retention.apps.keepNewest) that can be deleted. --dry-run only names what would be deleted |
POST …/apps/{appId}/releases/cleanup · platform.app-catalog.delete |
no | yes |
app-status list |
The apps with their operator status, installations, and exceptions | GET /v1/platform/app-catalog/managed-apps · platform.app-catalog.list |
no | no |
app-status set <app> --status=active|beta|disabled --reason=… |
Set an app platform-wide | PATCH /v1/platform/app-catalog/managed-apps/{appId} · platform.app-catalog.status.manage |
no | yes |
app-status override <app> |
Read exceptions per organization, set them with --tenant and --status, remove them with --clear |
GET …/managed-apps/{appId}/overrides · platform.app-catalog.list, PUT …/overrides/{tenantId}, POST …/overrides/{tenantId}/remove · platform.app-catalog.status.manage |
no | yes |
Whether a single person promotes to stable is decided by the setting releaseApproval.apps. If the platform requires a second person and POST …/promote with stable names no reason, it answers AppRelease.SecondPersonRequired (exit 6). With a reason, a request is created that a second person confirms with approval approve, and it expires after seven days. If the checklist of the version carries a block, promote (to beta as well as to stable) and the confirmation of a request to stable refuse with AppRelease.ReviewBlocked (exit 6), and the command names the blocked items: “New in this version” is missing in the required language, or a customer text carries a semicolon or a blocked word. “New in this version” is created in the review of the version in Szenera Ops, and set-notes sets only the text for operations.
Billing and items
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
subscription set-payment-way <tnt_…> --way=invoice|stripe|none |
Set the payment way of a contract | PUT /v1/platform/tenants/{tenantId}/billing/payment-way · platform.billing.override |
no | yes |
subscription approve-invoice <tnt_…> --yes |
Approve the purchase on invoice. --revoke withdraws the approval |
PUT /v1/platform/tenants/{tenantId}/billing/payment-way · platform.billing.override |
no | yes |
subscription check-stripe <tnt_…> |
Check the link of a contract to the payment provider. Changes nothing | GET /v1/platform/tenants/{tenantId}/billing/stripe-link · platform.billing.override |
no | no |
subscription relink-stripe <tnt_…> --yes |
Link a contract to the payment provider again. If the customer still exists there, nothing happens (unchanged) |
POST /v1/platform/tenants/{tenantId}/billing/relink-stripe · platform.billing.override |
no | yes |
subscription backfill-period-prices --yes |
Catch up the per-period unit prices of the existing contracts: the fix when the run at application startup failed. Idempotent | POST /v1/platform/billing/period-unit-prices/backfill · platform.billing.plan.manage |
no | yes |
invoice list --tenant=<tnt_…>|--all-tenants |
The invoices of all organizations | GET /v1/platform/invoices · platform.billing.invoice.read |
no | no |
invoice get <inv_…> |
An invoice with its line items | GET /v1/platform/invoices/{id} · platform.billing.invoice.read |
no | no |
invoice mark-paid <inv_…> --yes |
Book a payment received | POST /v1/platform/invoices/{id}/mark-paid · platform.billing.invoice.mark-paid |
no | yes |
invoice refund <inv_…> --reason=… --yes |
Refund an invoice | POST /v1/platform/invoices/{id}/refund · platform.billing.invoice.refund |
no | yes |
invoice issue-documents <inv_…> --yes |
Generate the PDF and e-invoice of a document after the fact. A document that already carries its files stays untouched | POST /v1/platform/invoices/{id}/issue-documents · platform.billing.invoice.refund |
no | yes |
catalog list |
The item catalog with the special terms that are set | GET /v1/platform/billing/catalog · platform.billing.plan.manage, GET /v1/platform/billing/overrides · platform.billing.override |
no | no |
catalog set [sku] |
Replace a catalog item (all five fields) or set the monthly price of an app with --app=<app-id> --price=<cent> |
PUT /v1/platform/billing/catalog/{skuCode}, PUT /v1/platform/billing/app-prices/{appId} · platform.billing.plan.manage |
no | yes |
Under an operator profile, audit list and audit get also run against GET /v1/platform/audit and GET /v1/platform/audit/{id} (platform.audit.read). --tenant or --all-tenants is mandatory there.