DEVELOPERS Integrate the Relayer API Integrate just-in-time mint/redeems of 80+ uAssets directly in your app or protocol.
The Universal Relayer API allows developers to seamlessly integrate uAssets into their applications. The Relayer acts as an intermediary, connecting users with Merchants to facilitate buying, selling, and cross-chain transactions.
What is the Relayer?
DeFi typically relies on liquidity pools (LPs) to provide assets for swaps. However, LPs are capital inefficient because liquidity sits unused until needed.
Universal solves this with JIT (just-in-time) Liquidity via the Universal Relayer meaning:
Instead of pre-depositing liquidity, Merchants mint and fulfill orders dynamically when demand arises.
Liquidity is provided on an as-needed basis, optimizing capital efficiency.
To obtain API access with higher rate limits, please reach out to the Universal Partnerships team for an API key.
BasicsAPI Basics
Base URL
This is the base URL for all API requests.
Copy https://relayer.universal.xyz/api (with an API key)
https://www.universal.xyz/api (without an API key)
Authentication
All API requests require authentication via a Bearer Token .
Copy Authorization: Bearer <YOUR_API_KEY>
Ensure that your API key is included in every request to authenticate and authorize API usage.
TypesTokenName
: BTC, SOL, XRP, DOGE, DOT, NEAR, LTC, ADA, BCH, ALGO
Quote
Copy type: "BUY" | "SELL";
token: TokenName;
token_amount: string; // wei
pair_token: PairTokenName;
slippage_bips: number; // 0-100
blockchain: BlockchainName;
deadline: string; // unix epoch
pair_token_amount: string; // wei
id: string;
user_address: string; // 0x..
merchant_address: string; // 0x..
gas_fee_nominal: string; // wei
gas_fee_dollars: number; // e.g. $1.23 = 1.23
relayer_nonce: number;
merchant_id: string;
Requesting a QuoteSend a Quote Request
To retrieve a price quote for a uAsset transaction, make a POST
request to the following endpoint:
Request Body Parameters
type
: Specifies if the user wants to BUY
or SELL
.
token
: The uAsset being bought or sold.
token_amount
: (Optional) The amount of the asset being transacted.
pair_token
: The stable asset used for the trade (e.g., USDC).
pair_token_amount
: (Optional) The amount of the paired asset.
slippage_bips
: Slippage tolerance in basis points (0-100).
blockchain
: The blockchain network where the transaction is executed.
user_address
: The wallet address initiating the trade.
Copy {
type: "BUY" | "SELL";
token: TokenName;
token_amount?: string;
pair_token_amount?: string;
pair_token: PairTokenName;
slippage_bips: number;
blockchain: BlockchainName;
user_address: string;
}
Response (200 OK)
Upon success, the API returns a quote containing:
A unique quote ID
for later use
Signing a QuoteUser Signs the Quote
The user must sign the quote using EIP-712 signature standards before submitting the order.
Example Code (Signing a Quote with EIP-712)
Copy import { DutchOrderBuilder } from "@uniswap/uniswapx-sdk";
import { BigNumber } from "ethers5"; // ethers v5
type TokenName = "BTC" | "SOL" | "XRP" | "DOGE" | "DOT" | "NEAR" | "LTC" | "ADA" | "BCH" | "ALGO";
type PairTokenName = "USDC";
type BlockchainName = "BASE";
interface Quote {
type: "BUY" | "SELL";
token: TokenName;
token_amount: bigint;
pair_token: PairTokenName;
slippage_bips: number;
blockchain: BlockchainName;
deadline: bigint;
pair_token_amount: bigint;
id: string;
user_address: string;
merchant_address: string;
gas_fee_nominal: bigint;
gas_fee_dollars: number;
relayer_nonce: number;
}
const CHAIN_ID: number = <CHAIN_ID>;
const REACTOR_ADDRESS: string = <REACTOR_ADDRESS>;
const PERMIT2_ADDRESS: string = <PERMIT2_ADDRESS>;
async function signTypedQuote(quote: Quote) {
const builder = new DutchOrderBuilder(
CHAIN_ID,
REACTOR_ADDRESS,
PERMIT2_ADDRESS
);
const TOKEN_ADDRESS = <TOKEN_ADDRESS>;
const PAIR_TOKEN_ADDRESS = <PAIR_TOKEN_ADDRESS>;
const order = builder
.deadline(Number(quote.deadline))
.decayEndTime(Number(quote.deadline))
.decayStartTime(Number(quote.deadline) - 100)
.nonce(BigNumber.from(quote.relayer_nonce))
.input({
token: quote.type == "BUY" ? PAIR_TOKEN_ADDRESS : TOKEN_ADDRESS,
startAmount:
quote.type == "BUY"
? BigNumber.from(quote.pair_token_amount.toString())
: BigNumber.from(quote.token_amount.toString()),
endAmount:
quote.type == "BUY"
? BigNumber.from(quote.pair_token_amount.toString())
: BigNumber.from(quote.token_amount.toString()),
})
.output({
token: quote.type == "BUY" ? TOKEN_ADDRESS : PAIR_TOKEN_ADDRESS,
startAmount:
quote.type == "BUY"
? BigNumber.from(quote.token_amount.toString())
: BigNumber.from(quote.pair_token_amount.toString()),
endAmount:
quote.type == "BUY"
? BigNumber.from(quote.token_amount.toString())
: BigNumber.from(quote.pair_token_amount.toString()),
recipient: quote.user_address,
})
.swapper(quote.user_address)
.exclusiveFiller(quote.merchant_address, BigNumber.from(0))
.build();
const { domain, types, values } = order.permitData();
const primaryType: "PermitWitnessTransferFrom" = "PermitWitnessTransferFrom";
const typedData = {
domain,
types,
primaryType,
message: values,
};
const signer = <SIGNER>;
const signature = await signer.signTypedData(typedData);
return signature;
}
Submitting an OrderSubmit a Signed Order
Once the quote is signed, submit it using the /order
endpoint:
Request Body Parameters
This request includes the signed quote along with the necessary parameters from the previous steps.
Copy {
...Quote,
"signature": string, // Quote signed by the user
}
Response (200 OK)
Upon success, the API will return the transaction hash confirming the execution of the trade.Response
Copy {
"transaction_hash": string // Transaction hash of the fulfillment
}