> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velora.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Delta V1 to V2

> Endpoint-by-endpoint migration for direct HTTP integrators moving to Delta V2's crosschain-first route model, server-built orders, /v2/quote, and limitAmount.

This page is for integrators calling the Velora Delta HTTP API directly. If you're on the [Velora SDK](/docs/sdk/products/delta), the SDK-level migration walks the same path with TypeScript snippets; see [SDK → Migrate from V1 to V2](/docs/sdk/products/delta#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

| V1                                       | V2                                                                                         | Notes                                                                                                                                          |
| ---------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /delta/prices`                      | [`GET /v2/delta/prices`](/docs/api-reference/delta/prices)                                      | Response carries `route` + `alternatives`; `price.hmac` removed                                                                                |
| `GET /delta/prices/bridge-info`          | [`GET /v2/delta/prices/bridge-routes`](/docs/api-reference/delta/bridge-routes)                 | Flat `routes[]` array instead of nested `srcChainId → destChainId → tokens[]` map                                                              |
| `GET /delta/prices/bridge-protocols`     | [`GET /v2/delta/prices/bridge-protocols`](/docs/api-reference/delta/bridge-protocols)           | Same shape                                                                                                                                     |
| `GET /delta/prices/strategies/{chainId}` | [`GET /v2/delta/prices/strategies/{chainId}`](/docs/api-reference/delta/strategies)             | Same shape                                                                                                                                     |
| `GET /delta/prices/is-token-supported`   | [`GET /v2/delta/prices/is-token-supported`](/docs/api-reference/delta/is-token-supported)       | Same shape                                                                                                                                     |
| `GET /prices/partnerfee/{chainId}`       | *Not needed*                                                                               | Pass `partner` / `partnerAddress` / `partnerFeeBps` raw on every V2 call                                                                       |
| `POST /delta/orders/build`               | [`POST /v2/delta/orders/build`](/docs/api-reference/delta/orders-build)                         | Different body — pass `route` (not `price` + `hmac`); response wraps typed data in `toSign`                                                    |
| `POST /delta/orders`                     | [`POST /v2/delta/orders`](/docs/api-reference/delta/orders-submit)                              | Submit `order: built.toSign.value` instead of `data` from V1 build                                                                             |
| `POST /delta/orders/cancel`              | [`POST /v2/delta/orders/cancel`](/docs/api-reference/delta/orders-cancel)                       | Same submit body; build the signable payload with [`POST /v2/delta/orders/build/cancellation`](/docs/api-reference/delta/orders-build-cancellation) |
| `GET /delta/orders`                      | [`GET /v2/delta/orders`](/docs/api-reference/delta/orders-list)                                 | Wraps array in `{ data, total, page, limit, hasMore }`                                                                                         |
| `GET /delta/orders/{orderId}`            | [`GET /v2/delta/orders/{orderId}`](/docs/api-reference/delta/orders-get-by-id)                  | New response shape — `input` / `output` carry expected + executed amounts                                                                      |
| `GET /delta/orders/hash/{hash}`          | [`GET /v2/delta/orders/hash/{hash}`](/docs/api-reference/delta/orders-get-by-hash)              | Same as above                                                                                                                                  |
| `GET /delta/orders/fillablebalance/...`  | [`GET /v2/delta/orders/fillablebalance/...`](/docs/api-reference/delta/orders-fillable-balance) | Same shape                                                                                                                                     |
| `GET /delta/agents/list/{chainId}`       | [`GET /v2/delta/agents/list/{chainId}`](/docs/api-reference/delta/agents-list)                  | Same shape                                                                                                                                     |
| `GET /quote` (`mode=ALL`)                | [`GET /v2/quote`](/docs/api-reference/delta/quote)                                              | Delta-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`.

```diff theme={null}
- 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`:

```diff theme={null}
- 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:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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.

```diff theme={null}
  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.

```diff theme={null}
  // 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.

```diff theme={null}
- 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`.

```diff theme={null}
+ 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"`:

```diff theme={null}
+ 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](/docs/integrate/api/limit-orders).

### 6. Poll for status

V1 status (`DeltaAuctionStatus`) splits into `status` + `bridgeStatus`. V2 collapses both into one `status` field.

```diff theme={null}
- 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_STARTED`                                       | `PENDING`            |
| `AWAITING_PRE_SIGNATURE`                            | `AWAITING_SIGNATURE` |
| `RUNNING`, `EXECUTING`                              | `ACTIVE`             |
| Suspension states (insufficient balance/allowance)  | `SUSPENDED`          |
| `CANCELLING`                                        | `CANCELLING`         |
| `EXECUTED` + `bridgeStatus: PENDING`                | `BRIDGING`           |
| `EXECUTED` + (same-chain OR `bridgeStatus: FILLED`) | `COMPLETED`          |
| `FAILED`, `INVALIDATED`                             | `FAILED`             |
| `EXPIRED` (or `bridgeStatus: EXPIRED`)              | `EXPIRED`            |
| `EXECUTED` + `bridgeStatus: REFUNDING`              | `REFUNDING`          |
| `CANCELLED`                                         | `CANCELLED`          |
| `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:

```json theme={null}
{
  "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

```diff theme={null}
- 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:

```diff theme={null}
- [ { "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

Posting the signed cancellation keeps the same request body under `/v2`. Build the typed data server-side first, then have the user sign the returned `toSign` object.

```diff theme={null}
- POST /delta/orders/cancel
+ POST /v2/delta/orders/cancel
  {
    "orderIds":  ["..."],
    "signature": "0x..."
  }
```

```bash theme={null}
curl -X POST 'https://api.velora.xyz/v2/delta/orders/build/cancellation' \
  -H 'Content-Type: application/json' \
  -d '{ "orderIds": ["..."] }'
```

### 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.

```diff theme={null}
- // 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 `ACTIVE` → `COMPLETED` (or `BRIDGING` → `COMPLETED` 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).

## Related pages

* [Delta V2 API overview](/docs/api-reference/delta/overview) — the recommended surface.
* [SDK → Migrate from V1 to V2](/docs/sdk/products/delta#migrate-from-v1-to-v2) — same migration at the TypeScript SDK level.
* [Crosschain Delta swaps](/docs/delta/crosschain-delta) — how `destChainId`, bridge routes, and crosschain status work.
* [Limit order API integration](/docs/integrate/api/limit-orders) — build with `limitAmount`, then submit with `type: "LIMIT"`.
