---
url: /tutorials/tutorial-qiskit-runtime.md
description: >-
  Build a service that uses qiskit-ibm-runtime sessions and samplers to run
  circuits on IBM Quantum Platform backends.
---

# Use Qiskit Runtime in a Service

This tutorial shows how to use the Qiskit Runtime SDK together with the IBM Quantum Platform from within a service.
As an example, the code will generate some random numbers on the least busy IBM Quantum Platform backend.

## Bootstrap Project

1. Install the [CLI](../cli-reference).
2. Create a new project using `qhubctl init` and select the `Starter` template.
3. Open the project in your IDE of choice, e.g., VSCode.

## Create Python Environment

Add the Qiskt Runtime SDK as a dependency to your project by adding `qiskit-ibm-runtime` to the `requirements.txt` file in the root folder.

You can now set up a Python environment using Conda:

```bash
conda env create -f environment.yml
conda activate <environment name>
```

Conda and the `environment.yml` file are used by the platform at runtime.
However, if you do not have Conda installed on your local computer, you are also able to initialize a Python virtual environment using the tooling of your choice, e.g., `pyenv` or `venv`.

You are now able to run the Python `src` folder as module from your console:

```bash
python3 -m src
```

## Extend Project

Open the `program.py` in your IDE.
The `run()` method is the main handler function and the entry point for your program.
The method takes two arguments:
(1) a `data` dictionary and (2) a `params` dictionary holding the input submitted by the user.
The platform [translates](../services/managed/runtime-interface) the Service API body/payload in the form of `{ "data": { <data> }, "params": { <params> } }` into these parameters.

It is also important that the `run()` method returns a JSON serializable `Response` object.
The template makes use of the classes `ResultResponse` and `ErrorResponse`.
It's recommended that you use these classes as well.

Next, remove the whole code from within the `run()` method.

Add some required import statements:

```python
from typing import Dict, Any, Union, cast

from qiskit import QuantumCircuit, transpile
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler
from qiskit_ibm_runtime.accounts import ChannelType
```

Add the following code to the `run()` method:

```python
# defines the range of random numbers between 0 and 2^n_bits - 1
n_bits = data.get("n_bits", 2)

channel: ChannelType = cast(ChannelType, os.getenv("QISKIT_IBM_CHANNEL", "ibm_quantum"))
token: str = os.getenv("QISKIT_IBM_TOKEN", None)
instance: str = os.getenv("QISKIT_IBM_INSTANCE", "ibm-q/open/main")
service = QiskitRuntimeService(channel=channel, token=token, instance=instance)

backend = service.least_busy(simulator=False, operational=True)

circuit = QuantumCircuit(n_bits, n_bits)
circuit.h(range(n_bits))

circuit.measure(range(n_bits), range(n_bits))

circuit = transpile(circuit, backend)

start_time = time.time()
with Session(service, backend=backend, max_time=None) as session:
    sampler = Sampler(session=session)
    job = sampler.run(circuit, shots=10)
    job_result = job.result()
    execution_time = time.time() - start_time
    session.close()

random_number = int(list(job_result.quasi_dists[0].keys())[0])
```

The code first instantiates the `QiskitRuntimeService` using required configuration coming from environment variables.
You can use `QISKIT_IBM_CHANNEL` to define if you want to use the IBM Quantum Platform (`ibm_quantum`) or the IBM Cloud (`ibm_cloud`).
With `QISKIT_IBM_TOKEN` you can specify your respective API token and with `QISKIT_IBM_INSTANCE` you can specify the instance string to be used when executing a circuit.
The default values from the code above lets you run your program against the IBM Quantum Platform by just setting the `QISKIT_IBM_TOKEN` environment variables.

Next, we determine the least busy backend followed by the creation of a simple circuit.
By using a `Session`, we request a session to run our circuit in.
Within this session, we can instantiate a `Sampler` and execute the problem by calling `sampler.run()`.
Finally, we close the session once the result is present, which is when we can extract a random number out of the job result.

Finally, return some result:

```python
result = {
    "random_number": random_number,
}
metadata = {
    "execution_time": round(execution_time, 3),
}

return ResultResponse(result=result, metadata=metadata)
```

::: details Source Code (program.py)

The full project can be found in our [Implementations `python-starter`](https://dashboard.hub.kipu-quantum.com/community/implementations/1a0ae675-4b23-405c-af8e-f4189ff14e0f).

```python
import os
import time
from typing import Dict, Any, Union, cast

from qiskit import QuantumCircuit, transpile
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler
from qiskit_ibm_runtime.accounts import ChannelType

from .libs.return_objects import ResultResponse, ErrorResponse


def run(data: Dict[str, Any] = None, params: Dict[str, Any] = None) -> Union[ResultResponse, ErrorResponse]:
    # defines the range of random numbers between 0 and 2^n_bits - 1
    n_bits = data.get("n_bits", 2)

    # initialize qiskit runtime service
    channel: ChannelType = cast(ChannelType, os.getenv("QISKIT_IBM_CHANNEL", "ibm_quantum"))
    token: str = os.getenv("QISKIT_IBM_TOKEN", None)
    instance: str = os.getenv("QISKIT_IBM_INSTANCE", "ibm-q/open/main")
    service = QiskitRuntimeService(channel=channel, token=token, instance=instance)

    backend = service.least_busy(simulator=False, operational=True)

    # create circuit
    circuit = QuantumCircuit(n_bits, n_bits)
    circuit.h(range(n_bits))

    # perform measurement
    circuit.measure(range(n_bits), range(n_bits))

    # transpile circuit
    circuit = transpile(circuit, backend)

    start_time = time.time()
    with Session(service, backend=backend, max_time=None) as session:
        sampler = Sampler(session=session)
        job = sampler.run(circuit, shots=10)
        job_result = job.result()
        execution_time = time.time() - start_time
        session.close()

    # extract random number
    random_number = int(list(job_result.quasi_dists[0].keys())[0])

    result = {
        "random_number": random_number,
    }
    metadata = {
        "execution_time": round(execution_time, 3),
    }

    return ResultResponse(result=result, metadata=metadata)
```

:::

## Run the Project Locally

Run the program using `QISKIT_IBM_TOKEN=9356f0193daa... python3 -m src` (copy the API token value from your IBM Quantum Platform account settings).

The output should be similar to the following:

```shell
{"result": {"random_number": 8}, "metadata": {"execution_time": 1467.637}}
```

The project, or the `__main__.py` respectively, uses the `data.json` and the `params.json` as input for the `run()` when executed locally.
You may experiment with different inputs of the `n_bits` input data parameter.

The next section shows how to create and run a service using the code you just have written.

## Create a Service

We use the CLI to create a new service in your personal account.

Login with the CLI:

```shell
qhubctl login -t <your personal access token>
```

Create the service:

```shell
qhubctl up
```

After a while, the console should print something similar like this:

```
Pushing Image (2/2)... Service created 🚀
```

Congratulations.
You have successfully created a service.

Before you can execute the service, a few more steps are necessary:

1. In case you want to run the circuit with a backend offered by the IBM Quantum Platform, you just have to add your respective API token in the Provider Access Tokens [settings](https://dashboard.hub.kipu-quantum.com/settings) of your account.
   In case you want to use the IBM Cloud, you have to add your IBM Cloud credentials by specifying the Service CRN and your API token.
   Then, the platform is able to provide the following environment variables at runtime: `QISKIT_IBM_INSTANCE` (Service CRN value) and `QISKIT_IBM_CHANNEL` (constant value: ibm\_cloud).
2. On the [service overview page](https://dashboard.hub.kipu-quantum.com/services), open your service and go to the Runtime Configuration (`Edit Service > Runtime Configuration`).
   Activate the option `Add secrets to runtime environment`.
   This option lets the platform inject your API token to the execution runtime.
   The value is made available through the environment variable `QISKIT_IBM_TOKEN`.
   And in case of IBM Cloud, also `QISKIT_IBM_INSTANCE` and `QISKIT_IBM_CHANNEL` are available at runtime.
   In your code, you already instrumented the `QiskitRuntimeService` accordingly whenever this environment variable is present.

## Run your Service

Using the CLI, you can quickly run a Service Job:

```shell
qhubctl run
```

The `run` command uses the `data.json` and `params.json` file as input for the job.
You may adjust the values accordingly.

Alternatively, you could have created a Service Job through the platform UI.
More information about Jobs and how to use them can be found in our [documentation](../services/managed/jobs).

Furthermore, you could also *publish your service for internal use* and read on how to use the service utilizing Applications.
Just follow the steps in the [Using a Service](../services/using-a-service) section in our documentation.
