Reference
API reference
Every LayerHop REST endpoint, parameter and schema — generated from openapi.yaml (API 0.1.0).
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 id7565164. - Tokens are given as a symbol from the built-in token list (
USDC) or as an address / mint. - Every response carries an
x-request-idheader; error bodies repeat it asrequestId. - Errors use one shape,
{ "error": { code, message, requestId, docsUrl } }, with a stablecode(see theErrorCodeschema).
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-idheader. Error bodies repeat it asrequestId. - Non-2xx responses use the Error schema; its
docsUrlpoints at the error catalog.
Meta#
Liveness and static registries.
Health check#
/v1/healthLiveness probe. Lists the providers loaded in this API instance.
Responses
| Status | Description | Body |
|---|---|---|
200 |
The API is up. | HealthResponse |
Example request
curl "http://localhost:8787/v1/health"Example response (200)
{
"ok": true,
"providers": [
"jupiter",
"relay",
"debridge",
"zerox",
"lifi"
]
}List chains#
/v1/chainsEvery chain LayerHop can route from or to.
Responses
| Status | Description | Body |
|---|---|---|
200 |
The chain registry. | ChainsResponse |
Example request
curl "http://localhost:8787/v1/chains"Example response (200)
{
"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#
/v1/tokensThe 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
curl "http://localhost:8787/v1/tokens?chain=base"Example response (200)
{
"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#
/v1/quoteFans 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
curl "http://localhost:8787/v1/quote?srcChain=base&srcToken=USDC&amount=100000000&dstChain=solana&dstToken=SOL&sender=0x1111111111111111111111111111111111111111&recipient=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"Example response (200)
{
"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#
/v1/ordersReturns 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
curl -X POST "http://localhost:8787/v1/orders" \
-H "content-type: application/json" \
-d '{"quoteId":"q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10"}'Example response (200)
{
"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#
/v1/orders/submitOnly 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
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)
{
"provider": "jupiter",
"txHash": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
}Get order status#
/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 alwaysunknown. 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
curl "http://localhost:8787/v1/orders/relay/0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f"Example response (200)
{
"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:
INVALID_PARAMSUNSUPPORTED_CHAINUNSUPPORTED_TOKENAMOUNT_TOO_SMALLAMOUNT_TOO_LARGENO_ROUTEQUOTE_NOT_FOUNDQUOTE_EXPIREDORDER_NOT_FOUNDPROVIDER_ERRORPROVIDER_TIMEOUTRATE_LIMITEDUNAUTHORIZEDINTERNAL
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:
jupiterrelaydebridgemayanzeroxodoslifimock
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:
webwidgetbotapi
Vm#
Virtual machine family. svm is Solana.
string, one of:
evmsvm
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:
pendingfilledrefundedfailedunknown
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 | — |