Cisco Security Cloud Control Python SDK

A Python SDK for interacting with the Cisco Security Cloud Control Platform Management APIs.

Installation

pip3 install cisco-scc-sdk

Or install from source:

pip3 install .

Using a virtual environment (recommended):

python3 -m venv venv
source venv/bin/activate && pip install -e .

Quick Start

from scc_sdk import Client

# Initialize the client with your access token
client = Client(access_token="your_bearer_token_here")

# Work with organizations
organizations = client.organizations.list()
org = client.organizations.get(org_id="550e8400-e29b-41d4-a716-446655440000")
new_org = client.organizations.create(name="New Org", region_code="NAM")

# Work with subscriptions
subscriptions = client.subscriptions.list(org_id="org-uuid")
subscription = client.subscriptions.get(org_id="org-uuid", subscription_id="sub-uuid")

# Work with groups
groups = client.groups.list(org_id="org-uuid")
group = client.groups.get(org_id="org-uuid", group_id="group-uuid")

Features

  • Simple Authentication: Just pass your bearer token
  • Resource-based API: Organized into logical resource classes
  • Type Hints: Full type hint support for better IDE integration
  • Context Manager Support: Use with with statement for automatic cleanup
  • Comprehensive Error Handling: Custom exceptions for different error types

Configuration

The SDK uses a configurable base URL. By default, it points to https://api.security.cisco.com/v1.

To use a different URL:

client = Client(
    access_token="your_token",
    base_url="https://api.security.cisco.com",
    base_path="v1"
)

Workshop Guide

Interactive Learning Template

We've created a workshop template designed for hands-on learning of the Cisco SCC SDK. This template is perfect for:

  • Self-paced learning (30-minute completion time)
  • Workshop sessions and training
  • Learning by doing without AI assistance

Workshop File: examples/workshop_template.py

The template includes:

  • ✅ Complete prerequisite setup instructions
  • ✅ TODO comments marking where you need to implement code
  • ✅ HINT comments with method signatures and guidance
  • ✅ Step-by-step exercises covering all major SDK features
  • ✅ Error handling structure already in place

Workshop Exercises:

  1. Getting Organization Details - Implement client.organizations.get()
  2. Reading and Claiming Subscriptions - Implement claim code validation and subscription creation
  3. Inviting Users - Implement user invitation logic
  4. Creating Admin Groups - Implement group creation and management
  5. Adding Users to Groups - Implement group membership updates
  6. Assigning Roles - Implement role discovery and assignment

To complete the workshop:

  1. Open examples/workshop_template.py
  2. Update the configuration section with your credentials
  3. Search for TODO: comments and implement the missing code
  4. Reference the API Reference section below for method details
  5. Run the script to test your implementation

Complete Working Example

For a fully implemented reference, see examples/setup_org_flow.py.

To run the complete example:

  1. Get your API Access Token: Generate an API key access token from the Security Cloud Control console

  2. Create or identify your Organization: Note the Organization ID you want to configure

  3. Update the configuration in setup_org_flow.py:

    • Set ACCESS_TOKEN to your API key access token
    • Set ORG_ID to your organization ID
    • Update USERS_TO_INVITE with the users you want to invite
    • Set CLAIM_CODE with your subscription claim code
  4. Run the script:

    python3 examples/setup_org_flow.py

This example demonstrates a complete workflow including:

  • Retrieving organization details
  • Claiming subscriptions
  • Inviting users to the organization
  • Creating an admin group
  • Assigning product roles to the group

API Reference

Organizations API

The Organizations resource provides methods to manage Security Cloud Control organizations.

list()

List organizations with optional filtering and pagination.

Method Signature:

client.organizations.list(
    name: Optional[str] = None,
    type: Optional[str] = None,
    region_code: Optional[str] = None,
    country_code: Optional[str] = None,
    manager_org_id: Optional[str] = None,
    max: int = 100,
    cursor: Optional[str] = None,
    sort_by: Optional[str] = None,
    order: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • name (str, optional): Filter by organization name (partial match)
  • type (str, optional): Filter by organization type (STANDALONE, MANAGER, MANAGED)
  • region_code (str, optional): Filter by region code (NAM, EMEA, APJC, GLOBAL)
  • country_code (str, optional): Filter by country code
  • manager_org_id (str, optional): Filter by manager organization ID
  • max (int, optional): Maximum number of items to return (default: 100, max: 500)
  • cursor (str, optional): Cursor for pagination
  • sort_by (str, optional): Field to sort by (e.g., "name")
  • order (str, optional): Sort order (ASC or DESC)

Returns: Dictionary containing list of organizations and pagination info

Example:

# List all organizations
orgs = client.organizations.list()

# List with filtering and pagination
orgs = client.organizations.list(
    name="Acme",
    type="STANDALONE",
    region_code="NAM",
    max=50,
    sort_by="name",
    order="ASC"
)

Common Use Cases:

  • Browse all organizations in your Security Cloud Control account
  • Find organizations by name or type
  • Paginate through large sets of organizations

get(org_id)

Get a specific organization by ID.

Method Signature:

client.organizations.get(org_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID

Returns: Organization dictionary with details including name, type, region, and creation date

Example:

org = client.organizations.get(org_id="550e8400-e29b-41d4-a716-446655440000")
print(f"Organization: {org['name']}")
print(f"Type: {org['type']}")
print(f"Region: {org['regionCode']}")

Common Use Cases:

  • Retrieve detailed information about a specific organization
  • Verify organization exists before performing operations
  • Display organization details to users

create(name, region_code, type)

Create a new organization.

Method Signature:

client.organizations.create(
    name: str,
    region_code: str,
    type: str = "STANDALONE"
) -> Dict[str, Any]

Parameters:

  • name (str, required): Organization name
  • region_code (str, required): Region code (NAM, EMEA, APJC)
  • type (str, optional): Organization type (STANDALONE, MANAGER, MANAGED). Default: "STANDALONE"

Returns: Created organization dictionary

Example:

new_org = client.organizations.create(
    name="New Organization",
    region_code="NAM",
    type="STANDALONE"
)
print(f"Created organization with ID: {new_org['id']}")

Common Use Cases:

  • Provision new organizations for customers
  • Set up multi-tenant environments
  • Create managed organizations under a manager organization

update(org_id, name)

Update an organization's name.

Method Signature:

client.organizations.update(org_id: str, name: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • name (str, required): New organization name

Returns: Updated organization dictionary

Example:

updated_org = client.organizations.update(
    org_id="550e8400-e29b-41d4-a716-446655440000",
    name="Updated Name"
)

Common Use Cases:

  • Rename organizations after company rebrand
  • Correct organization naming errors
  • Update organization display names

Subscriptions API

The Subscriptions resource provides methods to manage product subscriptions within organizations.

list(org_id, name)

List all subscriptions for an organization.

Method Signature:

client.subscriptions.list(
    org_id: str,
    name: Optional[str] = None
) -> List[Dict[str, Any]]

Parameters:

  • org_id (str, required): The organization UUID
  • name (str, optional): Optional subscription name filter

Returns: List of subscription dictionaries

Example:

subscriptions = client.subscriptions.list(org_id="org-uuid")
for sub in subscriptions:
    print(f"Subscription: {sub['name']}")

Common Use Cases:

  • View all active subscriptions for an organization
  • Find specific subscriptions by name
  • Audit subscription inventory

get(org_id, subscription_id)

Get a specific subscription by ID.

Method Signature:

client.subscriptions.get(org_id: str, subscription_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • subscription_id (str, required): The subscription UUID

Returns: Subscription dictionary with full details

Example:

subscription = client.subscriptions.get(
    org_id="org-uuid",
    subscription_id="3742d652-6740-489c-b628-143f00690fea"
)

Common Use Cases:

  • Retrieve detailed subscription information
  • Verify subscription status and entitlements
  • Check product activation status

create(org_id, claim_code, products)

Create a new subscription using a claim code.

Method Signature:

client.subscriptions.create(
    org_id: str,
    claim_code: str,
    products: Optional[List[Dict[str, Any]]] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • claim_code (str, required): Claim code for subscription creation
  • products (List[Dict], optional): List of products to provision with configuration

Returns: Dictionary with success status

Example:

# First, read claim code details
claim_info = client.subscriptions.read_claim_code(
    org_id="org-uuid",
    claim_code="PHJZ-DWMF-ZBYH-FYMB"
)

# Build products list from claim info
products = client.subscriptions.build_products_from_claim_info(claim_info)

# Create subscription
new_subscription = client.subscriptions.create(
    org_id="org-uuid",
    claim_code="PHJZ-DWMF-ZBYH-FYMB",
    products=products
)

Common Use Cases:

  • Activate new product subscriptions
  • Claim trial or promotional subscriptions
  • Provision products during customer onboarding

update(org_id, subscription_id, product_id, status, ...)

Update a subscription (activate/deactivate product).

Method Signature:

client.subscriptions.update(
    org_id: str,
    subscription_id: str,
    product_id: str,
    status: bool,
    source_instance_id: Optional[str] = None,
    region_code: Optional[str] = None,
    initial_admin: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • subscription_id (str, required): The subscription UUID
  • product_id (str, required): The product UUID
  • status (bool, required): True to activate, False to deactivate
  • source_instance_id (str, optional): Source instance ID for using existing tenant
  • region_code (str, optional): Product region code (NAM, EMEA, APJC, US, GLOBAL)
  • initial_admin (str, optional): Initial admin email for new tenant provisioning

Returns: Updated subscription dictionary

Example:

# Activate a product
updated_sub = client.subscriptions.update(
    org_id="org-uuid",
    subscription_id="sub-uuid",
    product_id="product-uuid",
    status=True,
    region_code="NAM",
    initial_admin="admin@example.com"
)

# Deactivate a product
deactivated = client.subscriptions.update(
    org_id="org-uuid",
    subscription_id="sub-uuid",
    product_id="product-uuid",
    status=False
)

Common Use Cases:

  • Enable or disable specific products within a subscription
  • Provision new product tenants
  • Migrate products between regions

patch(org_id, subscription_id, entitlements, use_existing_tenants)

Patch a subscription (update entitlement quantities for managed organizations).

Method Signature:

client.subscriptions.patch(
    org_id: str,
    subscription_id: str,
    entitlements: List[Dict[str, Any]],
    use_existing_tenants: Optional[List[str]] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The managed organization UUID
  • subscription_id (str, required): The subscription UUID
  • entitlements (List[Dict], required): List of entitlements with id and quantity
  • use_existing_tenants (List[str], optional): List of existing tenant UUIDs

Returns: Updated subscription dictionary

Example:

patched_sub = client.subscriptions.patch(
    org_id="org-uuid",
    subscription_id="sub-uuid",
    entitlements=[
        {"id": "E3S-AIDEF-ADV", "quantity": 10},
        {"id": "CPT-SEC-ADV", "quantity": 50}
    ],
    use_existing_tenants=["8a9f43fa-f8f5-4aac-8d0b-380cf6656255"]
)

Common Use Cases:

  • Update SKU quantities for managed organizations
  • Adjust entitlements after license changes
  • Scale product usage up or down

read_claim_code(org_id, claim_code)

Read and validate claim code details before creating a subscription.

Method Signature:

client.subscriptions.read_claim_code(org_id: str, claim_code: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • claim_code (str, required): Claim code to validate

Returns: Claim code information dictionary with products, entitlements, and allowed regions

Example:

claim_info = client.subscriptions.read_claim_code(
    org_id="org-uuid",
    claim_code="PHJZ-DWMF-ZBYH-FYMB"
)
print(f"Claim code name: {claim_info['name']}")
for product in claim_info['products']:
    print(f"Product: {product['name']}")

Common Use Cases:

  • Validate claim codes before subscription creation
  • Preview products and entitlements in a claim code
  • Display available regions for product deployment

build_products_from_claim_info(claim_info, preferred_region)

Build products list from claim info with region selection.

Method Signature:

client.subscriptions.build_products_from_claim_info(
    claim_info: Dict[str, Any],
    preferred_region: str = "NAM"
) -> List[Dict[str, Any]]

Parameters:

  • claim_info (Dict, required): Claim code information dictionary (from read_claim_code())
  • preferred_region (str, optional): Preferred region code (default: "NAM")

Returns: List of products ready for subscription creation

Example:

claim_info = client.subscriptions.read_claim_code(org_id="org-uuid", claim_code="XXXX")
products = client.subscriptions.build_products_from_claim_info(
    claim_info,
    preferred_region="EMEA"
)
client.subscriptions.create(org_id="org-uuid", claim_code="XXXX", products=products)

Common Use Cases:

  • Prepare product list for subscription creation
  • Select specific regions for product deployment
  • Automatically configure products from claim code

Users API

The Users resource provides methods to manage user accounts within organizations.

list(org_id, group_id, status)

List all users for an organization.

Method Signature:

client.users.list(
    org_id: str,
    group_id: Optional[str] = None,
    status: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, optional): Filter users by group membership
  • status (str, optional): Filter by status (ACTIVE, DISABLE, PENDING, SHARED)

Returns: Dictionary containing list of users

Example:

# List all users
users = client.users.list(org_id="org-uuid")

# Filter by group
group_users = client.users.list(org_id="org-uuid", group_id="group-uuid")

# Filter by status
active_users = client.users.list(org_id="org-uuid", status="ACTIVE")

Common Use Cases:

  • View all users in an organization
  • Find users belonging to specific groups
  • Filter users by account status

get(org_id, user_id)

Get a specific user by ID.

Method Signature:

client.users.get(org_id: str, user_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • user_id (str, required): The user UUID

Returns: User dictionary with full details

Example:

user = client.users.get(org_id="org-uuid", user_id="user-uuid")
print(f"User: {user['firstName']} {user['lastName']}")
print(f"Email: {user['email']}")

Common Use Cases:

  • Retrieve detailed user information
  • Verify user account details
  • Check user status and group memberships

invite(org_id, email, first_name, last_name)

Invite a new user to the organization.

Method Signature:

client.users.invite(
    org_id: str,
    email: str,
    first_name: str,
    last_name: str
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • email (str, required): User's email address
  • first_name (str, required): User's first name
  • last_name (str, required): User's last name

Returns: User operation response dictionary

Example:

result = client.users.invite(
    org_id="org-uuid",
    email="user@example.com",
    first_name="John",
    last_name="Doe"
)

Common Use Cases:

  • Add new users to an organization
  • Onboard employees or customers
  • Send invitation emails to new users

disable(org_id, email)

Disable a user account.

Method Signature:

client.users.disable(org_id: str, email: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • email (str, required): User's email address

Returns: User operation response dictionary

Example:

client.users.disable(org_id="org-uuid", email="user@example.com")

Common Use Cases:

  • Temporarily deactivate user accounts
  • Suspend access for terminated employees
  • Disable compromised accounts

enable(org_id, email)

Enable a user account.

Method Signature:

client.users.enable(org_id: str, email: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • email (str, required): User's email address

Returns: User operation response dictionary

Example:

client.users.enable(org_id="org-uuid", email="user@example.com")

Common Use Cases:

  • Re-enable previously disabled accounts
  • Restore access after suspension
  • Activate accounts after review

remove(org_id, email)

Remove a user from the organization.

Method Signature:

client.users.remove(org_id: str, email: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • email (str, required): User's email address

Returns: User operation response dictionary

Example:

client.users.remove(org_id="org-uuid", email="user@example.com")

Common Use Cases:

  • Permanently remove users from organization
  • Clean up inactive accounts
  • Remove users after offboarding

resend_email_invite(org_id, email)

Resend email invitation to a user.

Method Signature:

client.users.resend_email_invite(org_id: str, email: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • email (str, required): User's email address

Returns: User operation response dictionary

Example:

client.users.resend_email_invite(org_id="org-uuid", email="user@example.com")

Common Use Cases:

  • Resend invitations that were not received
  • Send reminder emails to pending users
  • Address email delivery issues

update(org_id, user_id, first_name, last_name)

Update a user's first and last name.

Method Signature:

client.users.update(
    org_id: str,
    user_id: str,
    first_name: Optional[str] = None,
    last_name: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • user_id (str, required): The user UUID
  • first_name (str, optional): User's first name
  • last_name (str, optional): User's last name

Returns: Updated user dictionary

Example:

updated_user = client.users.update(
    org_id="org-uuid",
    user_id="user-uuid",
    first_name="Jane",
    last_name="Smith"
)

Common Use Cases:

  • Update user profile information
  • Correct name spelling errors
  • Reflect name changes after marriage or legal change

patch(org_id, users)

Perform bulk operations on users (invite, disable, enable, remove, resend_email_invite).

Method Signature:

client.users.patch(
    org_id: str,
    users: List[Dict[str, Any]]
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • users (List[Dict], required): List of user operations with email, operation, and optional firstName/lastName

Returns: Operation result dictionary with results array

Example:

# Bulk invite multiple users
result = client.users.patch(
    org_id="org-uuid",
    users=[
        {
            "email": "user1@example.com",
            "operation": "invite",
            "firstName": "John",
            "lastName": "Doe"
        },
        {
            "email": "user2@example.com",
            "operation": "invite",
            "firstName": "Jane",
            "lastName": "Smith"
        }
    ]
)

# Bulk disable users
client.users.patch(
    org_id="org-uuid",
    users=[
        {"email": "user1@example.com", "operation": "disable"},
        {"email": "user2@example.com", "operation": "disable"}
    ]
)

Common Use Cases:

  • Bulk invite multiple users at once
  • Perform mass account operations
  • Automate user lifecycle management

get_groups(org_id, user_id)

List all groups to which a user is assigned.

Method Signature:

client.users.get_groups(org_id: str, user_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • user_id (str, required): The user UUID

Returns: Dictionary containing list of groups

Example:

groups = client.users.get_groups(org_id="org-uuid", user_id="user-uuid")
for group in groups.get("groups", []):
    print(f"Group: {group['name']}")

Common Use Cases:

  • View user's group memberships
  • Audit user access and permissions
  • Verify role assignments through groups

Groups API

The Groups resource provides methods to manage admin groups for role-based access control.

list(org_id)

List all admin groups for an organization.

Method Signature:

client.groups.list(org_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID

Returns: Dictionary containing list of groups

Example:

groups = client.groups.list(org_id="org-uuid")
for group in groups.get("groups", []):
    print(f"Group: {group['name']}")

Common Use Cases:

  • View all admin groups in an organization
  • List groups for user assignment
  • Audit group structure

get(org_id, group_id)

Get a specific admin group by ID.

Method Signature:

client.groups.get(org_id: str, group_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID

Returns: Group dictionary with full details

Example:

group = client.groups.get(org_id="org-uuid", group_id="group-uuid")
print(f"Group: {group['name']}")
print(f"Description: {group['description']}")

Common Use Cases:

  • Retrieve detailed group information
  • Verify group configuration
  • Display group details to administrators

create(org_id, name, description, applies_to)

Create a new admin group.

Method Signature:

client.groups.create(
    org_id: str,
    name: str,
    description: Optional[str] = None,
    applies_to: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • name (str, required): Group name
  • description (str, optional): Group description
  • applies_to (str, optional): Scope (all, manager, selected_managed)

Returns: Created group dictionary

Example:

new_group = client.groups.create(
    org_id="org-uuid",
    name="Engineering Team",
    description="Engineering department group",
    applies_to="all"
)
print(f"Created group with ID: {new_group['id']}")

Common Use Cases:

  • Create groups for departments or teams
  • Set up role-based access control
  • Organize users by function or location

update(org_id, group_id, name, description)

Update an existing admin group.

Method Signature:

client.groups.update(
    org_id: str,
    group_id: str,
    name: Optional[str] = None,
    description: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID
  • name (str, optional): New group name
  • description (str, optional): New group description

Returns: Updated group dictionary

Example:

updated_group = client.groups.update(
    org_id="org-uuid",
    group_id="group-uuid",
    name="Updated Team Name",
    description="Updated description"
)

Common Use Cases:

  • Rename groups after reorganization
  • Update group descriptions
  • Maintain accurate group information

delete(org_id, group_id)

Delete an admin group.

Method Signature:

client.groups.delete(org_id: str, group_id: str) -> bool

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID

Returns: True if deletion was successful

Example:

success = client.groups.delete(org_id="org-uuid", group_id="group-uuid")
if success:
    print("Group deleted successfully")

Common Use Cases:

  • Remove obsolete groups
  • Clean up after reorganization
  • Delete duplicate or test groups

patch(org_id, group_id, users, managed_orgs)

Patch admin group membership (add/remove users and managed organizations).

Method Signature:

client.groups.patch(
    org_id: str,
    group_id: str,
    users: Optional[List[Dict[str, str]]] = None,
    managed_orgs: Optional[List[Dict[str, str]]] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID
  • users (List[Dict], optional): User operations with 'operation' (add/remove) and 'id' (email)
  • managed_orgs (List[Dict], optional): Managed org operations with 'operation' (add/remove) and 'id'

Returns: Patch operation results

Example:

# Add users to group
result = client.groups.patch(
    org_id="org-uuid",
    group_id="group-uuid",
    users=[
        {"operation": "add", "id": "user@example.com"},
        {"operation": "add", "id": "admin@example.com"}
    ]
)

# Remove user and managed org
result = client.groups.patch(
    org_id="org-uuid",
    group_id="group-uuid",
    users=[{"operation": "remove", "id": "user@example.com"}],
    managed_orgs=[{"operation": "remove", "id": "managed-org-id"}]
)

Common Use Cases:

  • Add users to groups for access control
  • Remove users from groups
  • Manage shared group access to managed organizations

get_managed_organizations(org_id, group_id)

Get managed organizations for a shared admin group.

Method Signature:

client.groups.get_managed_organizations(org_id: str, group_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID

Returns: Dictionary containing list of managed organizations

Example:

managed_orgs = client.groups.get_managed_organizations(
    org_id="org-uuid",
    group_id="group-uuid"
)

Common Use Cases:

  • View organizations accessible to shared group
  • Audit multi-tenant access
  • Verify managed organization assignments

get_assigned_roles(org_id, group_id)

Get assigned roles for a specific admin group.

Method Signature:

client.groups.get_assigned_roles(org_id: str, group_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID

Returns: Dictionary containing list of roles

Example:

roles = client.groups.get_assigned_roles(org_id="org-uuid", group_id="group-uuid")
for role in roles.get("roles", []):
    print(f"Role: {role['displayName']}")

Common Use Cases:

  • View permissions assigned to a group
  • Audit group access levels
  • Verify role assignments

get_users(org_id, group_id)

Get all users that belong to a specific admin group.

Method Signature:

client.groups.get_users(org_id: str, group_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • group_id (str, required): The group UUID

Returns: Dictionary containing list of users

Example:

users = client.groups.get_users(org_id="org-uuid", group_id="group-uuid")
for user in users.get("users", []):
    print(f"User: {user['email']}")

Common Use Cases:

  • List group members
  • Audit group membership
  • Verify user assignments

Roles API

The Roles resource provides methods to manage role assignments for users and groups.

list(org_id, type)

List all roles for an organization.

Method Signature:

client.roles.list(
    org_id: str,
    type: Optional[str] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • type (str, optional): Filter by role type (CUSTOM, BUNDLED, STATIC)

Returns: Dictionary containing list of roles

Example:

# List all roles
roles = client.roles.list(org_id="org-uuid")

# List only static roles
static_roles = client.roles.list(org_id="org-uuid", type="STATIC")

Common Use Cases:

  • View all available roles
  • Filter roles by type
  • Display role options to administrators

get(org_id, role_id)

Get a specific role by ID.

Method Signature:

client.roles.get(org_id: str, role_id: str) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • role_id (str, required): The role UUID

Returns: Role dictionary with full details

Example:

role = client.roles.get(org_id="org-uuid", role_id="role-uuid")
print(f"Role: {role['displayName']}")
for product in role.get('products', []):
    print(f"Product: {product['name']}")

Common Use Cases:

  • Retrieve detailed role information
  • View role permissions and products
  • Display role details to users

patch(org_id, role_id, users, groups)

Update role assignments by adding or removing users and groups.

Method Signature:

client.roles.patch(
    org_id: str,
    role_id: str,
    users: Optional[List[Dict[str, str]]] = None,
    groups: Optional[List[Dict[str, str]]] = None
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • role_id (str, required): The role UUID
  • users (List[Dict], optional): User operations with 'operation' (add/remove) and 'id' (user UUID)
  • groups (List[Dict], optional): Group operations with 'operation' (add/remove) and 'id' (group UUID)

Returns: Dictionary with 'results' array and 'summary' containing success/failure counts

Example:

# Assign role to users and groups
result = client.roles.patch(
    org_id="org-uuid",
    role_id="role-uuid",
    users=[{"operation": "add", "id": "user-uuid"}],
    groups=[{"operation": "add", "id": "group-uuid"}]
)

# Check results
if result["summary"]["all_successful"]:
    print("All role assignments successful")
else:
    print(f"Failed: {result['summary']['failed']} operations")

Common Use Cases:

  • Assign roles to users or groups
  • Remove role assignments
  • Bulk update role memberships

find_role_id(org_id, product_name, role_display_name)

Find a role ID by product name and role display name.

Method Signature:

client.roles.find_role_id(
    org_id: str,
    product_name: str,
    role_display_name: str
) -> Optional[str]

Parameters:

  • org_id (str, required): The organization UUID
  • product_name (str, required): Product name (e.g., "Security Cloud Control")
  • role_display_name (str, required): Role display name (e.g., "Organization Administrator")

Returns: Role ID if found, None otherwise

Example:

role_id = client.roles.find_role_id(
    org_id="org-uuid",
    product_name="Security Cloud Control",
    role_display_name="Organization Administrator"
)
if role_id:
    print(f"Found role ID: {role_id}")

Common Use Cases:

  • Find role IDs by human-readable names
  • Automate role assignments without hardcoding IDs
  • Lookup roles for specific products

Tokens API

The Tokens resource provides methods to manage API token refresh operations.

refresh(org_id, api_key_id, refresh_token)

Refresh access token using a refresh token.

Method Signature:

client.tokens.refresh(
    org_id: str,
    api_key_id: str,
    refresh_token: str
) -> Dict[str, Any]

Parameters:

  • org_id (str, required): The organization UUID
  • api_key_id (str, required): The API key UUID
  • refresh_token (str, required): The refresh token value

Returns: Dictionary containing new access_token, refresh_token, and expires_in

Example:

new_tokens = client.tokens.refresh(
    org_id="org-uuid",
    api_key_id="key-uuid",
    refresh_token="your_refresh_token"
)

access_token = new_tokens["access_token"]
refresh_token = new_tokens["refresh_token"]
expires_in = new_tokens["expires_in"]

# Use new access token for subsequent requests
client = Client(access_token=access_token)

Common Use Cases:

  • Refresh expired access tokens
  • Implement token rotation for security
  • Maintain long-running API sessions

Usage Examples

Using Context Manager

with Client(access_token="your_token") as client:
    orgs = client.organizations.list()
    # Session is automatically closed when exiting the context

Organizations

# List organizations with filtering and pagination
orgs = client.organizations.list(
    name="Acme",
    type="STANDALONE",
    region_code="NAM",
    max=50,
    sort_by="name",
    order="ASC"
)

# Get a specific organization
org = client.organizations.get(org_id="550e8400-e29b-41d4-a716-446655440000")

# Create a new organization
new_org = client.organizations.create(
    name="New Organization",
    region_code="NAM",
    type="STANDALONE"
)

# Update an organization
updated_org = client.organizations.update(
    org_id="550e8400-e29b-41d4-a716-446655440000",
    name="Updated Name"
)

Subscriptions

org_id = "550e8400-e29b-41d4-a716-446655440000"

# List subscriptions
subscriptions = client.subscriptions.list(org_id=org_id)

# Get a specific subscription
subscription = client.subscriptions.get(
    org_id=org_id,
    subscription_id="3742d652-6740-489c-b628-143f00690fea"
)

# Create a subscription with claim code
new_subscription = client.subscriptions.create(
    org_id=org_id,
    claim_code="PHJZ-DWMF-ZBYH-FYMB",
    type="STANDALONE"
)

# Read claim code details before creating
claim_info = client.subscriptions.read_claim_code(
    org_id=org_id,
    claim_code="PHJZ-DWMF-ZBYH-FYMB"
)

# Update subscription (activate/deactivate product)
updated_sub = client.subscriptions.update(
    org_id=org_id,
    subscription_id="sub-uuid",
    product_id="product-uuid",
    status=True,
    region_code="NAM",
    initial_admin="admin@example.com"
)

# Patch subscription (update SKU quantities for managed orgs)
patched_sub = client.subscriptions.patch(
    org_id=org_id,
    subscription_id="sub-uuid",
    skus=[
        {"name": "E3S-AIDEF-ADV", "quantity": 10},
        {"name": "CPT-SEC-ADV", "quantity": 50}
    ]
)

Groups

org_id = "550e8400-e29b-41d4-a716-446655440000"

# List groups
groups = client.groups.list(org_id=org_id)

# Get a specific group
group = client.groups.get(
    org_id=org_id,
    group_id="e980e881-b61f-11f0-a9b4-06fbd2118f4e"
)

# Create a new group
new_group = client.groups.create(
    org_id=org_id,
    name="Engineering Team",
    description="Engineering department group",
    applies_to="SOME_MANAGED"
)

# Update a group
updated_group = client.groups.update(
    org_id=org_id,
    group_id="group-uuid",
    name="Updated Team Name",
    description="Updated description"
)

# Delete a group
client.groups.delete(org_id=org_id, group_id="group-uuid")

# Remove shared group from managed organization
client.groups.remove_shared_group(org_id=org_id, group_id="group-uuid")

Token Refresh

# Refresh access token using refresh token
new_tokens = client.tokens.refresh(
    org_id="org-uuid",
    api_key_id="key-uuid",
    refresh_token="your_refresh_token"
)

access_token = new_tokens["access_token"]
refresh_token = new_tokens["refresh_token"]
expires_in = new_tokens["expires_in"]

Error Handling

The SDK provides custom exceptions for different error scenarios:

from scc_sdk import (
    Client,
    SCCError,
    AuthenticationError,
    NotFoundError,
    ValidationError,
    ForbiddenError,
    ServerError
)

try:
    client = Client(access_token="your_token")
    org = client.organizations.get(org_id="invalid-uuid")
except AuthenticationError:
    print("Invalid access token")
except NotFoundError:
    print("Organization not found")
except ValidationError:
    print("Invalid request data")
except ForbiddenError:
    print("Access forbidden")
except ServerError:
    print("Server error occurred")
except SCCError as e:
    print(f"API error occurred: {e}")

Detailed Error Information

All SCCError exceptions include detailed error information from the API:

try:
    claim_info = client.subscriptions.read_claim_code(
        org_id="org-uuid",
        claim_code="INVALID-CODE"
    )
except SCCError as e:
    # Access error details
    print(f"Error: {e.message}")
    print(f"Status Code: {e.status_code}")
    print(f"Tracking ID: {e.tracking_id}")
    print(f"Timestamp: {e.timestamp}")
    print(f"Path: {e.path}")
    
    # Get full error response
    print(f"Full Response: {e.response}")
    
    # Or convert to dictionary
    error_dict = e.to_dict()

Available error attributes:

  • message - Error message
  • status_code - HTTP status code (e.g., 400, 404)
  • tracking_id - API tracking ID for support requests
  • timestamp - Error timestamp
  • path - API path that generated the error
  • response - Full response dictionary from the API

Example error response:

{
    "trackingId": "bb7d315e-502c-4427-9683-cc6fc824495f",
    "message": "invalid claim code provided",
    "timestamp": "2026-02-05T22:53:38.923039436Z",
    "statusCode": 400,
    "path": "/v1/organizations/94ff7d60-aebb-41d0-82cf-e06c74b63d81/subscriptions/claimInfo"
}

API Resources

Organizations Resource

  • list() - List organizations with filtering
  • get(org_id) - Get organization by ID
  • create(name, region_code, type) - Create new organization
  • update(org_id, name) - Update organization name

Subscriptions Resource

  • list(org_id, name) - List subscriptions
  • get(org_id, subscription_id) - Get subscription by ID
  • create(org_id, claim_code, type, products) - Create subscription
  • update(org_id, subscription_id, ...) - Update subscription
  • patch(org_id, subscription_id, skus, ...) - Patch subscription SKUs
  • read_claim_code(org_id, claim_code) - Validate claim code

Groups Resource

  • list(org_id) - List groups
  • get(org_id, group_id) - Get group by ID
  • create(org_id, name, description, applies_to) - Create group
  • update(org_id, group_id, name, description) - Update group
  • delete(org_id, group_id) - Delete group
  • remove_shared_group(org_id, group_id) - Remove shared group

Tokens Resource

  • refresh(org_id, api_key_id, refresh_token) - Refresh access token

Development

Running Tests

pip3 install -e ".[dev]"
pytest

Code Formatting

black scc_sdk/
flake8 scc_sdk/
mypy scc_sdk/

API Documentation

For full API documentation, refer to the Cisco Security Cloud Control API Documentation.

Contributing

Thanks for your interest in contributing! There are many ways to contribute to this project. Get started here.

Support

For questions, issues, or feedback regarding this SDK, please contact the Cisco SCC SDK Team:

📧 Email: cisco-scc-sdk-team@cisco.com

License

This library is distributed under the Apache 2.0 license found in the LICENSE file.

View code on GitHub

Code Exchange Community

Get help, share code, and collaborate with other developers in the Code Exchange community.View Community
Disclaimer:
Cisco provides Code Exchange for convenience and informational purposes only, with no support of any kind. This page contains information and links from third-party websites that are governed by their own separate terms. Reference to a project or contributor on this page does not imply any affiliation with or endorsement by Cisco.