---
sidebar_position: 65
title: Private Queues
---

Switchboard is architected to route off-chain data to an on-chain account. A publisher is responsible for building the job definition, which defines the task(s) the oracles must perform to fetch and transform external data. Sometimes a publisher may wish to bring private data on-chain using an API key which poses a set of challenges. In order for the oracle to retrieve the data, they need access to the publisher's API key. Blockchains are public so there is no easy way to conceal the API key on-chain.

Switchboard provides the ability to create your own queue with your own set of oracles, allowing the oracles access to your API key so they can resolve the private endpoints.

## Variable Expansion

Oracles can be provided a `configs.json` file to store various configurations needed to execute job definitions. If an oracle encounters a job definition with a variable, it will parse the `configs.json` and embed the value in the job definition.

Oracles can embed API Keys on a per job basis by specifying the jobAccount public key or by using an asterik character to use the variable for multiple job definitions. **_Wildcard variables should use a unique name to prevent incorrect substitution._**

```json title="configs.json"
{
  "jobVariables": {
    // Pubkey of the Job account for which this variable expansion applies
    "HtB62K71H49RJbATYpmB6UCMBXLK6G3Q5JtGveTMR8Mt": {
      "VARIABLE_NAME": "abc123"
    },
    // Global variable expansion that applies to any Job account. SEE CAUTION BELOW
    "*": {
      "GLOBAL_VARIABLE_NAME": "abc123"
    }
  }
}
```

:::caution

Private queue's should **_ALWAYS_** have `unpermissionedFeedsEnabled` set to false. Allowing unpermitted feeds could result in a malicous actor creating a job definition that leaks your sensitive API keys.

:::

## Example

We'll be using [commodities-api](https://www.commodities-api.com) to resolve our data for this example. You will need to signup for an account to get a `COMMODITIES_API_KEY`.

### Create a Queue

First, we will need to create our own queue. The following command will create a queue with a single oracle and crank.

```bash
sbv2 queue:create \
    --name "Private Queue" \
    --keypair ../payer-keypair.json \
    --authority ../payer-keypair.json \
    --numOracles 1 \
    --reward 0 \
    --outputFile "Private_Queue.json"
```

### Start Oracle

Create a docker-compose file, replacing `ORACLE_KEY`, `RPC_URL`, and `PAYER_KEYPAIR` with the appropriate values.

```yml title="docker-compose.yml"
version: "3.3"
services:
  oracle:
    image: "switchboardlabs/node:dev-v2-5-3-22"
    network_mode: host
    restart: always
    secrets:
      - PAYER_SECRETS
    environment:
      - LIVE=1
      - CLUSTER=devnet
      - HEARTBEAT_INTERVAL=30 # Seconds
      - ORACLE_KEY=${ORACLE_KEY}
      - RPC_URL=${RPC_URL}
    volumes:
      - ./configs.json:/configs.json
secrets:
  PAYER_SECRETS:
    file: ${PAYER_KEYPAIR}
```

We need to embed the commodities-api key in our oracle's configs.json file.

```json title="configs.json"
{
  "jobVariables": {
    // Pubkey of the OracleJob account for which this variable expansion applies or *.
    "*": {
      "COMMODITIES_API_KEY": "YOUR_API_KEY_HERE"
    }
  }
}
```

Start the oracle

```bash
docker-compose up
```

### Create WHEAT Aggregator

Looking at their docs, we'll need to fetch data from the following endpoint and take the inverse. The aggregator definition will look like this:

```json title="Wheat.json"
{
  "name": "WHEAT",
  "metadata": "",
  "oracleRequestBatchSize": 1,
  "minOracleResults": 1,
  "minJobResults": 1,
  "minUpdateDelaySeconds": 900,
  "jobs": [
    {
      "name": "commodities-api WHEAT",
      "tasks": [
        {
          "httpTask": {
            "url": "https://www.commodities-api.com/api/latest?access_key=${COMMODITIES_API_KEY}&base=USD&symbols=WHEAT"
          }
        },
        {
          "jsonParseTask": {
            "path": "$.data.rates.WHEAT"
          }
        },
        {
          "powTask": {
            "scalar": -1
          }
        }
      ]
    }
  ]
}
```

Now we need to create an aggregator and add this job definition to it.

```bash
sbv2 aggregator:create:json wheat.json \
    --keypair ../payer-keypair.json \
    --queueKey QUEUE_KEY_OUTPUTTED_ABOVE \
    --outputFile Wheat_Aggregator.json
```

Now we can request an update from our running oracle

```bash
sbv2 aggregator:update AGGREGATORKEY --keypair PAYERKEYPAIR
```

We should see the oracle respond to the job and update the on-chain value

```bash
sbv2 aggregator:print AGGREGATORKEY
```

### Other Aggregator Definitions

<details>

<summary>

#### Crude

</summary>

```json title="Crude.json"
{
  "name": "Crude WTIOIL",
  "metadata": "",
  "oracleRequestBatchSize": 1,
  "minOracleResults": 1,
  "minJobResults": 1,
  "minUpdateDelaySeconds": 900,
  "jobs": [
    {
      "name": "commodities-api WTIOIL",
      "tasks": [
        {
          "httpTask": {
            "url": "https://www.commodities-api.com/api/latest?access_key=${COMMODITIES_API_KEY}&base=USD&symbols=WTIOIL"
          }
        },
        {
          "jsonParseTask": {
            "path": "$.data.rates.WTIOIL"
          }
        },
        {
          "powTask": {
            "scalar": -1
          }
        }
      ]
    }
  ]
}
```

</details>

<details>

<summary>

#### Gold

</summary>

```json title="Gold.json"
{
  "name": "Gold",
  "metadata": "",
  "oracleRequestBatchSize": 1,
  "minOracleResults": 1,
  "minJobResults": 1,
  "minUpdateDelaySeconds": 900,
  "jobs": [
    {
      "name": "commodities-api XAU",
      "tasks": [
        {
          "httpTask": {
            "url": "https://www.commodities-api.com/api/latest?access_key=${COMMODITIES_API_KEY}&base=USD&symbols=XAU"
          }
        },
        {
          "jsonParseTask": {
            "path": "$.data.rates.XAU"
          }
        },
        {
          "powTask": {
            "scalar": -1
          }
        }
      ]
    }
  ]
}
```

</details>

<details>

<summary>

#### Silver

</summary>

```json title="Silver.json"
{
  "name": "Silver",
  "metadata": "",
  "oracleRequestBatchSize": 1,
  "minOracleResults": 1,
  "minJobResults": 1,
  "minUpdateDelaySeconds": 900,
  "jobs": [
    {
      "name": "commodities-api XAG",
      "tasks": [
        {
          "httpTask": {
            "url": "https://www.commodities-api.com/api/latest?access_key=${COMMODITIES_API_KEY}&base=USD&symbols=XAG"
          }
        },
        {
          "jsonParseTask": {
            "path": "$.data.rates.XAG"
          }
        },
        {
          "powTask": {
            "scalar": -1
          }
        }
      ]
    }
  ]
}
```

</details>

<details>

<summary>

#### Nickel

</summary>

```json title="Nickel.json"
{
  "name": "Nickel",
  "metadata": "",
  "oracleRequestBatchSize": 1,
  "minOracleResults": 1,
  "minJobResults": 1,
  "minUpdateDelaySeconds": 900,
  "jobs": [
    {
      "name": "commodities-api NI",
      "tasks": [
        {
          "httpTask": {
            "url": "https://www.commodities-api.com/api/latest?access_key=${COMMODITIES_API_KEY}&base=USD&symbols=NI"
          }
        },
        {
          "jsonParseTask": {
            "path": "$.data.rates.NI"
          }
        },
        {
          "powTask": {
            "scalar": -1
          }
        }
      ]
    }
  ]
}
```

</details>

<details>

<summary>

#### Coffee

</summary>

```json title="Coffee.json"
{
  "name": "Coffee",
  "metadata": "",
  "oracleRequestBatchSize": 1,
  "minOracleResults": 1,
  "minJobResults": 1,
  "minUpdateDelaySeconds": 900,
  "jobs": [
    {
      "name": "commodities-api COFFEE",
      "tasks": [
        {
          "httpTask": {
            "url": "https://www.commodities-api.com/api/latest?access_key=${COMMODITIES_API_KEY}&base=USD&symbols=COFFEE"
          }
        },
        {
          "jsonParseTask": {
            "path": "$.data.rates.COFFEE"
          }
        },
        {
          "powTask": {
            "scalar": -1
          }
        }
      ]
    }
  ]
}
```

</details>
