---
url: /tutorials/tutorial-ibmq.md
description: >-
  Build a service that uses qiskit-ibm-provider to generate random numbers on
  the least busy IBM Quantum Platform backend.
---

# Access IBM Quantum Platform Backends in a Service

This tutorial shows how to access backends offered by 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 Qiskt and the IBM Provider SDK as a dependency to your project by adding `qiskit` and `qiskit-ibm-provider` 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 qiskit import QuantumCircuit, transpile
from qiskit_ibm_provider import IBMProvider, least_busy
from qiskit_ibm_provider.job import job_monitor
```

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)

token = os.getenv('QISKIT_IBM_TOKEN', None)
provider = IBMProvider(token=token)

devices = provider.backends(simulator=False, operational=True)
backend = least_busy(devices)

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()
job = backend.run(circuit, shots=1000)

job_monitor(job)
execution_time = time.time() - start_time

random_number = int(list(job.result().get_counts().keys())[0], 2)
```

The code first instantiates the `IBMProvider` using an API token value from the environment variable `QISKIT_IBM_TOKEN`.
Next, we determine the least busy backend, create a simple circuit, and execute the problem by calling `backend.run()`.
The `job_monitor()` function waits till the job has been completed, 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 [Starter Implementation](https://dashboard.hub.kipu-quantum.com/community/implementations/1a0ae675-4b23-405c-af8e-f4189ff14e0f).

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

from qiskit import QuantumCircuit, transpile
from qiskit_ibm_provider import IBMProvider, least_busy
from qiskit_ibm_provider.job import job_monitor

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)

    token = os.getenv('QISKIT_IBM_TOKEN', None)
    provider = IBMProvider(token=token)

    devices = provider.backends(simulator=False, operational=True)
    backend = least_busy(devices)

    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()
    job = backend.run(circuit, shots=1000)

    job_monitor(job)
    execution_time = time.time() - start_time

    random_number = int(list(job.result().get_counts().keys())[0], 2)

    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": 235}, "metadata": {"execution_time": 2810.306}}
```

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. Add your IBM Quantum API token in the Provider Access Tokens [settings](https://dashboard.hub.kipu-quantum.com/settings) of your account.
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`.
   In your code, you already instrumented the `IBMProvider` 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.
