Python Client 203: Sharing a Resource with a Partner
In Share with a partner you used the Share dialog to send a model to a partner organization over a Secure Connection. Here you do the same from a short Python script: find the connections you are allowed to share to, share a resource at the right access level, check what it is shared to, and revoke the share when you are done.
This is the pattern to use when sharing is part of an automated pipeline — for example, publishing every approved revision of a model to a supplier without opening the web app.
By the end you will know how to:
- List the Secure Connections a resource may be shared to
- Share a resource with a partner at View or Edit access
- Check which partners a resource is currently shared to
- Revoke a share
Time: ~10 minutes.
Prerequisites
-
An Istari Digital Platform account with a Key. Details: Developer Settings — Keys.
-
A Sending Connection to a partner organization, configured by your organization administrator. If none exists yet, point your admin at Configure partner sharing.
-
Editor access or above on a model or artifact you are allowed to share externally.
-
istari-digital-clientinstalled in a virtual environment — see Install the client — plus python-dotenv to read the credentials file:uv pip install python-dotenv
What you need to know first
- Secure Connections sync models and artifacts. Systems cannot be shared as a whole.
- Sharing calls take the resource's
file_id, the storage-level identifier onResourceDto. Listing shares takes theresource_id. Both are on every resource the client returns. - Each connection has a received access level ceiling set by the administrator. You can request Edit access for the partner only on a connection whose ceiling is Editor.
- A connection may also restrict Permitted Senders. If it does, you must be on the list, and the per-user level your administrator gave you (View or Edit) caps your
share_levelas well. The SDK has no non-admin call to read that level, so an Edit share above it fails with403. Ask your administrator if that happens. - List calls return one page at a time. Each page carries the cursor for the next page in
next_page; pass it back ascursoruntil it isNone. - Sync is asynchronous. Your call returns as soon as the share is recorded; the partner receives the file on the next sync cycle (typically 1–2 minutes).
- The connection's Permitted Infosec Level, Tag Rules, and Permitted Senders are enforced on the server. A share that violates them is rejected, and a later change that makes a shared resource ineligible revokes it automatically.
Run the script
Create istari.env in the folder you will run the script from:
ISTARI_DIGITAL_API_URL=<API URL from Endpoints on Developer Settings>
ISTARI_CLIENT_IDENTITY_SERVICE_SECRET_FILE=/absolute/path/to/the-key-file-you-downloaded.json
ISTARI_DIGITAL_IDENTITY_SERVICE_ENABLED=true
These are the three names Configuration reads on its own, which is why the script constructs it with no arguments:
ISTARI_CLIENT_IDENTITY_SERVICE_SECRET_FILEtakes theISTARI_CLIENT_prefix. It is the only name read for the key, and there is no unprefixed fallback.- With the key path and
ISTARI_DIGITAL_API_URLset, Key authentication turns on even whenISTARI_DIGITAL_IDENTITY_SERVICE_ENABLEDis absent. The sample sets it totrueso the choice is explicit. Anistari.envfrom Python Client 201 or 202 already has that line. Set the variable tofalseonly when that file should keep a personal access token.
Because the credential type is decided entirely by istari.env, the script needs no changes to run against a Personal Access Token instead. Replace the three lines above with:
ISTARI_REGISTRY_URL=<registry URL from Endpoints on Developer Settings>
ISTARI_REGISTRY_AUTH_TOKEN=<your personal access token>
Keys are the current credential; Personal Access Tokens are deprecated (July 2026). Keep istari.env and the key file on disk — do not put a key or token on the command line, in a prompt, or in a chat log.
Save the full script as share_with_partner.py next to istari.env, then set two values at the top:
RESOURCE_ID— theresource_idof the model or artifact to share. You can copy it from the resource's URL in the web app.CONNECTION_LABEL— the label of the Sending Connection, as your administrator named it.
python share_with_partner.py
What you should see
Shareable connections:
a1b2c3d4-... partner-registry ceiling=Editor
e5f6a7b8-... supplier-b ceiling=Viewer
Sharing wing-stress.stl to partner-registry ...
share id : 9c8d7e6f-...
share level : Viewer
Currently shared to:
partner-registry (Viewer)
Revoking ...
is_archived : True
In the web app, open the resource's details pane. The Connections row shows the partner while the share is active, and returns to None after the revoke.
Understand the script
Connect
V3Client shares the same Configuration as Client. load_dotenv("istari.env") copies the file's KEY=VALUE lines into the environment, and Configuration() reads them from there — so there is no credential handling in the script and nothing secret in the code. load_dotenv does not overwrite variables already set in the shell, so exported credentials still win in CI.
Pass arguments to Configuration only for values you want to override in code. See SDK setup for every variable it recognizes.
Find a connection you can share to
list_shareable_sending_connections() is available to any authenticated user, not just administrators. It returns each active connection's id, label, description, and received_access_level. The script walks every page with next_page and matches on label to find the partner your administrator set up.
Share
share_file_to_sending_remote() records the share. The optional ShareFileToSendingRemoteDto sets share_level:
- Omit it, or pass
ReceivedAccessLevel.VIEWER, for a read-only copy on the partner side. - Pass
ReceivedAccessLevel.EDITORto let the partner run jobs on their copy and add their own revisions. Their edits stay on their copy and are not sent back to you. This needs both the connection's ceiling and, if the connection restricts senders, your own permitted-sender level to be Editor.
Calling the method again for the same connection and file is safe. It restores a revoked share, or updates the share_level of an active one.
Check what a resource is shared to
list_sending_remote_shares_for_resource() lists the active shares for a resource. Pass show_archived=True to include revoked shares as well. Each item is a RemoteFileShareDto with the connection id and label, the share_level, and is_archived.
Revoke
revoke_file_from_sending_remote() stops future synchronization and sends a revocation signal across the connection. The partner's platform tombstones its copy on a later sync cycle. Revocation is best-effort: it cannot remove data the partner already downloaded or exported. See Revocation and Tombstoned Files.
The script revokes at the end so you can run it repeatedly against the same resource. In a real pipeline you would leave the share in place and let new revisions sync automatically.
What you learned
- The Share dialog and the SDK use the same sharing model: a share ties one resource's file to one Sending Connection at one access level.
list_shareable_sending_connections()is the non-admin way to discover connections.share_file_to_sending_remote()andrevoke_file_from_sending_remote()take the resource'sfile_id;list_sending_remote_shares_for_resource()takes theresource_id.- Sharing is recorded immediately and synced asynchronously.
Full script
"""Share a resource with a partner organization over a Secure Connection.
Credentials come from istari.env. Set RESOURCE_ID and CONNECTION_LABEL before running.
"""
import sys
from dotenv import load_dotenv
from istari_digital_client import Configuration, V3Client
from istari_digital_client.v3.models.received_access_level import ReceivedAccessLevel
from istari_digital_client.v3.models.share_file_to_sending_remote_dto import (
ShareFileToSendingRemoteDto,
)
RESOURCE_ID = "<resource_id>" # model or artifact to share
CONNECTION_LABEL = "partner-registry" # Sending Connection label from your admin
WANT_EDIT_ACCESS = False # True to let the partner run jobs and add revisions
# 1. Connect. load_dotenv puts istari.env into the environment; Configuration() reads the
# API URL, key file, and identity-service switch from there, so no credential is in code.
load_dotenv("istari.env")
v3 = V3Client(Configuration())
# 2. List the connections this user may share to (works for non-admins).
# Walk every page: `next_page` is the cursor for the next one, None on the last.
print("Shareable connections:")
connections = []
cursor = None
while True:
page = v3.list_shareable_sending_connections(size=100, cursor=cursor)
connections.extend(page.items)
cursor = page.next_page
if not cursor:
break
for candidate in connections:
print(f" {candidate.id} {candidate.label} ceiling={candidate.received_access_level}")
connection = next((c for c in connections if c.label == CONNECTION_LABEL), None)
if connection is None:
sys.exit(f"No active Sending Connection labelled {CONNECTION_LABEL!r}")
# 3. Decide the access level, respecting the connection's ceiling.
share_level = ReceivedAccessLevel.VIEWER
if WANT_EDIT_ACCESS:
if connection.received_access_level != ReceivedAccessLevel.EDITOR:
sys.exit(f"{connection.label} only permits view access")
share_level = ReceivedAccessLevel.EDITOR
# 4. Share — takes the resource's file_id, not its resource_id
resource = v3.get_resource(RESOURCE_ID)
print(f"\nSharing {resource.name} to {connection.label} ...")
share = v3.share_file_to_sending_remote(
remote_id=connection.id,
file_id=resource.file_id,
share_file_to_sending_remote_dto=ShareFileToSendingRemoteDto(share_level=share_level),
)
print(f" share id : {share.id}")
print(f" share level : {share.share_level}")
# 5. Confirm what the resource is shared to — takes the resource_id
print("\nCurrently shared to:")
shares = v3.list_sending_remote_shares_for_resource(resource_id=resource.resource_id)
for existing in shares.items:
print(f" {existing.sending_connection_label} ({existing.share_level})")
# 6. Revoke so the script can be re-run. Drop this step in a real pipeline.
print("\nRevoking ...")
revoked = v3.revoke_file_from_sending_remote(remote_id=connection.id, file_id=resource.file_id)
print(f" is_archived : {revoked.is_archived}")
What's next
- V3Client reference — Secure Connection Sharing for full signatures and return types.
- Share with a partner for what the partner sees, automatic unsharing, and revocation semantics.
- Configure partner sharing if you are the administrator setting up the connection.