# Canton request-response oracle

{% hint style="info" %}
This guide provides step-by-step instructions for creating market data requests to Kaiko using the Kaiko oracle on the Canton blockchain. You can see our full range of Reference Rates and Multi-Asset Indices available on Canton [here](https://explorer.kaiko.com/).
{% endhint %}

{% hint style="success" icon="copy" %}
DAR files must be uploaded on your node to use this Oracle [\[Click here to download\]](https://kaiko-delivery-links.s3.us-east-1.amazonaws.com/prepaid-oracle-kaiko-0.0.1.zip)
{% endhint %}

## Overview

The Kaiko oracle enables secure, paid/licensed requests for real-time Reference Rates and Multi-Asset Indices through the Canton blockchain. The system follows the standard request-response oracle workflow:<br>

1. **Prepare request parameters:** Format the Kaiko-specific payload.
2. **Retrieve contracts:** Get the current Amulet rules and open mining round contracts.
3. **Exercise a contract choice:** Submit a transaction to create a data request.

The oracle processes the request off-chain (settling payment via Amulets) and posts the Kaiko market data response back on-ledger.

## Prerequisites

### Required information

You need the following information before starting:

* **Canton participant endpoint:** URL of your Canton participant JSON API
* **Canton authentication token:** Valid token for API access
* **Consumer party ID:** Your party identifier in Canton (e.g., `Consumer::1220...)`
* **RequestFactory contract ID:** Contract ID for the request factory
* **DSO party ID:** DSO party identifier
* **Data provider details (provider-dependent):** Data request payload (stringified JSON)
* **Amulet contract ID:** An Amulet contract to fund payment
* **Payment locked amount:** Amount to lock for the request

### Environment setup

Ensure you have:

* A Canton node connected to the same domain as the oracle node
* The Prepaid Oracle DAR uploaded to your Canton node
* Sufficient Amulet balance for the request

## Creating a Data Request

### Prepare provider request parameters

The Kaiko oracle accepts requests for one or more tickers (real-time reference rates and indices).

#### Input model (Kaiko)

You must prepare the payload as valid JSON and then stringify it for the Canton command.

You must first select the Asset Class for the ticker you need to request. One asset class is allowed per request.

Asset Classes:

* `crypto`: Array of Kaiko tickers for Crypto Assets. E.g.:
  * `KK_RFR_BTCUSD`
  * `KK_RFR_CCUSD`
* `equity`: Array of Kaiko tickers for Equity Assets. E.g.:
  * `KK_RFR_TSLAUSD`

Example Request 1: Accessing Crypto Data

```json
JSON
{
    "crypto": ["KK_RFR_BTCUSD", "KK_RFR_CCUSD"]
}
```

Example Request 2: Accessing Equity Data

```json
{
    "equity": ["KK_RFR_TSLAUSD"]
}
```

#### Stringified payload

When sending the request to Canton, pass the **stringified** version (quotes escaped):

```
"{\"crypto\":[\"KK_RFR_BTCUSD\",\"KK_RFR_CCUSD\"]}"
```

### Submit the request creation transaction

Make a POST request to Canton to exercise the `CreateRequest` choice.

#### **Request Endpoint:**

**POST**

`{PARTICIPANT_NODE_JSON_API_URL}/v2/commands/submit-and-wait-for-transaction-tree`

**Headers**

* `Authorization: Bearer {CANTON_TOKEN}`
* `Content-Type: application/json`

**Request body example:**

```json
{
    "actAs": [
        "{YOUR_CONSUMER_PARTY}"
    ],
    "commandId": "kaiko-request-1",
    "commands": [
        {
            "actAs": [
                "{YOUR_CONSUMER_PARTY}"
            ],
            "commandId": "kaiko-request-1",
            "ExerciseCommand": {
                "contractId": "{REQUEST_FACTORY_CONTRACT_ID}",
                "templateId": "{PACKAGE_ID}:PrepaidOracle.RequestFactory:RequestFactory",
                "choice": "CreateRequest",
                "choiceArgument": {
                    "dso": "{DSO_PARTY}",
                    "amuletRulesCid": "{AMULET_RULES_CONTRACT_ID}",
                    "openRoundCid": "{OPEN_ROUND_CONTRACT_ID}",
                    "inputs": [
                        {
                            "tag": "InputAmulet",
                            "value": "{YOUR_AMULET_CONTRACT_ID}"
                        }
                    ],
                    "dataRequest": "{\"rates\":[\"KK_RFR_BTCUSD\",\"EGLXRT\"]}",
                    "lockedAmount": {PAYMENT_LOCKED_AMOUNT
                    }
                }
            }
        }
    ],
    "disclosedContracts": [
        {
            "templateId": "{AMULET_PACKAGE_ID}:Splice.AmuletRules:AmuletRules",
            "contractId": "{AMULET_RULES_CONTRACT_ID}",
            "synchronizerId": "{GLOBAL_DOMAIN_SYNCHRONIZER_ID}",
            "createdEventBlob": "{AMULET_RULES_DISCLOSED_BLOB}"
        },
        {
            "templateId": "{AMULET_PACKAGE_ID}:Splice.Round:OpenMiningRound",
            "contractId": "{OPEN_ROUND_CONTRACT_ID}",
            "synchronizerId": "{GLOBAL_DOMAIN_SYNCHRONIZER_ID}",
            "createdEventBlob": "{OPEN_ROUND_DISCLOSED_BLOB}"
        }
    ]
}
```

## Reading the `FilledRequest`

Once the oracle processes your request, it archives the pending request and creates a `FilledRequest` contract containing the Kaiko data.

### Query for `FilledRequest`

Use the active contracts endpoint to retrieve the result.

#### Request endpoint

**POST**

`{PARTICIPANT_NODE_JSON_API_URL}/v2/state/active-contracts`

#### Request body filter: filter for template

`{PACKAGE_ID}:PrepaidOracle.Request:FilledRequest.`

### Kaiko response structure

In the resulting `FilledRequest` contract, the `responseData` field contains the stringified Kaiko output.

#### Response data model (Kaiko)

The response is a JSON object keyed by rate id(s), containing the returned value(s).

**Example (conceptual):**

```json
{
    "KK_RFR_BTCUSD": "{\"value\": 76293.2345454545, \"timestamp\": 1772633545286}",
    "KK_RFR_CCUSD": "{\"value\": 0.1698132000, \"timestamp\": 1772633526495}"
}
```

**Example `FilledRequest` content**

```json
{
    "oracle": "{ORACLE_PARTY}",
    "consumer": "{YOUR_CONSUMER_PARTY}",
    "requestData": "{\"rates\":[\"KK_RFR_BTCUSD\",\"KK_RFR_BTCUSD\"]}",
    "responseData": "{\"KK_RFR_BTCUSD\": \"{\\\"value\\\": 76293.2345454545, \\\"timestamp\\\": 1772633545286}\",\"KK_RFR_CCUSD\": \"{\\\"value\\\": 0.1698132000, \\\"timestamp\\\": 1772633526495}\"}",
    "serviceAmountCharged": "1.0000000000"
}
```

## Troubleshooting

### Invalid JSON structure

* **Cause**: The `dataRequest` string was not properly escaped or contained invalid JSON.
* **Solution**: Ensure your stringified JSON does not contain unescaped quotes, stray backslashes, or newlines.

### Unknown/unsupported rate identifier

* Cause: One or more requested rate identifiers are not available to your entitlement, are misspelled, or are not supported by the oracle.
* Solution: Validate the exact rate tickers (e.g., `KK_RFR_BTCUSD)`, confirm access/entitlements, and retry with supported identifiers.
