---
editLink: false
lastUpdated: false
outline: [2, 3]
---

<!-- Generated by python/b2c-tooling-sdk/scripts/generate_api_docs.py. Do not edit. -->

# b2c_tooling_sdk.operations.jobs

Job execution operations for B2C Commerce.

Mirrors `src/operations/jobs/index.ts`. SDK consumers should call the SCAPI
ops directly via the `scapi_*` free functions (or, for legacy code, the OCAPI
free functions from `run`). Ordered import
sets use the site-archive/WebDAV workflow.

The SCAPI ops are defined in `scapi_ops`
with plain names (`execute_job` etc.) and re-exported here under `scapi_*`
names, matching the TS `executeJob as scapiExecuteJob` aliasing.

## Classes

### JobExecutionError {#jobexecutionerror}

```python
class JobExecutionError(Exception)
```

Raised when a job execution fails.

Carries the raw OCAPI [`JobExecution`](/python/api/operations/jobs#jobexecution) so callers can read fields
(`exit_status`, `log_file_path`, ...) for error reporting.

### ExecuteJobOptions {#executejoboptions}

```python
class ExecuteJobOptions
```

Options for executing a job.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `parameters` | `list[JobExecutionParameter]` | `field(default_factory=list)` |
| `body` | `dict[str, Any] \| None` | `None` |
| `wait_for_running` | `bool` | `True` |

### WaitForJobOptions {#waitforjoboptions}

```python
class WaitForJobOptions
```

Options for waiting on a job.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `poll_interval_seconds` | `float` | `3` |
| `timeout_seconds` | `float` | `0` |
| `on_poll` | `Callable[[WaitForJobPollInfo], None] \| None` | `None` |
| `sleep` | `Callable[[float], Awaitable[None]]` | `asyncio.sleep` |

### WaitForJobPollInfo {#waitforjobpollinfo}

```python
class WaitForJobPollInfo
```

Poll info passed to the `on_poll` callback during job waiting.

**Fields**

| Name | Type |
| --- | --- |
| `job_id` | `str` |
| `execution_id` | `str` |
| `elapsed_seconds` | `int` |
| `status` | `str` |

### SearchJobExecutionsOptions {#searchjobexecutionsoptions}

```python
class SearchJobExecutionsOptions
```

Search options for job executions.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `job_id` | `str \| None` | `None` |
| `status` | `str \| list[str] \| None` | `None` |
| `count` | `int` | `25` |
| `start` | `int` | `0` |
| `sort_by` | `str` | `'start_time'` |
| `sort_order` | `str` | `'desc'` |

### JobExecutionSearchResult {#jobexecutionsearchresult}

```python
class JobExecutionSearchResult
```

Search results for job executions (raw OCAPI hits).

**Fields**

| Name | Type |
| --- | --- |
| `total` | `int` |
| `count` | `int` |
| `start` | `int` |
| `hits` | `list[JobExecution]` |

### ScapiJobStartError {#scapijobstarterror}

```python
class ScapiJobStartError(ScapiRequestError)
```

Raised when the SCAPI job-start POST is rejected with a response (non-2xx).

Carries the received HTTP `status` so callers can tell a *request
rejection* (server refused before starting the job — safe to treat as "no
job created") from an ambiguous failure. A network/timeout error during the
POST does NOT produce this — it surfaces as a raw thrown error with no
status, because the request may have reached the server.

### ExecuteJobScapiOptions {#executejobscapioptions}

```python
class ExecuteJobScapiOptions
```

Options for [`execute_job`](/python/api/operations/jobs#execute-job) (SCAPI).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `tenant_id` | `str` |  |
| `parameters` | `list[dict[str, Any]]` | `field(default_factory=list)` |
| `body` | `dict[str, Any] \| None` | `None` |
| `wait_for_running` | `bool` | `True` |
| `sleep` | `Callable[[float], Awaitable[None]]` | `asyncio.sleep` |

### SearchJobExecutionsScapiOptions {#searchjobexecutionsscapioptions}

```python
class SearchJobExecutionsScapiOptions
```

Options for [`search_job_executions`](/python/api/operations/jobs#search-job-executions) (SCAPI).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `tenant_id` | `str` |  |
| `job_id` | `str \| None` | `None` |
| `status` | `str \| list[str] \| None` | `None` |
| `count` | `int` | `25` |
| `start` | `int` | `0` |
| `sort_by` | `str` | `'start_time'` |
| `sort_order` | `str` | `'desc'` |

### JobExecutionInfo {#jobexecutioninfo}

```python
class JobExecutionInfo
```

Canonical, backend-agnostic job execution shape.

`raw` mirrors the TypeScript `_raw` field: the original backend payload,
preserved for a lossless round-trip when mapping back to OCAPI.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `id` | `str` |  |
| `job_id` | `str` |  |
| `execution_status` | `JobCanonicalStatus` |  |
| `exit_status` | `JobExitStatus \| None` | `None` |
| `start_time` | `str \| None` | `None` |
| `end_time` | `str \| None` | `None` |
| `duration` | `int \| None` | `None` |
| `step_executions` | `list[JobStepExecutionResult] \| None` | `None` |
| `log_file_path` | `str \| None` | `None` |
| `is_log_file_existing` | `bool \| None` | `None` |
| `parameters` | `list[dict[str, str]] \| None` | `None` |
| `raw` | `Any` | `field(default=None)` |

### JobStepExecutionResult {#jobstepexecutionresult}

```python
class JobStepExecutionResult
```

Canonical, backend-agnostic step execution.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `id` | `str \| None` | `None` |
| `step_id` | `str \| None` | `None` |
| `execution_status` | `str \| None` | `None` |
| `exit_status` | `JobExitStatus \| None` | `None` |
| `duration` | `int \| None` | `None` |

### JobExecutionSearchResults {#jobexecutionsearchresults}

```python
class JobExecutionSearchResults
```

Canonical search results over [`JobExecutionInfo`](/python/api/operations/jobs#jobexecutioninfo).

**Fields**

| Name | Type |
| --- | --- |
| `total` | `int` |
| `limit` | `int` |
| `offset` | `int` |
| `hits` | `list[JobExecutionInfo]` |

### CanonicalJobExecutionError {#canonicaljobexecutionerror}

```python
class CanonicalJobExecutionError(Exception)
```

Raised by [`wait_for_job_execution`](/python/api/operations/jobs#wait-for-job-execution) when a job reaches a failure state.

Carries the canonical [`JobExecutionInfo`](/python/api/operations/jobs#jobexecutioninfo) so callers can read fields
(`exit_status.code`, `log_file_path`, ...) without knowing which backend
served the response.

### SystemJobSpec {#systemjobspec}

```python
class SystemJobSpec
```

Declarative description of a system job to run.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `job_id` | `str` |  |
| `ocapi_body` | `dict[str, Any]` |  |
| `parameters` | `list[dict[str, str]]` |  |
| `fail_verb` | `str` |  |
| `deprecated_scopes` | `list[str] \| None` | `None` |
| `wait` | `bool` | `True` |
| `wait_options` | `WaitForJobOptions \| None` | `None` |

### SiteArchiveImportOptions {#sitearchiveimportoptions}

```python
class SiteArchiveImportOptions
```

Options for [`site_archive_import`](/python/api/operations/jobs#site-archive-import).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `keep_archive` | `bool` | `False` |
| `wait` | `bool` | `True` |
| `wait_options` | `WaitForJobOptions \| None` | `None` |
| `paths` | `list[str] \| None` | `None` |
| `max_bytes` | `int \| None` | `None` |
| `on_oversize` | `Callable[[dict[str, int]], None] \| None` | `None` |
| `archive_name` | `str \| None` | `None` |

### SiteArchiveImportResult {#sitearchiveimportresult}

```python
class SiteArchiveImportResult
```

Result of a site archive import.

**Fields**

| Name | Type |
| --- | --- |
| `execution` | `JobExecution` |
| `archive_filename` | `str` |
| `archive_kept` | `bool` |

### SiteArchiveImportSplitOptions {#sitearchiveimportsplitoptions}

```python
class SiteArchiveImportSplitOptions
```

Options for [`site_archive_import_split`](/python/api/operations/jobs#site-archive-import-split).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `max_bytes` | `int` | `190 * 1024 * 1024` |
| `keep_archive` | `bool` | `False` |
| `wait_options` | `WaitForJobOptions \| None` | `None` |
| `archive_name` | `str \| None` | `None` |
| `on_plan` | `Callable[[SplitImportPlanInfo], None] \| None` | `None` |
| `on_part` | `Callable[[SplitImportPartInfo], None] \| None` | `None` |

### SplitImportPlanInfo {#splitimportplaninfo}

```python
class SplitImportPlanInfo
```

Summary of the computed split plan.

**Fields**

| Name | Type |
| --- | --- |
| `part_count` | `int` |
| `xml_part_count` | `int` |
| `asset_part_count` | `int` |
| `max_bytes` | `int` |

### SplitImportPartInfo {#splitimportpartinfo}

```python
class SplitImportPartInfo
```

Per-part progress info.

**Fields**

| Name | Type |
| --- | --- |
| `index` | `int` |
| `total` | `int` |
| `kind` | `str` |
| `filename` | `str` |
| `file_count` | `int` |
| `bytes` | `int` |

### SiteArchiveExportOptions {#sitearchiveexportoptions}

```python
class SiteArchiveExportOptions
```

Options for site archive export.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `wait_options` | `WaitForJobOptions \| None` | `None` |
| `keep_archive` | `bool` | `False` |
| `extract_zip` | `bool` | `True` |

### SiteArchiveExportResult {#sitearchiveexportresult}

```python
class SiteArchiveExportResult
```

Result of a site archive export.

**Fields**

| Name | Type |
| --- | --- |
| `execution` | `JobExecution` |
| `archive_filename` | `str` |

### ExportDataUnitsConfiguration {#exportdataunitsconfiguration}

```python
class ExportDataUnitsConfiguration
```

Data units configuration for an export (all fields optional).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `catalog_static_resources` | `dict[str, bool] \| None` | `None` |
| `catalogs` | `dict[str, bool] \| None` | `None` |
| `customer_lists` | `dict[str, bool] \| None` | `None` |
| `inventory_lists` | `dict[str, bool] \| None` | `None` |
| `library_static_resources` | `dict[str, bool] \| None` | `None` |
| `libraries` | `dict[str, bool] \| None` | `None` |
| `price_books` | `dict[str, bool] \| None` | `None` |
| `sites` | `dict[str, Any] \| None` | `None` |
| `global_data` | `dict[str, Any] \| None` | `None` |

### ExportSitesConfiguration {#exportsitesconfiguration}

```python
class ExportSitesConfiguration
```

Configuration for a single site in an export (all fields optional).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `ab_tests` | `bool \| None` | `None` |
| `active_data_feeds` | `bool \| None` | `None` |
| `all` | `bool \| None` | `None` |
| `cache_settings` | `bool \| None` | `None` |
| `campaigns_and_promotions` | `bool \| None` | `None` |
| `commerce_feature_states` | `bool \| None` | `None` |
| `content` | `bool \| None` | `None` |
| `coupons` | `bool \| None` | `None` |
| `custom_objects` | `bool \| None` | `None` |
| `customer_cdn_settings` | `bool \| None` | `None` |
| `customer_groups` | `bool \| None` | `None` |
| `distributed_commerce_extensions` | `bool \| None` | `None` |
| `dynamic_file_resources` | `bool \| None` | `None` |
| `gift_certificates` | `bool \| None` | `None` |
| `ocapi_settings` | `bool \| None` | `None` |
| `payment_methods` | `bool \| None` | `None` |
| `payment_processors` | `bool \| None` | `None` |
| `redirect_urls` | `bool \| None` | `None` |
| `search_settings` | `bool \| None` | `None` |
| `shipping` | `bool \| None` | `None` |
| `site_descriptor` | `bool \| None` | `None` |
| `site_preferences` | `bool \| None` | `None` |
| `sitemap_settings` | `bool \| None` | `None` |
| `slots` | `bool \| None` | `None` |
| `sorting_rules` | `bool \| None` | `None` |
| `source_codes` | `bool \| None` | `None` |
| `static_dynamic_alias_mappings` | `bool \| None` | `None` |
| `stores` | `bool \| None` | `None` |
| `tax` | `bool \| None` | `None` |
| `url_rules` | `bool \| None` | `None` |

### ExportGlobalDataConfiguration {#exportglobaldataconfiguration}

```python
class ExportGlobalDataConfiguration
```

Configuration for global data in an export (all fields optional).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `access_roles` | `bool \| None` | `None` |
| `all` | `bool \| None` | `None` |
| `csc_settings` | `bool \| None` | `None` |
| `csrf_whitelists` | `bool \| None` | `None` |
| `custom_preference_groups` | `bool \| None` | `None` |
| `custom_quota_settings` | `bool \| None` | `None` |
| `custom_types` | `bool \| None` | `None` |
| `geolocations` | `bool \| None` | `None` |
| `global_custom_objects` | `bool \| None` | `None` |
| `job_schedules` | `bool \| None` | `None` |
| `job_schedules_deprecated` | `bool \| None` | `None` |
| `locales` | `bool \| None` | `None` |
| `meta_data` | `bool \| None` | `None` |
| `oauth_providers` | `bool \| None` | `None` |
| `ocapi_settings` | `bool \| None` | `None` |
| `page_meta_tags` | `bool \| None` | `None` |
| `preferences` | `bool \| None` | `None` |
| `price_adjustment_limits` | `bool \| None` | `None` |
| `services` | `bool \| None` | `None` |
| `sorting_rules` | `bool \| None` | `None` |
| `static_resources` | `bool \| None` | `None` |
| `system_type_definitions` | `bool \| None` | `None` |
| `users` | `bool \| None` | `None` |
| `webdav_client_permissions` | `bool \| None` | `None` |

### ImportSetStateError {#importsetstateerror}

```python
class ImportSetStateError(Exception)
```

Thrown when WebDAV lock or receipt state cannot be safely read or written.

### DiscoverImportSetOptions {#discoverimportsetoptions}

```python
class DiscoverImportSetOptions
```

Options for discovering import-set items.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `include_cartridge_metadata` | `bool` | `True` |
| `cartridge_root` | `str \| None` | `None` |
| `exclude_directories` | `list[str] \| None` | `None` |

### ImportSetItem {#importsetitem}

```python
class ImportSetItem
```

A local archive in an import set.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `id` | `str` |  |
| `target` | `str` |  |
| `kind` | `str` |  |
| `note` | `str \| None` | `None` |

### ImportSetReceipt {#importsetreceipt}

```python
class ImportSetReceipt
```

Durable directory receipt created after an import completes successfully.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `set_id` | `str` |  |
| `item_id` | `str` |  |
| `receipt_path` | `str` |  |
| `version` | `int` | `1` |

### ImportSetItemResult {#importsetitemresult}

```python
class ImportSetItemResult(ImportSetItem)
```

Result for one item in an import set.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `status` | `str` | `'pending'` |
| `receipt` | `ImportSetReceipt \| None` | `None` |
| `import_result` | `SiteArchiveImportResult \| None` | `None` |

### ImportSetResult {#importsetresult}

```python
class ImportSetResult
```

Result of planning or applying an import set.

**Fields**

| Name | Type |
| --- | --- |
| `set_id` | `str` |
| `directory` | `str` |
| `dry_run` | `bool` |
| `run_id` | `str` |
| `items` | `list[ImportSetItemResult]` |
| `imported` | `int` |
| `skipped` | `int` |
| `pending` | `int` |

### ImportSetEvent {#importsetevent}

```python
class ImportSetEvent
```

Structured lifecycle event delivered while planning and applying an import set.

The `type` field selects the variant; only the fields relevant to that
variant are populated (mirrors the TS discriminated union).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `type` | `str` |  |
| `set_id` | `str \| None` | `None` |
| `total` | `int \| None` | `None` |
| `pending` | `int \| None` | `None` |
| `skipped` | `int \| None` | `None` |
| `dry_run` | `bool \| None` | `None` |
| `run_id` | `str \| None` | `None` |
| `owner` | `ImportSetLockOwner \| None` | `None` |
| `age_seconds` | `float \| None` | `None` |
| `forced` | `bool \| None` | `None` |
| `item` | `ImportSetItem \| None` | `None` |
| `receipt` | `ImportSetReceipt \| None` | `None` |
| `index` | `int \| None` | `None` |
| `receipt_path` | `str \| None` | `None` |

### ImportSetLockOwner {#importsetlockowner}

```python
class ImportSetLockOwner
```

Owner information stored inside the WebDAV lock directory.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `set_id` | `str` |  |
| `run_id` | `str` |  |
| `created_at` | `str` |  |
| `heartbeat_at` | `str` |  |
| `owner` | `str \| None` | `None` |
| `version` | `int` | `1` |

### SiteArchiveImportSetOptions {#sitearchiveimportsetoptions}

```python
class SiteArchiveImportSetOptions
```

Options for [`site_archive_import_set`](/python/api/operations/jobs#site-archive-import-set).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `set_id` | `str \| None` | `None` |
| `dry_run` | `bool` | `False` |
| `keep_archive` | `bool` | `False` |
| `include_cartridge_metadata` | `bool` | `True` |
| `cartridge_root` | `str \| None` | `None` |
| `exclude_directories` | `list[str] \| None` | `None` |
| `state_root` | `str \| None` | `None` |
| `stale_lock_seconds` | `int \| None` | `None` |
| `lock_poll_interval_seconds` | `int \| None` | `None` |
| `heartbeat_interval_seconds` | `int \| None` | `None` |
| `break_lock` | `bool` | `False` |
| `owner` | `str \| None` | `None` |
| `wait_options` | `Any` | `None` |
| `on_event` | `Callable[[ImportSetEvent], None] \| None` | `None` |
| `import_archive` | `_ImportArchiveFn \| None` | `None` |
| `sleep` | `_SleepFn` | `field(default=asyncio.sleep)` |

### ExportableUnits {#exportableunits}

```python
class ExportableUnits
```

IDs discovered on an instance, grouped by data-unit category.

Each list is sorted alphabetically. A category that could not be read (e.g.
missing OCAPI permission) is returned as an empty list with a matching entry
in `warnings`.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `sites` | `list[str]` | `field(default_factory=list)` |
| `catalogs` | `list[str]` | `field(default_factory=list)` |
| `inventory_lists` | `list[str]` | `field(default_factory=list)` |
| `warnings` | `list[str]` | `field(default_factory=list)` |

## Functions

### execute_job {#execute-job}

```python
async def execute_job(instance: B2CInstance, job_id: str, options: ExecuteJobOptions | None = None) -> JobExecution
```

Execute a job on a B2C Commerce instance (OCAPI).

Starts a job execution and returns immediately with the execution details.
Use [`wait_for_job`](/python/api/operations/jobs#wait-for-job) to wait for completion.

**Raises**

- `RuntimeError` — if the job is already running (when `wait_for_running` is `False`) or the job cannot be executed.
- [`OcapiDeprecatedError`](/python/api/clients#ocapideprecatederror) — when OCAPI is deprecated for the instance.

### get_job_execution {#get-job-execution}

```python
async def get_job_execution(instance: B2CInstance, job_id: str, execution_id: str) -> JobExecution
```

Get the current status of a job execution (OCAPI).

**Raises**

- `RuntimeError` — if the execution is not found.
- [`OcapiDeprecatedError`](/python/api/clients#ocapideprecatederror) — when OCAPI is deprecated for the instance.

### wait_for_job {#wait-for-job}

```python
async def wait_for_job(instance: B2CInstance, job_id: str, execution_id: str, options: WaitForJobOptions | None = None) -> JobExecution
```

Wait for a job execution to complete (OCAPI).

Polls the job status until it reaches a terminal state (finished or aborted).

**Raises**

- [`JobExecutionError`](/python/api/operations/jobs#jobexecutionerror) — if the job fails (status ERROR or aborted).
- `RuntimeError` — if the timeout is exceeded.

### search_job_executions {#search-job-executions}

```python
async def search_job_executions(instance: B2CInstance, options: SearchJobExecutionsOptions | None = None) -> JobExecutionSearchResult
```

Search for job executions (OCAPI).

**Raises**

- `RuntimeError` — if the search request fails.
- [`OcapiDeprecatedError`](/python/api/clients#ocapideprecatederror) — when OCAPI is deprecated for the instance.

### find_running_job_execution {#find-running-job-execution}

```python
async def find_running_job_execution(instance: B2CInstance, job_id: str) -> JobExecution | None
```

Find a currently running job execution, or `None` if none found.

**Raises**

- `RuntimeError` — if the underlying search request fails.

### get_job_log {#get-job-log}

```python
async def get_job_log(instance: B2CInstance, execution: JobExecution) -> str
```

Get the log file content for a job execution over WebDAV.

**Raises**

- `RuntimeError` — if the log file path is missing or the file does not exist.

### get_job_error_message {#get-job-error-message}

```python
def get_job_error_message(execution: JobExecution) -> str | None
```

Extract the error message from a failed job execution.

Looks for the last step execution with `exit_status.code == 'ERROR'` and
returns its message, or `None` when none is found.

### scapi_execute_job {#scapi-execute-job}

```python
async def scapi_execute_job(client: ScapiJobsClient, job_id: str, options: ExecuteJobScapiOptions) -> JobExecutionInfo
```

Execute a job (SCAPI). Requires the rw scope (no ro fallback for writes).

If the job is already running and `wait_for_running` is not `False`,
polls until the prior run reaches a terminal state, then retries.

**Raises**

- [`ScapiJobStartError`](/python/api/operations/jobs#scapijobstarterror) — when the server rejects the start with a response.
- `RuntimeError` — when the job is already running and `wait_for_running` is `False`.

### scapi_get_job_execution {#scapi-get-job-execution}

```python
async def scapi_get_job_execution(client: ScapiJobsClient, job_id: str, execution_id: str, tenant_id: str) -> JobExecutionInfo
```

Get a job execution by ID (SCAPI).

**Raises**

- [`ScapiRequestError`](/python/api/clients#scapirequesterror) — on a failed request.

### scapi_search_job_executions {#scapi-search-job-executions}

```python
async def scapi_search_job_executions(client: ScapiJobsClient, options: SearchJobExecutionsScapiOptions) -> JobExecutionSearchResults
```

Search for job executions (SCAPI).

**Raises**

- [`ScapiRequestError`](/python/api/clients#scapirequesterror) — on a failed request.

### scapi_delete_job_execution {#scapi-delete-job-execution}

```python
async def scapi_delete_job_execution(client: ScapiJobsClient, job_id: str, execution_id: str, tenant_id: str) -> None
```

Delete a job execution (SCAPI).

**Raises**

- [`ScapiRequestError`](/python/api/clients#scapirequesterror) — on a failed request.

### scapi_get_job_log {#scapi-get-job-log}

```python
async def scapi_get_job_log(instance: B2CInstance, execution: JobExecutionInfo) -> str
```

Retrieve a job's log file content over WebDAV.

Both backends (SCAPI and OCAPI) expose `log_file_path` under
`/Sites/LOGS/...`; WebDAV is shared.

**Raises**

- `RuntimeError` — if the log file path is missing or the file does not exist.

### wait_for_job_execution {#wait-for-job-execution}

```python
async def wait_for_job_execution(get_execution: Callable[[str, str], Awaitable[JobExecutionInfo]], job_id: str, execution_id: str, options: WaitForJobOptions | None = None) -> JobExecutionInfo
```

Poll `get_execution(job_id, execution_id)` until a terminal state.

**Returns:** the final [`JobExecutionInfo`](/python/api/operations/jobs#jobexecutioninfo).

**Raises**

- [`CanonicalJobExecutionError`](/python/api/operations/jobs#canonicaljobexecutionerror) — on job failure.
- `RuntimeError` — on timeout.

### map_ocapi_execution {#map-ocapi-execution}

```python
def map_ocapi_execution(ocapi: JobExecution) -> JobExecutionInfo
```

Map a raw OCAPI [`JobExecution`](/python/api/operations/jobs#jobexecution) into the canonical shape.

### map_ocapi_search_result {#map-ocapi-search-result}

```python
def map_ocapi_search_result(result: JobExecutionSearchResult) -> JobExecutionSearchResults
```

Map a raw OCAPI search result into the canonical shape.

### map_canonical_to_ocapi_execution {#map-canonical-to-ocapi-execution}

```python
def map_canonical_to_ocapi_execution(canonical: JobExecutionInfo) -> JobExecution
```

Map a canonical [`JobExecutionInfo`](/python/api/operations/jobs#jobexecutioninfo) back into the raw OCAPI shape.

The reverse of [`map_ocapi_execution`](/python/api/operations/jobs#map-ocapi-execution). Prefers the original OCAPI
payload when present in `raw` (lossless round-trip for the OCAPI path);
otherwise projects the canonical fields.

### site_archive_import {#site-archive-import}

```python
async def site_archive_import(instance: B2CInstance, target: str | bytes | Mapping[str, Any] | RemoteArchiveTarget, options: SiteArchiveImportOptions | None = None, **overrides: Any) -> SiteArchiveImportResult
```

Import a site archive to a B2C Commerce instance.

Supports importing from a local directory (zipped automatically), a local
zip file, a `bytes` buffer containing zip data, or a filename already on
the instance (via a `RemoteArchiveTarget` or a mapping with a
`remote_filename` key).

Options may be passed as a [`SiteArchiveImportOptions`](/python/api/operations/jobs#sitearchiveimportoptions) object or as
keyword overrides (e.g. `wait_options=...`).

**Raises**

- [`JobExecutionError`](/python/api/operations/jobs#jobexecutionerror) — if the import job fails.

### site_archive_import_split {#site-archive-import-split}

```python
async def site_archive_import_split(instance: B2CInstance, directory: str, options: SiteArchiveImportSplitOptions | None = None, **overrides: Any) -> list[SiteArchiveImportResult]
```

Import a large site archive by splitting it into multiple size-bounded parts,
imported sequentially. Order-sensitive XML/metadata is imported first; static
assets are deferred to subsequent parts.

**Raises**

- `ValueError` — if a single file or data unit cannot fit under `max_bytes`.
- [`JobExecutionError`](/python/api/operations/jobs#jobexecutionerror) — if any part's import job fails.

### site_archive_export {#site-archive-export}

```python
async def site_archive_export(instance: B2CInstance, data_units: Mapping[str, Any] | ExportDataUnitsConfiguration, options: SiteArchiveExportOptions | None = None, **overrides: Any) -> SiteArchiveExportResult
```

Export a site archive from a B2C Commerce instance.

**Raises**

- [`JobExecutionError`](/python/api/operations/jobs#jobexecutionerror) — if the export job fails.

### site_archive_export_to_buffer {#site-archive-export-to-buffer}

```python
async def site_archive_export_to_buffer(instance: B2CInstance, data_units: Mapping[str, Any] | ExportDataUnitsConfiguration, options: SiteArchiveExportOptions | None = None, **overrides: Any) -> SiteArchiveExportToBufferResult
```

Export a site archive and download it into memory (`.data` bytes).

### site_archive_export_to_path {#site-archive-export-to-path}

```python
async def site_archive_export_to_path(instance: B2CInstance, data_units: Mapping[str, Any] | ExportDataUnitsConfiguration, output_path: str, options: SiteArchiveExportOptions | None = None, **overrides: Any) -> SiteArchiveExportToPathResult
```

Export a site archive, download it, and save it to a local path.

When `output_path` ends in `.zip` (or `extract_zip` is `False`) the
archive is written as a zip file; otherwise it is extracted into the
directory at `output_path`.

### discover_import_set {#discover-import-set}

```python
async def discover_import_set(directory: str, options: DiscoverImportSetOptions | None = None) -> list[ImportSetItem]
```

Discover import items from cartridge `metadata/` directories followed by the
explicit import-set directory.

A cartridge metadata directory that resembles a site archive is one item;
otherwise its immediate child directories and zip archives are items.

**Raises**

- `ValueError` — when no items are found or an item ID collides.

### site_archive_import_set {#site-archive-import-set}

```python
async def site_archive_import_set(instance: B2CInstance, directory: str, options: SiteArchiveImportSetOptions | None = None) -> ImportSetResult
```

Apply an ordered set of site archives exactly until a verified receipt
directory exists for each item.

A missing or invalid receipt always leaves the item pending. The operation
never logs or writes output; callers consume structured progress through
`SiteArchiveImportSetOptions.on_event`.

### discover_exportable_units {#discover-exportable-units}

```python
async def discover_exportable_units(instance: B2CInstance) -> ExportableUnits
```

Discover the data units that can be exported from an instance.

Each category is read independently: a failure in one records a warning and
leaves that list empty rather than failing the whole discovery.

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `instance` | `B2CInstance` | B2C instance to query. |

**Returns:** Discovered IDs grouped by category, with per-category warnings.

## Attributes

### JobExecution {#jobexecution}

```python
JobExecution = dict[str, Any]
```

### JobStepExecution {#jobstepexecution}

```python
JobStepExecution = dict[str, Any]
```

### JobExecutionStatus {#jobexecutionstatus}

```python
JobExecutionStatus = str
```

### JobExecutionParameter {#jobexecutionparameter}

```python
JobExecutionParameter = dict[str, Any]
```
