# Get Orderbook Source: https://docs.kipseli.capital/api-reference/get-price get /v2/price Returns the latest cached on-chain orderbook for all configured token pairs. The cache refreshes on every new block via `eth_subscribe`, so the data always reflects the most recent chain state. Each pair has a `baseToken` (the traded token, e.g. WETH) and a `quoteToken` — the chain's quote stablecoin: USDC on Base (`8453`), USDT on BNB Chain (`56`), USDG on Robinhood Chain (`4663`). Prices are expressed as **quote token per base token** (decimal strings). Amounts are **human-readable base token quantities** (decimal strings). Levels are **marginal** — each level is an independent price point, not cumulative depth. `bids` are sorted descending (best bid first); `asks` are sorted ascending (best ask first). Use the `chainId` query parameter to select the chain. Omitting it (or passing `0`) targets the default chain, Base (`8453`). `chainId`, `blockNumber`, and `blockTime` in the response all belong to the selected chain. Returns the live on-chain orderbook for all configured token pairs on a given chain. The cache is refreshed on every new block via `eth_subscribe`, so the response always reflects the most recent chain state. Use this endpoint to get current market prices before executing a swap, or to display market depth to users. ## Selecting a Chain Pass the target chain with the `chainId` query parameter: ```bash theme={null} # Base (8453) curl "https://propamm.kipseli.win/v2/price?chainId=8453" \ -H "X-API-KEY: $KIPSELI_API_KEY" # BNB Chain (56) curl "https://propamm.kipseli.win/v2/price?chainId=56" \ -H "X-API-KEY: $KIPSELI_API_KEY" # chainId omitted — falls back to Base (8453) curl "https://propamm.kipseli.win/v2/price" \ -H "X-API-KEY: $KIPSELI_API_KEY" ``` Each chain quotes against its own stablecoin — the `quoteToken`: | Chain | `chainId` | Quote token | | --------------- | --------- | --------------------------------------------------- | | BNB Chain | `56` | USDT — `0x55d398326f99059fF775485246999027B3197955` | | Base | `8453` | USDC — `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | | Robinhood Chain | `4663` | USDG — `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` | Every pair on a chain shares that chain's quote token, and each pair echoes it in `quoteToken`. Read it on-chain with `getQuoteToken()` on the chain's [QuoteLens helper](/index#contract-addresses) if you need to confirm it at runtime. If `chainId` is omitted (or `0`), the request targets Base (`8453`). The response echoes the resolved chain in `chainId`, and `blockNumber` / `blockTime` refer to that chain. Chain-related failures: | Status | Code | When | | ------ | --------------------- | -------------------------------------------------------------------------- | | 400 | `UNSUPPORTED_CHAIN` | Well-formed `chainId` the service does not serve | | 422 | `VALIDATION_ERROR` | `chainId` is not a base-10 unsigned integer | | 503 | `SERVICE_UNAVAILABLE` | Supported chain with no live orderbook yet (bootstrapping, or RPC is down) | ## Understanding the Orderbook * **bids** — prices at which PropAMM will **buy** the base token (you sell base, receive the quote token). Sorted **descending**. * **asks** — prices at which PropAMM will **sell** the base token (you buy base, pay the quote token). Sorted **ascending**. * **price** is always **quote token per base token** — USDC on Base, USDT on BNB Chain, USDG on Robinhood Chain. * Each level is **marginal** — independent price points, not cumulative depth. * Prices and amounts are **decimal strings** to preserve EVM-scale precision. Quote-token decimals differ per chain — USDC and USDG use **6**, BNB Chain's USDT uses **18**. `price` and `amount` are human-readable decimal strings and unaffected, but any wei-denominated value you compute from them (e.g. `minAmountOut` in [Request Swap Verification](/api-reference/sign-quote)) must be scaled with the right decimals for that chain. A chain whose orderbook has not bootstrapped yet does not return an empty book — it returns `503 SERVICE_UNAVAILABLE`. A `200` with an empty `pairs` array means the chain is live but currently tracks no pairs. ## Alternative: On-chain Quote For a precise quote for a specific input amount, use the on-chain `quote()` function with an EIP-712 signature. See the [Integration Guide](/index#getting-a-quote). *** ## Query Parameters | Parameter | Type | Required | Description | | --------- | ------- | -------- | ------------------------------------------------------------------------ | | `chainId` | integer | No | Chain to return the orderbook for. Omitted or `0` targets `8453` (Base). | *** ## Response Fields ### Top-level | Field | Type | Description | | ------------- | ------- | -------------------------------------------------------- | | `chainId` | integer | Chain this orderbook belongs to (the resolved `chainId`) | | `blockNumber` | integer | Block at which the orderbook was last refreshed | | `blockTime` | integer | Unix timestamp (seconds) of that block | | `pairs` | array | One entry per pair configured on that chain | ### `pairs[].PairOrderbook` | Field | Type | Description | | ------------ | ------ | ----------------------------------------------------------- | | `baseToken` | string | EVM address of the traded token (e.g. WETH) | | `quoteToken` | string | EVM address of the chain's quote token (USDC / USDT / USDG) | | `bids` | array | Buy-side levels, sorted by descending price | | `asks` | array | Sell-side levels, sorted by ascending price | ### `bids[].OrderbookLevel` / `asks[].OrderbookLevel` | Field | Type | Description | | -------- | ------ | ------------------------------------------------------------- | | `price` | string | Quote token per base token, decimal string (e.g. `"3200.50"`) | | `amount` | string | Base token quantity, decimal string (e.g. `"1.5"`) | # Request Swap Verification Source: https://docs.kipseli.capital/api-reference/sign-quote post /v2/swap/sign ABI-encodes `(tokenIn, tokenOut, timestamp, fee, originRate, userAddress)`, Keccak256-hashes the payload, and signs it with secp256k1. The recovery ID is adjusted from `[0,1]` to `[27,28]` per the Ethereum Yellow Paper. The response contains ABI-encoded verification data `(fee, originRate, userAddress, signature)` ready for on-chain submission. Use the `chainId` body field to select the chain the swap will be executed on; the token pair must be supported there. Omitting it (or passing `0`) targets the default chain, Base (`8453`). Note that the signed payload itself does **not** include the chain id — `chainId` selects which chain's pair list and signing key are used. Before executing a swap on-chain, call this endpoint to obtain `verificationData` and `timestamp`. Both values must be passed directly into the `swap()` function — if either is modified or expired, the transaction will revert. Optionally, pass `amountIn` (and `minAmountOut`) to receive pre-built `calldata` ready for direct submission. ## Selecting a Chain Pass the target chain in the request body with `chainId`: | Chain | `chainId` | Router (PropAmm) | Quote token | | --------------- | --------- | -------------------------------------------- | ----------- | | BNB Chain | `56` | `0x4cb2140C29518db6203f661B9F6dD60B68BB7f0d` | USDT | | Base | `8453` | `0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99` | USDC | | Robinhood Chain | `4663` | `0x4f1ce663bF2E5e3b4A4ba88F6D1BF227e5597402` | USDG | Every pair is base token / quote token, so the stablecoin leg of your `tokenIn`/`tokenOut` must be that chain's quote token — USDT on BNB Chain, not USDC. See [Get Orderbook](/api-reference/get-price#selecting-a-chain) for addresses. If `chainId` is omitted (or `0`), the request targets Base (`8453`). `chainId` selects which chain's pair list is validated against and which signing key is used — the token pair must be supported on that chain, or the request fails with `400 PAIR_NOT_FOUND`. An unsupported chain returns `400 UNSUPPORTED_CHAIN`. ## Swap Execution Flow ### Step 1 — Call this endpoint **Minimal (verification data only):** ```bash theme={null} curl -X POST https://propamm.kipseli.win/v2/swap/sign \ -H "Content-Type: application/json" \ -H "X-API-KEY: $KIPSELI_API_KEY" \ -d '{ "chainId": 8453, "tokenIn": "0x4200000000000000000000000000000000000006", "tokenOut": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "fee": "30", "userAddress": "0x1111111111111111111111111111111111111111" }' ``` **Response:** ```json theme={null} { "verificationData": "0x...", "timestamp": 1741737600 } ``` **With calldata (pass `amountIn` and optionally `minAmountOut`):** ```bash theme={null} curl -X POST https://propamm.kipseli.win/v2/swap/sign \ -H "Content-Type: application/json" \ -H "X-API-KEY: $KIPSELI_API_KEY" \ -d '{ "chainId": 8453, "tokenIn": "0x4200000000000000000000000000000000000006", "tokenOut": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "fee": "30", "userAddress": "0x1111111111111111111111111111111111111111", "amountIn": "1000000000000000000", "minAmountOut": "3150000000" }' ``` **Response:** ```json theme={null} { "verificationData": "0x...", "timestamp": 1741737600, "calldata": "0x..." } ``` The `calldata` field is ABI-encoded for `swap(address,uint256,address,uint256,uint256,bytes)` and can be submitted directly to the router without further encoding. ### Step 2 — Approve the Router Use the Router for the chain you passed as `chainId` (see [Selecting a Chain](#selecting-a-chain)). The example below is Base. ```solidity theme={null} IERC20(tokenIn).approve( 0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99, // Router on Base (8453) amountIn ); ``` ### Step 3 — Execute the swap on-chain **Option A — build the call yourself:** ```solidity theme={null} IPropAmm(0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99).swap( // Router on Base (8453) tokenIn, amountIn, tokenOut, minOutAmount, // slippage protection — use quote() to calculate timestamp, // from API response verificationData // from API response ); ``` | Parameter | Description | | ------------------ | ---------------------------------------------------------------- | | `tokenIn` | Input token address | | `amountIn` | Amount of input token (in token decimals) | | `tokenOut` | Output token address | | `minOutAmount` | Minimum acceptable output — set this to protect against slippage | | `timestamp` | Returned by this API — pass through unchanged | | `verificationData` | Returned by this API — pass through unchanged | **Option B — use the `calldata` from the API (requires `amountIn` in Step 1):** ```solidity theme={null} // Router on Base (8453) (bool success, ) = address(0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99).call(calldata); require(success, "swap failed"); ``` The `calldata` is already ABI-encoded for `swap(address,uint256,address,uint256,uint256,bytes)` — no further encoding needed. *** ## Request Fields | Field | Type | Required | Description | | -------------- | ------- | -------- | -------------------------------------------------------------------------- | | `chainId` | integer | No | Chain the swap will be executed on. Omitted or `0` targets `8453` (Base). | | `tokenIn` | string | Yes | Input token address on `chainId` | | `tokenOut` | string | Yes | Output token address on `chainId` | | `fee` | string | Yes | Fee tier in 0.1 bps resolution — see [Fee Parameter](#fee-parameter) | | `userAddress` | string | Yes | Address that will submit the swap | | `amountIn` | string | No | Input amount in wei. When provided, the response includes `calldata` | | `minAmountOut` | string | No | Minimum accepted output in wei. Only used with `amountIn`; defaults to `0` | *** ## Fee Parameter The `fee` field uses **0.1 bps resolution**: | Value | Rate | | ----- | ---------------- | | `1` | 0.1 bps (0.001%) | | `10` | 1 bps (0.01%) | | `30` | 3 bps (0.03%) | | `100` | 10 bps (0.10%) | The fee is deducted from the output amount (`amountOut`) and settled monthly in a mutually agreed currency. # Kipseli PropAMM Source: https://docs.kipseli.capital/index Integrate with Kipseli PropAMM — a professional AMM for token swaps on Base, BNB Chain and Robinhood Chain ## What is Kipseli PropAMM? Kipseli PropAMM is a professional Automated Market Maker deployed on Base, BNB Chain and Robinhood Chain that enables token swaps with competitive, on-chain pricing. Integrators can get quotes and execute swaps by combining on-chain contract calls with a lightweight signing API. ## Contract Addresses The **Router (PropAmm)** is the contract you approve `tokenIn` on and call `swap()` / `quote()` against. The **Helper (QuoteLens)** is a read-only view contract for listed tokens and reserves. | Chain | Router (PropAmm) | Helper (QuoteLens) | QuoteToken | | --------------- | -------------------------------------------- | -------------------------------------------- | ---------- | | BNB Chain | `0x4cb2140C29518db6203f661B9F6dD60B68BB7f0d` | `0x6E56480F8D8e17A1c7148f43BC3762E59C3Abe90` | USDT | | Base | `0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99` | `0x62aFF80b3d2afE0E497f1ef735a6FDc9C3ef1acF` | USDC | | Robinhood Chain | `0x4f1ce663bF2E5e3b4A4ba88F6D1BF227e5597402` | `0xABa7C80918d8127C23BE2bef649832050a0Cf08a` | USDG | The **EIP-712 Verifier** is deployed at the same address on every chain — `0xCa369e97cc161c3c3a7368f9bC55A47F36a0A91E`. Only the `chainId` in the EIP-712 domain changes per chain. See [EIP-712 Signature](#eip-712-signature). *** ## Contract Interfaces ### Router (IPropAmm) ```solidity theme={null} interface IPropAmm { function swap( address tokenIn, uint amountIn, address tokenOut, uint minOutAmount, uint quoteTimestamp, bytes calldata verificationData ) external returns (uint amountOut); function quote( address tokenIn, uint amountIn, address tokenOut, uint timestampInMilisec, bytes memory sig ) external view returns (uint amountOut); } ``` ### Helper (IQuoteLens) ```solidity theme={null} interface IQuoteLens { function getListedTokens() external view returns (address[] memory); function getQuoteToken() external view returns (address); function getReserveBalances(address[] memory tokens) external view returns (uint[] memory); } ``` *** ## Whitelist Requirement Both on-chain quoting (EIP-712 signature) and the swap signing API require your address to be **whitelisted**. Contact the Kipseli team and provide your signing address to get access. ## API Authentication All HTTP API endpoints (`/v2/*`) require an API key. Pass it on every request via the `X-API-KEY` header: ```bash theme={null} -H "X-API-KEY: $KIPSELI_API_KEY" ``` Contact the Kipseli team to obtain your API key. Requests with a missing or invalid key return `401 UNAUTHORIZED`. *** ## Integration Overview ### Getting a Quote Choose one of two methods: **Method 1 — On-chain via EIP-712 signature** 1. Generate `timestampInMilisec` (current time in ms). Must be within **10 seconds** of the current block. 2. Sign the EIP-712 typed data with your whitelisted key (see [EIP-712 Signature](#eip-712-signature) below). 3. Call `quote(tokenIn, amountIn, tokenOut, timestampInMilisec, signature)` on the Router. 4. Receive `amountOut` — your expected output amount. **Method 2 — Off-chain via API** Call `GET /v2/price?chainId=` to get the live on-chain orderbook for all configured pairs on that chain. If `chainId` is omitted, it falls back to Base (`8453`). See [Get Orderbook](/api-reference/get-price). *** ### Executing a Swap **Step 1 — Get verification data** Call `POST /v2/swap/sign` with your swap parameters, including `chainId` for the chain you are trading on (omitted falls back to Base `8453`). The API returns `verificationData` and `timestamp`. Optionally pass `amountIn` (and `minAmountOut`) to also receive pre-built `calldata`. See [Request Swap Verification](/api-reference/sign-quote). **Step 2 — Approve the Router** ```solidity theme={null} IERC20(tokenIn).approve( 0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99, amountIn ); ``` **Step 3 — Call `swap()`** *Option A — build the call yourself:* ```solidity theme={null} IPropAmm(0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99).swap( tokenIn, amountIn, tokenOut, minOutAmount, // slippage protection — derive from quote() timestamp, // from API response verificationData // from API response ); Both `timestamp` and `verificationData` must be passed directly from the API response without modification. If either is changed or expired, the transaction will revert. ``` *Option B — use the `calldata` returned by the API (requires `amountIn` in Step 1):* ```solidity theme={null} (bool success, ) = address(0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99).call(calldata); require(success, "swap failed"); ``` *** ## EIP-712 Signature To call `quote()` on-chain, you must sign the following struct with a whitelisted key: ```solidity theme={null} PropAmmVerification( address tokenIn, address tokenOut, uint256 timestampInMilisec ) ``` **Domain:** ```json theme={null} { "name": "VerificationImpl", "version": "1", "chainId": 8453, "verifyingContract": "0xCa369e97cc161c3c3a7368f9bC55A47F36a0A91E" } ``` `verifyingContract` is the same on every chain — set `chainId` to the chain you are trading on (`56` BNB Chain, `8453` Base, `4663` Robinhood Chain). **Example (ethers.js):** ```javascript theme={null} const domain = { name: "VerificationImpl", version: "1", chainId: 8453, verifyingContract: "0xCa369e97cc161c3c3a7368f9bC55A47F36a0A91E", }; const types = { PropAmmVerification: [ { name: "tokenIn", type: "address" }, { name: "tokenOut", type: "address" }, { name: "timestampInMilisec", type: "uint256" }, ], }; const value = { tokenIn, tokenOut, timestampInMilisec }; const signature = await signer.signTypedData(domain, types, value); // Call on-chain: // quote(tokenIn, amountIn, tokenOut, timestampInMilisec, signature) ``` *** ## Fee Structure The `fee` field in swap requests uses **0.1 bps resolution**: | Value | Rate | | ----- | ---------------- | | `1` | 0.1 bps (0.001%) | | `10` | 1 bps (0.01%) | | `30` | 3 bps (0.03%) | | `100` | 10 bps (0.10%) | * Fee is **deducted from the output amount** (`amountOut`). * Fees are **settled monthly** in a mutually agreed currency (e.g. USDC, ETH). ## Error Format All API errors follow a consistent envelope: ```json theme={null} { "error": { "code": "VALIDATION_ERROR", "message": "tokenIn: invalid EVM address", "requestId": "abc-123" } } ``` | Code | HTTP Status | Description | | --------------------- | ----------- | ----------------------------------------------------------- | | `INVALID_JSON` | 400 | Malformed or missing JSON body | | `UNSUPPORTED_FIELD` | 400 | Unknown field in request body | | `UNSUPPORTED_CHAIN` | 400 | `chainId` is not a chain the service serves | | `PAIR_NOT_FOUND` | 400 | Token pair is not tracked on the selected chain | | `UNAUTHORIZED` | 401 | Missing or invalid API key | | `VALIDATION_ERROR` | 422 | Field-level validation failure | | `SIGNING_FAILED` | 500 | secp256k1 signing error | | `ENCODING_FAILED` | 500 | ABI encoding error | | `INTERNAL_ERROR` | 500 | Unexpected server error | | `SERVICE_UNAVAILABLE` | 503 | Chain has no live orderbook yet (bootstrapping or RPC down) |