Understand how SAP BTP accounts, runtimes, service keys, destinations and roles fit together, and read your trial's destinations from Python the way an AI app does.
SAP Business Technology Platform (BTP) is where SAP customers build and run their own extensions and AI services. Almost every SAP AI project touches it, even when the AI itself is bought, not built.
Four ideas explain most of what happens in a BTP project:
Accounts. A global account is the contract with SAP. Subaccounts inside it are the rooms where work happens, each in one region.
Runtimes. A subaccount can run apps in Cloud Foundry, in Kyma (Kubernetes) or in the ABAP environment.
Services and keys. Teams switch on services such as SAP AI Core. Each service hands out credentials, called a service key or a binding, that an app uses to prove who it is.
Connections and roles.Destinations store where a backend system lives and how to log on to it. The Cloud Connector reaches systems inside the company network. Role collections decide what each person may do.
An AI assistant that explains blocked sales orders needs all four. It runs in a subaccount, calls an AI service with a key, reads S/4HANA through a destination, and must respect the user's roles.
BTP decisions end up in the budget, the risk register and the timeline:
Cost. In a paid BTP account, what a subaccount is entitled to use drives the bill. A clean split into subaccounts (for example development, test and production) makes costs traceable to a project.
Risk. Service keys are passwords for machines. A key pasted into a chat, a slide or a code repository gives anyone who finds it access to that service. It is an avoidable risk.
Speed. AI pilots can stall for weeks on plumbing, not on the model. Typical blockers are "we have no destination to the S/4HANA system", "the Cloud Connector isn't installed" and "nobody owns the role collections". Asking early saves the timeline.
Data residency. Each subaccount lives in one region. Where the AI service runs, and where the data flows, is decided when the subaccount is created.
Example: a team wants an assistant that tells order-to-cash clerks why a sales order is blocked for credit. The model is the easy part. The team also needs a subaccount in the right region, an AI service entitlement, a destination to S/4HANA through the Cloud Connector, and a rule that the assistant only shows orders the clerk may already see.
As of September 2026, SAP describes BTP with these building blocks:
Global account, directories and subaccounts. The global account is "the realization of a contract" with SAP. Directories optionally group subaccounts. Each subaccount is tied to one region.
Entitlements and quotas. An entitlement is the right to use a service plan; the quota is how much. Both are bought for the global account and handed down to subaccounts.
Runtime environments. Cloud Foundry for new business apps and services, Kyma for containers and serverless functions on managed Kubernetes, and the ABAP environment for ABAP-based extensions. The older Neo environment is only for existing customers.
Security. The SAP Authorization and Trust Management service (often called XSUAA) issues tokens and groups roles into role collections. It trusts an identity provider, such as SAP Cloud Identity Services, to log users on.
Connectivity. The Destination service stores connection details. The Connectivity service and the SAP Cloud Connector reach systems in the company network.
AI services. SAP AI Core, including the generative AI hub, is a BTP service. Apps call it with credentials from a service key, like any other service. SAP offers a 30-day basic trial of the generative AI hub; after that it needs Pay-As-You-Go or an enterprise agreement. Unit 5 covers it in depth.
The free 90-day BTP trial from the Unit 3 setup has the same structure, which is why this course uses it.
"BTP is one product." It is a platform of many services, each with its own plans and prices. Two teams can both "use BTP" and share nothing.
"The AI model decides what users can see." It doesn't. Authorizations, destinations and role collections decide. The model only sees what the app hands it.
"A service key is just configuration." It is a password for a machine. Treat it like one.
"Our S/4HANA is on-premise, so BTP can't reach it." It can, through the Cloud Connector, which opens the link from inside the company network.
"The trial is a small production account." SAP rules out production and team use for trials, and deletes them after 90 days.
Pick one answer for each question. The explanation appears after you choose.
1In BTP terms, what is a global account?
Answer: B. SAP describes the global account as the realization of a contract. Subaccounts, entitlements and quotas hang below it; the work itself happens in subaccounts.
2Why does the choice of subaccount matter for an AI use case?
Answer: C. Each subaccount is tied to one region and receives its own entitlements. A clean split keeps data residency, costs and test versus production under control.
3A developer pastes a service key into a team chat. What is the risk?
Answer: D. A service key holds the client ID and secret an app uses to get tokens. It works like a password for a machine, so it belongs in a secure store, not in chats, slides or code.
4Your S/4HANA runs in your own data center. How does a BTP AI app reach it?
Answer: B. A destination with an on-premise proxy type routes calls through the Connectivity service and the Cloud Connector, which runs inside the company network. The common belief that on-premise systems are out of reach is wrong.
5What decides which sales orders an AI assistant may show a clerk?
Answer: C. The model only sees what the app hands it. Role collections in BTP and authorizations in S/4HANA decide what a user may see; ask whether the destination uses the user's identity or a shared technical user.
6A pilot has been stuck for three weeks. Which question most likely finds the blocker?
Answer: D. Pilots can stall on plumbing, not the model: a missing entitlement, no destination to S/4HANA, or no Cloud Connector. Owners for each BTP piece prevent that.
7How can a team try SAP's generative AI hub before buying?
Answer: A. As of September 2026, SAP offers a 30-day basic trial of the generative AI hub. Continued use needs Pay-As-You-Go for SAP BTP or an enterprise agreement.
Ask a question
Testing: only staff see this
Stuck on something in this layer? Ask it here. Questions are answered in the order they arrive, and the answer appears under My questions.
Sign in (free) to ask a question. You can ask anonymously.
Deep layer · 40 min read
#Mental model: every call is "who are you, where are you going, what may you do"
Strip away the product names and every call an AI app makes on BTP answers three questions:
Who are you? The app proves its identity with credentials from a service key or binding and gets a short-lived token.
Where are you going? A destination says which system to call, at which URL, through which network path.
What may you do? The token carries scopes, and the target system checks the user's authorizations.
The account model (global account, subaccounts, entitlements) decides where all of this is allowed to exist. Once you see those three questions, the Destination service, SAP AI Core and your own apps all look the same: get a token, call a URL, get checked.
flowchart LR
K[Service key<br/>client ID + secret] --> A[Authorization server<br/>XSUAA]
A -->|token| APP[Your AI app]
APP -->|Bearer token| D[Destination service]
D -->|URL + logon info| APP
APP --> S[S/4HANA, via<br/>Cloud Connector]
APP --> AI[SAP AI Core]
You met the structure in the Unit 3 setup. Here is what each level means when you build:
Level
What you do there
Builder's rule of thumb
Global account
Nothing day to day; it holds the contract, entitlements and quotas
You rarely have admin rights here in a customer landscape
Directory (optional)
Groups subaccounts, up to 7 levels deep, and can hand out entitlements
Often one per business unit or project
Subaccount
Create service instances, deploy apps, create destinations, assign role collections
Your daily workplace; one region each
Cloud Foundry org and space
Deploy apps and create service instances
One org per subaccount; spaces such as dev separate work
Entitlements are the bridge between contract and code. If a service doesn't appear in the Service Marketplace, or a plan is greyed out, the subaccount usually lacks the entitlement. In a customer account, you ask the platform team; in your trial, you can add it yourself under Entitlements.
SAP also lets admins attach labels to subaccounts, directories, subscriptions and service instances, for example cost-center or use-case. They make an AI landscape easier to filter and audit.
A service in the marketplace is a template. When you create an instance, you get your own copy with its own credentials. There are two ways to hand those credentials out:
Binding: you bind an instance to an app deployed on BTP. The platform passes the credentials to the app through its environment. No human copies anything.
Service key: you create credentials by hand, for a caller outside that app: your laptop, a test tool, another system. The Cloud Foundry documentation says service keys are for "manually configuring consumers" of marketplace services.
A service key is a small JSON document. For the Destination service, SAP's documentation names four values you need:
Field
What it is
clientid
The app's user name at the authorization server
clientsecret
The app's password; secret
url
The authorization server that issues tokens
uri
The address of the Destination service itself
Other services use the same pattern with different extra fields. For SAP AI Core, SAP's Python SDK maps clientid, clientsecret, url and serviceurls.AI_API_URL from the service key to its settings.
BTP services don't accept the secret on every call. The app first swaps it for a token, using the OAuth 2.0 client credentials flow:
sequenceDiagram
participant App as Your script
participant UAA as Authorization server (url)
participant Dest as Destination service (uri)
App->>UAA: POST /oauth/token (client_credentials, client ID, secret)
UAA-->>App: access_token (a JWT), expires_in
App->>Dest: GET /destination-configuration/v1/subaccountDestinations<br/>Authorization: Bearer token
Dest-->>App: JSON list of destinations
The token is a JWT (JSON Web Token): three parts separated by dots. The middle part holds claims, such as which client it was issued to, when it expires and which scopes it grants. The authorization server signs it, so services can check it hasn't been changed. Anyone holding the token can use it until it expires, so treat it like the secret.
The authorization server here is the SAP Authorization and Trust Management service (XSUAA). SAP's documentation describes how it separates two kinds of callers:
Technical clients, like your script, get credentials directly from the service. That is the flow above.
Business users log on through a trusted identity provider, such as SAP Cloud Identity Services. Their token carries their own scopes, which come from the roles in their role collections.
For AI apps this difference is the whole security story. A technical client sees whatever its credentials allow. A token that carries the user's identity lets the backend apply that user's authorizations. Unit 11 builds on this.
A destination is a named connection stored in the subaccount. It holds at least a name, a type (usually HTTP), a URL, a proxy type and an authentication method. Apps ask the Destination service for a destination by name, so URLs and passwords stay out of the code and can differ between test and production.
The proxy type decides the network path:
Proxy type
Meaning
Internet
The target is on the public internet, for example an SAP cloud API
OnPremise
The target is inside the company network; calls go through the Connectivity service and the SAP Cloud Connector
PrivateLink
The target is reached over a private link; the flow is the same as Internet
The authentication method decides how the destination logs on. NoAuthentication is the simplest. Customer landscapes use methods such as OAuth flows or principal propagation, which passes the user's identity through to S/4HANA so its authorizations apply.
The SAP Cloud Connector is software that runs inside the customer's network. For OnPremise destinations, the Connectivity service routes the call through it to the internal system. This is how an AI app on BTP reads blocked sales orders from an on-premise S/4HANA.
You can do everything in this topic in the cockpit. Teams automate it with two command-line tools:
The btp CLI manages accounts, for example btp list accounts/subaccount after btp login --sso.
The Cloud Foundry CLI works inside a space, for example cf create-service-key MY-SERVICE MY-KEY.
Later units install them when they're needed.
#Build it yourself: read your trial's destinations from Python
You will create a Destination service instance in your trial, make a service key, and create one destination. Then a Python script swaps the key for a token and asks the Destination service for your destinations. It is the same pattern your AI apps will use for SAP AI Core in Unit 5.
Before you start: complete Set up your computer for this course and Set up for Unit 3. They give you the orchestrate-course folder with its .venv, requests, python-dotenv, a .env file listed in .gitignore, and your SAP BTP trial with unit03/btp_trial_notes.md.
flowchart LR
E[.env<br/>4 values from<br/>the service key] --> P[btp_destinations.py]
P -->|1. get token| U[Trial authorization server]
P -->|2. list destinations| D[Destination service]
D --> O[Table on screen]
In VS Code's file list, right-click unit03, choose New File, and name it btp_destinations.py.
Paste the code below and save.
"""Read the destinations in your SAP BTP trial subaccount, the way an AI app does it.
The flow: service key values -> OAuth token from your subaccount's authorization server
-> call the Destination service REST API with that token -> print what it returns.
How to run (from the unit03 folder, with the course .venv turned on):
python btp_destinations.py --sample # no account needed: made-up data, no network
python btp_destinations.py # your trial: reads the four DEST_ values from .env
python btp_destinations.py --name Northwind # details of one destination
python btp_destinations.py --name Northwind --call "/V2/Northwind/Northwind.svc/Customers?$top=2&$format=json"
# also call the target system through that destination
Secrets stay in .env. The script never prints the client secret or the full token.
"""
import argparse
import base64
import json
import os
import sys
import time
SECRET_WORDS = ("password", "secret", "apikey", "token") # property names we never print (URLs are fine)
SAMPLE_DESTINATIONS = [ # made-up, shaped like the Destination service's response
{"Name": "Northwind", "Type": "HTTP", "URL": "https://services.odata.org",
"ProxyType": "Internet", "Authentication": "NoAuthentication",
"Description": "Northwind OData services"},
{"Name": "S4_SALES_ORDERS", "Type": "HTTP", "URL": "http://s4h-virtual:443",
"ProxyType": "OnPremise", "Authentication": "PrincipalPropagation",
"Description": "Made-up example: S/4HANA behind a Cloud Connector"},
{"Name": "AI_CORE", "Type": "HTTP", "URL": "https://api.ai.example.invalid",
"ProxyType": "Internet", "Authentication": "OAuth2ClientCredentials",
"clientId": "sb-made-up", "clientSecret": "never-printed",
"tokenServiceURL": "https://example.invalid/oauth/token",
"Description": "Made-up example: an AI service called with its own client"},
]
def fake_jwt(claims: dict) -> str:
"""Build an unsigned token with the same three-part shape as a real one (sample mode only)."""
def part(obj: dict) -> str:
raw = json.dumps(obj).encode()
return base64.urlsafe_b64encode(raw).decode().rstrip("=")
return f"{part({'alg': 'none', 'typ': 'JWT'})}.{part(claims)}.sample-signature"
def read_claims(token: str) -> dict:
"""Decode the middle part of a JWT to read its claims. This does NOT verify the signature."""
try:
payload = token.split(".")[1]
payload += "=" * (-len(payload) % 4) # base64 needs padding to a multiple of 4
return json.loads(base64.urlsafe_b64decode(payload))
except (IndexError, ValueError):
return {}
def settings_from_env() -> dict:
"""Read the four service key values from .env (or the environment)."""
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
pass # python-dotenv missing: fall back to real environment variables
names = ["DEST_CLIENT_ID", "DEST_CLIENT_SECRET", "DEST_AUTH_URL", "DEST_SERVICE_URI"]
values = {n: os.getenv(n, "").strip() for n in names}
missing = [n for n, v in values.items() if not v]
if missing:
sys.exit("Missing in .env: " + ", ".join(missing)
+ "\nCopy them from your service key (Step 4), or run with --sample.")
return values
def get_token(session, s: dict) -> dict:
"""Ask the subaccount's authorization server for a token (OAuth 2.0 client credentials)."""
url = s["DEST_AUTH_URL"].rstrip("/") + "/oauth/token"
form = {"grant_type": "client_credentials",
"client_id": s["DEST_CLIENT_ID"], "client_secret": s["DEST_CLIENT_SECRET"]}
reply = session.post(url, data=form, timeout=30)
if reply.status_code == 401:
sys.exit("401 from the token endpoint: client ID or secret is wrong. Copy them again (Step 4).")
reply.raise_for_status()
return reply.json()
def list_destinations(session, s: dict, token: str) -> list:
"""GET <uri>/destination-configuration/v1/subaccountDestinations with the token."""
url = s["DEST_SERVICE_URI"].rstrip("/") + "/destination-configuration/v1/subaccountDestinations"
reply = session.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=30)
if reply.status_code in (401, 403):
sys.exit(f"{reply.status_code} from the Destination service: the token was refused. "
"Check that all four DEST_ values come from the same service key.")
reply.raise_for_status()
return reply.json()
def show_token(token: str, expires_in) -> None:
claims = read_claims(token)
scopes = claims.get("scope", [])
print(f" token: {token[:12]}... ({len(token)} characters, valid {expires_in} seconds)")
print(f" issued to client: {claims.get('client_id', '?')}")
print(f" scopes: {len(scopes)} ({', '.join(scopes[:3])}{', ...' if len(scopes) > 3 else ''})")
def show_table(destinations: list) -> None:
if not destinations:
print(" No destinations yet. Create one in the cockpit (Step 5), then run again.")
return
print(f" {'Name':<18} {'Proxy':<10} {'Authentication':<26} URL")
for d in destinations:
print(f" {d.get('Name', '?'):<18} {d.get('ProxyType', '?'):<10} "
f"{d.get('Authentication', '?'):<26} {d.get('URL', '?')}")
def show_one(destination: dict) -> None:
for prop, value in destination.items():
hidden = any(w in prop.lower() for w in SECRET_WORDS) and not prop.lower().endswith("url")
print(f" {prop:<18} {'(hidden)' if hidden else value}")
def call_target(session, destination: dict, path: str) -> None:
"""Call the target system through a destination. Only simple Internet destinations."""
if destination.get("ProxyType") != "Internet" or destination.get("Authentication") != "NoAuthentication":
print(" --call only handles Internet destinations with NoAuthentication. Others need the "
"Connectivity service or a token flow, which later units cover.")
return
url = destination["URL"].rstrip("/") + path
print(f" GET {url}")
try:
reply = session.get(url, timeout=30)
except Exception as err: # network, proxy or DNS problem on the target side
print(f" Could not reach the target ({type(err).__name__}). Try another network.")
return
print(f" status {reply.status_code}, {len(reply.content)} bytes")
print(" " + reply.text[:300].replace("\n", " "))
def main() -> None:
parser = argparse.ArgumentParser(description="Read SAP BTP destinations with a service key.")
parser.add_argument("--sample", action="store_true", help="use made-up data, no account or network")
parser.add_argument("--name", help="show the details of one destination")
parser.add_argument("--call", metavar="PATH", help="with --name: GET this path on the destination's URL")
args = parser.parse_args()
if args.sample:
print("SAMPLE MODE: made-up data, nothing leaves your computer.")
print("\n1. Token (OAuth 2.0 client credentials)")
claims = {"client_id": "sb-made-up-client-id",
"scope": ["made-up.scope"], "exp": int(time.time()) + 43199}
show_token(fake_jwt(claims), 43199)
destinations = SAMPLE_DESTINATIONS
session = None
else:
try:
import requests
except ImportError:
sys.exit("The requests library is missing. Run: pip install requests python-dotenv")
s = settings_from_env()
session = requests.Session()
try:
print("1. Token (OAuth 2.0 client credentials)")
reply = get_token(session, s)
token = reply["access_token"]
show_token(token, reply.get("expires_in", "?"))
destinations = list_destinations(session, s, token)
except requests.exceptions.ConnectionError as err:
sys.exit(f"Could not connect ({type(err).__name__}). Check the URLs in .env and your "
"network or proxy. --sample still works.")
except requests.exceptions.HTTPError as err:
sys.exit(f"The server answered with an error: {err}")
print(f"\n2. Destinations in the subaccount: {len(destinations)}")
show_table(destinations)
if args.name:
match = [d for d in destinations if d.get("Name", "").lower() == args.name.lower()]
if not match:
sys.exit(f"\nNo destination named {args.name}. Names are listed above.")
print(f"\n3. Details of {match[0]['Name']}")
show_one(match[0])
if args.call:
print("\n4. Calling the target system")
if session is None:
print(" Skipped in sample mode (no network).")
else:
call_target(session, match[0], args.call)
if __name__ == "__main__":
main()
This proves the script works before you touch the cockpit.
Go into the unit03 folder:
cd unit03
Run:
python btp_destinations.py --sample
What success looks like:
SAMPLE MODE: made-up data, nothing leaves your computer.
1. Token (OAuth 2.0 client credentials)
token: eyJhbGciOiAi... (169 characters, valid 43199 seconds)
issued to client: sb-made-up-client-id
scopes: 1 (made-up.scope)
2. Destinations in the subaccount: 3
Name Proxy Authentication URL
Northwind Internet NoAuthentication https://services.odata.org
S4_SALES_ORDERS OnPremise PrincipalPropagation http://s4h-virtual:443
AI_CORE Internet OAuth2ClientCredentials https://api.ai.example.invalid
The token length may differ slightly. The three destinations show the three situations you will meet: a public API, an on-premise S/4HANA behind a Cloud Connector, and an AI service with its own credentials. All three are made up.
1. Token (OAuth 2.0 client credentials)
token: eyJ... (... characters, valid ... seconds)
issued to client: sb-...
scopes: ... (...)
2. Destinations in the subaccount: 1
Name Proxy Authentication URL
Northwind Internet NoAuthentication https://services.odata.org
Your token length, client name, validity and scopes will differ. What matters: a token arrives, and the table lists the destination you created. If you see No destinations yet, the token worked but the subaccount has no destinations; go back to Step 5.
Show the details and call Northwind through the destination:
The command is the same in PowerShell and on macOS/Linux. The single quotes stop the terminal from treating $top as a variable.
What success looks like (the end of the output):
4. Calling the target system
GET https://services.odata.org/V2/Northwind/Northwind.svc/Customers?$top=2&$format=json
status 200, ... bytes
{"d" : {"results": [ ...
Your laptop called Northwind directly, using the URL the destination stored. A BTP app does the same, but the Destination service can also hand it logon details or route it through the Cloud Connector.
An app deployed to Cloud Foundry is bound to its Destination, XSUAA and AI Core instances. The platform passes the credentials through the environment, so there is no .env and nobody copies a secret. SAP's SDKs read those credentials, fetch tokens and look up destinations by name. The AI Core Python SDK, for example, can read its settings from a service key, from individual variables such as AICORE_CLIENT_ID and AICORE_BASE_URL, or from the bound environment (VCAP_SERVICES).
For an S/4HANA system in the company network, the pattern is:
The customer runs the SAP Cloud Connector in its network and connects it to the subaccount.
A destination with proxy type OnPremise points to the S/4HANA system.
The app calls through the Connectivity service. With principal propagation, the user's identity reaches S/4HANA, and S/4HANA's own authorizations decide what comes back.
A cloud system reachable on the internet needs no Cloud Connector; its destination uses proxy type Internet. Unit 7 covers grounding AI on SAP data with authorizations.
SAP AI Core, with the generative AI hub, is a BTP service like the Destination service: you get an entitlement, create an instance and a service key, then swap clientid and clientsecret for a token at url. The difference is the extra serviceurls.AI_API_URL, where the AI API lives. As of September 2026 SAP offers a 30-day basic trial of the generative AI hub on sap.com. Unit 5 covers plans, setup and the orchestration service.
Secrets. Service keys are for people and outside systems; bindings are for deployed apps. Keep keys out of Git, chats, tickets and AI prompts. Delete keys you no longer use, and replace any key that may have leaked.
Least privilege. One service key per consumer, so you can revoke one without breaking others. Give technical clients only the scopes they need.
User identity. A shared technical user in a destination means the AI app sees everything that user sees. Prefer propagating the user's identity to S/4HANA, and log which user asked for what.
Separation. Use separate subaccounts for development, test and production, with separate destinations and keys. Never point a test app at production S/4HANA "just for a demo".
Region and data flow. Check the subaccount's region and where each AI service processes data before any real data moves.
Cost. Entitlements and quotas cap what a subaccount can consume. Labels such as use-case make AI costs traceable.
Clean core. BTP side-by-side extensions call S/4HANA through released APIs, instead of modifying the core system. Destinations and the Cloud Connector are how they get there. Unit 6 covers CAP and side-by-side extensions.
Operations. Tokens expire; code must fetch a new one, not store one. Trials stop apps daily; production doesn't, but certificates, keys and Cloud Connector versions need an owner.
Committing .env or the service key JSON. Check git status before every commit.
Mixing values from two keys. Client ID from one key and URI from another gives 401 or 403 errors that look mysterious.
Printing the token "for debugging". Logs live long. Print a prefix and length, as the script does.
Treating decoded claims as verified. Decoding a JWT is not checking it. Only the signature check proves it is genuine.
Hard-coding backend URLs. Use destinations, so test and production differ by configuration, not code.
Assuming the model filters data. Authorizations must be applied before data reaches the model.
Building in the trial for a customer. Trials are for learning, not team or production use.
#Exercise: design the BTP landscape for the blocked-orders assistant
You will turn what you learned into a one-page landscape design for the running example: an assistant that explains why sales orders are blocked for credit. It feeds the solution design document in Unit 6.
In VS Code, create unit03/btp_landscape.md.
Add a heading ## Subaccounts and list three subaccounts (development, test, production), each with a region you would pick and one sentence on why.
Add ## Entitlements and list the services each subaccount needs: at least Destination service, SAP AI Core, and SAP Authorization and Trust Management service. Mark any you are not sure about with (check).
Add ## Destinations and describe one destination for S/4HANA in each subaccount: proxy type (OnPremise or Internet), and whether it uses the user's identity or a technical user. Write one sentence on why.
Add ## Keys and bindings and say which consumers get service keys (for example, a developer laptop in development only) and which use bindings.
Add ## Roles and name two role collections you would create, for example one for clerks and one for admins, and what each may do.
Run your script once more and paste its table (not the token) under ## Evidence:
python btp_destinations.py
No trial? Run it with --sample and paste that table instead, marked "sample".
Save your work:
git add unit03/btp_landscape.md
git commit -m "BTP landscape for the blocked-orders assistant"
Done when:btp_landscape.md has all six sections filled in, the evidence table shows at least one destination, git status doesn't list .env, and git log shows the commit.
Pick one answer for each question. The explanation appears after you choose.
1What is the difference between a binding and a service key?
Answer: B. Binding an instance to a deployed app hands the credentials over through the app's environment. A service key creates credentials by hand for consumers outside that app, such as your laptop script.
2In btp_destinations.py, what does get_token() send to <url>/oauth/token?
Answer: C. The client credentials flow swaps the client ID and secret for a short-lived access token. The script then sends only that token, as a Bearer header, to the Destination service.
3What does read_claims() prove about the token?
Answer: D. Decoding a JWT just reads its claims. Only checking the signature proves it is genuine, and the services do that, not the script.
4Your script gets a token but the Destination service answers 401. What is the likeliest cause?
Answer: A. A token from one key doesn't fit a service URI from another. No destinations gives an empty list, not a 401, and Northwind only matters for --call.
5An AI app on BTP must read sales orders from an on-premise S/4HANA. What do you set up?
Answer: B. Calls to on-premise systems go through the Connectivity service and the SAP Cloud Connector, which the customer installs in its own network. The destination's proxy type is OnPremise.
6Why prefer principal propagation over a shared technical user for an AI assistant?
Answer: C. With a technical user, the assistant sees everything that user can see. Propagating the user's identity lets S/4HANA's authorizations decide what reaches the model.
7A colleague's commit contains .env with a service key. What do you do first?
Answer: D. Once a secret is in Git history, assume it is known. Deleting the service key retires those credentials; then fix .gitignore and store the new key's values only in .env.
8How does calling SAP AI Core differ from calling the Destination service?
Answer: D. Both are BTP services with service keys. You swap clientid and clientsecret for a token at url; AI Core adds the address of its AI API in serviceurls.AI_API_URL.
9The Destination Service tile is missing from your trial's Service Marketplace. What is the likely fix?
Answer: B. Services and plans a subaccount isn't entitled to don't show up or can't be used. In a trial you add the plan yourself under Entitlements; in a customer account you ask the platform team.
Ask a question
Testing: only staff see this
Stuck on something in this layer? Ask it here. Questions are answered in the order they arrive, and the answer appears under My questions.
Sign in (free) to ask a question. You can ask anonymously.
Managing service keys (Cloud Foundry documentation)— service keys are credentials for consumers outside a bound app; cf create-service-key, cf service-key, cf delete-service-key; some brokers don't support keys
sap-ai-sdk-core 3.4.0 (PyPI)— SAP AI Core credentials come from a service key; AICORE_CLIENT_ID, AICORE_CLIENT_SECRET, AICORE_AUTH_URL, AICORE_BASE_URL map to clientid, clientsecret, url and serviceurls.AI_API_URL
Generative AI Hub trial (sap.com)— 30-day basic trial of generative AI hub; afterwards Pay-As-You-Go for SAP BTP or an enterprise agreement