LayerHopdocs

Reference

API reference

Every LayerHop REST endpoint, parameter and schema — generated from openapi.yaml (API 0.1.0).

Open in ClaudeOpen in ChatGPT

Note

This page is generated at build time from services/api/openapi.yaml (OpenAPI 3.1.0, API version 0.1.0).

LayerHop is a meta-aggregator. GET /v1/quote asks every liquidity provider that supports the route (Jupiter, Relay, deBridge, 0x, LI.FI) in parallel and ranks the answers by time-adjusted output for the user. POST /v1/orders turns a quote into a transaction the user's own wallet signs. LayerHop never holds funds.

Conventions:

  • Amounts are integer strings in base units (never floats).
  • Chains are given as a numeric id or a slug (base, solana). Solana uses LayerHop's internal id 7565164.
  • Tokens are given as a symbol from the built-in token list (USDC) or as an address / mint.
  • Every response carries an x-request-id header; error bodies repeat it as requestId.
  • Errors use one shape, { "error": { code, message, requestId, docsUrl } }, with a stable code (see the ErrorCode schema).

Base URLs#

URL Description
http://localhost:8787 Local API (pnpm --filter @layerhop/api dev)
https://api.layerhop.com Hosted API (planned — not live yet)

Authentication#

  • x-api-key (header) — Optional. The SDK sends it when configured, but the API does not enforce keys or rate limits yet (coming soon).

Conventions#

  • All paths are under /v1. Request and response bodies are JSON.
  • Every response has an x-request-id header. Error bodies repeat it as requestId.
  • Non-2xx responses use the Error schema; its docsUrl points at the error catalog.

Meta#

Liveness and static registries.

Health check#

GET/v1/health

Liveness probe. Lists the providers loaded in this API instance.

Responses

Status Description Body
200 The API is up. HealthResponse

Example request

Terminal
curl "http://localhost:8787/v1/health"

Example response (200)

JSON
{
  "ok": true,
  "providers": [
    "jupiter",
    "relay",
    "debridge",
    "zerox",
    "lifi"
  ]
}

List chains#

GET/v1/chains

Every chain LayerHop can route from or to.

Responses

Status Description Body
200 The chain registry. ChainsResponse

Example request

Terminal
curl "http://localhost:8787/v1/chains"

Example response (200)

JSON
{
  "chains": [
    {
      "id": 8453,
      "slug": "base",
      "name": "Base",
      "vm": "evm",
      "nativeSymbol": "ETH",
      "nativeDecimals": 18,
      "explorerTx": "https://basescan.org/tx/"
    },
    {
      "id": 7565164,
      "slug": "solana",
      "name": "Solana",
      "vm": "svm",
      "nativeSymbol": "SOL",
      "nativeDecimals": 9,
      "explorerTx": "https://solscan.io/tx/"
    }
  ]
}

List tokens#

GET/v1/tokens

The built-in token list for one chain. Symbols on this list can be used in place of addresses in GET /v1/quote. Any other token can still be quoted by address / mint.

Query parameters

Name Type Required Description
chain string yes Chain id or slug.

Responses

Status Description Body
200 Tokens on the chain. TokensResponse
400 The chain is unknown (UNSUPPORTED_CHAIN). Error
500 Unexpected server error (INTERNAL). Error

Example request

Terminal
curl "http://localhost:8787/v1/tokens?chain=base"

Example response (200)

JSON
{
  "tokens": [
    {
      "chainId": 8453,
      "address": "0x0000000000000000000000000000000000000000",
      "symbol": "ETH",
      "decimals": 18
    },
    {
      "chainId": 8453,
      "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "symbol": "USDC",
      "decimals": 6
    }
  ]
}

Quotes#

Ask every provider for a price.

Get quotes#

GET/v1/quote

Fans the request out to every provider that supports the route, in parallel, with a per-provider timeout (8 s by default). Successful quotes are ranked best-for-the-user first by time-adjusted output (1 bp penalty per minute of ETA beyond the first minute, capped at 50 bps), then by speed. Providers that failed are listed in errors and do not fail the request, unless every provider failed (NO_ROUTE).

Each quote has its own quoteId; pass it to POST /v1/orders before expiresAt.

Query parameters

Name Type Required Description
srcChain string yes Source chain id or slug.
srcToken string yes Source token symbol from the token list, or address / mint.
amount string yes Input amount, integer string in base units of srcToken. Must be greater than 0. (pattern ^\d+$)
dstChain string yes Destination chain id or slug.
dstToken string yes Destination token symbol from the token list, or address / mint.
sender string yes Address that signs and pays on the source chain. (min length 1)
recipient string yes Address that receives the output on the destination chain. (min length 1)
slippageBps integer no Maximum slippage in basis points. (default 50) (1–5000)
channel FeeChannel no Where the trade comes from. Decides the LayerHop fee (see FeeChannel).

Responses

Status Description Body
200 Ranked quotes. QuoteResponse
400 Invalid request (INVALID_PARAMS, UNSUPPORTED_CHAIN, UNSUPPORTED_TOKEN, AMOUNT_TOO_SMALL, AMOUNT_TOO_LARGE). Error
404 No provider supports the route, or every provider failed (NO_ROUTE). Error
500 Unexpected server error (INTERNAL). Error

Example request

Terminal
curl "http://localhost:8787/v1/quote?srcChain=base&srcToken=USDC&amount=100000000&dstChain=solana&dstToken=SOL&sender=0x1111111111111111111111111111111111111111&recipient=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"

Example response (200)

JSON
{
  "best": {
    "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
    "provider": "relay",
    "dstAmount": "612345678",
    "dstAmountMin": "609283949",
    "estimatedSeconds": 8,
    "fees": {
      "ourFeeBps": 20,
      "providerFeeUsd": 0.12,
      "gasUsd": 0.03
    },
    "expiresAt": 1760000030
  },
  "quotes": [
    {
      "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
      "provider": "relay",
      "dstAmount": "612345678",
      "dstAmountMin": "609283949",
      "estimatedSeconds": 8,
      "fees": {
        "ourFeeBps": 20,
        "providerFeeUsd": 0.12,
        "gasUsd": 0.03
      },
      "expiresAt": 1760000030
    },
    {
      "quoteId": "q_0b9a4f7e-1d2c-4e3b-8a6f-5c4d3e2b1a09",
      "provider": "debridge",
      "dstAmount": "611900000",
      "dstAmountMin": "611900000",
      "estimatedSeconds": 6,
      "fees": {
        "ourFeeBps": 20
      },
      "expiresAt": 1760000030
    }
  ],
  "errors": [
    {
      "provider": "lifi",
      "code": "PROVIDER_TIMEOUT",
      "message": "Timed out: li.quest"
    }
  ]
}

Orders#

Build, submit and track the transaction for a quote.

Build the transaction#

POST/v1/orders

Returns the transaction for a quote, for the user's wallet to sign. EVM transactions may carry an approval (an ERC-20 approve to send first). Solana transactions are a base64 serialized VersionedTransaction; when submitViaApi is true, sign it and send it to POST /v1/orders/submit instead of an RPC node.

The quote must not be expired. Some providers ask you to submit within ~30 s of building.

Request body — BuildOrderRequest (required)

Responses

Status Description Body
200 The transaction to sign. BuildOrderResponse
400 Invalid request (INVALID_PARAMS, UNSUPPORTED_CHAIN, UNSUPPORTED_TOKEN, AMOUNT_TOO_SMALL, AMOUNT_TOO_LARGE). Error
404 Unknown quoteId, or the provider can no longer build it (QUOTE_NOT_FOUND). Error
410 The quote is past expiresAt (QUOTE_EXPIRED). Error
500 Unexpected server error (INTERNAL). Error
502 The upstream provider failed (PROVIDER_ERROR). Error
504 The upstream provider did not answer in time (PROVIDER_TIMEOUT). Error

Example request

Terminal
curl -X POST "http://localhost:8787/v1/orders" \
  -H "content-type: application/json" \
  -d '{"quoteId":"q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10"}'

Example response (200)

JSON
{
  "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
  "provider": "relay",
  "tx": {
    "vm": "evm",
    "chainId": 8453,
    "to": "0xa5F565650890fBA1824Ee0F21EbBbF660a179934",
    "data": "0x58109c...",
    "value": "0",
    "approval": {
      "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "spender": "0xa5F565650890fBA1824Ee0F21EbBbF660a179934",
      "amount": "100000000"
    }
  }
}

Submit a signed transaction#

POST/v1/orders/submit

Only for Solana transactions built with submitViaApi: true (today: Jupiter, whose RFQ and gasless transactions are co-signed and never land through a plain RPC node). Send the wallet-signed transaction as base64; LayerHop forwards it to the provider and returns the transaction signature. For every other provider this returns INVALID_PARAMS — broadcast from the wallet instead.

Request body — SubmitOrderRequest (required)

Responses

Status Description Body
200 The provider accepted and executed the transaction. SubmitOrderResponse
400 Invalid request (INVALID_PARAMS, UNSUPPORTED_CHAIN, UNSUPPORTED_TOKEN, AMOUNT_TOO_SMALL, AMOUNT_TOO_LARGE). Error
404 Unknown quoteId, or the provider can no longer build it (QUOTE_NOT_FOUND). Error
500 Unexpected server error (INTERNAL). Error
502 The upstream provider failed (PROVIDER_ERROR). Error
504 The upstream provider did not answer in time (PROVIDER_TIMEOUT). Error

Example request

Terminal
curl -X POST "http://localhost:8787/v1/orders/submit" \
  -H "content-type: application/json" \
  -d '{"quoteId":"q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10","signedTransaction":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..."}'

Example response (200)

JSON
{
  "provider": "jupiter",
  "txHash": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
}

Get order status#

GET/v1/orders/{provider}/{id}

Asks the provider for the current state of an order. What id means depends on the provider:

  • relay: Relay request id or the source deposit tx hash.
  • debridge: source tx hash (EVM hash or Solana signature) or a DLN order id.
  • lifi: source tx hash.
  • jupiter, zerox: same-chain swaps have nothing to track off-chain; the state is always unknown. Confirm the transaction on chain instead.

Poll until state is filled, refunded or failed.

Path parameters

Name Type Required Description
provider ProviderId yes The provider from the quote. Must be a provider loaded in this API instance.
id string yes Provider order id or source tx hash (see above). URL-encode it.

Responses

Status Description Body
200 Current order state. OrderStatus
400 Invalid request (INVALID_PARAMS, UNSUPPORTED_CHAIN, UNSUPPORTED_TOKEN, AMOUNT_TOO_SMALL, AMOUNT_TOO_LARGE). Error
404 The provider does not know this order (ORDER_NOT_FOUND). Error
429 The upstream provider rate-limited LayerHop (RATE_LIMITED). Error
500 Unexpected server error (INTERNAL). Error
502 The upstream provider failed (PROVIDER_ERROR). Error
504 The upstream provider did not answer in time (PROVIDER_TIMEOUT). Error

Example request

Terminal
curl "http://localhost:8787/v1/orders/relay/0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f"

Example response (200)

JSON
{
  "provider": "relay",
  "id": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f",
  "state": "filled",
  "srcTxHash": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f",
  "dstTxHash": "3nKqYdW1hS8vZ4cT2pXeR7mB9uJfL6aG5oN1wQ8kE3sD7yH2xV4tC6bM9rP1zA5uF8jL2gK7eW3qS6dN4hT9vB1"
}

Schemas#

ErrorCode#

Stable error code. Each has a page at https://docs.layerhop.com/errors/{code}.

string, one of:

Error#

Every non-2xx response has this body.

Field Type Required Description
error object yes —
error.code ErrorCode yes —
error.message string yes Human-readable detail. Do not parse it.
error.requestId string (uuid) yes Same value as the x-request-id header.
error.docsUrl string (uri) yes Error catalog page, https://docs.layerhop.com/errors/{code}.

ProviderId#

Liquidity provider. Loaded by default: jupiter, relay, debridge, zerox, lifi. mayan is quote-only and disabled; odos is shut down; mock exists only in local development (LAYERHOP_ENABLE_MOCK=1).

string, one of:

  • jupiter
  • relay
  • debridge
  • mayan
  • zerox
  • odos
  • lifi
  • mock

FeeChannel#

Where the trade comes from; decides LayerHop's fee. Defaults: web 30 bps, widget 30 bps, api 20 bps, bot 90 bps (operators can override them).

string, one of:

  • web
  • widget
  • bot
  • api

Vm#

Virtual machine family. svm is Solana.

string, one of:

  • evm
  • svm

Chain#

Field Type Required Description
id integer yes EVM chain id, or 7565164 for Solana (LayerHop internal id).
slug string yes Short name usable anywhere a chain is expected, e.g. base.
name string yes —
vm Vm yes —
nativeSymbol string yes —
nativeDecimals integer yes —
explorerTx string (uri) yes Block explorer prefix; append a tx hash.

Token#

Field Type Required Description
chainId integer yes —
address string yes Token address or mint. The native coin is 0x0000000000000000000000000000000000000000 on EVM chains and the wrapped-SOL mint So11111111111111111111111111111111111111112 on Solana.
symbol string yes —
decimals integer yes —

HealthResponse#

Field Type Required Description
ok true yes —
providers ProviderId[] yes —

ChainsResponse#

Field Type Required Description
chains Chain[] yes —

TokensResponse#

Field Type Required Description
tokens Token[] yes —

FeeBreakdown#

Field Type Required Description
ourFeeBps integer yes LayerHop's fee in bps of the input amount actually applied to this quote. Can be lower than the channel fee (or 0) when a provider cannot carry it.
providerFeeUsd number no Provider / protocol fees in USD, when the provider reports them.
gasUsd number no Estimated network gas in USD, when known.

Quote#

Field Type Required Description
quoteId string yes Pass to POST /v1/orders. (pattern ^q_)
provider ProviderId yes —
dstAmount string yes Expected output in base units of the destination token, after all fees. (pattern ^\d+$)
dstAmountMin string yes Minimum output after slippage. (pattern ^\d+$)
estimatedSeconds integer yes Estimated time until funds arrive. (≥ 0)
fees FeeBreakdown yes —
expiresAt integer yes Unix seconds. Build the order before this time.

ProviderError#

A provider that failed while the request as a whole succeeded.

Field Type Required Description
provider ProviderId yes —
code ErrorCode yes —
message string yes —

QuoteResponse#

Field Type Required Description
best Quote yes Same object as quotes[0].
quotes Quote[] yes Every successful quote, best for the user first. (min items 1)
errors ProviderError[] yes —

Approval#

An ERC-20 approve(spender, amount) on token that must be mined before the main transaction.

Field Type Required Description
token string yes ERC-20 contract to call approve on.
spender string yes —
amount string yes Base units. (pattern ^\d+$)

EvmTx#

Field Type Required Description
vm "evm" yes —
chainId integer yes —
to string yes —
data string yes Hex calldata.
value string yes Native value in wei. (pattern ^\d+$)
approval Approval no —

SvmTx#

Field Type Required Description
vm "svm" yes —
serializedTx string yes Base64 serialized Solana VersionedTransaction, for the user's wallet to sign. (base64)
submitViaApi boolean no When true the wallet must only sign; send the signed transaction to POST /v1/orders/submit. Plain RPC will not land it.

BuiltTx#

The transaction for the user's wallet, discriminated by vm.

One of: EvmTx · SvmTx, discriminated by vm.

BuildOrderRequest#

Field Type Required Description
quoteId string yes —

BuildOrderResponse#

Field Type Required Description
quoteId string yes —
provider ProviderId yes —
tx BuiltTx yes —

SubmitOrderRequest#

Field Type Required Description
quoteId string yes —
signedTransaction string yes The wallet-signed transaction, base64. (min length 1) (base64)

SubmitOrderResponse#

Field Type Required Description
provider ProviderId yes —
txHash string yes Solana transaction signature.

OrderState#

pending in flight · filled delivered · refunded returned to the sender · failed · unknown the provider cannot tell (yet), or does not track this kind of order.

string, one of:

  • pending
  • filled
  • refunded
  • failed
  • unknown

OrderStatus#

Field Type Required Description
provider ProviderId yes —
id string yes The id you asked about.
state OrderState yes —
srcTxHash string no —
dstTxHash string no —