QuantinuumProvider
Runtime integration for access to Quantinuum trapped-ion quantum processors via Quantinuum Nexus.
API Reference: qbraid.runtime.quantinuum
Overview
The qbraid.runtime.QuantinuumProvider provides support for Quantinuum’s trapped-ion quantum systems
through the Quantinuum Nexus platform. This means you can write quantum circuits using
pytket, compile and execute them on Quantinuum’s H-series processors and emulators,
all from within the qBraid Runtime framework.
This page covers QuantinuumProvider, which runs against your own Nexus account. If you would rather
have the Nexus account managed by qBraid, see Through qBraid at the end. You need only a
qBraid API key.
Device names
Quantinuum names hardware <family>-<n> and derives its other targets from it by suffix. The suffix is
the only thing distinguishing an emulator from the QPU it models, so it is worth reading carefully before
submitting:
| Name | Kind |
|---|---|
H1-1, H2-1, Helios-1 | QPU |
H1-1E, H2-1E | Device-hosted emulator (noise model of the QPU) |
H1-1LE, H2-1LE | Nexus-hosted emulator |
H1-Emulator, H2-Emulator | Nexus-hosted emulator |
H1-1SC, H2-1SC | Syntax checker (validates without executing) |
device.profile.simulator reflects this classification. device.status() reports ONLINE,
UNAVAILABLE (maintenance), or OFFLINE; Nexus-hosted emulators have no machine-status endpoint and
always report ONLINE.
Getting started
Before you begin, make sure you have:
- A Quantinuum Nexus account with valid credentials.
- The qnexus CLI tool installed and authenticated (see Authentication below).
- Python >= 3.10
Set up the qBraid-SDK
Install qBraid with the quantinuum extra from PyPI using pip:
pip install 'qbraid[quantinuum]'This installs the required dependencies: pytket, pytket-quantinuum, and qnexus.
Note: The qBraid-SDK requires Python 3.10 or greater. You can check your
Python version by running python --version from the command line.
Authentication
The QuantinuumProvider authenticates through the qnexus library. Before using the provider, you must
log in using the qnexus CLI:
qnx loginThis opens a browser-based authentication flow and stores your credentials locally. Once authenticated, the provider will automatically use your stored credentials. No API keys or environment variables are needed.
Then initialize the provider:
from qbraid.runtime.quantinuum import QuantinuumProvider
provider = QuantinuumProvider()List available devices
Use the QuantinuumProvider to list all devices to which you have access:
from qbraid.runtime.quantinuum import QuantinuumProvider
provider = QuantinuumProvider()
devices = provider.get_devices()
print(devices)Get a specific device by its ID:
device = provider.get_device("H1-1")
print(device.status())
# <DeviceStatus.ONLINE>Devices with an “E” suffix (e.g., H1-1E) are emulators (simulators) that
model the behavior of the corresponding hardware device.
Submitting jobs
The QuantinuumProvider accepts quantum programs written as pytket Circuit objects.
Create a circuit
from pytket.circuit import Circuit
# Bell state circuit
circuit = Circuit(2)
circuit.H(0)
circuit.CX(0, 1)
circuit.measure_all()Run a job
Use device.run() to compile and submit a circuit:
from pytket.circuit import Circuit
from qbraid.runtime.quantinuum import QuantinuumProvider
provider = QuantinuumProvider()
device = provider.get_device("H1-1E")
circuit = Circuit(2)
circuit.H(0)
circuit.CX(0, 1)
circuit.measure_all()
job = device.run(circuit, shots=1000)
print(f"Job ID: {job.id}")Batch submission
Submit multiple circuits in a single call. All circuits are bundled into one Nexus job:
from pytket.circuit import Circuit
from qbraid.runtime.quantinuum import QuantinuumProvider
provider = QuantinuumProvider()
device = provider.get_device("H1-1E")
circuits = [
Circuit(1).H(0).measure_all(),
Circuit(1).X(0).measure_all(),
Circuit(2).H(0).CX(0, 1).measure_all(),
]
job = device.run(circuits, shots=500)
print(f"Job ID: {job.id}")When submitting a list of circuits, all circuits are compiled and executed as
a single batch job on Quantinuum Nexus. The returned measurement_counts will
be a list of dictionaries, one per circuit.
Retrieving results
result = job.result()
# Measurement counts
print(result.data.measurement_counts)
# {'00': 512, '11': 488}
# Job metadata
print(f"Device: {result.device_id}")
print(f"Job ID: {result.job_id}")
print(f"Success: {result.success}")Counts are keyed most-significant-bit first, matching qBraid’s other providers. Nexus and pytket use least-significant-bit-first ordering internally, and qBraid converts on the way out, so a bitstring read here is reversed relative to the same result fetched through pytket directly.
Your circuit must contain measurements. Quantinuum executes exactly the circuit you submit, so a circuit with no measurement instruction produces no counts. Some frameworks imply a final measure-all that does not survive conversion, so add measurements explicitly rather than relying on it.
Check job status
from qbraid.runtime.enums import JobStatus
status = job.status()
print(status)
# <JobStatus.COMPLETED>Cancel a job
job.cancel()Cancellation is best-effort. Jobs already in a terminal state (COMPLETED,
FAILED, CANCELLED) cannot be cancelled.
Execution time
You can retrieve the wall-clock execution time (in seconds) for a completed job:
print(f"Execution time: {job.execution_time_s()} seconds")Configuration options
The device.run() method accepts additional keyword arguments to control compilation and project scoping:
| Parameter | Type | Default | Description |
|---|---|---|---|
shots | int | 1000 | Number of measurement shots per circuit. |
project_name | str | "qbraid" | Nexus project name to scope compile/execute jobs. |
optimisation_level | int | 1 | pytket optimization level (0-2). |
The project_name and optimisation_level parameters can also be set via environment variables:
| Variable | Default | Description |
|---|---|---|
QUANTINUUM_NEXUS_PROJECT_NAME | "qbraid" | Default Nexus project name. |
QUANTINUUM_NEXUS_OPT_LEVEL | 1 | Default pytket optimization level. |
QUANTINUUM_NEXUS_COMPILE_TIMEOUT | 900 | Seconds run waits for compilation before raising. |
QUANTINUUM_NEXUS_HTTP_TIMEOUT | 60 | Per-request timeout on every Nexus HTTP call. |
Nexus runs a submission as two jobs: a compile job, which run blocks on, and an execute job, which the
returned QuantinuumJob tracks. QUANTINUUM_NEXUS_COMPILE_TIMEOUT bounds that blocking wait, so a compile
stuck in the Nexus queue raises QuantinuumDeviceError rather than holding the calling thread
indefinitely. Raise it if you routinely submit large circuits.
A malformed value for any of these raises QuantinuumDeviceError naming the variable, rather than
surfacing later as an unrelated failure.
Full example
A complete end-to-end workflow targeting a Quantinuum emulator:
from pytket.circuit import Circuit
from qbraid.runtime.quantinuum import QuantinuumProvider
# 1. Initialize provider (assumes qnx login was run)
provider = QuantinuumProvider()
# 2. Get an emulator device
device = provider.get_device("H1-1E")
print(f"Device status: {device.status()}")
# 3. Define a GHZ state circuit
circuit = Circuit(3)
circuit.H(0)
circuit.CX(0, 1)
circuit.CX(1, 2)
circuit.measure_all()
# 4. Submit the job
job = device.run(circuit, shots=1000, optimisation_level=2)
print(f"Submitted job: {job.id}")
# 5. Retrieve results
result = job.result()
print(f"Counts: {result.data.measurement_counts}")
# Expected output (approximate): {'000': ~500, '111': ~500}Through qBraid
If you do not have a Nexus account, you can reach the same devices through QbraidProvider, where
the Nexus credentials are managed by qBraid. You need a qBraid API key and nothing
else: no qnexus install, no qnx login:
pip install qbraid
export QBRAID_API_KEY="your_api_key_here"Devices are addressed by their qBraid resource name rather than the Nexus device name:
from qiskit import QuantumCircuit
from qbraid.runtime import QbraidProvider
provider = QbraidProvider()
device = provider.get_device("quantinuum:quantinuum:sim:h2-emulator")
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
job = device.run(circuit, shots=1000)
print(job.result().data.get_counts()){'00': 496, '11': 504}To see which are available to you:
devices = [d for d in provider.get_devices() if d.profile.provider_name == "quantinuum"]The bit-ordering and measurement notes above apply equally here. Two differences from the direct path:
circuits are submitted one per job rather than as a Nexus batch, and the QUANTINUUM_NEXUS_* variables
are set on the qBraid runtime rather than by you.
Related links
Thanks for your feedback.

