curl --request GET \
--url https://api.dev.leneutre.trade/v1/opportunitiesconst options = {method: 'GET'};
fetch('https://api.dev.leneutre.trade/v1/opportunities', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dev.leneutre.trade/v1/opportunities"
response = requests.get(url)
print(response.text){
"opportunities": [
{
"asset": "ETH",
"long": {
"venue": "aster",
"market": "ETHUSDT",
"symbol": "ETHUSDT",
"quoteAsset": "USDT",
"carryApr": 7.59,
"maxLeverage": 50,
"intervalHours": 8,
"nextSettlement": "2026-10-04T08:00:00.000Z"
},
"short": {
"venue": "hyperliquid",
"market": "ETH",
"symbol": "ETH",
"quoteAsset": "USDC",
"carryApr": 10.95,
"maxLeverage": 25,
"intervalHours": 1,
"nextSettlement": "2026-10-04T03:00:00.000Z"
},
"grossApr": 3.36,
"onMargin": {
"leverage": {
"long": 10,
"short": 10
},
"marginUsd": 0.2,
"grossApr": 16.8,
"netApr": null
},
"atMaxLeverage": {
"leverage": {
"long": 50,
"short": 25
},
"marginUsd": 0.06,
"grossApr": 56,
"netApr": null
},
"carry24hApr": 3.1,
"carry7dApr": 2.8,
"carry30dApr": 2.4,
"historyHours": 720
}
],
"snapshot": "7c1e0a42-1f",
"offset": 0,
"next": null,
"total": 56,
"unfiltered": 56,
"hiddenUntradable": 0,
"coverage": {
"at": "2026-10-04T02:40:00.000Z",
"collector": {
"startedAt": "2026-10-03T18:00:00.000Z",
"at": "2026-10-04T02:39:52.000Z"
},
"venues": [
{
"venue": "hyperliquid",
"rates": 336,
"fresh": 336,
"at": "2026-10-04T02:39:59.000Z"
},
{
"venue": "aster",
"rates": 616,
"fresh": 616,
"at": "2026-10-04T02:39:58.000Z"
}
]
}
}{
"error": "<string>",
"detail": "<string>"
}{
"error": "Too many requests: wait, then try again."
}{
"error": "<string>",
"detail": "<string>"
}List opportunities
Every long/short pair across venues, filtered and ordered as asked, a page at a time: best gross APR now first unless asked otherwise. Only pairs that earn on the rate the list ranks on are listed, and a leg whose rate is older than five minutes is left out. Every filter applies to every pair before the order does, so a page is the best of the pairs the filters hold. A page past the first comes from the same state of the market data as the first, by the cursor the previous page gave: read page after page, the list has no pair twice and misses none, whatever moved meanwhile.
curl --request GET \
--url https://api.dev.leneutre.trade/v1/opportunitiesconst options = {method: 'GET'};
fetch('https://api.dev.leneutre.trade/v1/opportunities', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dev.leneutre.trade/v1/opportunities"
response = requests.get(url)
print(response.text){
"opportunities": [
{
"asset": "ETH",
"long": {
"venue": "aster",
"market": "ETHUSDT",
"symbol": "ETHUSDT",
"quoteAsset": "USDT",
"carryApr": 7.59,
"maxLeverage": 50,
"intervalHours": 8,
"nextSettlement": "2026-10-04T08:00:00.000Z"
},
"short": {
"venue": "hyperliquid",
"market": "ETH",
"symbol": "ETH",
"quoteAsset": "USDC",
"carryApr": 10.95,
"maxLeverage": 25,
"intervalHours": 1,
"nextSettlement": "2026-10-04T03:00:00.000Z"
},
"grossApr": 3.36,
"onMargin": {
"leverage": {
"long": 10,
"short": 10
},
"marginUsd": 0.2,
"grossApr": 16.8,
"netApr": null
},
"atMaxLeverage": {
"leverage": {
"long": 50,
"short": 25
},
"marginUsd": 0.06,
"grossApr": 56,
"netApr": null
},
"carry24hApr": 3.1,
"carry7dApr": 2.8,
"carry30dApr": 2.4,
"historyHours": 720
}
],
"snapshot": "7c1e0a42-1f",
"offset": 0,
"next": null,
"total": 56,
"unfiltered": 56,
"hiddenUntradable": 0,
"coverage": {
"at": "2026-10-04T02:40:00.000Z",
"collector": {
"startedAt": "2026-10-03T18:00:00.000Z",
"at": "2026-10-04T02:39:52.000Z"
},
"venues": [
{
"venue": "hyperliquid",
"rates": 336,
"fresh": 336,
"at": "2026-10-04T02:39:59.000Z"
},
{
"venue": "aster",
"rates": 616,
"fresh": 616,
"at": "2026-10-04T02:39:58.000Z"
}
]
}
}{
"error": "<string>",
"detail": "<string>"
}{
"error": "Too many requests: wait, then try again."
}{
"error": "<string>",
"detail": "<string>"
}Query Parameters
The leverage you want on each leg, capped per leg at the venue's maximum. Adds onMargin.
x <= 100010
Leave out pairs earning this gross APR or less, in percent, on the rate the list ranks on (rank): its average over the window, or the rate now for a pair without that average.
5
One asset, by its matching key or any venue's name for it (XAU finds GOLD).
"ETH"
A part of the asset's name, any case.
40"eth"
Venues, comma-separated, that neither leg may be on.
"aster,lighter"
Venues, comma-separated, that both legs must be on, such as the ones an executor trades. The pairs this leaves out are counted in hiddenUntradable.
"hyperliquid,polymarket-perps"
List pairs of two contracts on one venue.
true, false List pairs across a proxy and its asset (PAXG against gold).
true, false Only pairs whose long leg is this market, as venue:market; with short, one pair alone.
"aster:ETHUSDT"
Only pairs whose short leg is this market, as venue:market.
"hyperliquid:ETH"
How many pairs the page holds.
1 <= x <= 1000The rate the APR on margin stands on, and what ranks the pairs when sort is left out, best first: the gross APR now, or its average over the last 24 hours, 7 days or 30 days. A pair ranks on its 30-day average once it has 28 days of history. The pairs without that average come last.
now, 24h, 7d, 30d The column the pairs are sorted by: the asset's name, the long or the short leg's rate, the spread now or on average, or the APR on margin at leverage on the rate rank says. A pair without the figure comes last either way; ties go to the higher spread now. The rate rank says unless asked.
asset, long, short, now, 24h, 7d, 30d, margin Which way. Highest first unless asked, A to Z for the asset.
asc, desc Where the page starts: the next of the page before, with the same other parameters. Answered 410 once that state of the list is no longer kept, 30 seconds after a newer one replaced it: read the list again from the top.
"7c1e0a42-1f.50"
Response
The pairs, best first.
The state of the market data the page comes from, which its next reads on in.
The cursor of the next page; null once the list ends.
Show child attributes
Show child attributes
Every pair the filters hold, before limit.
Every pair that earns more than minApr, before the other filters.
The pairs the filters hold but for a leg outside venues; 0 without it.
The place of the page's first pair in the list
What the list stands on: a venue without a fresh rate has no pair listed, because the collector just started and hasn't read it yet, can't reach it, or has stopped.
Show child attributes
Show child attributes