There are four ways to connect a QPU to QCOS. Pick by who owns the hardware and the credentials: How the catalog works: GET /api/v1/runtime/backends iterates every supplier’s providers; each provider target string becomes a backend id. A backend shows available: true only when all of its required environment variables are set. Dispatch resolves a backend_id to execution through dispatch_provider_job (built-in cloud branches first, then the HAL for plugins / on-premise / vendor drivers).

A. Built-in cloud provider — set the credential env var

The provider already exists in the registry. Set its credential(s), restart the server, and its backends flip to available: true.
Azure Quantum caveat (important, differs from older docs): the Azure providers (IonQ/Rigetti/Quantinuum/PASQAL) declare no required env var, so they always show available: true in the catalog. Their execution credentials are read at dispatch time: set AZURE_QUANTUM_RESOURCE_ID (or the trio AZURE_QUANTUM_SUBSCRIPTION_ID + AZURE_QUANTUM_RESOURCE_GROUP
  • AZURE_QUANTUM_WORKSPACE_NAME) plus AZURE_QUANTUM_LOCATION. The variables IONQ_API_KEY / QUANTINUUM_API_KEY / RIGETTI_API_KEY are not used for the Azure path — do not rely on them.
Config changes are read at process start — restart the server after setting any variable. Full list in Configuration.

B. Bring-your-own (BYO) credentials — per tenant/user

A tenant attaches their own cloud account at runtime, without the operator setting a server-wide env var. Only azure_quantum, ibm_quantum and braket backends support BYO (they carry supports_byo: true).
provider_type: ibm_quantum | azure_quantum | aws_braket | google_quantum | ionq_direct | other. scope: tenant | workspace | user. Manage with GET /provider-connections and POST /provider-connections/{id}/test. After connecting, the matching backends report supports_byo: true and jobs dispatch to the concrete provider adapter with your credentials.

C. On-premise supplier — you host the QPU

Register a SupplierType.ON_PREMISE supplier. Its provider targets become backend ids; dispatch instantiates your backend_class. On-premise devices are always classified real_qpu, so the real-QPU gates (QCOS_REAL_QPU_ENABLED, payment reservation, plan tier) apply.
Working example: examples/oem_console/server.py. The catalog entry provides identity + billing + gating; execution happens through a driver (usually method D). In practice you pair C (catalog) + D (driver wheel) for a real customer QPU. Behaviour (proven by tests/unit/test_onprem_byo_dispatch.py): the target appears in /backends with provider_source = your supplier id; without a qpu_reservation_id the job parks in approval_required; with payment but QCOS_REAL_QPU_ENABLED=false the door returns 403 real_qpu_disabled.

D. Vendor HAL driver — the manufacturer’s own driver

A QPU manufacturer ships a pip-installable wheel that implements the canonical QPUDriver contract and declares a qcos.drivers entry point. pip install on the QCOS host is the whole deployment — no core source, no code changes. The contract (src/hal/driver.py) — two mandatory methods:
execute must return at least: job_id, backend_id, shots, counts, execution_time_ms, timestamp, status (ACOS-ISA-009). Optional overrides (with defaults): transpile_to_native, execute_batch, get_job_status, cancel_job, connect/disconnect. Ship it — one line in the wheel’s pyproject.toml:
Or register in-process:
Develop & certify with the public SDK (install it on your workstation, not the server):
Copy ReferenceSimulatorDriver (src/hal/reference.py) as a full-contract template; full worked example in examples/vendor-driver-demo/. Licensing (commercial builds): driver registration is gated by license features (hal:*, hal:<glob>, hal_<vendor>, hal_max_devices:N). Skipped when QCOS_SKIP_LICENSE_CHECK=true or in internal build mode. See docs/oem/VENDOR_ONBOARDING.md.

How dispatch resolves a backend id

dispatch_provider_job(backend_id, qasm, shots) (src/adapters/providers/router.py) — first match wins:
  1. Built-in simulator ids → local engines (auto_sim, statevector_sim, …)
  2. Built-in cloud ids → ionq./rigetti./quantinuum./pasqal. (Azure), ibm* (IBM), braket/sv1/tn1/dm1 (Braket)
  3. Anything else → the HAL: registered drivers (exact) → plugin backends → on-premise suppliers → HAL wildcard drivers
If nothing matches, dispatch fails explicitly (No runtime provider adapter for backend '<id>') — a QPU id is never silently run on a simulator. Hardware drivers are serialized one-job-at-a-time per device by the scheduler; simulators run concurrently.