> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/dsx-air/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/dsx-air/_mcp/server.

# Training Operations

## Setup

Initialize the API client

```python
# Imports (run once)
from datetime import datetime, timedelta, timezone

from air_sdk import AirApi
from air_sdk.endpoints import Training
```

```python
# Authentication (run once)
api = AirApi.with_ngc_config()
# OR api = AirApi.with_api_key(api_key="...")
# OR api = AirApi.with_device_login(email="...", org_num="...")
#    ^ use in terminal only — not supported in Jupyter notebooks
```

## Create a Training Event

Create a new training event with:

* NGC external user group
* Template simulation that will be cloned
* Attendee list
* Timing configuration for workbench lifecycle

**Note**: The parent simulation will transition to INACTIVE state after cloning completes. A dedicated `training_simulation` will be created for the training session.

```python
# First, get a simulation to use as the template
simulation_id = '...'  # Replace with actual simulation ID
template_sim = api.simulations.get(simulation_id)

# Create training event
event_time = datetime.now(timezone.utc) + timedelta(days=7)
training: Training = api.trainings.create(
    name='network-training-101',
    parent_simulation=template_sim.id,
    attendees=['student1@example.com', 'student2@example.com'],
    event_time=event_time,
    sim_start_time=event_time - timedelta(hours=5),
    sim_end_time=event_time + timedelta(days=1),
)

print(f'Created training: {training.name}')
print(f'NGC Group ID: {training.ngc_group_id}')
print(f'Attendees: {len(training.attendees)}')
training.dict()
```

## List Training Events

List all training events visible to your account. Supports filtering and pagination.

```python
# List all trainings
for training in api.trainings.list():
    print(f'{training.name}: {training.id}')

# Filter by name
filtered = list(api.trainings.list(name='network-training-101'))

# Filter by workbenches status
active_trainings = list(api.trainings.list(workbenches_created=True))

# Search across multiple fields
search_results = list(api.trainings.list(search='network'))
```

## Get Training Details

Retrieve a specific training event by ID

```python
training_id = '...'  # Replace with actual training ID
training: Training = api.trainings.get(training_id)

print(f'Training: {training.name}')
print(f'Event time: {training.event_time}')
print(f'Template simulation: {training.training_simulation_name}')
print(f'State: {training.training_simulation_state}')
print(f'Workbenches created: {training.workbenches_created}')
print(f'Attendee details: {training.attendee_details}')

# Access the template simulation object (lazy loaded)
template_sim_name = training.training_simulation.name
print(f'Template simulation (via FK): {template_sim_name}')
```

## Update Training Fields

Update training event details. Only `event_time`, `sim_start_time`, and `sim_end_time` can be updated after creation.

**Timing Constraints:**

* `event_time`: Must be at least 5h in the future
* `sim_start_time`: Must be 1h+ in future and 4h before `event_time`
* `sim_end_time`: Must be at least 24h after `event_time`

**Note:** The `name` field cannot be updated after creation.

```python
# Update timing fields
new_event_time = datetime.now(timezone.utc) + timedelta(days=10)
training.update(
    event_time=new_event_time,
    sim_start_time=new_event_time - timedelta(hours=5),  # 5h before event
    sim_end_time=new_event_time + timedelta(days=1),  # 1 day after event
)

print(f'Updated event time: {training.event_time}')
print(f'Updated sim_start_time: {training.sim_start_time}')
print(f'Updated sim_end_time: {training.sim_end_time}')

# Or update via API method
updated = api.trainings.update(
    training=training.id,
    event_time=new_event_time,
    sim_start_time=new_event_time - timedelta(hours=5),
    sim_end_time=new_event_time + timedelta(days=1),
)
```

## Manage Attendees

Add or remove attendees from a training event

```python
# Add attendees via instance method
training.add_attendees(attendees=['student3@example.com', 'student4@example.com'])
print(f'Total attendees: {len(training.attendees)}')

# Remove attendees
training.remove_attendees(attendees=['student1@example.com'])
print(f'Remaining attendees: {len(training.attendees)}')

# Or use API-level methods
api.trainings.add_attendees(training=training.id, attendees=['student5@example.com'])
api.trainings.remove_attendees(training=training.id, attendees=['student2@example.com'])
```

## Get NGC External User Group Information

Retrieve full details about the training's NGC external user group, including confirmed users and pending invitations.

**Note**: This makes an external API call to NGC and requires `AIR_INSTRUCTOR`, `AIR_ORG_ADMIN`, or `USER_ADMIN` roles.

```python
# Get NGC group info via instance method
group_data = training.get_external_user_group()

print(f'Group Name: {group_data["name"]}')
print(f'Organization: {group_data["orgName"]}')
print(f'Resource Group: {group_data["resourceGroup"]}')
print(f'Confirmed Users: {len(group_data.get("confirmedUsers", []))}')
print(f'Pending Invitations: {len(group_data.get("pendingInvitations", []))}')

# Or use API-level method
group_data = api.trainings.get_external_user_group(training=training.id)
```

## Delete a Training Event

Delete a training event and its associated NGC user group

```python
# Delete via instance method
training.delete()
print('Training deleted successfully')

# Or delete via API method
api.trainings.delete('training-id-123')
```