API Reference: qbraid.runtime.native

Everything on this page works the same on every device you reach through QbraidProvider, whichever vendor or submission path it uses. The examples use the free QIR simulator, qbraid:qbraid:sim:qir-sv:

from qbraid.runtime import QbraidProvider

provider = QbraidProvider()
device = provider.get_device("qbraid:qbraid:sim:qir-sv")

bell = """
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
h q[0];
cx q[0], q[1];
c = measure q;
"""

Before you submit

Check the device

device.status()
# <DeviceStatus.ONLINE: 'ONLINE'>

device.queue_depth()
# 0

device.run() warns when a device isn’t ONLINE: the job may be refused, or wait a long time. provider.get_devices() lists the devices you can submit to now. Pass include_retired=True to also list devices that have been retired.

Estimate the cost

provider.client.estimate_cost prices a job before you submit it, in qBraid credits:

estimate = provider.client.estimate_cost("aws:iqm:qpu:garnet", shots=100)

estimate.pricingAvailable
# True
estimate.estimatedCost
# Credits('44.5')

Some devices are priced dynamically by their vendor, so no estimate is possible in advance. For those, pricingAvailable is False and reason says why, such as 'dynamic_pricing_unavailable'. Devices with openquantum: IDs estimate 0, because they spend credits from your linked Open Quantum account rather than qBraid credits.

The device catalog shows the same prices.

Check your balance

balance = provider.client.get_credits_balance()
balance["qbraidCredits"]

The balance belongs to the organization your API key is tied to.

Submitting

job = device.run(
    bell,
    shots=100,
    name="bell-test",
    tags={"experiment": "docs-managing-jobs"},
)
job.id
# 'qbraid:qbraid:sim:qir-sv-8ce1-qjob-6ad8144c34188ba734e7a279'
ArgumentEffect
shotsNumber of shots.
nameA name for the job, shown in Quantum Jobs.
tagsKey-value labels, with string, integer or boolean values. Find jobs by tag later.
runtime_optionsOptions passed to the device. See Runtime options.

Keep job.id: it is all you need to get the job back later.

To run several circuits at once, see Batch & group jobs.

While it runs

job.status()
# <QUEUED: 'job is queued'>

job.queue_position()
# 3

queue_position() returns None once the job has left the queue, or when the device doesn’t report positions.

A job moves through INITIALIZING, QUEUED, RUNNING, and then one of COMPLETED, FAILED or CANCELLED. job.is_terminal_state() tells you whether it has finished.

Wait for it

job.result() blocks until the job finishes. Pass timeout, in seconds, to give up waiting. The job keeps running.

result = job.result(timeout=600)

job.wait_for_final_state(timeout=600, poll_interval=5) waits without fetching the result. In async code, await job.async_result() waits without blocking the event loop.

Cancel it

job.cancel()

cancel() raises JobStateError if the job has already finished. A job that has started running on a QPU may finish before the cancellation reaches it.

Results

result.success
# True

result.data.get_counts()
# {'00': 46, '11': 54}

result.data also has get_probabilities(), and measurements for the individual shots where the device returns them.

Cost and timing

result.details records what the job actually cost and how long it took:

result.details["cost"]
# Credits('0')

result.details["time_stamps"]
# TimeStamps(createdAt=datetime.datetime(2026, 10, 21, 1, 24, 30, tzinfo=datetime.timezone.utc),
#            endedAt=datetime.datetime(2026, 10, 21, 1, 24, 30, tzinfo=datetime.timezone.utc),
#            executionDuration=12)

executionDuration is in milliseconds.

When a job fails

A job that doesn’t complete still returns a result, with success set to False and no data. When the platform gives a reason, it is in details["status_message"]:

result = job.result()

if not result.success:
    print(result.details["status"])
    print(result.details.get("status_message"))

After it runs

What you submitted

job.program() returns the program as qBraid received it, after any conversion from your framework:

job.program()
# Program(format='qasm3', data='OPENQASM 3.0;\ninclude "stdgates.inc";\nqubit[2] q; ...')

What ran on the device

job.compiled_program() returns the program the device’s compiler produced. On a QPU this shows which physical qubits your circuit ran on and the native gates it was compiled to, which the counts alone can’t tell you:

compiled = job.compiled_program()
compiled.format
# 'qir.ll'
DevicesFormat
IQM through Amazon Braketqasm3
Rigetti, direct or through Amazon Braketquil
QIR simulatorqir.ll

It returns None when there is no compiled program: the job hasn’t finished, the device doesn’t report one, or the job predates this feature. A batch job returns a list, one program per circuit.

Reconnect to a job

A job ID is enough to get a job back, for example after restarting a notebook kernel, or on another machine:

from qbraid.runtime import load_job

job = load_job("qbraid:qbraid:sim:qir-sv-8ce1-qjob-6ad8144c34188ba734e7a279", provider="qbraid")
job.status()
# <COMPLETED: 'job has successfully run'>

The returned job supports everything on this page.

Find past jobs

provider.client.list_jobs searches your jobs. Filter by tag, status or text:

jobs = provider.client.list_jobs(tags={"experiment": "docs-managing-jobs"})
[(j.jobQrn, j.name, j.status) for j in jobs]
# [('qbraid:qbraid:sim:qir-sv-8ce1-qjob-6ad8144c34188ba734e7a279', 'bell-test', <COMPLETED: ...>)]
FilterExample
tags{"experiment": "bell-state"}
status"COMPLETED", "FAILED"
status_group"pending" (not finished yet), "returned" (finished), "all"
searchText matched against your jobs
page, limitPagination

Pass a result’s jobQrn to load_job to work with that job. Quantum Jobs shows the same jobs in your account.