Skip to main content
An OTC trade on Velora is a deal between two parties who already know each other. The maker signs an AugustusRFQ order off-chain and posts it to the REST API; the taker fills it on-chain. The taker field decides who that can be: name an address for a private, P2P trade, or leave the zero address to let anyone fill. To start, tag your app with any partner string.
  • Name the taker and the order is fillable by exactly one address: bilateral OTC rather than a public order.
  • The maker sets price, size, token pair, and expiry directly; nothing is exposed as a public order before it settles.
  • Offering is gasless. The maker only signs (EIP-712) and posts, and the taker pays gas on the fill.
  • A taker can fill less than the full makerAmount; the order stays live for the remainder until expiry.
  • The fill resolves on-chain through AugustusRFQ, so the outcome is auditable and non-custodial.
Want an open, target-price order any solver can fill, gasless and MEV-protected? That’s a Delta limit order, not OTC. Call GET /v2/quote and submit with type=LIMIT via POST /v2/delta/orders. This RFQ surface is specifically for bilateral OTC/P2P settlement against a known counterparty.

Lifecycle

1

Approve

The maker approves the AugustusRFQ contract to pull the makerAsset they’re selling. AugustusRFQ is its own contract, separate from the Augustus v6.2 router. Native ETH must be wrapped first.
2

Build & sign

The maker builds the order (nonceAndMeta, expiry, makerAsset, takerAsset, makerAmount, takerAmount, maker, taker) and signs the EIP-712 typed data. The domain is name: "AUGUSTUS RFQ", version: "1", chainId, and verifyingContract set to the AugustusRFQ address.
3

Post

POST /ft/p2p/{chainId}/ with the signed order and signature. The server returns the stored order with its orderHash and state. Size against GET /ft/fillablebalance/{chainId}/{address} first; it returns the lesser of the maker’s balance, allowance, and unreserved amount.
4

Deliver

Hand the signed order to the taker over any off-chain channel: your backend, the API listing endpoints, or directly.
5

Fill

The taker approves AugustusRFQ for the takerAsset, then calls AugustusRFQ.fillOrder on-chain. The contract verifies the signature and the named taker, then settles atomically. This is an on-chain transaction, not a REST call. The fill reverts if the order is expired, already filled, or the caller isn’t the named taker.

Endpoints

MethodPathPurpose
POST/ft/p2p/{chainId}/Post a signed maker order — body carries the order fields plus signature and optional permitMakerAsset
GET/ft/order/{orderHash}Fetch a single order by hash
GET/ft/p2p/{chainId}/maker/{address}List a maker’s orders — limit, offset, orderBy, hideSmallBalances
GET/ft/p2p/{chainId}/taker/{address}List orders addressed to a taker
GET/ft/fillablebalance/{chainId}/{address}Maker’s fillable balance for order sizing, optionally scoped to a token
Everything lives under https://api.velora.xyz. Filling and cancelling are on-chain calls to AugustusRFQ, not REST endpoints (see Filling an order and Cancelling an order). AugustusRFQ is deployed on Ethereum, Arbitrum, Avalanche, Base, BSC, Gnosis, Optimism, and Polygon; see Chains & contracts for per-chain addresses and availability.

Filling an order

Once the maker has posted an order, the named taker can fill it programmatically or through a Velora interface; both settle through the same AugustusRFQ.fillOrder call on-chain.
  • For bots, backends, and market-maker systems: approve AugustusRFQ for the takerAsset, then call fillOrder directly, or use sdk.otcOrders.fillOTCOrder({ order, signature }), which encodes and submits the transaction for you.
  • From the Velora app: every order has a shareable fill link keyed on its orderHash. Hand it to the counterparty and they approve and fill from the web app:
    https://app.velora.xyz/#/FT/OTC/{orderHash}
    
  • Inside the Velora Widget: the same OTC fill flow runs embedded, so partners can offer it in-app without sending users to app.velora.xyz.
Whichever path the taker uses, the same on-chain checks apply: expired, already-filled, or wrong-taker fills revert.

Cancelling an order

There is no cancel endpoint. A maker cancels by sending a transaction to the AugustusRFQ contract (the same contract that verifies fills), so cancellation costs gas. This is the one place the OTC flow differs sharply from Delta, where cancellation is a gasless signed message to the relayer. AugustusRFQ exposes two methods, both taking the order’s orderHash (the EIP-712 hash returned when the order was posted):
MethodSignatureUse
cancelOrdercancelOrder(bytes32 orderHash)Cancel a single order
cancelOrderscancelOrders(bytes32[] orderHashes)Cancel many in one transaction — cheaper than one tx each
Cancelling marks the hash as cancelled on-chain, so any later fillOrder against it reverts. Send it from the maker wallet. Once the transaction is indexed, the order’s state flips to CANCELLED and its transactionHash is populated. From the SDK, use sdk.otcOrders.cancelOTCOrder(orderHash).
Letting an order lapse past its expiry makes it unfillable with no transaction and no gas. For short-lived orders, a tight expiry is often cheaper than an explicit cancel.

Order states

An order reports one of six states: DRAFT, PENDING, FULFILLED, CANCELLED, SUSPENDED (the maker’s balance or allowance dropped below the order), and EXPIRED. Always re-check expiry against the current block before filling.

SDK shortcut

Every step is wrapped by sdk.otcOrders.*: maker approvals, build → sign → post (submitOTCOrder), taker approval and fillOTCOrder, plus getOTCOrders and cancelOTCOrder. For a copy-paste maker/taker walkthrough see SDK → OTC.
Last modified on June 11, 2026