Commands for your organization
All szenera commands that run with a key or account of your organization: media, scenes, playlists, programs, devices, team, apps, package.
21 minute readCLIUpdated: 10/25/2026
On this page
Before you start
- For
- Anyone who wants to trigger an operation of their organization from a script or the terminal and needs to know which command requires which route and permission
- Prerequisite
- a profile with a key or account of the organization. The credential must carry the permissions named in the “Route and permission” column.
All commands of the szenera command line. They run with an API key ak_… or an account of your organization. Each table names, per command, the route, the permission required, whether an API key may carry the permission (“Key”), and whether the command changes something. The “Key” column follows the platform’s permission catalog: a permission reserved for accounts is never granted to a key. The command then answers with 403 (exit 4), and you need a profile with password sign-in.
szenera <befehl> --help shows the positional arguments, flags, and examples of every command. The description there is the source of these tables. This page follows the registry of szenera with 136 commands, and all of them are listed here. 21 of them also serve platform operations and partly take a different route there. Those routes, and the commands that serve operations only, are described under Commands for platform operations.
Flags valid everywhere
| Flag | Effect |
|---|---|
--help |
Show help for the command without doing anything. Never signs in |
--profile=<name> |
Which profile applies (environment, credential, service addresses) |
--json |
Force output as JSON |
--table |
Force output as a table |
--raw |
If a response breaks the contract, print the raw response |
A flag carries its value after the equals sign (--limit=20), and --limit 20 does not exist. An unknown flag is an error (exit 1), not a silent hint. List commands page through results with --limit=<anzahl> (1 to 200, up to 100 for filtered lists), --cursor=<marke>, and --all (follow all pages). Commands that wait for an operation accept --timeout=<dauer> (90s, 20m, 2h, or a number in seconds) and some also --interval=<dauer> and --no-wait. Irreversible actions require --yes. Without the flag, the command aborts with exit 1 and says what would happen.
Environment and credential
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
health |
Whether the environment reports ready, and which check says what | GET /health/ready, no credential needed, exit 9 on 503 |
— | no |
health public |
What the status page shows publicly: state per component, maintenance windows, public incidents | GET /v1/public/status, no credential needed |
— | no |
whoami |
Who your own credential is: account, organization, permissions | GET /v1/me, sign-in only, no permission of its own |
yes | no |
hygiene get |
What has been left lying around: six numbers, and for each number the command that shows the rows behind it | GET /v1/analytics/hygiene · analytics.query.run. --offline-since (default P7D) and --dormant-since (default P90D) set the two thresholds |
yes | no |
Media and folders
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
asset list |
The media of the media library. --usage=unused finds what is in no scene, no playlist, and no brand mark |
GET /v1/assets · asset.list |
yes | no |
asset get <ast_…> |
One media item with its variants. --usages names where it is used |
GET /v1/assets/{id}, GET /v1/assets/{id}/usage · asset.read |
yes | no |
asset upload --file=<pfad> |
Upload a file to the media library and wait until it is usable | POST /v1/assets/upload-precheck → bytes → POST /v1/assets/upload-complete · asset.upload. Waits until ready, default --timeout=10m, --no-wait |
yes | yes |
asset download <ast_…> --output=<pfad> |
Fetch a media item or one of its variants | POST /v1/assets/{id}/download-url (variant: /variant-url) → bytes · asset.read |
yes | no |
asset update <ast_…> |
Change the name, tags, or folder of a media item | PATCH /v1/assets/{id} · asset.update |
yes | yes |
asset reprocess <ast_…> |
Regenerate the variants of a media item and wait | POST /v1/assets/{id}/reprocess · asset.update. Waits as with uploading |
yes | yes |
asset delete <ast_…> --yes |
Move a media item to the trash | DELETE /v1/assets/{id} · asset.delete |
yes | yes |
asset restore <ast_…> |
Bring a media item back from the trash | POST /v1/assets/{id}/restore · asset.update |
yes | yes |
asset purge <ast_…> --yes |
Delete a media item permanently | POST /v1/assets/{id}/purge · asset.delete |
yes | yes |
asset bulk-update --assets=<ast_…,…> |
Move or tag many media items (up to 100) | POST /v1/assets/bulk-move or POST /v1/assets/bulk-tag · asset.update |
yes | yes |
folder list |
The folder tree of the media library | GET /v1/folders · asset.folder.list |
yes | no |
folder create --name=<name> |
Create a folder | POST /v1/folders · asset.folder.create |
yes | yes |
folder update <fld_…> |
Rename or move a folder | PATCH /v1/folders/{id} (--name), POST /v1/folders/{id}/move (--parent) · asset.folder.update |
yes | yes |
folder delete <fld_…> --yes |
Delete a folder. The media move up one level | DELETE /v1/folders/{id} · asset.folder.delete |
yes | yes |
If the same content is already there, the byte stream is skipped on upload: the precheck recognizes it by its sha256 checksum. From 50 MiB on, the stream runs in 8 MiB chunks.
Scenes, versions, and layouts
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
scene list |
The organization’s scenes. --assignment=none finds those that no program, no schedule, and no assigned playlist points to (useful with --status=published) |
GET /v1/scenes · scene.list |
yes | no |
scene get <scn_…> |
A scene with its open findings | GET /v1/scenes/{id}, GET /v1/scenes/{id}/integrity-issues · scene.read |
yes | no |
scene create --name=<name> |
Create an empty scene | POST /v1/scenes · scene.create |
yes | yes |
scene create-from-template --template=<sct_…> --name=<name> |
Create a scene from a curated template | POST /v1/scenes/from-template · scene.create |
yes | yes |
scene update <scn_…> |
Change the draft of a scene. Without --version, the command reads the version beforehand |
PATCH /v1/scenes/{id} · scene.update |
yes | yes |
scene publish <scn_…> |
Publish the draft as a new version. Names findings instead of swallowing them | POST /v1/scenes/{id}/publish · scene.publish |
yes | yes |
scene recheck <scn_…> |
Re-check the integrity and name the findings | POST /v1/scenes/{id}/integrity-issues/recheck · scene.read |
yes | yes |
scene resolve-issue <sii_…> --scene=<scn_…> --resolution=manual-fixed|ignored |
Close a finding as fixed or ignored | POST /v1/scenes/{id}/integrity-issues/{iid}/resolve · scene.update |
yes | yes |
scene archive <scn_…> |
Archive a scene | POST /v1/scenes/{id}/archive · scene.archive |
yes | yes |
scene restore <scn_…> |
Bring back an archived or deleted scene | POST /v1/scenes/{id}/restore · scene.update |
yes | yes |
scene delete <scn_…> --yes |
Move a scene to the trash | DELETE /v1/scenes/{id} · scene.delete |
yes | yes |
scene bulk-update --entries=<pfad> |
Change up to 50 scenes in one call | POST /v1/scenes/bulk-update · scene.update |
yes | yes |
layout list |
The layout templates, built-in and custom | GET /v1/layout-templates · layout-template.list |
yes | no |
scene-template list |
The curated scene templates. --orientation=landscape|portrait filters |
GET /v1/scene-templates · scene.read |
yes | no |
scene-version list --scene=<scn_…> |
The published versions of a scene | GET /v1/scenes/{id}/versions · scene.read |
yes | no |
scene-version get <scv_…> --scene=<scn_…> |
A version with its snapshot | GET /v1/scenes/{id}/versions/{vid} · scene.read |
yes | no |
scene-version diff <scv_…> --scene=<scn_…> --against=<scv_…> |
Compare two versions | GET /v1/scenes/{id}/versions/{vid}/diff/{vid2} · scene.read |
yes | no |
scene-version revert <scv_…> --scene=<scn_…> |
Reset the draft to an older version. Publishes nothing | POST /v1/scenes/{id}/versions/{vid}/revert · scene.publish |
yes | yes |
scene-version thumbnail <scv_…> --scene=<scn_…> |
Store the preview image (--file) or fetch its address |
POST …/versions/{vid}/thumbnail · scene.update, POST …/thumbnail-url · scene.read |
yes | yes |
The version of a scene appears twice in the response: as the field version in the body and as the header ETag. The command line reads it itself when --version is missing. For scene publish, two refusals mean different things: Scene.PublishValidationFailed (422, exit 7) is a cause to fix, and Scene.PublishBlocked (409, exit 6) means blocking findings that --ignore-issues closes.
Playlists and programs
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
playlist list |
The organization’s playlists | GET /v1/playlists · playlist.list |
yes | no |
playlist get <pll_…> |
A playlist with its items | GET /v1/playlists/{id} · playlist.read |
yes | no |
playlist create --name=<name> |
Create a playlist: --items (sequence) or --folder/--tags (rule) |
POST /v1/playlists · playlist.create |
yes | yes |
playlist update <pll_…> |
Change a playlist. --items replaces the whole sequence |
PATCH /v1/playlists/{id} · playlist.update |
yes | yes |
playlist delete <pll_…> --yes |
Delete a playlist. The API refuses assigned ones | DELETE /v1/playlists/{id} · playlist.delete |
yes | yes |
playlist preview-source |
Resolve an automatic source on a trial basis | POST /v1/playlists/source-preview · playlist.read and asset.read |
yes | no |
schedule list |
The organization’s programs | GET /v1/schedules · schedule.list |
yes | no |
schedule get <sch_…> |
A program with its entries. --players names the devices that play it |
GET /v1/schedules/{id}, GET /v1/schedules/{id}/players · schedule.read |
yes | no |
schedule create --name=<name> |
Create a program. Without --base, its base is off air |
POST /v1/schedules · schedule.create |
yes | yes |
schedule update <sch_…> |
Change the name or base of a program | PATCH /v1/schedules/{id} · schedule.update |
yes | yes |
schedule delete <sch_…> --yes |
Delete a program. The API refuses assigned ones | DELETE /v1/schedules/{id} · schedule.delete |
yes | yes |
schedule create-item --schedule=<sch_…> --content=… --recurrence=… |
Create a program entry (once:, daily:, weekly:, monthly:) |
POST /v1/schedules/{id}/items · schedule.update |
yes | yes |
schedule update-item <sci_…> --schedule=<sch_…> |
Change a program entry, disable it (--disabled), or enable it (--enabled) |
PATCH /v1/schedules/{id}/items/{itemId} · schedule.update |
yes | yes |
schedule delete-item <sci_…> --schedule=<sch_…> |
Delete a program entry | DELETE /v1/schedules/{id}/items/{itemId} · schedule.update |
yes | yes |
player get-program <ply_…> |
What is assigned to a display, including the override | GET /v1/players/{id}/program · fleet.player.read |
yes | no |
player set-program <ply_…> --content=… |
Assign something to a display. --clear removes the assignment. Idempotent |
PUT /v1/players/{id}/program · schedule.update |
yes | yes |
display-group set-program <dgr_…> --content=… |
Assign something to a video wall, and with it to all of its displays. --clear removes the assignment. Idempotent |
PUT /v1/display-groups/{id}/program · schedule.update |
yes | yes |
player set-override <ply_…> --content=… |
Show something else on a display right now (--until or --indefinite) |
PUT /v1/players/{id}/override · schedule.update |
yes | yes |
player clear-override <ply_…> |
End the override of a display | DELETE /v1/players/{id}/override · schedule.update |
yes | yes |
Content is passed in short form: schedule:sch_…, scene:scn_…, playlist:pll_…, asset:ast_…, and for the base of a program also pause.
Playback and widgets
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
playback now |
What is playing on all displays right now (play, pause, gap) |
GET /v1/players/now-playing · fleet.player.list |
yes | no |
playback timeline <ply_…> |
The resolved playback timeline of a display (window from now, 4 hours to 7 days) | GET /v1/players/{id}/timeline · fleet.player.read |
yes | no |
playback history <ply_…> --date=<datum> |
The recorded daily history of a display (retained for 90 days) | GET /v1/players/{id}/playback-history · fleet.playback-history.read |
no | no |
playback refresh <ply_…> |
Recompute the snapshot of a display | POST /v1/players/{id}/snapshot/refresh · fleet.player.update |
yes | yes |
widget preview --widget=<pfad> |
Resolve a widget’s data for a preview | POST /v1/widget-data/preview · scene.read |
yes | no |
Advertising
Advertisers, ad campaigns, bookings, and creatives of your own advertising business. Reading works in every package. Creating and approving additionally require the advertisingDirect capability of the package. Without it, the server answers with 403 and Billing.FeatureNotEntitled (exit 4). Ad campaigns of the ad network appear in campaign list as soon as they reach displays of your organization, without price and without the operator’s note.
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
advertiser list |
The advertisers, filterable by --status, --industry, and --search |
GET /v1/advertising/advertisers · advertising.advertiser.read |
yes | no |
advertiser get <adv_…> |
One advertiser with brands, contacts, and note | GET /v1/advertising/advertisers/{id} · advertising.advertiser.read |
yes | no |
advertiser create --name=<name> --industry=<branche> |
Create an advertiser. --brand may be repeated |
POST /v1/advertising/advertisers · advertising.advertiser.manage |
yes | yes |
campaign list |
The ad campaigns with phase, period, number of bookings, and displays reached. --owner=tenant or --owner=network separates your own business from the network |
GET /v1/advertising/campaigns · advertising.campaign.read |
yes | no |
campaign get <acp_…> |
One ad campaign with phase, period, goal, and price | GET /v1/advertising/campaigns/{id} · advertising.campaign.read |
yes | no |
booking list --campaign=<acp_…> |
The bookings of an ad campaign with spot length, frequency, and commitment | GET /v1/advertising/campaigns/{id}/booking-lines · advertising.campaign.read |
yes | no |
creative list |
The creatives. --approval=pending gives the list awaiting review |
GET /v1/advertising/creatives · advertising.campaign.read, advertising.creative.manage, or advertising.creative.approve |
yes | no |
creative approve <crv_…> |
Approve a creative. If the industry requires a mandatory text, --text-present and --text-legible confirm that it is in the creative and legible |
POST /v1/advertising/creatives/{id}/approval · advertising.creative.approve |
yes | yes |
A creative is rejected in the portal, where the note for the advertiser is written. Which displays a booking reaches, and why others are not reached, is answered by GET /v1/advertising/booking-lines/{id}/reach through the escape hatch szenera api get.
Devices
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
player list |
The organization’s displays. --program=none finds those without content, --offline-since=P7D those that have reported nothing for that long (one that never reported counts too) |
GET /v1/players · fleet.player.list, plus --status, --search |
yes | no |
device list |
The devices: what is out in the field, and does it still check in | GET /v1/devices · identity.device.list |
no | no |
device get <dev_…> |
One device in detail: certificate and surfaces | GET /v1/devices/{id} · identity.device.list |
no | no |
device send-command <dev_…> <kind> |
Issue a remote maintenance command to a device (reboot, locate, tail-log, mark-good, check-ota) or to a surface (screenshot, identify, set-config, display-power, display-source, refresh-snapshot, with --screen=<n>). A 201 response means accepted, and --wait stays attached |
POST /v1/devices/{id}/commands, POST /v1/players/{id}/commands · fleet.player.command.issue. Surface kinds also resolve through identity.device.list. That permission is not key-capable, so only the machine kinds run with a key |
yes | yes |
device list-commands <dev_…> |
The latest remote maintenance commands of a device | GET /v1/devices/{id}/commands · fleet.player.read |
yes | no |
device screenshot <dev_…> |
Request a screenshot, wait for it, and fetch it (--file) |
POST /v1/players/{id}/commands → GET …/commands/{cid}/output · fleet.player.command.issue, fleet.player.read, and identity.device.list. The last one is not key-capable, so this command stays reserved for sessions. Default --timeout=5m, --interval=5s |
no | yes |
Searching by serial number, releasing and blocking a device, and looking up a single command are commands of platform operations and not part of szenera. See Commands for platform operations.
To re-pair a device, reset it to factory state, remove it from the organization, or report it as lost, there is no command of its own under an organization profile. Use the Lifecycle card in the portal, or api post against POST /v1/devices/{id}/release with {"reason":"reconnect"}, "factory", or "removed", or against POST /v1/devices/{id}/block with a reason (identity.device.lifecycle, not key-capable). If a paired device reports in with a new key, POST /v1/devices/{id}/reregistration decides, with {"decision":"keep"}, "reconnect", or {"decision":"block","reason":"…"}. There is no remote maintenance command for a factory reset.
Locations
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
location list |
The organization’s locations. The last column counts the displays at the location | GET /v1/locations · location.list, complete, without paging |
yes | no |
location get <loc_…> |
A location with address, time zone, position, note, and version | GET /v1/locations/{id} · location.read |
yes | no |
location create --name=<name> --timezone=<IANA> |
Create a location. The address comes through --street, --postal-code, --city, --country, the position through --latitude/--longitude, plus --note |
POST /v1/locations · location.create, needs the Locations capability |
yes | yes |
location update <loc_…> |
Change the name, time zone, address, position, or note. --clear-address and --clear-coordinates remove the value |
PATCH /v1/locations/{id} · location.update |
yes | yes |
location delete <loc_…> --yes |
Delete an empty location. With displays attached, the API answers 409 Location.HasPlayers |
DELETE /v1/locations/{id} · location.delete |
yes | yes |
player assign-location <ply_…> --location=<loc_…> |
Attach a display to a location. A second call moves it instead of duplicating it | PATCH /v1/players/{id} · fleet.player.update |
yes | yes |
player unassign-location <ply_…> |
Detach a display from its location. It keeps its program, settings, and license | PATCH /v1/players/{id} · fleet.player.update |
yes | yes |
A location is a folder for displays: it carries no permissions and no inventory of its own, and deleting it never takes a display with it. The fields and error codes are under Locations.
Analytics
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
analytics overview |
The overview: per display the availability within the planned time, and above it gaps, planned hours reported on time, and plays. --location (repeatable) restricts it to locations |
GET /v1/analytics/overview · analytics.query.run |
yes | no |
analytics explore --measure=<kennzahl> |
Analyze metrics ad hoc: --measure and --by are repeatable, plus --sort, --ascending, --limit, --perspective, and --granularity. --query=<pfad> takes the complete query, including filters, as JSON |
POST /v1/analytics/explore · analytics.query.run |
yes | no |
analytics delivery <acp_…> |
The delivery of an ad campaign: per booking the commitment, what was delivered, fulfillment, pacing, forecast with range, and the finding | GET /v1/analytics/campaigns/{id}/delivery · advertising.campaign.read |
yes | no |
Without --from and --to, the last seven days up to yesterday apply. Without a window, an ad campaign shows its run up to yesterday. The table gives hours instead of seconds and percent instead of share, and next to a value stands its upper bound as long as open gaps can still be reported late. Which metric can be calculated with which dimension is shown by szenera api get /v1/analytics/catalog.
Proofs
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
proof list |
The organization’s proofs, newest first: closings, addenda, and interim statements with number, period, ad campaign, booking, valid plays, and fulfillment. --campaign, --advertiser, --line, --kind, --from, and --to narrow the list |
GET /v1/analytics/proofs · analytics.proof.read |
yes | no |
proof show <prf_…> |
One proof with check code, signature, and its files including checksum. --json shows the figures, the addenda, and the status of each delivery |
GET /v1/analytics/proofs/{id} · analytics.proof.read |
yes | no |
proof download <prf_…> --output=<pfad> |
Fetch a file: --kind=pdf (default), csv, manifest, or capture with --file=<pfi_…>. If the checksum does not match, the file is removed again |
GET /v1/analytics/proofs/{id}/files/{kind} · analytics.proof.read |
yes | no |
With the number and check code from proof show, anyone can verify a proof on the verification page, even without an account. Interim statements and links for advertisers are created in the portal or through the API.
Event targets
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
webhook list |
The organization’s event targets. --status=dead shows those that delivery itself gave up on (disabled and with an error chain longer than twenty) |
GET /v1/webhooks · webhook.list |
no | no |
A target that was switched off by hand is under --status=disabled and is something different. Targets are created and changed in the portal or through the API. See Create a webhook endpoint.
Team, roles, and grants
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
user list |
The organization’s members. --last-login-before=<zeitpunkt mit Zone> finds dormant accounts, including ones that never signed in |
GET /v1/users · identity.user.list |
no | no |
user get <usr_…> |
One member in detail | GET /v1/users/{id} · identity.user.read |
no | no |
user create --email=… --name=… --role=<rol_…> |
Create a member directly (without an invitation), with --password or --federated |
POST /v1/users · identity.user.create |
no | yes |
user update <usr_…> |
Change a member’s profile | PATCH /v1/users/{id} · identity.user.update |
no | yes |
user set-role <usr_…> --role=<rol_…> --reason=… |
Set the role of a member. It replaces the previous one | PATCH /v1/users/{id}/roles · identity.user.assign-roles |
no | yes |
user suspend <usr_…> --reason=… |
Suspend a member | POST /v1/users/{id}/suspend · identity.user.suspend |
no | yes |
user reactivate <usr_…> |
Lift the suspension of a member | POST /v1/users/{id}/reactivate · identity.user.reactivate |
no | yes |
user delete <usr_…> --reason=<kategorie> --yes |
Delete a member. The reason is one of the API’s five categories | DELETE /v1/users/{id} · identity.user.delete |
no | yes |
invitation list |
The organization’s invitations, with --pending only the open ones |
GET /v1/invitations · identity.invitation.list |
no | no |
invitation create --email=… --role=<rol_…> |
Invite someone to the organization | POST /v1/invitations · identity.user.invite |
no | yes |
invitation resend <ivt_…> |
Send an invitation again. That extends the deadline | POST /v1/invitations/{id}/resend · identity.user.invite |
no | yes |
invitation revoke <ivt_…> |
Withdraw an invitation | DELETE /v1/invitations/{id} · identity.invitation.revoke |
no | yes |
role list |
The organization’s roles, custom and built-in | GET /v1/roles · access.role.list |
no | no |
role get <rol_…> |
A role with its permissions | GET /v1/roles/{id} · access.role.read |
no | no |
role create --name=… --permissions=<a,b,c> |
Create a role. Permissions are exact catalog keys, not wildcards | POST /v1/roles · access.role.create |
no | yes |
role update <rol_…> |
Change a role. --permissions replaces the list, If-Match comes from the version, and a conflict is exit 6 |
PATCH /v1/roles/{id} · access.role.update |
no | yes |
role delete <rol_…> --yes |
Delete a role. With accounts attached, the API refuses | DELETE /v1/roles/{id} · access.role.delete |
no | yes |
grant list |
Permissions attached to individual resources | GET /v1/grants · access.grant.list |
no | no |
grant create --user=<usr_…> --resource-type=… --resource=… --permissions=… |
Give a permission on exactly one resource, or block it with --deny |
POST /v1/grants · access.grant.create |
no | yes |
grant revoke <grn_…> |
Withdraw a grant | DELETE /v1/grants/{id} · access.grant.revoke |
no | yes |
Keys
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
api-key list |
Your own access keys, with --organization all keys of the organization |
GET /v1/me/api-keys (session only), with --organization GET /v1/api-keys · identity.api-key.list |
no | no |
api-key issue --name=… --permissions=<a,b,c> |
Issue a key. The secret value appears exactly once. --list-allowed shows the permissions that are allowed |
POST /v1/me/api-keys · identity.api-key.create |
no | yes |
api-key rotate <akm_…> |
Renew a key. The old one stays valid for a grace period (0–72 hours) | POST /v1/me/api-keys/{id}/rotate · identity.api-key.create |
no | yes |
api-key revoke <akm_…> --yes |
Revoke a key, immediately and permanently. --compromised records in the log the suspicion that the secret value fell into the wrong hands |
DELETE /v1/me/api-keys/{id} · identity.api-key.revoke |
no | yes |
A key can never do more than its issuer, and it can never carry a permission that is not allowed for keys. The CLI checks the second condition before the call.
Package, invoices, and apps
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
subscription get |
The package and the licensing status of your own organization | GET /v1/me/subscription · billing.subscription.read, GET /v1/me/licensing · billing.usage.read |
no | no |
subscription set-licenses --count=<n> |
Change the number of booked licenses, but not below the number in use | PUT /v1/me/licensing/licenses · billing.subscription.update |
no | yes |
subscription cancel --yes |
Cancel the contract: at the end of the period, or immediately with --immediately |
POST /v1/me/subscription/cancel · billing.subscription.update |
no | yes |
subscription reactivate |
Withdraw a cancellation that is already scheduled | POST /v1/me/subscription/reactivate · billing.subscription.update |
no | yes |
app subscribe <app> |
Book a priced app for billing | POST /v1/me/licensing/apps/{appId} · billing.subscription.update |
no | yes |
app unsubscribe <app> --yes |
Cancel a booked app, effective at the end of the period | DELETE /v1/me/licensing/apps/{appId} · billing.subscription.update |
no | yes |
invoice list |
Your own invoices | GET /v1/me/invoices · billing.invoice.read |
no | no |
invoice get <inv_…> |
An invoice with its line items. --pdf fetches the address of the PDF |
GET /v1/me/invoices/{id} · billing.invoice.download |
no | no |
app list |
The apps in the store, with --installed only the installed ones |
GET /v1/me/apps/store, no permission of its own |
yes | no |
app get <app> |
One app in detail: permissions, data access, widgets | GET /v1/me/apps/store/{appId}, no permission of its own, session only |
no | no |
app install <app> |
Install an app. The manifest hash travels along as proof | GET /v1/me/apps/store/{appId} → POST /v1/marketplace/apps/{appId}/install · marketplace.app.install |
no | yes |
app upgrade <app> --version=<semver> |
Switch an installed app to a different version | POST /v1/marketplace/apps/{appId}/upgrade · marketplace.app.upgrade |
no | yes |
app uninstall <app> |
Preview the consequences first, then uninstall with --yes |
POST …/uninstall/preview → POST /v1/marketplace/apps/{appId}/uninstall · marketplace.app.uninstall |
no | yes |
app accept <app> |
Accept the update of an app. The command shows where the update leads and what it adds. --yes accepts it |
GET /v1/me/apps/{appId}/update → POST /v1/me/apps/{appId}/update/accept · marketplace.app.accept |
no | yes |
app reject <app> --yes |
Reject the update of an app. Until a higher version appears, the platform does not ask again. If a deadline applies, rejecting works only until it passes | GET /v1/me/apps/{appId}/update → POST /v1/me/apps/{appId}/update/reject · marketplace.app.accept |
no | yes |
Log, permission catalog, and escape hatch
| Command | Purpose | Route and permission | Key | Modifies |
|---|---|---|---|---|
audit list |
Read the audit log: append-only, payloads redacted | GET /v1/audit · audit.read or audit.read.self (then only your own operations) |
no | no |
audit get <aud_…> |
One log entry with its payload | GET /v1/audit/{id} · audit.read or audit.read.self |
no | no |
permission catalog |
The permission catalog as the running environment knows it, with --key-eligible the allowlist |
GET /v1/permission-catalog, sign-in only |
n/a | no |
api get <path> |
A GET on any path of the API | the route of the path and its permission | per route | no |
api post <path> <body> |
A POST on any path, plus --idempotency-key=<schluessel> |
the route of the path and its permission | per route | yes |
api put <path> <body> |
A PUT on any path, plus --idempotency-key=<schluessel> |
the route of the path and its permission | per route | yes |
api patch <path> <body> |
A PATCH on any path, plus --idempotency-key=<schluessel> |
the route of the path and its permission | per route | yes |
api delete <path> [body] |
A DELETE on any path, plus --idempotency-key=<schluessel> |
the route of the path and its permission | per route | yes |
api … is the escape hatch to every route that has no command of its own. The path begins with a slash and may carry a query. The body is JSON directly or @datei.json. This way also goes through the generated client, so headers, trace ID, and error kinds apply as everywhere, but it does not check the response against a contract: no one knows which schema belongs to a freely typed path.
szenera api get "/v1/devices?limit=5" --json | jq -r '.items[].id'
szenera api post /v1/playlists @playlist.json --idempotency-key=import-2026-09-08-01