Skip to main content

sap_commerce_cloud_management_apis

A Python client library for the SAP Commerce Cloud — Cloud Portal APIs (a.k.a. the Management APIs). It lets you automate operational tasks against your Commerce Cloud subscription — listing environments, triggering deployments, managing data backups, endpoints, TLS certificates, scaling, scheduled activities, and user role assignments — from Python instead of the Cloud Portal UI or CLI.

Built on httpx and attrs; every request and response is typed.

  • Base URL: https://portalapi.commerce.ondemand.com/v2
  • Format: REST / JSON
  • Auth: OAuth2 client-credentials bearer token, sent in the x-approuter-authorization header
  • Reference: Cloud Portal API Documentation

⚠️ Two things that trip people up — read these before your first call:

  1. The token goes in x-approuter-authorization, not the standard Authorization header. You must pass auth_header_name="x-approuter-authorization" (see below).
  2. The base_url must include the /v2 suffix — endpoint paths are relative to it.

Installation

This project uses Poetry:

poetry install

To use it from another project, either poetry add <path-to-this-client>, or build a wheel (poetry build -f wheel) and pip install it.

Authentication

1. Obtain a bearer token

Create a technical user in the Cloud Portal (see Technical Users), then exchange its credentials for a token using the OAuth2 client-credentials grant:

import httpx

token_response = httpx.post(
    TOKEN_URL,  # your token endpoint
    headers={"Accept": "application/json"},
    data={
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "grant_type": "client_credentials",
        "resource": RESOURCE,  # the required SAP "resource" parameter
    },
)
access_token = token_response.json()["access_token"]  # valid ~3600s

2. Build an authenticated client

from sap_commerce_cloud_management_apis import AuthenticatedClient

client = AuthenticatedClient(
    base_url="https://portalapi.commerce.ondemand.com/v2",
    token=access_token,
    auth_header_name="x-approuter-authorization",  # REQUIRED for Cloud Portal
)

Without auth_header_name, the token defaults to the standard Authorization header, which the Cloud Portal approuter does not accept.

Loading credentials from .env

Never hard-code secrets. Copy .env.example to .env (gitignored) and load it:

CCV2_SUBSCRIPTION_CODE=your-subscription-code
CCV2_TOKEN_URL=https://<tenant>.accounts.ondemand.com/oauth2/token
CCV2_CLIENT_ID=your-client-id
CCV2_CLIENT_SECRET=your-client-secret
SAP_CCV2_RESOURCE=urn:sap:identity:application:provider:name:...
import os
from dotenv import load_dotenv

load_dotenv()
subscription_code = os.environ["CCV2_SUBSCRIPTION_CODE"]
# ...etc

Calling the API

Every operation lives under sap_commerce_cloud_management_apis.api.<tag>.<operation> and exposes four functions:

Function Blocking? Returns
sync yes parsed model, or None
sync_detailed yes Response[T] (status code, headers, raw content, parsed)
asyncio no parsed model, or None
asyncio_detailed no Response[T]

Path/query params and request bodies are keyword/positional arguments. Most operations take subscription_code and often environment_code.

Example: list environments

from sap_commerce_cloud_management_apis.api.environment import get_environments
from sap_commerce_cloud_management_apis.models import EnvironmentDetailsDTO, ErrorDTO

with client as c:
    result = get_environments.sync(subscription_code, client=c)

if isinstance(result, EnvironmentDetailsDTO):
    for env in result.value or []:
        print(env.code, env.type_, env.status)
elif isinstance(result, ErrorDTO):
    print("API error:", result.title, "-", result.detail)

Use sync_detailed when you need the status code or headers:

from sap_commerce_cloud_management_apis.types import Response

resp: Response = get_environments.sync_detailed(subscription_code, client=client)
print(resp.status_code)   # e.g. 200
env_details = resp.parsed

Example: trigger a deployment

from sap_commerce_cloud_management_apis.api.deployment import create_deployment
from sap_commerce_cloud_management_apis.models import CreateDeploymentRequestDTO
from sap_commerce_cloud_management_apis.models.create_deployment_request_dto_database_update_mode import (
    CreateDeploymentRequestDTODatabaseUpdateMode,
)
from sap_commerce_cloud_management_apis.models.create_deployment_request_dto_strategy import (
    CreateDeploymentRequestDTOStrategy,
)

body = CreateDeploymentRequestDTO(
    build_code="20240101.1",
    environment_code="d1",
    database_update_mode=CreateDeploymentRequestDTODatabaseUpdateMode.NONE,
    strategy=CreateDeploymentRequestDTOStrategy.ROLLING_UPDATE,
)

deployment = create_deployment.sync(subscription_code, client=client, body=body)

Example: create a data backup

from sap_commerce_cloud_management_apis.api.databackup import create_databackup
from sap_commerce_cloud_management_apis.models import CreateDatabackupRequestDTO

body = CreateDatabackupRequestDTO(description="pre-release snapshot", databackup_type="STANDARD")
created = create_databackup.sync(subscription_code, "d1", client=client, body=body)

Async

Every operation has an async twin — use asyncio / asyncio_detailed inside an async with:

async with client as c:
    result = await get_environments.asyncio(subscription_code, client=c)

Pagination

Paginated list endpoints (e.g. deployment.get_deployments) cap out at 100 items per page and accept OData-style params: top, skip, orderby, count.

from sap_commerce_cloud_management_apis.api.deployment import get_deployments

page = get_deployments.sync(subscription_code, client=client, environment_code="d1", top=100, skip=0)

Available operations

Tag Module Operations
Environments api.environment list environments
Deployments api.deployment create / get / cancel deployments, deployment decisions & progress, traffic split
Data backups api.databackup create/get/delete backups, create/get restores, change states
Endpoints api.endpoint create / get / update / delete endpoints
Scaling api.environment_scaling get / update scaling details & options
Scheduled activities api.scheduled_activity create / get / update / cancel scheduled activities
Service properties api.service_properties get / put a property
TLS certificates api.ssl_certificate create / get / delete certificates
User role assignments api.user_role_assignments list roles, create / get / update / delete assignments

Note: build-related DTOs exist in models/ but the build API module is not generated in this client.

Error handling

Documented failures (4xx/5xx) parse into an ErrorDTO (RFC 7807) with title and detail fields — always branch on the return type rather than assuming success.

⚠️ Known caveat: the generated parsers call response.json() on error responses. When the approuter returns a non-JSON body (for example a plain-text Bad Request on a malformed token), this raises json.JSONDecodeError. For hard-failure paths (bad/absent token), inspect the raw HTTP status instead — e.g. issue the request with httpx directly, or wrap the call in a try/except json.JSONDecodeError.

TLS

Public Cloud Portal APIs require TLS 1.2+. Certificate verification is on by default. To use a custom CA bundle, pass verify_ssl="/path/to/bundle.pem"; disabling it (verify_ssl=False) is a security risk and not recommended.

Testing

Tests live in tests/ and split into two kinds:

  • Contract tests (offline) — drive the real client through an httpx.MockTransport, asserting method, URL, the x-approuter-authorization header, query/body serialization, and response→DTO parsing. No network, no credentials.
  • Live integration tests (marked integration) — perform the real OAuth2 token exchange and hit your tenant. They load credentials from .env and skip automatically if any variable is missing.
poetry run pytest                      # everything (live tests run only if .env is present)
poetry run pytest -m "not integration" # offline contract tests only
poetry run pytest -m integration       # live tests against your tenant (needs .env)

Advanced customization

You can customize the underlying httpx client — e.g. to log every request/response:

def log_request(request):
    print(f"→ {request.method} {request.url}")

def log_response(response):
    print(f"← {response.status_code} {response.request.url}")

client = AuthenticatedClient(
    base_url="https://portalapi.commerce.ondemand.com/v2",
    token=access_token,
    auth_header_name="x-approuter-authorization",
    httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}},
)

Other useful knobs on AuthenticatedClient: timeout, follow_redirects, raise_on_unexpected_status (raise on undocumented status codes instead of returning None), plus with_headers() / with_cookies() / with_timeout() to derive a modified copy. See the class docstring in client.py for the full list.

Building / publishing

This project uses Poetry:

  1. Bump version (and other metadata) in pyproject.toml.
  2. Lint: ruff check . (line length 120; rules F, I, UP).
  3. Build a wheel: poetry build -f wheel.
  4. Publish: poetry publish --build (add -r <repo> for a private repository configured via poetry config repositories.<repo> <url> and poetry config http-basic.<repo> <user> <pass>).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sap_commerce_cloud_management_apis-1.0.0.tar.gz (56.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file sap_commerce_cloud_management_apis-1.0.0.tar.gz.

File metadata

File hashes

Hashes for sap_commerce_cloud_management_apis-1.0.0.tar.gz
Algorithm Hash digest
SHA256 69db0d8e7995acf1a15456ba1c1453fecbefe87c11442533e3d2a655351caa96
MD5 6d13805302126458297d9a431edd7ddf
BLAKE2b-256 61f4ffec8fc204104b3a169814ee5bda74f80e775e9730b431ee522c3d059f50

See more details on using hashes here.

File details

Details for the file sap_commerce_cloud_management_apis-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sap_commerce_cloud_management_apis-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8f725d05d7a5cfdbb49a77402865af67ad61824b0cd4611712a4ad9ac2c865a5
MD5 74922be278541c556f7693f0d78b9c94
BLAKE2b-256 92a61a5d3bed0b16829f6e16431cb2aabaa6edd5ca8123e6f115a138580ccaae

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page