| name | btp-cli-reference |
| description | Reference skill for all BTP CLI operations — session management, command taxonomy, JSON output patterns, and scope boundaries. Intended to be read by other skills before issuing BTP CLI commands. |
| disable-model-invocation | false |
| allowed-tools | Read, Bash |
BTP CLI Reference
Complete reference for the SAP BTP CLI (btp) — session management, full command taxonomy, JSON output patterns, and scope boundaries. Use this skill as a toolset when other skills need to issue BTP CLI commands.
CLI Version and Architecture
btp --version
The BTP CLI operates against the BTP Account API — it manages the account layer (subaccounts, entitlements, security, service manager). It does NOT manage Cloud Foundry runtime objects (apps, CF service instances, CF spaces) — those require the cf CLI.
The CLI uses a session file stored in ~/.btp/ that caches the login token. A session is valid for a limited time (roughly 12 hours for SSO, longer for some flows). Commands fail silently with "Authorization failed" or "Unknown session" when expired.
Session Management
Login Methods
SSO Login (browser-based, recommended for interactive use)
btp login --sso
User/Password Login (non-interactive environments)
btp login --user <email> --password <password>
Custom IDP Login
btp login --sso --idp <custom-idp-origin>
IMPORTANT: There is NO client-credentials login for the BTP CLI. For headless/automated workflows, use the underlying BTP REST APIs directly with OAuth2 service keys instead.
Targeting
After login, set the default subaccount scope so you don't need --subaccount on every command:
btp target --subaccount <subaccount-id>
Check current target:
btp target
Clear target:
btp target --reset
JSON Output (always use for scripting)
btp set config --format json
btp --format json list security/role-collection
Session Health Check
Before running commands in a script, verify the session is active:
btp --format json list accounts/subaccount 2>&1 | grep -q '"subaccounts"' \
&& echo "Session OK" || echo "Session expired — run: btp login"
Gotchas
- Session expires silently — commands return "Authorization failed. Unknown session." with no hint. Always check first.
--subaccount is optional when targeted — if you ran btp target --subaccount <id>, omit it. If targeting a different subaccount, pass it explicitly.
btp vs cf — BTP CLI manages the account layer; cf CLI manages the CF runtime layer. Neither can substitute for the other.
- Interactive-only login —
btp login requires a browser or interactive terminal; cannot be used in CI pipelines with stored credentials. Use REST APIs with service keys instead.
- Global account vs. subaccount scope — some commands apply at global account level (entitlements, provisioning), others at subaccount level (security, services). Use
--global-account or --subaccount to specify.
--of-idp vs --origin — when assigning role collections to users from a custom IdP, use --of-idp <idp-origin> (not --origin). Example: btp assign security/role-collection "MyRC" --to-user user@example.com --of-idp sap.default.
btp update security/trust --set-default does not exist — setting the default IdP in a CF subaccount must be done manually in BTP Cockpit → Security → Trust Configuration.
- JSON output structure — top-level key names vary by command. Always inspect output with
jq keys on first use.
--format json placement — must come right after btp, before the verb: btp --format json list ... (not btp list ... --format json).
Full Command Taxonomy
See references/command-quick-reference.md for a single-table quick reference of all 70+ commands.
Accounts Group
Commands for managing the global account, subaccounts, directories, and environment instances.
btp get accounts/global-account
btp update accounts/global-account --display-name <name>
btp list accounts/subaccount
btp get accounts/subaccount <id>
btp create accounts/subaccount \
--display-name <name> \
--region <region> \
--subdomain <subdomain>
btp update accounts/subaccount <id> --display-name <name>
btp delete accounts/subaccount <id>
btp move accounts/subaccount <id> --to-directory <dir-id>
btp list accounts/directory
btp get accounts/directory <id>
btp create accounts/directory --display-name <name>
btp update accounts/directory <id> --display-name <name>
btp delete accounts/directory <id>
btp enable accounts/directory <id> --for entitlements
btp enable accounts/directory <id> --for authorizations
btp list accounts/environment-instance [--subaccount <id>]
btp get accounts/environment-instance <id> [--subaccount <id>]
btp create accounts/environment-instance \
--environment cloudfoundry \
--service cloudfoundry \
--plan standard \
--subaccount <id> \
--display-name <name> \
--parameters '{"instance_name":"<org-name>"}'
btp update accounts/environment-instance <id> \
--subaccount <id> \
--parameters '{"memory":<MB>}'
btp delete accounts/environment-instance <id> [--subaccount <id>]
btp list accounts/label [--subaccount <id>]
btp set accounts/label --key <key> --value <val> [--subaccount <id>]
btp delete accounts/label --key <key> [--subaccount <id>]
btp list accounts/resource-provider
btp get accounts/resource-provider <provider>/<key>
btp create accounts/resource-provider \
--provider <AWS|AZURE|GCP> \
--technical-name <key>
btp delete accounts/resource-provider <provider>/<key>
btp list accounts/custom-property [--subaccount <id>]
btp set accounts/custom-property --key <key> --value <val>
Entitlements Group
btp list accounts/entitlement [--subaccount <id>]
btp list accounts/entitlement --show-technical-info
btp assign accounts/entitlement \
--service-name <service> \
--plan-name <plan> \
--subaccount <id> \
--amount <N>
btp assign accounts/entitlement \
--service-name APPLICATION_RUNTIME \
--plan-name MEMORY \
--subaccount <id> \
--amount <MB>
btp assign accounts/entitlement \
--service-name <service> \
--plan-name <plan> \
--directory <id> \
--amount <N> \
--distribute
btp list accounts/subscription [--subaccount <id>]
btp subscribe accounts/subaccount \
--app-name <app> \
--plan <plan> \
[--subaccount <id>]
btp unsubscribe accounts/subaccount \
--app-name <app> \
[--subaccount <id>]
Security Group
Commands for managing roles, role collections, users, and trust.
btp list security/role-collection [--subaccount <id>]
btp get security/role-collection "<name>" [--subaccount <id>]
btp create security/role-collection "<name>" \
--description "<desc>" \
[--subaccount <id>]
btp update security/role-collection "<name>" \
--description "<new-desc>" \
[--subaccount <id>]
btp delete security/role-collection "<name>" [--subaccount <id>]
btp add security/role \
--role-collection "<rc-name>" \
--role-name "<role-name>" \
--app-id "<appid>" \
--role-template "<template-name>" \
[--subaccount <id>]
btp remove security/role \
--role-collection "<rc-name>" \
--role-name "<role-name>" \
--app-id "<appid>" \
--role-template "<template-name>" \
[--subaccount <id>]
btp list security/user [--subaccount <id>]
btp get security/user <email> [--of-idp <idp-origin>] [--subaccount <id>]
btp create security/user <email> [--of-idp <idp-origin>] [--subaccount <id>]
btp delete security/user <email> [--of-idp <idp-origin>] [--subaccount <id>]
btp assign security/role-collection "<rc-name>" \
--to-user <email> \
[--of-idp <idp-origin>] \
[--subaccount <id>]
btp unassign security/role-collection "<rc-name>" \
--from-user <email> \
[--of-idp <idp-origin>] \
[--subaccount <id>]
btp assign security/role-collection "<rc-name>" \
--to-group <group-name> \
[--of-idp <idp-origin>] \
[--subaccount <id>]
btp list security/app [--subaccount <id>]
btp get security/app <appid> [--subaccount <id>]
btp list security/trust [--subaccount <id>]
btp get security/trust <origin> [--subaccount <id>]
btp create security/trust \
--idp <ias-tenant-id-or-host> \
[--subaccount <id>]
btp update security/trust <origin> \
--description "<desc>" \
[--subaccount <id>]
btp delete security/trust <origin> [--subaccount <id>]
btp migrate security/trust "<origin>" [--subaccount <id>]
btp list security/setting [--subaccount <id>]
btp get security/setting <key> [--subaccount <id>]
btp set security/setting <key>=<value> [--subaccount <id>]
btp unset security/setting <key> [--subaccount <id>]
Services Group
Commands for managing services via Service Manager.
btp list services/offering [--subaccount <id>]
btp get services/offering <id> [--subaccount <id>]
btp list services/plan [--subaccount <id>]
btp get services/plan <id> [--subaccount <id>]
btp list services/instance [--subaccount <id>]
btp get services/instance <id> [--subaccount <id>]
btp create services/instance \
--offering-name <svc> \
--plan-name <plan> \
--display-name <name> \
[--parameters '{"key":"value"}'] \
[--subaccount <id>]
btp update services/instance <id> \
--display-name <new-name> \
[--parameters '{"key":"value"}'] \
[--subaccount <id>]
btp delete services/instance <id> [--subaccount <id>]
btp list services/binding [--subaccount <id>]
btp get services/binding <id> [--subaccount <id>]
btp create services/binding \
--instance-id <instance-id> \
--display-name <binding-name> \
[--parameters '{"key":"value"}'] \
[--subaccount <id>]
btp delete services/binding <id> [--subaccount <id>]
btp list services/broker [--subaccount <id>]
btp get services/broker <id> [--subaccount <id>]
btp create services/broker \
--name <name> \
--url <url> \
--user <user> \
--password <password> \
[--subaccount <id>]
btp update services/broker <id> \
--url <new-url> \
[--subaccount <id>]
btp delete services/broker <id> [--subaccount <id>]
btp list services/platform [--subaccount <id>]
btp get services/platform <id> [--subaccount <id>]
btp register services/platform \
--name <name> \
--type <type> \
[--subaccount <id>]
btp unregister services/platform <id> [--subaccount <id>]
Connectivity Group (Experimental)
btp list connectivity/destination [--subaccount <id>]
btp get connectivity/destination <name> [--subaccount <id>]
Disaster Recovery Group
btp list accounts/backup-configuration
btp get accounts/backup-configuration <id>
btp update accounts/backup-configuration <id> --enable
JSON Output Patterns
See references/json-output-schemas.md for full schema examples.
Common jq Patterns
btp --format json list security/role-collection | jq '.[].name'
btp --format json list security/app | \
jq '.[] | select(.name | startswith("nonosgi-auth")) | {name, appId}'
btp --format json get security/app "<appid>" | \
jq '.roleTemplates[] | {name, description}'
btp --format json list security/role-collection | \
jq 'any(.[]; .name == "MyRoleCollection")'
btp --format json list accounts/environment-instance | \
jq '.environmentInstances[] | select(.environmentType == "cloudfoundry") | {displayName, labels}'
btp --format json get security/role-collection "MyRC" | \
jq '.userReferences[] | .value'
btp --format json list accounts/subaccount | \
jq '.value[] | select(.displayName == "MySubaccount") | .guid'
btp --format json get services/binding <binding-id> | \
jq '.credentials'
Script Template: Safe BTP CLI Execution
#!/bin/bash
set -e
if ! btp --format json list accounts/global-account &>/dev/null; then
echo "ERROR: BTP CLI session expired. Run: btp login"
exit 1
fi
SUBACCOUNT_ID="2f964175-0856-47b2-b77a-469c74df0cca"
btp target --subaccount "$SUBACCOUNT_ID"
RC_NAME="MyApp-Users"
EXISTS=$(btp --format json list security/role-collection | jq --arg name "$RC_NAME" 'any(.[]; .name == $name)')
if [ "$EXISTS" = "false" ]; then
btp create security/role-collection "$RC_NAME" --description "Users of MyApp"
echo "Created role collection: $RC_NAME"
else
echo "Role collection already exists: $RC_NAME"
fi
Auth/Trust Domain Reference
XSUAA App IDs
After deploying an MTA with XSUAA, get the appId (needed for btp add security/role):
btp --format json list security/app | jq '.[] | {name, appId}'
Assigning Role-Templates to Role Collections After Deployment
Role collections created before XSUAA app deployment have no roles. After deploying, add them:
APP_ID=$(btp --format json list security/app | \
jq -r '.[] | select(.name | startswith("nonosgi-auth")) | .appId')
btp --format json get security/app "$APP_ID" | jq '.roleTemplates[] | .name'
btp add security/role \
--role-collection "nonosgi-auth-Everyone" \
--role-name "Everyone" \
--app-id "$APP_ID" \
--role-template "Everyone"
Creating Trust with IAS
btp list security/trust
btp create security/trust \
--idp <ias-tenant-hostname-or-id> \
--subaccount <subaccount-id>
Entitlements and Provisioning Reference
CF Runtime Quota (most common blocker)
When cf push or cf deploy fails with SUBSCRIPTION_QUOTA — total memory: 0, routes: 0:
btp list accounts/entitlement --subaccount <id>
btp assign accounts/entitlement \
--service-name APPLICATION_RUNTIME \
--plan-name MEMORY \
--subaccount <id> \
--amount 3072
Gotcha: Space quotas (cf create-space-quota) do NOT override org-level route limits. The org quota must be fixed. Only BTP Cockpit entitlement assignment (or the btp assign accounts/entitlement command above) creates the correct org quota automatically.
Provisioning a CF Org
btp --format json list accounts/environment-instance --subaccount <id> | \
jq '.environmentInstances[] | select(.environmentType == "cloudfoundry")'
btp create accounts/environment-instance \
--environment cloudfoundry \
--service cloudfoundry \
--plan standard \
--subaccount <id> \
--display-name "My CF Org" \
--parameters '{"instance_name":"my-org-name"}'
Verification Commands
After any BTP CLI operation, verify with:
btp --format json list security/role-collection | jq '.[].name'
btp --format json get security/role-collection "<rc-name>" | \
jq '.roleReferences[] | {roleTemplateName, roleTemplateAppId}'
btp --format json get security/role-collection "<rc-name>" | \
jq '.userReferences[] | .value'
btp list security/trust
btp --format json list accounts/entitlement | \
jq '.[] | select(.serviceName == "APPLICATION_RUNTIME")'
btp --format json list services/instance | jq '.[] | {name, offering, plan, state}'
Common Issues
| Symptom | Cause | Solution |
|---|
Authorization failed. Unknown session | BTP CLI session expired | Run btp login (browser SSO) |
btp add security/role fails with "app not found" | Wrong --app-id format | Use full XSUAA appId (xsappname!tXXXX), get from btp list security/app |
btp assign with --of-idp fails | Wrong flag name | Use --of-idp (not --origin) for custom IdP users |
Role collection shows empty after btp add security/role | Race condition or targeting wrong subaccount | Verify with btp get security/role-collection <name>, check --subaccount param |
btp create security/trust fails | IAS tenant not yet connected | Use IAS tenant hostname (not GUID), verify IAS tenant exists |
btp assign accounts/entitlement appears to do nothing | BTP Cockpit hasn't reflected the change yet | Wait 60 seconds; then check btp list accounts/entitlement |
| CF quota still 0 after entitlement assignment | BTP creates quota async | Wait 1-2 minutes, then run cf quotas to see new quota appear |
--set-default flag not recognized by btp update security/trust | This subcommand does not exist | Set default IdP manually in BTP Cockpit → Security → Trust Configuration |
Scope Boundary: What BTP CLI Cannot Do
| Task | Reason | Alternative |
|---|
| Manage CF apps, spaces, routes, services | These are CF runtime layer objects | cf CLI |
| Create CF service instances | CF service instances live in CF org/space | cf create-service |
| Manage destinations (create, update, delete) | No reliable BTP CLI support for destinations | Destination Service REST API |
| Headless/CI login with client credentials | Login is always interactive (browser/password) | BTP REST APIs with service keys |
| Set default IdP in trust configuration | No --set-default flag exists | BTP Cockpit → Security → Trust |
| Abort stuck MTA operations | MTA operations run in CF layer | cf mta-ops, cf deploy -i -a abort |
| Access Neo subaccount resources | BTP CLI targets CF subaccounts only | Neo CLI (neo.sh) or Neo REST APIs |
See Also
References