Skip to main content
This page is for integrators calling the Velora Delta HTTP API directly. If you’re on the Velora SDK, the SDK-level migration walks the same path with TypeScript snippets; see SDK → Migrate from V1 to V2.

What breaks if you do nothing

Nothing. Delta V1 (/delta/*) remains fully supported and shares on-chain contracts with V2. Your existing integration keeps working as-is.

Why migrate

V2 keeps the same on-chain settlement model. The main reason to migrate is that V2 is built crosschain-first: same-chain and crosschain intents share one route model, so you quote the source chain, optionally add destChainId, and pass the returned route into build unchanged. That crosschain-first model also cleans up the protocol surface:
  • Crosschain is native to pricing. GET /v2/quote or GET /v2/delta/prices returns a recommended route with route.bridge populated for crosschain, plus alternatives when other bridge routes are available.
  • Orders are built server-side. POST /v2/delta/orders/build returns EIP-712 typed data ready to sign, and you stop composing domain, types, and value on the client.
  • Pricing is route-based. The route replaces the bridge / bridgeInfo / availableBridges triple V1 returns.
  • Limit orders use the same build flow. Add limitAmount to POST /v2/delta/orders/build, then submit the signed order with type: "LIMIT".
  • Order history is paginated. GET /v2/delta/orders returns { data, total, page, limit, hasMore } where V1 returns a flat array with no total.
  • Status is a single field. Twelve values (PENDING, AWAITING_SIGNATURE, ACTIVE, SUSPENDED, CANCELLING, BRIDGING, COMPLETED, FAILED, EXPIRED, REFUNDING, CANCELLED, REFUNDED) replace V1’s status + bridgeStatus pair.
  • Partner fees resolve on the server. Pass partner / partnerAddress / partnerFeeBps directly on every call; the separate GET /prices/partnerfee/{chainId} round-trip goes away.
  • The hmac is gone. V2 doesn’t sign the price payload, so there’s no opaque blob to thread from /prices into /orders/build.

Endpoint mapping

V1V2Notes
GET /delta/pricesGET /v2/delta/pricesResponse carries route + alternatives; price.hmac removed
GET /delta/prices/bridge-infoGET /v2/delta/prices/bridge-routesFlat routes[] array instead of nested srcChainId → destChainId → tokens[] map
GET /delta/prices/bridge-protocolsGET /v2/delta/prices/bridge-protocolsSame shape
GET /delta/prices/strategies/{chainId}GET /v2/delta/prices/strategies/{chainId}Same shape
GET /delta/prices/is-token-supportedGET /v2/delta/prices/is-token-supportedSame shape
GET /prices/partnerfee/{chainId}Not neededPass partner / partnerAddress / partnerFeeBps raw on every V2 call
POST /delta/orders/buildPOST /v2/delta/orders/buildDifferent body — pass route (not price + hmac); response wraps typed data in toSign
POST /delta/ordersPOST /v2/delta/ordersSubmit order: built.toSign.value instead of data from V1 build
POST /delta/orders/cancelPOST /v2/delta/orders/cancelSame shape
GET /delta/ordersGET /v2/delta/ordersWraps array in { data, total, page, limit, hasMore }
GET /delta/orders/{orderId}GET /v2/delta/orders/{orderId}New response shape — input / output carry expected + executed amounts
GET /delta/orders/hash/{hash}GET /v2/delta/orders/hash/{hash}Same as above
GET /delta/orders/fillablebalance/...GET /v2/delta/orders/fillablebalance/...Same shape
GET /delta/agents/list/{chainId}GET /v2/delta/agents/list/{chainId}Same shape
GET /quote (mode=ALL)GET /v2/quoteDelta-or-Market fallback still exists; branch on top-level delta or market

Steps

1. Pricing

V1 returns a flat price object with a server-signed hmac. V2 returns a structured route plus alternatives. You can read that Delta route directly from GET /v2/delta/prices, or from the delta block of GET /v2/quote?mode=DELTA.
- GET /delta/prices?chainId=1&srcToken=0x...&destToken=0x...&amount=...&partner=my-app-name
+ GET /v2/delta/prices?chainId=1&srcToken=0x...&destToken=0x...&amount=...&partner=my-app-name
If your V1 integration used the unified quote path, migrate it to /v2/quote:
- GET /quote?chainId=1&srcToken=0x...&destToken=0x...&amount=...&mode=ALL&partner=my-app-name
+ GET /v2/quote?chainId=1&srcToken=0x...&destToken=0x...&amount=...&mode=ALL&partner=my-app-name
With mode=ALL, V2 returns one path for you to handle: a top-level delta block when Delta can price the trade, or a top-level market block when it falls back to Market. Do not expect both blocks in one response. V1 response:
{
  "price": {
    "srcToken": "0x...", "destToken": "0x...",
    "srcAmount": "...", "destAmount": "...",
    "partner": "my-app-name", "partnerFee": 0.05,
    "bridge": { "destinationChainId": 0, "protocolSelector": "0x00000000", ... },
    "hmac": "0x..."
  },
  "deltaAddress": "0x..."
}
V2 response:
{
  "id": "req_...",
  "side": "SELL",
  "inputToken": { "chainId": 1, "address": "0x..." },
  "outputToken": { "chainId": 8453, "address": "0x..." },
  "route": {
    "origin": { "input": { ... }, "output": { ... } },
    "destination": { "input": { ... }, "output": { ... } },
    "bridge": { "...": "present for crosschain, null for same-chain" },
    "fees": { "gas": { ... }, "bridge": [] }
  },
  "alternatives": [],
  "partner": { "name": "my-app-name", "feePercent": 0.05 },
  "spender": "0x..."
}
Handle these in your client:
  • price.hmac is gone; don’t thread it into /orders/build.
  • deltaAddress moved to spender. Approve spender as the ERC-20 spender (the on-chain Delta contract address itself is unchanged).
  • Bridge detection changed. V1 used bridge.destinationChainId !== 0; V2 sets route.bridge to null for same-chain and populates it for crosschain. Read route.origin.input.token.chainId vs route.destination.output.token.chainId if you need a direct check.

2. Build

V1 takes the price object + hmac. V2 takes the route plus order params on top. Pass the route from GET /v2/delta/prices, or delta.route from GET /v2/quote, without editing it.
  POST /delta/orders/build
  {
-   "chainId": 1,
-   "owner": "0x...",
-   "price": { /* the full delta price object including hmac */ },
-   "slippage": 100
+   /* request goes to /v2/delta/orders/build instead */
  }

+ POST /v2/delta/orders/build
+ {
+   "owner": "0x...",
+   "route": { /* the route from /v2/delta/prices, verbatim */ },
+   "side": "SELL",
+   "slippage": 100,
+   "deadline": 1893456000,
+   "partner": "my-app-name",
+   "partnerFeeBps": 25
+ }
The chain ID is no longer part of the build request; V2 derives it from the route.
V1 returned { data, orderHash, domain, types }, where data was the on-chain Order struct. V2 returns { toSign: { domain, types, value }, orderHash }: value is the on-chain Order struct, wrapped one level deeper.
  // V1 response
- {
-   "data":  { /* on-chain Order struct */ },
-   "orderHash": "0x...",
-   "domain": { ... },
-   "types":  { ... }
- }

  // V2 response
+ {
+   "toSign": {
+     "domain": { ... },
+     "types":  { ... },
+     "value":  { /* on-chain Order struct, same shape as V1's `data` */ }
+   },
+   "orderHash": "0x..."
+ }

3. Sign

The EIP-712 domain (name: "Portikus", version: "2.0.0", chainId, verifyingContract) is unchanged. The signature you compute over V2’s toSign is the same string V1 would produce over its data/domain/types triple.

4. Submit

V1 took { order, signature, partner, ... }. V2 is the same shape; only the source of order changes.
- POST /delta/orders
+ POST /v2/delta/orders
  {
    "chainId": 1,
-   "order": /* V1 build response's `data` */,
+   "order": /* V2 build response's `toSign.value` */,
    "signature": "0x...",
    "type": "MARKET",
    "partner": "my-app-name"
  }
V2 doesn’t accept referrerAddress differently: same field, same semantics.

5. Limit orders

V1 limit-order code often had a separate builder path. In V2, a limit order is a Delta order with a target-price constraint, so you use the same POST /v2/delta/orders/build endpoint and add limitAmount.
+ POST /v2/delta/orders/build
+ {
+   "owner": "0x...",
+   "route": { /* the route from /v2/quote or /v2/delta/prices, verbatim */ },
+   "side": "SELL",
+   "deadline": 1893456000,
+   "limitAmount": "3000000000000000000",
+   "partner": "my-app-name"
+ }
For SELL orders, limitAmount is the minimum destination amount the user accepts. For BUY orders, it is the maximum source amount the user is willing to spend. The response is still { toSign, orderHash }; after the user signs, submit toSign.value with type: "LIMIT":
+ POST /v2/delta/orders
+ {
+   "chainId": 1,
+   "order": /* V2 build response's `toSign.value` */,
+   "signature": "0x...",
+   "type": "LIMIT",
+   "partner": "my-app-name"
+ }
For the full flow, see Limit order API integration.

6. Poll for status

V1 status (DeltaAuctionStatus) splits into status + bridgeStatus. V2 collapses both into one status field.
- GET /delta/orders/{orderId}
+ GET /v2/delta/orders/{orderId}
Status mapping you’ll need on the client when migrating queries:
V1 (status + bridgeStatus)V2 (status)
NOT_STARTEDPENDING
AWAITING_PRE_SIGNATUREAWAITING_SIGNATURE
RUNNING, EXECUTINGACTIVE
Suspension states (insufficient balance/allowance)SUSPENDED
CANCELLINGCANCELLING
EXECUTED + bridgeStatus: PENDINGBRIDGING
EXECUTED + (same-chain OR bridgeStatus: FILLED)COMPLETED
FAILED, INVALIDATEDFAILED
EXPIRED (or bridgeStatus: EXPIRED)EXPIRED
EXECUTED + bridgeStatus: REFUNDINGREFUNDING
CANCELLEDCANCELLED
REFUNDED (or bridgeStatus: REFUNDED)REFUNDED
V2 separates an in-flight bridge refund from a verified refund. REFUNDING means the bridge leg failed or expired and Velora is still polling for the actual refund transaction. REFUNDED means the refund is complete. V1 order endpoints temporarily map bridgeStatus: REFUNDING back to REFUNDED for compatibility, so migrate status handling before relying on that distinction. The V2 response also restructures order details: input and output each carry { chainId, token, amount } (SELL: input has amount, output has expectedAmount + executedAmount; BUY: vice versa). V1 returned order.srcToken / order.destToken plus a separate transactions[] array. V2 keeps both, but the headline numbers move to input / output. For crosschain refunds, V2 also adds top-level refunds[] to the order response. Each verified refund item has:
{
  "tx": "0x...",
  "chainId": 42161,
  "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
  "amount": "1454437"
}
Treat amounts as raw token units. refunds[] can stay empty while the order is REFUNDING, and it can also be empty for bridge-provider failure modes that do not emit source-chain token refund metadata.

7. List orders

- GET /delta/orders?userAddress=0x...&page=1&limit=100
+ GET /v2/delta/orders?userAddress=0x...&page=1&limit=100
V1 returns a plain array; V2 wraps it:
- [ { "id": "...", "status": "...", ... }, ... ]
+ {
+   "data":    [ { "id": "...", "status": "...", ... }, ... ],
+   "total":   1234,
+   "page":    1,
+   "limit":   100,
+   "hasMore": true
+ }
You now know how many pages remain, which is useful for “load more” UIs without falling back to “fetch until you get fewer than limit”.

8. Cancel

No semantic change: same path under /v2, same request body.
- POST /delta/orders/cancel
+ POST /v2/delta/orders/cancel
  {
    "orderIds":  ["..."],
    "signature": "0x..."
  }

9. Partner fee

V1: integrators called GET /prices/partnerfee/{chainId}?partner=... to look up the registered config, then encoded it into the order locally. V2: just pass partner on every call (/v2/delta/prices, /v2/delta/orders/build, /v2/delta/orders). The server resolves the registered config, validates the fee, and encodes it into the on-chain order. To override per call, pass partnerAddress and partnerFeeBps (and/or partnerTakesSurplus) on the same call.
- // V1: separate round-trip, then re-encode in build params
- const { partnerAddress, partnerFee, takeSurplus } =
-   await fetch(`/prices/partnerfee/${chainId}?partner=${key}`).then(r => r.json());
- POST /delta/orders/build { ..., partnerAddress, partnerFeeBps: partnerFee * 100, ... }

+ // V2: server resolves; just pass `partner`
+ POST /v2/delta/orders/build { ..., partner: "my-app-name" }
GET /prices/partnerfee/{chainId} still exists; keep using it if you need the resolved config for your UI (e.g., to show “0.25% fee” alongside the quote).

Breaking changes you might miss

  • price.hmac is gone in V2. Existing code that re-attaches hmac to the build payload will fail validation.
  • The replacement for V1 GET /quote is GET /v2/quote, not “no quote endpoint.” With mode=ALL, branch on top-level delta or market.
  • Limit orders move onto the standard V2 build path. Add limitAmount to POST /v2/delta/orders/build, then submit with type: "LIMIT".
  • The bridge.destinationChainId !== 0 check breaks. V2 sets route.bridge = null for same-chain; the V1 sentinel is no longer present in V2 responses.
  • bridge-info changed shape, from a nested object to a flat routes[] array, and the replacement endpoint is named bridge-routes.
  • The status enum changed, so your status-handling code needs the mapping table above. Don’t rely on EXECUTED alone: V2 reports COMPLETED for executed-and-finalized orders, BRIDGING while the destination leg is still pending, and REFUNDING while a failed bridge leg is waiting for a verified refund transaction.
  • REFUNDED is now distinct from REFUNDING in V2. If your V1 UI showed any refund state as final, add an in-progress state before moving users to V2.
  • The order list response changed from Order[] to { data: Order[], total, page, limit, hasMore }. Code that does orders.length or orders.map(...) on the response needs to unwrap .data first.

End-state check

  1. GET /v2/quote?mode=DELTA or GET /v2/delta/prices returns a route and a non-empty spender.
  2. POST /v2/delta/orders/build returns { toSign, orderHash }.
  3. The signature your wallet produces over toSign is accepted by POST /v2/delta/orders (status 200, response carries the new order shape with id and status: "PENDING").
  4. GET /v2/delta/orders/{id} polls through ACTIVECOMPLETED (or BRIDGINGCOMPLETED for crosschain). If a bridge refund happens, your UI can show REFUNDING until the order reaches REFUNDED and any verified refunds[] entries appear.
  5. A limit-order build with limitAmount returns { toSign, orderHash }, and the signed order submits with type: "LIMIT".
  6. grep -r "partnerfee\|/delta/prices\b\|/delta/orders\b" your-codebase/: every hit is intentional (e.g., /prices/partnerfee for UI lookup; /delta/orders only if you intentionally stayed on V1).
Last modified on June 15, 2026