API reference
QubitraClient
Client for the Qubitra quantum platform.
The API key resolves from api_key, then QUBITRA_API_KEY; the platform
it reaches from api_url, then QUBITRA_API_URL, then the hosted
deployment. A custom adapter substitutes the whole transport layer.
QubitraClient(*, api_key: str | None = None, api_url: str | None = None, adapter: ProviderAdapter | None = None) -> NoneThe client is a context manager: with QubitraClient() as client: closes the connection pool on exit, and close() does the same by hand.
client.close() -> NoneRelease the underlying HTTP connection pool.
client.backends
The catalogue of execution targets available to the caller's organization.
client.backends.list() -> list[Backend]client.backends.get(backend_id: str) -> Backendclient.jobs
Jobs: submission, status, results and cancellation.
A job carries an ordered list of PUBs, and its result comes back index-aligned
with them. submit is the one-circuit form and builds a job of a single PUB;
run takes the list.
client.jobs.submit(*, backend_id: str, circuit: str, circuit_format: CircuitFormat = CircuitFormat.OPENQASM_3, shots: int = 1024, name: str | None = None, observables: Sequence[Observable] | None = None, parameter_values: Sequence[Sequence[float]] | None = None, session_id: str | None = None) -> JobSubmit one circuit — the common case, as a job of a single PUB.
Everything a PUB can carry is available here for one circuit: pass
observables for an expectation value instead of counts, and
parameter_values to sweep the circuit's input declarations. For several
circuits in one job, use run.
session_id puts the job inside a Session (client.sessions), which
groups a run of jobs and bounds the run's budget.
client.jobs.run(*, backend_id: str, pubs: Sequence[Pub], shots: int | None = None, name: str | None = None, session_id: str | None = None) -> JobSubmit an ordered list of PUBs as one job.
JobResult.pubs comes back index-aligned with this list: entry *i* belongs
to pubs[i] regardless of what happened to the others, including a PUB that
failed on its own.
shots is the job's default; a PUB carrying its own overrides it. Not every
backend accepts more than one PUB; one that does not rejects the whole
submission at submit.
client.jobs.list() -> list[Job]The caller's organization's jobs, newest first.
client.jobs.get(job_id: str) -> Jobclient.jobs.result(job_id: str) -> JobResultclient.jobs.cancel(job_id: str) -> Noneclient.jobs.wait(job_id: str, *, timeout: float = 300.0, poll_interval: float = 5.0) -> JobPoll until the job reaches a terminal status; raises on timeout.
client.sessions
Sessions: group a run of jobs and bound what the run may spend.
Jobs submitted with a session's id are reported as one run, and the session's
max_credits and max_seconds bound what the whole run may spend — the
useful bound for a variational loop, where a per-job limit says little about
the total.
A Qubitra session is not a hardware reservation: it does not reserve a backend, grant queue priority, or make any scheduling promise. Sessions are free to open and free to leave open.
client.sessions.create(*, name: str | None = None, max_credits: float | None = None, max_seconds: int | None = None) -> SessionOpen a session. Pass its id as session_id when submitting jobs.
max_credits and max_seconds are the run's budget, enforced across every
job in it; omitting both opens a session that correlates without bounding. A job
that would take the run past either bound is rejected at submit.
client.sessions.list() -> list[Session]The caller's organization's sessions, newest first.
client.sessions.get(session_id: str) -> SessionOne session, including what it has spent so far against its budget.
client.sessions.close(session_id: str) -> SessionClose a session and return its final state.
Closing stops further jobs joining the session, which makes the run's totals final.
client.marketplace
client.marketplace.offerings() -> list[Offering]Models
Every model is frozen, so an instance is a snapshot rather than a handle — re-read the platform to see a change. Unset optional fields are None: the SDK reports what the platform sent and invents nothing.
ApiKeyCredentials
| Field | Type | Default |
|---|---|---|
token | str | required |
Backend
An execution target: a simulator, a QPU, or a vendor service.
A Backend is identified by a Qubitra-owned slug, and the model describes capability — what a caller needs to choose one. There is no vendor, hardware owner, or access-tier field; the hardware behind a Backend can change without caller code changing.
basis_gates, operations, connectivity and calibration are absent
until known: they are populated from what a backend publishes, so a backend whose
metadata has not yet been populated carries None. None means *not
reported*, never *not supported* — treat these fields as background information
rather than as a guarantee, and do not gate a submission on one.
| Field | Type | Default |
|---|---|---|
id | str | required |
name | str | None | None |
type | BackendType | None | None |
technology | str | None | None |
qubit_count | int | None | None |
queue_size | int | None | None |
available | bool | None | None |
shots_min | int | None | None |
shots_max | int | None | None |
supported_formats | tuple[CircuitFormat, ...] | () |
basis_gates | tuple[str, ...] | None | None |
operations | tuple[str, ...] | None | None |
connectivity | tuple[tuple[int, int], ...] | None | None |
calibration | dict[str, Any] | None | None |
CountsResult
Measured bitstring counts — what a sampler PUB returns.
| Field | Type | Default |
|---|---|---|
type | Literal[<COUNTS: 'counts'>] | ResultType.COUNTS |
counts | dict[str, int] | {} |
shots | int | None | None |
ErrorResult
One PUB failed while others may have succeeded.
Results are index-aligned with submission, so a failed PUB occupies its own slot rather than collapsing the whole job's result.
| Field | Type | Default |
|---|---|---|
type | Literal[<ERROR: 'error'>] | ResultType.ERROR |
detail | str | '' |
ExpectationValuesResult
Expectation values — what an estimator PUB returns.
values is index-aligned with the PUB's observables, or with its parameter rows
when the PUB is a sweep of one observable. stds carries the standard error of each
value where the backend reports one; an exact simulator samples nothing, so it may
report none.
| Field | Type | Default |
|---|---|---|
type | Literal[<EXPECTATION_VALUES: 'expectation_values'>] | ResultType.EXPECTATION_VALUES |
values | tuple[float, ...] | () |
stds | tuple[float, ...] | None | None |
shots | int | None | None |
Job
One asynchronous execution of an ordered list of PUBs on a Backend.
| Field | Type | Default |
|---|---|---|
id | str | required |
backend_id | str | None | None |
status | JobStatus | JobStatus.UNKNOWN |
shots | int | None | None |
name | str | None | None |
session_id | str | None | None |
created_at | str | None | None |
ended_at | str | None | None |
error | str | None | None |
JobResult
The normalized result of a completed Job: one entry per submitted PUB.
pubs is index-aligned with the job's PUB list, so pubs[0] belongs to the first
PUB whatever the others did. The convenience properties read the first entry, which is
the whole answer for a single-circuit submission.
| Field | Type | Default |
|---|---|---|
pubs | tuple[Annotated[CountsResult | ProbabilitiesResult | ExpectationValuesResult | ErrorResult, FieldInfo(annotation=NoneType, required=True, discriminator='type')], ...] | () |
JobResult.first: PubResult | NoneThe first PUB's result, or None for a job that produced none.
JobResult.kind: strThe first PUB's result type, as a string; "unknown" when there is none.
JobResult.counts: dict[str, int] | NoneThe first PUB's counts, or None when it did not return counts.
JobResult.probabilities: dict[str, float] | NoneThe first PUB's probabilities, or None when it did not return them.
JobResult.values: tuple[float, ...] | NoneThe first PUB's expectation values, or None when it returned none.
JobResult.shots: int | NoneThe shot count the first PUB ran at, where the backend reported one.
Observable
A weighted sum of Pauli strings, whose expectation value an estimator PUB returns.
num_qubits is the width the observable is written against — the circuit's width,
not the number of qubits the terms happen to name.
The Hamiltonian 1.5·Z₀Z₁ − 0.5·X₀ on two qubits::
Observable( num_qubits=2, terms=( PauliTerm(pauli="ZZ", qubits=(0, 1), coefficient=1.5), PauliTerm(pauli="X", qubits=(0,), coefficient=-0.5), ), )
| Field | Type | Default |
|---|---|---|
num_qubits | int | required |
terms | tuple[PauliTerm, ...] | () |
Offering
Anything published to the marketplace.
| Field | Type | Default |
|---|---|---|
id | str | required |
name | str | None | None |
summary | str | None | None |
type | OfferingType | OfferingType.APPLICATION |
provider_name | str | None | None |
PauliTerm
One weighted Pauli string of an Observable.
pauli is a string of I/X/Y/Z, one character per entry in
qubits: PauliTerm(pauli="ZZ", qubits=(0, 1)) measures Z on qubit 0 and Z on
qubit 1. The representation is sparse, so a two-qubit term on a 26-qubit circuit
names two qubits rather than padding to the width.
| Field | Type | Default |
|---|---|---|
pauli | str | required |
qubits | tuple[int, ...] | required |
coefficient | float | 1.0 |
ProbabilitiesResult
A quasi-distribution over bitstrings, for a backend that reports one.
| Field | Type | Default |
|---|---|---|
type | Literal[<PROBABILITIES: 'probabilities'>] | ResultType.PROBABILITIES |
probabilities | dict[str, float] | {} |
shots | int | None | None |
Pub
A Primitive Unit Bloc: one circuit and everything needed to run it.
A job carries an ordered list of PUBs, and a PUB's contents determine what kind of result it returns:
- circuit alone — **sampler**: measured counts.
- circuit + observables — **estimator**: an expectation value per observable, and
no measurement instructions in the circuit.
- either, plus parameter_values — a **sweep**: the circuit is run once per row.
parameter_values is a list of rows, each row one value per input declaration
in the circuit, in declaration order. Parameter binding is expressed in the circuit
itself: an OpenQASM 3 input float[64] theta; declares the value a row supplies.
A published cap bounds rows per PUB and is enforced at submit.
shots overrides the job's shot count for this PUB alone; None takes the job's.
| Field | Type | Default |
|---|---|---|
circuit | str | required |
format | CircuitFormat | CircuitFormat.OPENQASM_3 |
observables | tuple[Observable, ...] | () |
parameter_values | tuple[tuple[float, ...], ...] | () |
shots | int | None | None |
Session
A run of Jobs, grouped under one id and bounded by a budget.
Jobs submitted with this session's id are reported as one run, and
max_credits and max_seconds bound what the whole run may spend,
enforced across it.
A Qubitra session is not a hardware reservation: it does not reserve a backend, grant queue priority, or make any scheduling promise. This differs from sessions on some other platforms, such as Qiskit Runtime.
credits_used and elapsed_seconds are what the platform has counted against
the bounds so far.
| Field | Type | Default |
|---|---|---|
id | str | required |
name | str | None | None |
status | SessionStatus | SessionStatus.UNKNOWN |
max_credits | float | None | None |
max_seconds | int | None | None |
credits_used | float | None | None |
elapsed_seconds | int | None | None |
created_at | str | None | None |
ended_at | str | None | None |
Enumerations
All four are string enums, so a member compares equal to its wire value and prints as itself. A value this SDK version does not know is not fatal: an unrecognised status reads as JobStatus.UNKNOWN and an unrecognised circuit format is dropped from a backend's supported_formats.
BackendType
QPUSIMULATORANNEALER
CircuitFormat
Circuit interchange formats a job may be submitted in.
The first four are text programs. IONQ_CIRCUIT is a JSON circuit document — a
gateset, a qubit count and a list of gates — so a circuit in that format is JSON text
rather than program source. It is still passed as a string.
A backend reports what it accepts as Backend.supported_formats; a backend that
reports none places no constraint of its own.
OPENQASM_3 is accepted as static circuits with parameters, not as the whole
language: for/while loops, def subroutines, classical int declarations
and mid-circuit branching are rejected. The circuit-formats documentation page
describes the boundary in full.
OPENQASM_2OPENQASM_3QIRQPYIONQ_CIRCUIT
JobStatus
UNKNOWNPENDINGRUNNINGCANCELLINGCOMPLETEDFAILEDCANCELLEDABORTED
JobStatus.is_terminal: boolOfferingType
APPLICATIONTOOL_LIBRARYBACKENDINFRASTRUCTUREEXPERTISE
ResultType
What a per-PUB result carries. The discriminator of the PubResult union.
COUNTScountsPROBABILITIESprobabilitiesEXPECTATION_VALUESexpectation_valuesERRORerror
SessionStatus
UNKNOWNOPENCLOSEDEXPIRED
Errors
Every failure the SDK raises is a QubitraError, so oneexcept QubitraError is a complete catch. What a caller does about each is on the error handling page.
QubitraErrorBase class for all errors raised by the Qubitra SDK.
Attributes
message: str, status_code: int | None, detail: AnyAuthenticationErrorextends QubitraErrorMissing or rejected credentials.
InsufficientCreditsErrorextends QubitraErrorThe organization cannot pay for the operation. The request was well-formed; the same call succeeds once the balance covers it.
InvalidRequestErrorextends QubitraErrorThe platform rejected the request as malformed or unprocessable.
NotFoundErrorextends QubitraErrorThe requested resource does not exist.
ProviderErrorextends QubitraErrorAn upstream platform failure that maps to no more specific error.
Configuration
Constructor arguments take precedence over the environment. These values are read from the package's own constants.
| Constant | Kind | Value |
|---|---|---|
ENV_API_KEY | environment variable | QUBITRA_API_KEY |
ENV_API_URL | environment variable | QUBITRA_API_URL |
DEFAULT_API_URL | default | https://api.qubitra.io |
DEFAULT_TIMEOUT_S | default | 30.0 |
DEFAULT_POLL_INTERVAL_S | default | 5.0 |
DEFAULT_WAIT_TIMEOUT_S | default | 300.0 |