# REST API

### 1. Authentication

Include the following headers with each request:

* `solver` - name of the Solver
* `authorization` - authorization token

### 2. View connected makers

Use the following endpoint to retrieve a list of currently connected makers:

**URL:** `https://api.liquorice.tech/v1/solver/connected-makers`

**Method:** `GET`

#### Response:

```typescript
[
    "maker-a", 
    "maker-b"
]
```

### 3. Obtain list of supported tokens

Use the following endpoint to retrieve a list of currently supported tokens:

**URL:** `https://api.liquorice.tech/v1/solver/supported-tokens?chainId=<string>`&#x20;

**Method:** `GET`

#### Response:

```typescript
[
    {
        "symbol": "USDT",
        "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "decimals": 6
    },
    {
        "symbol": "WETH",
        "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
        "decimals": 18
    }
]
```

### 4. Query price levels

To understand indicative prices and available liquidity, we expose price levels for the different market makers.&#x20;

This step will allow you to do price discovery before requesting signed quotes.

**URL:** `https://api.liquorice.tech/v1/solver/price-levels?chainId=<string>`&#x20;

**Method:** `GET`&#x20;

#### Response:

```json
{
  "prices": {
    "maker_a": [
      {
        "baseToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
        "quoteToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "levels": [
          ["2999.5", "0.5"],
          ["3000.5", "1"],
          ["3002.0", "2"]
        ],
        "updatedAt": 1769174084710
      }
    ]
  }
}
```

Assuming that trader wants to swap `2 WETH` for `USDC`, the maker would be buying `0.5 WETH` for `2999.5 USDC`, `1 WETH` for `3000.5 USDC`, and another `0.5 WETH` for `3002.0 USDC`&#x20;

### 5. RFQ

To obtain a quote from Liquorice, send an RFQ to the following endpoint:

**URL:** `https://api.liquorice.tech/v1/solver/rfq`

**Method:** `POST`

**Body:**&#x20;

```typescript
{
    /// Chain ID (e.g for ArbitrumOne chainId = 42161)
    chainId: number;
    /// UUID of the RFQ (Must be generated by caller)
    rfqId: string;
    /// RFQ expiration UNIX timestamp (seconds)
    expiry: number,
    /// Address of token to be sent by trader
    baseToken: string;
    /// Address of the token to be received by trader
    quoteToken: string;
    /// Address of the account receiving quoteToken   
    trader: string;
    /// Optional address of the account sending baseToken
    /// If omitted, the system assumes that baseToken will be sent from trader address 
    effectiveTrader?: string;
    /// Note: Exactly one of the following two fields must be present
    /// Amount of baseToken with up to 18 decimal places, e.g. 100000000 (1 WBTC)
    baseTokenAmount?: string;
    /// Amount of quoteToken with up to 18 decimal places
    quoteTokenAmount?: string;
    /// List of maker names excluded from RFQ processing
    excludedMakers?: string[];
    /// Optional metadata that provides context about the intent origin
    intentMetadata?: {
        source: 'cow_protocol';
        content: { 
            /// CoW auction ID
            auctionId: number;
        }
    }
}
```

* The RFQ must include either `baseTokenAmount` or `quoteTokenAmount`, but not both.\
  \
  When `baseTokenAmount` is specified, the `trader` (order initiator) is requesting the amount of `quoteToken` they would receive in exchange for a specific amount of `baseToken`.\
  \
  When `quoteTokenAmount` is specified, the `trader` (order initiator) is requesting the amount of `baseToken` they need to provide to receive a specific amount of `quoteToken`.
* `excludedMakers`- to exclude specific makers from RFQ processing, obtain the complete maker list from the relevant [API endpoint](#id-2.-connected-makers)
* `intentMetadata` - For the moment, only CoW Protocol is supported. Omit this setting when requesting quotes for other intent origins.

#### Response

```typescript
{
  /// UUID of the RFQ
  rfqId: string,
  /// Indicates whether liquidity is available to fulfill RFQ
  liquidityAvailable: boolean,
  /// Array of available quote levels.
  /// Empty when liquidityAvailable is false
  levels: [{
    /// UUID of the maker RFQ that sourced this quote level
    makerRfqId: string,
    /// Name of the maker providing this quote level
    maker: string,
    /// Hex-encoded 32-byte nonce
    nonce: string,
    /// Quote expiration UNIX timestamp (seconds)
    expiry: number,
    /// Transaction details
    tx: {
      /// Address of the LiquoriceSettlement contract
      to: string,
      /// 0x-prefixed calldata string for the function within 
      /// LiquoriceSettlement contract
      data: string
    },
    /// Address of token to be sent by trader
    baseToken: string,
    /// Address of the token to be received by trader
    quoteToken: string,
    /// Amount of baseToken with up to 18 decimal places, e.g. 100000000 (1 WBTC)
    baseTokenAmount: string,
    /// Amount of quoteToken with up to 18 decimal places
    quoteTokenAmount: string,
    /// Settings for partial fill functionality.
    /// If absent, the order cannot be filled partially
    partialFill?: {
      /// Byte offset of the fill amount parameter in tx.data
      offset: number,
      /// Minimum fillable amount of baseToken, with up to 18 decimal places
      minBaseTokenAmount: string
    },
    /// List of allowances that trader should approve before executing settlement transaction
    allowances: [{
      /// Address of the Token
      token: string,
      /// Address of the spender 
      spender: string,
      /// Amount of the token to approve
      amount: string,
    }]
  }]
}
```

Market makers can provide multiple quote levels with different amounts, but the quoted amounts will not exceed those specified in the RFQ.

Example\
For an RFQ where:

* baseToken = ETH
* quoteToken = USDT
* baseTokenAmount = 1 ETH

The resulting quote may contain these levels:&#x20;

Level 0: Exchange 1 ETH for 3,000 USDT&#x20;

Level 1: Exchange 0.5 ETH for 1,502 USDT&#x20;

Level 2: Exchange 0.1 ETH for 310 USDT

<mark style="color:red;">**IMPORTANT NOTE**</mark>: While solvers typically execute a single quote level, it is technically possible to execute multiple quote levels if they come from different market makers. \
When using multiple quote levels, ensure that they come from different makers, as quotes from the same maker will result in only one successful execution.

### Error handling

When the application cannot return any quote levels, the response is still HTTP `200`, but an `error` object is set. \
It has three fields: `category` (`service` or `client`), `reason` (a stable, machine-readable identifier — branch on this), and `message` (human-readable detail for logs).

`service` means the request is valid but the application or its maker network can't fulfill it right now — retrying later may help. `client` means the request violates a business rule and must be fixed before retrying.

```
{
    "rfqId": "c99d2e3f-702b-49c9-8bb8-43775770f2f3",
    "liquidityAvailable": false,
    "levels": [],
    "error": {
        "category": "client",
        "reason": "invalid_request",
        "message": "Expiration is in the past"
    }
}
```

Possible `reason` values:

* `makers_unavailable` *(service)* — no makers are connected, or the RFQ could not be dispatched to any eligible maker.
* `quote_deadline` *(service)* — the RFQ was dispatched, but no maker returned a usable quote before the deadline.
* `invalid_request` *(client)* — payload failed domain validation (expiry, amounts, `baseToken == quoteToken`, etc.); see `message`.
* `unsupported_token` *(client)* — `baseToken` or `quoteToken` is not supported on this `chainId`.
* `effective_trader_not_whitelisted` *(client)* — the effective trader is not whitelisted on this chain.
* `no_eligible_price_levels` *(client)* — no connected maker has price levels covering this pair/amount; consult price levels first.
* `all_makers_excluded` *(client)* — every connected maker is in `excludedMakers`.

### 5.1. Partial fills

The quote level's `partialFill.offset` field specifies the byte offset of `filledTakerAmount` parameter within tx.data.

The partial fill amount must be greater than or equal to `partialFill.minBaseTokenAmount`.

If the `partialFill` field is not present, the quote level must be filled completely.

```javascript
let calldata = tx.data.slice(0, 10 + partialFill.offset * 2) // Calldata up to offset. 2 is for `0x` prefix and 8 for the function selector.
    + fillAmount.toString(16).padStart(64, "0") // Replace with partial fill amount in hex, padded to 64 chars
    + tx.data.slice(10 + partialFillOffset * 2 + 64); // Remaining calldata after filledTakerAmount
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://liquorice.gitbook.io/liquorice-docs/for-solvers/rest-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
