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

# Arbitrage Opportunities API — Session Auth

> List and inspect scored arbitrage opportunities using a session JWT. Filter by score, classification, lifecycle status, and policy guarantee class.

The arbitrage opportunities endpoints give web app users access to Predexy's full cross-platform arbitrage detection output. Opportunities are scored 0–100 using a multi-factor model, classified into tiers, and enriched with fee breakdowns, risk gate states, and governance metadata. These endpoints require a session JWT — if you are building an automated integration, see the [external API key endpoint](/api-reference/arbitrage-external) instead.

## Endpoints

| Method | Path                                                      | Description                     |
| ------ | --------------------------------------------------------- | ------------------------------- |
| `GET`  | `/api/v1/arbitrage/opportunities`                         | List opportunities with filters |
| `GET`  | `/api/v1/arbitrage/opportunities/{id}`                    | Single opportunity by ID        |
| `GET`  | `/api/v1/arbitrage/opportunities/{id}/certificate`        | Governance certificate bundle   |
| `GET`  | `/api/v1/arbitrage/opportunities/{id}/execution-advisory` | Execution advisory              |
| `GET`  | `/api/v1/arbitrage/opportunities/{id}/policy-decision`    | Policy decision record          |

## Authentication

All endpoints require a session JWT:

```
Authorization: Bearer <your_jwt>
```

***

## List opportunities

```
GET https://api.predexy.com/api/v1/arbitrage/opportunities
```

Returns a list of scored and classified arbitrage opportunities detected across integrated platforms. Results are sourced from the background pipeline and include lifecycle state, runtime risk-gate information, and execution advisory metrics.

### Query parameters

<ParamField query="min_score" type="number" default="40">
  Minimum arbitrage score to include. Range 0–100. The default of 40 excludes noise-tier opportunities.
</ParamField>

<ParamField query="classification" type="string">
  Filter by classification tier. One of `actionable`, `informational`, or `noise`.

  * `actionable` — Score ≥ 70, positive net spread, liquidity above \$500.
  * `informational` — Score 40–69 or low liquidity. Worth monitoring but not immediately executable.
  * `noise` — Score below 40. Likely ephemeral or uneconomical.
</ParamField>

<ParamField query="category" type="string">
  Filter by market category, e.g. `crypto`, `politics`, `sports`.
</ParamField>

<ParamField query="status" type="string">
  Filter by lifecycle status: `active`, `stale`, or `resolved`.
</ParamField>

<ParamField query="guarantee" type="string">
  Filter by policy guarantee class: `STRICT` or `QUASI`. `STRICT` indicates the opportunity passed all policy checks cleanly.
</ParamField>

<ParamField query="risk_gate" type="string">
  Filter by runtime risk gate state: `allowed`, `degraded`, or `blocked`.
</ParamField>

<ParamField query="limit" type="number" default="50">
  Maximum items to return (1–200).
</ParamField>

### Example request

```bash cURL theme={null}
curl "https://api.predexy.com/api/v1/arbitrage/opportunities?classification=actionable&min_score=70&limit=10" \
  -H "Authorization: Bearer <your_jwt>"
```

### Response structure

The response contains a `data` object with two keys:

* `data.opportunities` — array of `ArbitrageOpportunity` objects.
* `data.stats` — `ScanStats` for the filtered result set.
* `data.stats_all` — `ScanStats` for the unfiltered result set (useful for dashboard summaries).
* `meta` — pagination state plus `source` (`database`, `cache`, or `empty`) and a `disclaimer` note about guarantee interpretation.

***

## ArbitrageOpportunity schema

<ResponseField name="id" type="string" required>
  Unique opportunity identifier, e.g. `"arb_poly_limit_abc123"`.
</ResponseField>

<ResponseField name="canonical_question_id" type="string" required>
  UUID of the canonical question this opportunity belongs to.
</ResponseField>

<ResponseField name="question_title" type="string" required>
  Human-readable question text, e.g. `"Will BTC reach $100k by 2026?"`.
</ResponseField>

<ResponseField name="question_slug" type="string">
  URL-safe question slug.
</ResponseField>

<ResponseField name="category" type="string">
  Market category.
</ResponseField>

<ResponseField name="end_time" type="string">
  ISO 8601 market expiry timestamp. `null` for perpetual markets.
</ResponseField>

<ResponseField name="type" type="string" required>
  Arbitrage strategy: `direct` (same outcome priced differently across platforms) or `dutch_book` (buy Yes on one platform and No on another for a combined cost below \$1).
</ResponseField>

<ResponseField name="buy_platform" type="object" required>
  Platform where you buy the outcome. Contains `id`, `slug`, and `name`.
</ResponseField>

<ResponseField name="sell_platform" type="object" required>
  Platform where you sell (or buy the opposite outcome). Contains `id`, `slug`, and `name`.
</ResponseField>

<ResponseField name="buy_price" type="number" required>
  Price to buy the outcome, expressed as a probability from 0 to 1.
</ResponseField>

<ResponseField name="sell_price" type="number" required>
  Price to sell the outcome on the other platform, from 0 to 1.
</ResponseField>

<ResponseField name="spread" type="number" required>
  Raw price spread (`sell_price – buy_price`).
</ResponseField>

<ResponseField name="spread_bps" type="number" required>
  Spread in basis points (1 bps = 0.01%).
</ResponseField>

<ResponseField name="net_spread" type="number" required>
  Spread after deducting platform fees from both legs.
</ResponseField>

<ResponseField name="estimated_profit" type="number" required>
  Estimated profit per \$100 deployed, in USD.
</ResponseField>

<ResponseField name="annualized_return" type="number">
  Annualized return based on time remaining to market expiry.
</ResponseField>

<ResponseField name="arbitrage_score" type="number" required>
  Multi-factor quality score from 0 to 100. Combines execution quality (spread, fees), market quality (liquidity, volume), and temporal quality (time to expiry).
</ResponseField>

<ResponseField name="classification" type="string" required>
  `actionable`, `informational`, or `noise`.
</ResponseField>

<ResponseField name="liquidity" type="number">
  Combined available liquidity across both legs in USD.
</ResponseField>

<ResponseField name="volume24h" type="number">
  Combined 24-hour trading volume across both legs in USD.
</ResponseField>

<ResponseField name="platform_count" type="number">
  Number of platforms listing this question.
</ResponseField>

<ResponseField name="detected_at" type="string" required>
  ISO 8601 timestamp when this opportunity was first detected.
</ResponseField>

<ResponseField name="last_seen_at" type="string">
  Last timestamp when this opportunity was observed in a scan cycle.
</ResponseField>

<ResponseField name="status" type="string">
  Lifecycle state: `active`, `stale`, or `resolved`.
</ResponseField>

<ResponseField name="fees" type="object" required>
  Fee breakdown for both legs.

  <Expandable title="FeeBreakdown fields">
    <ResponseField name="buy_fee" type="number">
      Fee to execute the buy leg as a fraction (e.g. `0.02` = 2%).
    </ResponseField>

    <ResponseField name="sell_fee" type="number">
      Fee to execute the sell leg.
    </ResponseField>

    <ResponseField name="total_fees" type="number">
      Total round-trip fees.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="expected_fill_prob" type="number">
  Estimated probability of execution fill, from 0 to 1.
</ResponseField>

<ResponseField name="expected_slippage_bps" type="number">
  Estimated slippage in basis points.
</ResponseField>

<ResponseField name="net_edge_after_execution" type="number">
  Net expected edge after accounting for fill probability and slippage.
</ResponseField>

<ResponseField name="recommended_notional" type="number">
  Advisory position size in USD.
</ResponseField>

<ResponseField name="portfolio_weight" type="number">
  Advisory portfolio allocation weight from 0 to 1.
</ResponseField>

<ResponseField name="risk_gate_state" type="string">
  Runtime risk gate: `allowed`, `degraded`, or `blocked`.
</ResponseField>

<ResponseField name="risk_gate_reason" type="string">
  Machine-readable reason when the gate is `degraded` or `blocked`. `null` when `allowed`.
</ResponseField>

<ResponseField name="guarantee" type="string">
  Policy guarantee class: `STRICT` or `QUASI`.
</ResponseField>

<ResponseField name="certificate_id" type="string">
  Certificate identifier when governance evidence exists.
</ResponseField>

<ResponseField name="freshness" type="object">
  Freshness metadata for this opportunity.

  <Expandable title="OpportunityFreshness fields">
    <ResponseField name="age_ms" type="number">
      Milliseconds since the detection timestamp.
    </ResponseField>

    <ResponseField name="source_lag_ms" type="number">
      Estimated source data lag in milliseconds.
    </ResponseField>

    <ResponseField name="is_stale" type="boolean">
      `true` when the freshness SLO threshold has been exceeded.
    </ResponseField>

    <ResponseField name="stale_reason" type="string">
      Machine-readable stale reason. `null` when fresh.
    </ResponseField>

    <ResponseField name="source_updated_at" type="string">
      Upstream source last update timestamp.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="quality_breakdown" type="object">
  Per-dimension quality scores that feed into the final `arbitrage_score`.

  <Expandable title="OpportunityQualityBreakdown fields">
    <ResponseField name="spread_score" type="number">Score from the spread magnitude dimension.</ResponseField>
    <ResponseField name="liquidity_score" type="number">Score from the liquidity depth dimension.</ResponseField>
    <ResponseField name="volume_score" type="number">Score from the 24h volume dimension.</ResponseField>
    <ResponseField name="activity_score" type="number">Score from market activity signals.</ResponseField>
    <ResponseField name="platform_score" type="number">Score based on platform reliability.</ResponseField>
    <ResponseField name="resolution_score" type="number">Score based on resolution certainty.</ResponseField>
    <ResponseField name="freshness_score" type="number">Score based on data freshness.</ResponseField>
    <ResponseField name="trust_score_component" type="number">Trust adjustment component.</ResponseField>
    <ResponseField name="execution_score" type="number">Execution quality composite score.</ResponseField>
    <ResponseField name="final_score" type="number">Final integer score (same as `arbitrage_score`).</ResponseField>
    <ResponseField name="primary_drivers" type="string[]">List of score driver labels for display.</ResponseField>
  </Expandable>
</ResponseField>

***

## Get single opportunity

```
GET https://api.predexy.com/api/v1/arbitrage/opportunities/{id}
```

Returns full details for a single opportunity by its identifier.

### Path parameters

<ParamField path="id" type="string" required>
  Opportunity identifier, e.g. `arb_poly_limit_abc123`.
</ParamField>

### Example request

```bash cURL theme={null}
curl https://api.predexy.com/api/v1/arbitrage/opportunities/arb_poly_limit_abc123 \
  -H "Authorization: Bearer <your_jwt>"
```

***

## Get certificate

```
GET https://api.predexy.com/api/v1/arbitrage/opportunities/{id}/certificate
```

Returns the governance certificate bundle for an opportunity. Certificates document the policy checks and evidence that determined the `guarantee` class. Only opportunities with a non-null `certificate_id` have a certificate.

***

## Get execution advisory

```
GET https://api.predexy.com/api/v1/arbitrage/opportunities/{id}/execution-advisory
```

Returns execution advisory details — including recommended notional sizing, slippage estimates, and fill probability breakdown — for the specified opportunity.

***

## Get policy decision

```
GET https://api.predexy.com/api/v1/arbitrage/opportunities/{id}/policy-decision
```

Returns the latest policy decision record, including the policy version used and the decision label applied during evaluation.

***

## Sample opportunity response

```json theme={null}
{
  "data": {
    "id": "arb_poly_limit_abc123",
    "canonical_question_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "question_title": "Will BTC reach $100k by 2026?",
    "question_slug": "will-btc-reach-100k-by-2026",
    "category": "crypto",
    "end_time": "2026-01-01T00:00:00Z",
    "type": "direct",
    "buy_platform": { "id": "...", "slug": "limitless", "name": "Limitless" },
    "sell_platform": { "id": "...", "slug": "polymarket", "name": "Polymarket" },
    "buy_price": 0.58,
    "sell_price": 0.65,
    "spread": 0.07,
    "spread_bps": 700,
    "net_spread": 0.03,
    "estimated_profit": 3.00,
    "arbitrage_score": 78,
    "classification": "actionable",
    "liquidity": 15000.00,
    "volume24h": 52000.00,
    "status": "active",
    "guarantee": "STRICT",
    "risk_gate_state": "allowed",
    "risk_gate_reason": null,
    "detected_at": "2026-04-25T14:22:00Z",
    "fees": {
      "buy_fee": 0.02,
      "sell_fee": 0.02,
      "total_fees": 0.04
    }
  }
}
```
