Skip to main content

Overview

This page gives you a working Python integration. Each function maps to one ION operation you can lift into your own codebase. By the end you have:
  • A reusable IonClient that handles auth, query and mutation calls, and error parsing.
  • Working examples for four common starting tasks: list parts, create a run, submit a run step result, and upload a file attachment.
  • Patterns for fragments, error handling, and retry with backoff.
The script needs two environment variables:
If you don’t have a token yet, see Getting a token.

Set up the environment

You don’t need a GraphQL-specific client. httpx handles the transport. tenacity gives you declarative retry. If you prefer the gql library, these patterns translate directly.

Build the client

You only call IonClient.query and IonClient.mutate. _post_graphql handles transport-level retries for 5xx and network errors. It surfaces GraphQL-level errors as IonError.

Confirm the token works

Check who you are authenticated as before you do anything else:
If this fails, see the 401 table in Error codes. The error message names the fix.

List parts

Create a run

Replace procedureId and partInventoryId with real IDs from your org. To find candidate procedures, see Example requests.

Submit a run step result

The etag field is required on update. For details, see Etag-based concurrency. If you get a 409, re-fetch the run step, take its new etag, and retry.

Upload a file attachment

This is the full three-step pattern from File upload:
Two parts of this pattern are easy to miss. You must capture the S3 ETag. You must fetch entity.id, not the parent’s id. Both are documented in File upload.

Error handling pattern

The IonClient raises IonError on GraphQL-level errors. It uses tenacity for transport retries. Wrap your business logic in a try and except block that handles each error type:
For the full HTTP status reference and the GraphQL errors[] payload shape, see Error codes.

Reuse fragments

When several queries return the same entity, such as parts, runs, or purchase orders, define one fragment per entity and inline it everywhere:
This keeps field selection consistent across calls. A forgotten field, such as _etag, becomes a one-line fix instead of a multi-file refactor.