> 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.

# Publishing Images and Marketplace Demos

```python
# Imports (run once)
from air_sdk import AirApi
from air_sdk.endpoints import (
    ImagePublishAccessRecord,
    MarketplaceDemoPublishAccessRecord,
)
```

```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
```

## The Publish Access Record Lifecycle

A publish access record moves through a set of statuses (the `PAR_STATUS` type alias
in `air_sdk.types`). The `PENDING_*` states are awaiting reviewer action:

| Status                           | Meaning                                                      |
| -------------------------------- | ------------------------------------------------------------ |
| `PENDING`                        | First-time publish request, awaiting review.                 |
| `PENDING_ELEVATION`              | Restricted → public request, awaiting review.                |
| `PENDING_RESTRICTION`            | Public → restricted request, awaiting review.                |
| `PENDING_ALLOWLIST`              | Allow-list change on a restricted resource, awaiting review. |
| `PENDING_UNPUBLISH`              | Unpublish request, awaiting review.                          |
| `APPROVED_PENDING_IMAGE_PUBLISH` | Approved, waiting on referenced images to finish publishing. |
| `APPROVED`                       | Approved and live.                                           |
| `DENIED`                         | Rejected by a reviewer.                                      |
| `REMOVED`                        | Unpublished.                                                 |
| `CANCELLED`                      | Withdrawn by the requester before review.                    |

## Requester Flow

The requester actions are the same five on both `Image` and `MarketplaceDemo`:
`request_publish`, `request_public`, `request_allowlist_change`, `request_unpublish`,
and `cancel_publish_access_record`. Each returns the updated resource, whose
`publish_access_record_id` points at the PAR the request created.

### 1. Request to Publish

Submit a resource for review. `justification` is required. Set `prefer_public=False`
to ask for restricted (allow-list) access, and describe the desired orgs in
`allowed_orgs_request_text`.

```python
# --- Image ---
image_id = '...'  # replace with an image you own
image = api.images.request_publish(
    image=image_id,
    justification='Ready to share with the community.',
    prefer_public=True,
)
print(image.publicly_published, image.publish_access_record_id)
```

```python
# --- Marketplace demo ---
# Demos additionally accept `tags` (assign tag names as part of the request) and
# `publish_images` (auto-publish referenced images that aren't yet visible).
demo_id = '...'  # replace with a demo you own
demo = api.marketplace_demos.request_publish(
    marketplace_demo=demo_id,
    justification='Ready to share with the community.',
    prefer_public=True,
    publish_images=True,
    tags=['networking', 'sonic'],
)
print(demo.publicly_published, demo.publish_access_record_id)
```

### 2. Request a Visibility Change

For an already-published resource, request a switch between public and restricted
(`request_public`), or update the allow-list on a restricted resource
(`request_allowlist_change`).

```python
# Elevate to public (prefer_public=True) or restrict (prefer_public=False).
api.images.request_public(
    image=image_id, prefer_public=True, justification='Broad interest.'
)
api.marketplace_demos.request_public(
    marketplace_demo=demo_id, prefer_public=True, justification='Broad interest.'
)
```

```python
# Change who may access a restricted resource.
api.images.request_allowlist_change(
    image=image_id,
    justification='Add partner org.',
    allowed_orgs_request_text='Acme Corp and Globex.',
)
api.marketplace_demos.request_allowlist_change(
    marketplace_demo=demo_id,
    justification='Add partner org.',
    allowed_orgs_request_text='Acme Corp and Globex.',
)
```

### 3. Request to Unpublish, or Cancel a Pending Request

`request_unpublish` queues removal for review; `cancel_publish_access_record`
withdraws whatever request is currently pending so you can resubmit.

```python
api.images.request_unpublish(image=image_id, justification='No longer maintained.')
api.marketplace_demos.request_unpublish(
    marketplace_demo=demo_id, justification='No longer maintained.'
)

# Withdraw a pending request
api.images.cancel_publish_access_record(image=image_id)
api.marketplace_demos.cancel_publish_access_record(marketplace_demo=demo_id)
```

## Reviewer Flow

Reviewers (community managers) act on the publish access records themselves. The PAR
endpoints — `api.image_publish_access_records` and
`api.marketplace_demo_publish_access_records` — expose the same interface: `list`,
`get`, `approve`, `deny`, and `set_visibility`.

### 1. Find Records Awaiting Review

List by `status` to triage the queue. Both endpoints accept the same filters
(`status`, `publicly_published`, `requested_by_email`, `requesting_org_display_name`,
`requesting_org_ngc_org_name`, plus the resource id).

```python
pending_image_pars: list[ImagePublishAccessRecord] = list(
    api.image_publish_access_records.list(status='PENDING')
)
pending_demo_pars: list[MarketplaceDemoPublishAccessRecord] = list(
    api.marketplace_demo_publish_access_records.list(status='PENDING')
)
[par.dict() for par in pending_image_pars]
```

### 2. Approve

Approve as public (`publicly_published=True`) or restricted (`publicly_published=False`
with `allowed_orgs`). When omitted, `publicly_published` defaults to the record's
`prefer_public`.

```python
image_par_id = '...'  # a pending image PAR id
demo_par_id = '...'  # a pending demo PAR id

api.image_publish_access_records.approve(record=image_par_id, publicly_published=True)
api.marketplace_demo_publish_access_records.approve(
    record=demo_par_id,
    publicly_published=False,
    allowed_orgs=['<org-uuid>'],
)
```

### 3. Deny

Reject a pending request, optionally with a `denial_reason` that is surfaced back to
the requester.

```python
api.image_publish_access_records.deny(
    record=image_par_id, denial_reason='Needs more docs.'
)
api.marketplace_demo_publish_access_records.deny(
    record=demo_par_id, denial_reason='Needs more docs.'
)
```

### 4. Set Visibility Directly

On an already-approved record, a reviewer can change visibility immediately without a
new request. When restricting, `allowed_orgs` is the **full replacement** allow-list.

```python
api.image_publish_access_records.set_visibility(
    record=image_par_id, publicly_published=True
)
api.marketplace_demo_publish_access_records.set_visibility(
    record=demo_par_id,
    publicly_published=False,
    allowed_orgs=['<org-uuid>'],
)
```

## Privileged Immediate Publish / Unpublish

Privileged callers can publish or unpublish directly, auto-approving the underlying
record and skipping the request/review cycle. Use `allowed_orgs` (org UUIDs) here —
the authoritative allow-list, distinct from the free-text `allowed_orgs_request_text`
hint used by the gated `request_*` actions.

```python
# Images return the updated Image; demos return None.
api.images.publish(image=image_id, prefer_public=True, justification='Curated release.')
api.marketplace_demos.publish(
    marketplace_demo=demo_id,
    prefer_public=False,
    allowed_orgs=['<org-uuid>'],
    justification='Curated release.',
    publish_images=True,
)

api.images.unpublish(image=image_id)
api.marketplace_demos.unpublish(marketplace_demo=demo_id)
```

## Resource-Specific Differences

The flows are otherwise identical; a few extras exist only on demos:

* **`tags`** — `marketplace_demos.request_publish` accepts a `tags` list to assign tag
  names as part of the request (omit to leave tags unchanged, `[]` to clear).
* **`publish_images`** — demo publish/visibility requests can cascade to the images the
  demo references, publishing org-owned images so they reach the demo's audience. When
  `False` (default), a request that needs image publishing is rejected with **400**.
* **Return types** — image publish/unpublish return the updated `Image`; the demo
  equivalents return `None`.
* **409 conflicts** — while a demo's images are still cascading, `publish`, `unpublish`,
  and `provision` may return **409**; retry once the cascade settles.