# Orus Partner API v1

> Official read-only token scan API. Whitelisted partners only; request access at https://x.com/Orus_agent.

Human reference: https://www.orusagent.xyz/docs#partner-api

## Endpoint & authentication

GET https://www.orusagent.xyz/api/v1/scan

Authorization: Bearer <partner key>. Keep ORUS_PARTNER_API_KEY on your backend. No request body.

## Query parameters

| Parameter | Type | Required | Default | Values | Description |
| --- | --- | --- | --- | --- | --- |
| chainId | integer | Yes | — | 4663 | Robinhood Chain mainnet (4663) only. Testnet (46630) returns 400 unsupported_chain. Never relabel a testnet contract as mainnet. |
| token | string | Yes | — | 0x + 40 hexadecimal characters | Non-zero EVM contract address. Normalized to lowercase. |
| include | string | No | chart | none · chart · launch · chart,launch · launch,chart | Optional chart and launch reads. Core data and agents are always included. |
| dipThresholdPct | number | No | 30 | 1–99 inclusive | Percent decline from ATH that defines a dip. Used when chart is included. |
| lookbackHours | number | No | 48 | 1–168 inclusive | Hours of five-minute candle history. Used when chart is included; does not change the fixed 24h agent window. |

## Include options

| include | Chart/dip | Launch | Use case |
| --- | --- | --- | --- |
| none | No | No | Token cards: core data and agents only. |
| chart | Yes | No | Default. Add dip timing and chart coverage. |
| launch | No | Yes | Add the earliest-trade launch sample. |
| chart,launch | Yes | Yes | Request all available indicators. launch,chart is equivalent. |

## Request examples

Replace the illustrative contract with the token to scan.

### cURL

```sh
curl --get 'https://www.orusagent.xyz/api/v1/scan' \
  --header "Authorization: Bearer $ORUS_PARTNER_API_KEY" \
  --data-urlencode 'chainId=4663' \
  --data-urlencode 'token=0x1111111111111111111111111111111111111111' \
  --data-urlencode 'include=chart,launch' \
  --data-urlencode 'dipThresholdPct=30' \
  --data-urlencode 'lookbackHours=48'
```

### Node.js

```js
// Run on your server. Replace token with the contract to scan.
const url = new URL("https://www.orusagent.xyz/api/v1/scan");
url.search = new URLSearchParams({
  chainId: "4663",
  token: "0x1111111111111111111111111111111111111111",
  include: "chart,launch",
  dipThresholdPct: "30",
  lookbackHours: "48",
}).toString();

const response = await fetch(url, {
  headers: {
    Authorization: `Bearer ${process.env.ORUS_PARTNER_API_KEY}`,
  },
  signal: AbortSignal.timeout(25_000),
});
const result = await response.json();
if (!response.ok) {
  // On 429/503, honor Retry-After before a bounded retry.
  throw new Error(`${response.status}: ${result.error.code}`);
}
console.log(result.card.text, result.card.url);
```

### Python

```python
# Run on your server with requests installed.
import os
import requests

response = requests.get(
    "https://www.orusagent.xyz/api/v1/scan",
    headers={
        "Authorization": f"Bearer {os.environ['ORUS_PARTNER_API_KEY']}",
    },
    params={
        "chainId": 4663,
        "token": "0x1111111111111111111111111111111111111111",
        "include": "chart,launch",
        "dipThresholdPct": 30,
        "lookbackHours": 48,
    },
    timeout=25,
)
# On 429/503, honor Retry-After before a bounded retry.
response.raise_for_status()
result = response.json()
print(result["card"]["text"], result["card"]["url"])
```

## Response example

Complete synthetic 200 response for include=chart,launch; illustrative values, not a live scan.

```json
{
  "apiVersion": "1.0",
  "requestId": "11111111-1111-4111-8111-111111111111",
  "chainId": 4663,
  "checkedAt": "2026-09-17T12:00:00.000Z",
  "cache": {
    "hit": false,
    "ageSeconds": 0,
    "maxAgeSeconds": 30
  },
  "token": {
    "address": "0x1111111111111111111111111111111111111111",
    "name": "Example token",
    "symbol": "EXAMPLE",
    "image": null,
    "createdAt": "2026-09-15T12:00:00.000Z",
    "decimals": 18,
    "ageSeconds": 172800,
    "totalSupply": 1000000000,
    "circulatingSupply": 1000000000
  },
  "market": {
    "priceUsd": 0.0006,
    "marketCapUsd": 600000,
    "fdvUsd": 600000,
    "liquidityUsd": 90000,
    "maxLiquidityUsd": null,
    "liquidityToMarketCapPct": 15,
    "volumeChange5mPct": null,
    "totalFeesUsd": null,
    "secondsSinceLastTrade": 5,
    "latestTradeAt": "2026-09-17T11:59:55.000Z",
    "priceUpdatedAt": null,
    "windows": {
      "1m": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "5m": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "15m": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "1h": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "4h": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "6h": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "12h": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      },
      "24h": {
        "volumeUsd": null,
        "buyVolumeUsd": null,
        "sellVolumeUsd": null,
        "organicVolumeUsd": null,
        "organicBuyVolumeUsd": null,
        "organicSellVolumeUsd": null,
        "buys": null,
        "sells": null,
        "trades": null,
        "buyers": null,
        "sellers": null,
        "traders": null,
        "organicTrades": null,
        "organicTraders": null,
        "feesUsd": null,
        "priceChangePct": null
      }
    }
  },
  "pool": {
    "address": null,
    "dex": null,
    "dexKey": null,
    "launchpad": null,
    "factory": null,
    "bonded": null,
    "bondingPct": null,
    "bondedAt": null,
    "bondingCurveAddress": null,
    "launchpadUrl": null
  },
  "security": {
    "isHoneypot": false,
    "isProxy": false,
    "buyTaxPct": 0,
    "sellTaxPct": 0,
    "liquidityBurnPct": 99.8
  },
  "risk": {
    "bundlersPct": 4,
    "snipersPct": null,
    "insidersPct": null,
    "devHoldingsPct": null,
    "top10Pct": null,
    "top50Pct": null,
    "top100Pct": null,
    "top200Pct": null,
    "freshTradersPct": null,
    "proTradersPct": null,
    "smartTradersPct": null,
    "holdersCount": 1200,
    "bundlersCount": null,
    "snipersCount": null,
    "insidersCount": null,
    "laggedFields": [
      "bundlersPct",
      "snipersPct",
      "insidersPct"
    ]
  },
  "ath": {
    "priceUsd": 0.001,
    "at": "2026-09-17T10:00:00.000Z",
    "ageSeconds": 7200,
    "marketCapUsd": 1000000,
    "changeFromAthPct": -40,
    "drawdownPct": 40,
    "supplyBasis": "current_supply"
  },
  "atl": {
    "priceUsd": null,
    "at": null
  },
  "dip": {
    "thresholdPct": 30,
    "thresholdPriceUsd": 0.0007,
    "firstDipAgeSeconds": 3600,
    "athToFirstDipSeconds": 3600,
    "secondsSinceLastObservedDip": 3600,
    "requestedLookbackHours": 48,
    "candleCount": 24,
    "lastCandleAgeSeconds": 0,
    "windowLowUsd": 0.0005,
    "windowHighUsd": 0.001,
    "reboundFromWindowLowPct": 20,
    "isCurrentlyBelowThreshold": true,
    "firstDipAt": "2026-09-17T11:00:00.000Z",
    "lastObservedDipAt": "2026-09-17T11:00:00.000Z",
    "windowStart": "2026-09-17T10:00:00.000Z",
    "windowEnd": "2026-09-17T12:00:00.000Z",
    "historyStatus": "covers_ath",
    "hasGaps": false,
    "interval": "5m"
  },
  "launch": {
    "firstTradeAt": "2026-09-15T12:00:00.000Z",
    "sampleWindowSeconds": 1,
    "priceUsd": 0.00001,
    "marketCapUsd": 10000,
    "sampledTrades": 100,
    "supplyBasis": "current_supply",
    "mayBeTruncated": true
  },
  "deployer": {
    "status": "partial",
    "address": "0x2222222222222222222222222222222222222222",
    "launches": 3,
    "migrations": 1,
    "rugs": null,
    "reason": "Rug classification is unavailable."
  },
  "socials": {
    "website": null,
    "twitter": null,
    "telegram": null,
    "discord": null,
    "description": null
  },
  "agents": {
    "status": "available",
    "scope": "all_orus_agents",
    "coverage": "retained_history",
    "asOf": "2026-09-17T12:00:00.000Z",
    "windowHours": 24,
    "real": {
      "tradedAgents": 8,
      "holdingAgents": 3,
      "entries24h": 5,
      "exits24h": 2,
      "lastEntryAt": "2026-09-17T11:50:00.000Z",
      "lastExitAt": "2026-09-17T11:40:00.000Z"
    },
    "simulation": {
      "tradedAgents": 12,
      "holdingAgents": 4,
      "entries24h": 7,
      "exits24h": 3,
      "lastEntryAt": "2026-09-17T11:55:00.000Z",
      "lastExitAt": "2026-09-17T11:45:00.000Z"
    }
  },
  "availability": {
    "details": {
      "status": "available"
    },
    "chart": {
      "status": "available"
    },
    "launch": {
      "status": "available"
    },
    "agents": {
      "status": "available"
    },
    "security": {
      "status": "available",
      "missingFields": [],
      "conflictingFields": []
    }
  },
  "warnings": [
    "rug_classification_unavailable",
    "price_timestamp_unavailable"
  ],
  "attribution": {
    "text": "checked by orus",
    "url": "https://www.orusagent.xyz/token/4663/0x1111111111111111111111111111111111111111"
  },
  "card": {
    "text": "orus: no honeypot reported · tax 0/0 · bundled 4% · deployer 3 launches, rugs unknown · checked by orus ↗",
    "url": "https://www.orusagent.xyz/token/4663/0x1111111111111111111111111111111111111111"
  }
}
```

## Response fields

Top-level keys are present on success. Child fields apply when their parent object is available. Nullable values may be unknown. Market {window} is one of 1m, 5m, 15m, 1h, 4h, 6h, 12h or 24h.

### envelope (object)

Version, chain, collection time and request ID.

| Field | Type | Description |
| --- | --- | --- |
| apiVersion | string | Response contract version (1.0). |
| requestId | string | Request correlation ID; include this when contacting support. |
| chainId | integer | Robinhood Chain mainnet: 4663. Testnet 46630 is unsupported. |
| checkedAt | string | Collection start; not the quote timestamp. |

### cache (object)

Cache hit and observation age.

| Field | Type | Description |
| --- | --- | --- |
| cache.hit | boolean | True when this scan was served from the shared cache. |
| cache.ageSeconds | integer | Elapsed seconds since checkedAt. |
| cache.maxAgeSeconds | integer | Maximum cache lifetime: 30 seconds. |

### token (object)

Identity, supply and creation time.

| Field | Type | Description |
| --- | --- | --- |
| token.address | string | Requested contract, normalized to lowercase. |
| token.name | string \| null | Token name. |
| token.symbol | string \| null | Token ticker. |
| token.image | string \| null | Public image URL, or null when the image cannot be published. |
| token.createdAt | string \| null | Reported token creation timestamp. |
| token.decimals | number \| null | Token decimal precision. |
| token.ageSeconds | number \| null | Seconds since token creation. |
| token.totalSupply | number \| null | Total supply in token units. |
| token.circulatingSupply | number \| null | Circulating supply in token units. |

### market (object)

USD price, capitalization, liquidity and rolling activity windows.

| Field | Type | Description |
| --- | --- | --- |
| market.priceUsd | number \| null | Current reported token price in USD. |
| market.marketCapUsd | number \| null | Reported circulating market capitalization in USD. |
| market.fdvUsd | number \| null | Fully diluted valuation in USD. |
| market.liquidityUsd | number \| null | Current reported liquidity in USD. |
| market.maxLiquidityUsd | number \| null | Maximum reported liquidity in USD. |
| market.liquidityToMarketCapPct | number \| null | Liquidity / market cap × 100. May exceed 100. |
| market.volumeChange5mPct | number \| null | Current 5m volume versus the average of the preceding two 5m periods, derived from 15m volume. |
| market.totalFeesUsd | number \| null | Cumulative reported pool fees in USD. |
| market.secondsSinceLastTrade | number \| null | Seconds since latestTradeAt. |
| market.latestTradeAt | string \| null | Timestamp of the latest reported trade, separate from quote freshness. |
| market.priceUpdatedAt | null | Exact quote timestamp is unavailable; latestTradeAt is separate. |
| market.windows.{window}.volumeUsd | number \| null | Total USD volume in this rolling window. |
| market.windows.{window}.buyVolumeUsd | number \| null | Buy-side USD volume. |
| market.windows.{window}.sellVolumeUsd | number \| null | Sell-side USD volume. |
| market.windows.{window}.organicVolumeUsd | number \| null | USD volume classified as organic. |
| market.windows.{window}.organicBuyVolumeUsd | number \| null | Organic buy-side USD volume. |
| market.windows.{window}.organicSellVolumeUsd | number \| null | Organic sell-side USD volume. |
| market.windows.{window}.buys | number \| null | Number of buys. |
| market.windows.{window}.sells | number \| null | Number of sells. |
| market.windows.{window}.trades | number \| null | Number of trades. |
| market.windows.{window}.buyers | number \| null | Distinct buyers in the window. |
| market.windows.{window}.sellers | number \| null | Distinct sellers in the window. |
| market.windows.{window}.traders | number \| null | Distinct traders in the window. |
| market.windows.{window}.organicTrades | number \| null | Trades classified as organic. |
| market.windows.{window}.organicTraders | number \| null | Traders classified as organic. |
| market.windows.{window}.feesUsd | number \| null | Fees in USD for this window. |
| market.windows.{window}.priceChangePct | number \| null | Signed price change, in percentage points. |

### pool (object)

Venue, launchpad and bonding state.

| Field | Type | Description |
| --- | --- | --- |
| pool.address | string \| null | Dominant pool address. |
| pool.dex | string \| null | Venue display name. |
| pool.dexKey | string \| null | Venue identifier. |
| pool.launchpad | string \| null | Originating launchpad. |
| pool.factory | string \| null | Pool factory address. |
| pool.bonded | boolean \| null | Whether the token has graduated from its bonding curve. |
| pool.bondingPct | number \| null | Bonding-curve progress in percent. |
| pool.bondedAt | string \| null | Reported graduation timestamp. |
| pool.bondingCurveAddress | string \| null | Bonding-curve contract address. |
| pool.launchpadUrl | string \| null | Launchpad token page URL. |

### security (object)

Honeypot, proxy, taxes and liquidity burn observations.

| Field | Type | Description |
| --- | --- | --- |
| security.isHoneypot | boolean \| null | Reported honeypot flag; null is unknown. false is not a safety guarantee or an execution simulation. |
| security.isProxy | boolean \| null | Reported proxy-contract flag; null is unknown. |
| security.buyTaxPct | number \| null | Reported token buy tax in percent: 1 means 1%. Excludes pool fees, hook fees, slippage and gas. null is unknown. |
| security.sellTaxPct | number \| null | Reported token sell tax in percent: 1 means 1%. Excludes pool fees, hook fees, slippage and gas. null is unknown. |
| security.liquidityBurnPct | number \| null | Reported liquidity burn percentage; null is unknown. Independent of honeypot and tax coverage. |

### risk (object)

Holder concentration and wallet classifications.

| Field | Type | Description |
| --- | --- | --- |
| risk.bundlersPct | number \| null | Supply held by wallets classified as bundlers. |
| risk.snipersPct | number \| null | Supply held by wallets classified as launch snipers. |
| risk.insidersPct | number \| null | Supply held by wallets classified as insiders. |
| risk.devHoldingsPct | number \| null | Supply held by the developer. |
| risk.top10Pct | number \| null | Supply held by the top 10 holders. |
| risk.top50Pct | number \| null | Supply held by the top 50 holders. |
| risk.top100Pct | number \| null | Supply held by the top 100 holders. |
| risk.top200Pct | number \| null | Supply held by the top 200 holders. |
| risk.freshTradersPct | number \| null | Supply held by wallets classified as fresh traders. |
| risk.proTradersPct | number \| null | Supply held by wallets classified as pro traders. |
| risk.smartTradersPct | number \| null | Supply held by wallets classified as smart traders. |
| risk.holdersCount | number \| null | Reported number of holders. |
| risk.bundlersCount | number \| null | Reported number of bundler wallets. |
| risk.snipersCount | number \| null | Reported number of sniper wallets. |
| risk.insidersCount | number \| null | Reported number of insider wallets. |
| risk.laggedFields | string[] | Risk field names whose classifications can change after launch. |

### ath (object)

All-time high, drawdown and elapsed time.

| Field | Type | Description |
| --- | --- | --- |
| ath.priceUsd | number \| null | Reported all-time high price in USD. |
| ath.ageSeconds | number \| null | Seconds elapsed since the ATH. |
| ath.marketCapUsd | number \| null | ATH price × current circulating supply (total supply fallback). Approximation. |
| ath.changeFromAthPct | number \| null | (current price / ATH − 1) × 100. Negative below the ATH. |
| ath.drawdownPct | number \| null | Decline from the ATH in percent, clamped at zero. |
| ath.at | string \| null | Timestamp of the reported ATH. |
| ath.supplyBasis | string | current_supply: the market-cap approximation uses current supply. |

### atl (object)

All-time low price and date.

| Field | Type | Description |
| --- | --- | --- |
| atl.priceUsd | number \| null | Reported all-time low price in USD. |
| atl.at | string \| null | Timestamp of the reported ATL. |

### dip (object | null)

Candle-based dip timing; null when chart was not requested.

| Field | Type | Description |
| --- | --- | --- |
| dip.thresholdPct | number \| null | Requested drawdown threshold; defaults to 30%. |
| dip.thresholdPriceUsd | number \| null | ATH × (1 − thresholdPct / 100). |
| dip.firstDipAgeSeconds | number \| null | Seconds elapsed since firstDipAt. |
| dip.athToFirstDipSeconds | number \| null | Seconds between the ATH and firstDipAt. |
| dip.secondsSinceLastObservedDip | number \| null | Seconds elapsed since lastObservedDipAt. |
| dip.requestedLookbackHours | number \| null | Requested candle history window in hours. |
| dip.candleCount | number \| null | Closed, valid five-minute candles in the window. |
| dip.lastCandleAgeSeconds | number \| null | Seconds since the latest closed candle ended. |
| dip.windowLowUsd | number \| null | Lowest candle low in the returned window. |
| dip.windowHighUsd | number \| null | Highest candle high in the returned window. |
| dip.reboundFromWindowLowPct | number \| null | (current price / window low − 1) × 100. |
| dip.isCurrentlyBelowThreshold | boolean \| null | Whether the current reported price is at or below the threshold. |
| dip.firstDipAt | string \| null | First qualifying closed-candle crossing since the ATH; null without complete history. |
| dip.lastObservedDipAt | string \| null | Latest observed crossing from above to below the threshold, not a local low. |
| dip.windowStart | string \| null | First retained candle open timestamp. |
| dip.windowEnd | string \| null | Last retained candle close timestamp. |
| dip.historyStatus | string | covers_ath, partial or unavailable. Only covers_ath supports a first-dip claim. |
| dip.hasGaps | boolean | Whether the observed post-ATH candles contain missing intervals. |
| dip.interval | string | Fixed five-minute candles (5m). |

### launch (object | null)

Earliest-trade sample; null when launch was not requested.

| Field | Type | Description |
| --- | --- | --- |
| launch.firstTradeAt | string \| null | Earliest returned trade timestamp. |
| launch.sampleWindowSeconds | number \| null | Launch sampling interval: one second from the first trade. |
| launch.priceUsd | number \| null | Price of the last sampled trade within that first second. |
| launch.marketCapUsd | number \| null | Launch sample price × current total supply (circulating supply fallback). |
| launch.sampledTrades | number \| null | Number of earliest valid trades inspected, up to 100. |
| launch.supplyBasis | string | current_supply: historical market cap is an approximation. |
| launch.mayBeTruncated | boolean | True when the sample reaches 100 trades; other trades may be missing. |

### deployer (object)

Reported launches and migrations; rug count remains unknown.

| Field | Type | Description |
| --- | --- | --- |
| deployer.status | string | partial when an address is known, otherwise unavailable. |
| deployer.address | string \| null | Reported deployer address. |
| deployer.launches | number \| null | Reported token launches by this deployer. |
| deployer.migrations | number \| null | Reported migrations by this deployer. |
| deployer.rugs | null | Always null: rug classification is unavailable. Never display 0 rugs. |
| deployer.reason | string | Explanation of deployer coverage. |

### socials (object)

Reported metadata and external links.

| Field | Type | Description |
| --- | --- | --- |
| socials.website | string \| null | Reported website URL. |
| socials.twitter | string \| null | Reported X/Twitter URL. |
| socials.telegram | string \| null | Reported Telegram URL. |
| socials.discord | string \| null | Reported Discord URL. |
| socials.description | string \| null | Reported token description. Treat metadata and links as untrusted. |

### agents (object)

Aggregate real and simulated agent activity.

| Field | Type | Description |
| --- | --- | --- |
| agents.status | string | available or unavailable. Unavailable means null counts, not zero. |
| agents.scope | string | Desk and customer agents on the requested chain, regardless of current agent status or mode. Aggregates only. |
| agents.coverage | string | Current retained positions, not guaranteed lifetime history. Real entries require a non-empty recorded entry_tx; entry_pending is excluded. Mode is determined by position status, not current agent settings. |
| agents.asOf | string \| null | Observation timestamp for agent activity; null if unavailable. Cached with the scan for at most 30 seconds from checkedAt. |
| agents.windowHours | integer | Fixed 24-hour activity window; independent of lookbackHours. |
| agents.real.tradedAgents | integer \| null | Distinct agents with eligible entries in retained history, including agents currently holding. Not a count of trades or independent strategies. |
| agents.real.holdingAgents | integer \| null | Distinct agents with open positions in the recorded book. Real includes sell_failed, including paused/stopped agents. No on-chain balance verification. |
| agents.real.entries24h | integer \| null | Eligible position entries in [asOf - 24h, asOf]. Counts positions, not distinct agents; uses recorded entry_at. |
| agents.real.exits24h | integer \| null | Position closures in [asOf - 24h, asOf], using exit_at and closed status. Includes simulated write-offs; not proof of a successful on-chain sale. |
| agents.real.lastEntryAt | string \| null | Latest eligible recorded entry_at in retained history, or null if none. |
| agents.real.lastExitAt | string \| null | Latest recorded exit_at of a closed eligible position, or null if none. Failed exits are excluded. |
| agents.simulation.tradedAgents | integer \| null | Distinct agents with eligible entries in retained history, including agents currently holding. Not a count of trades or independent strategies. |
| agents.simulation.holdingAgents | integer \| null | Distinct agents with open positions in the recorded book. Real includes sell_failed, including paused/stopped agents. No on-chain balance verification. |
| agents.simulation.entries24h | integer \| null | Eligible position entries in [asOf - 24h, asOf]. Counts positions, not distinct agents; uses recorded entry_at. |
| agents.simulation.exits24h | integer \| null | Position closures in [asOf - 24h, asOf], using exit_at and closed status. Includes simulated write-offs; not proof of a successful on-chain sale. |
| agents.simulation.lastEntryAt | string \| null | Latest eligible recorded entry_at in retained history, or null if none. |
| agents.simulation.lastExitAt | string \| null | Latest recorded exit_at of a closed eligible position, or null if none. Failed exits are excluded. |

### availability (object)

Availability of each requested data section.

| Field | Type | Description |
| --- | --- | --- |
| availability.details.status | string | Core token details availability. available on a successful scan. |
| availability.chart.status | string | available, unavailable or not_requested for the chart analysis. |
| availability.launch.status | string | available, unavailable or not_requested for the launch sample. |
| availability.agents.status | string | available or unavailable for agent activity; always requested. |
| availability.security.status | string | Coverage of the five security fields: available = all known, partial = some known, unavailable = none known. Not a safety verdict. Always requested, including include=none. |
| availability.security.missingFields | string[] | Names of security fields that are null. security_data_incomplete is emitted when this list is nonempty. |
| availability.security.conflictingFields | string[] | Fields with conflicting observations, returned as null and also listed in missingFields. Raises security_data_conflict. Empty when no conflict was observed. |

### warnings (string[])

Coverage and freshness caveats.

| Field | Type | Description |
| --- | --- | --- |
| warnings | string[] | Machine-readable caveats. May be nonempty on HTTP 200; clients should tolerate new codes. |

### attribution (object)

Orus label and public token link.

| Field | Type | Description |
| --- | --- | --- |
| attribution.text | string | Attribution label: checked by orus. |
| attribution.url | string | Public Orus token intelligence URL, without a partner key. |

### card (object)

Telegram-ready summary and attribution link.

| Field | Type | Description |
| --- | --- | --- |
| card.text | string | Ready-to-display plain-text summary, preserving unknown values. |
| card.url | string | Public token deep link for the card's attribution arrow. |

## HTTP errors

| HTTP | Code | Action |
| --- | --- | --- |
| 400 | invalid_request / invalid_token / unsupported_chain | Fix the query. Unknown or repeated parameters are rejected. |
| 401 | unauthorized | Missing, invalid, expired or revoked key, or inactive partner. Stop and contact Orus. |
| 404 | token_not_found | Token is not indexed. This does not prove the contract is invalid. |
| 429 | rate_limited | Partner quota exceeded. Wait the number of seconds in Retry-After. |
| 503 | scan_unavailable / market_data_unavailable / unverified_token_data | Temporarily unavailable. Honor Retry-After; retry at most twice with jitter. |
| 405 | Method not allowed | Use GET. This framework response does not use the JSON error envelope. |

## Headers

| Header | Where | Meaning |
| --- | --- | --- |
| Authorization | Request | Bearer <partner key>. Required; send from your backend over HTTPS. |
| X-Request-Id | Response | Correlation ID on every GET response. |
| X-RateLimit-Limit | Response | Partner minute quota, after admission. |
| X-RateLimit-Remaining | Response | Remaining admitted requests this minute. |
| X-RateLimit-Day-Remaining | Response | Remaining admitted requests this UTC day. |
| Retry-After | 429 / 503 | Seconds to wait before retrying. |
| Cache-Control | Response | private, no-store. Orus maintains the shared scan cache internally. |

## Data semantics & integration

### Access by invitation

The Orus Partner API is available only to approved partners. Contact @Orus_agent on X with your product, expected traffic and integration use case. The team whitelists your partner account and delivers a private API key. There is no self-service signup.

Send Authorization: Bearer <key> from your backend over HTTPS. Never put a key in a URL, Telegram message, browser bundle, screenshot or AI prompt. Console login cookies do not grant API access. Keys expire, can be revoked individually, and share their partner's quota.

### One scan endpoint

GET /api/v1/scan?chainId=4663&token=<contract>. Version 1 supports Robinhood Chain mainnet only. Unsupported chains and invalid, zero, repeated or unknown parameters return 400. Addresses are normalized to lowercase.

Only Robinhood Chain mainnet (chainId=4663) is supported. Robinhood testnet (46630) returns 400 unsupported_chain. A bot running in testnet mode must not scan its testnet contracts as mainnet addresses. Enable live scans on mainnet cards; use the clearly labeled synthetic response examples to test the renderer offline. There is no testnet scan endpoint.

include=chart is the default. Use include=none for a fast Telegram card, include=launch for the launch sample, or include=chart,launch for all available indicators. dipThresholdPct defaults to 30 (range 1–99). lookbackHours defaults to 48 (range 1–168). Candles use a fixed five-minute interval.

All response sections are part of the Orus API and are organized by subject. Successful responses contain token, market, pool, security, risk, ath, atl, dip, launch, deployer, socials, agents, availability, warnings, attribution and card. Agent activity is always included, even with include=none; include controls only chart and launch reads. Optional sections can fail independently: a 200 response may contain unavailable data. Inspect availability and warnings. null always means unknown or unavailable, never zero, false or safe.

### Market and risk data

token contains identity, creation time, age, decimals and supply. market contains USD price, circulating market cap, FDV, liquidity, total fees, liquidity-to-market-cap percentage and 1m/5m/15m/1h/4h/6h/12h/24h windows. Available window fields cover total/buy/sell volume, organic volume, buys, sells, trades, distinct buyers/sellers/traders, fees and price changes. latestTradeAt and secondsSinceLastTrade describe the last reported trade, separately from quote freshness. pool contains the dominant pool, venue, launchpad and bonding progress.

security contains isHoneypot, buyTaxPct, sellTaxPct and liquidityBurnPct. risk contains holder and bundler/sniper/insider counts, supply percentages, developer holdings and top-10/50/100/200 concentration and fresh/pro/smart trader holdings. These observations do not constitute an execution simulation or a safety guarantee. Bundler, sniper and insider classifications can change after launch; risk.laggedFields identifies them.

Security is always requested, including include=none. Orus combines token observations with a dedicated security check when available. Inspect availability.security.status: available means all five security fields are known, partial means some are known, and unavailable means none are known. None of these statuses is a safety verdict. missingFields names exactly which security values are null. security_data_incomplete means that list is nonempty, even if honeypot and taxes are known but liquidity burn is not.

Coverage varies by token; Uniswap v4 does not by itself imply missing data or a safe contract. null means no usable observation, a timeout, or conflicting observations. conflictingFields names disagreements; those fields remain null and raise security_data_conflict. A missing check does not fail the entire scan. Display the known fields and preserve unknown values; never turn null into false or 0.

buyTaxPct and sellTaxPct describe reported token taxes, not the total cost of a trade. They exclude pool fees, v4 hook fees, price impact, slippage and gas. A reported 0/0 therefore does not mean a free swap. isHoneypot=false means no honeypot was reported by the available checks, not that every wallet, route or future trade can sell. This endpoint does not simulate a specific trade, and checkedAt is collection time rather than the underlying audit time.

deployer.address, launches and migrations contain available deployer observations, with status=partial. Rug classification is not available: rugs is always null. Missing deployer data has status=unavailable. Never render ‘0 rugs’ or ‘0 launches’ from null. ATL, social URLs and description are returned when supplied. Treat all token names, symbols, descriptions and external links as untrusted content.

### ATH, dips and launch

All money values are USD. Percentage values use 0–100 units: tax 1 means 1%, not 100%. Durations use seconds; timestamps are ISO 8601 UTC. ATH changeFromAthPct = (price / ATH − 1) × 100 and is negative below ATH. drawdownPct is the positive decline, clamped at zero. An ATH below the current quote raises a warning. ATH and launch market caps use today's supply and are approximations when supply has changed.

A dip is a closed five-minute candle at or after the reported ATH whose close is at or below ATH × (1 − dipThresholdPct / 100). Wicks and the unfinished candle do not qualify. firstDipAt is populated only when the history covers the ATH without gaps. athToFirstDipSeconds measures the ATH-to-first-crossing duration; firstDipAgeSeconds measures time elapsed since that crossing.

lastObservedDipAt is the latest observed transition from above to below that same threshold. It is not the most recent local low. secondsSinceLastObservedDip measures its age. A later recovery does not erase the observation. A truncated window or a gap may hide other crossings: inspect historyStatus, hasGaps, windowStart, windowEnd and lastCandleAgeSeconds. Times label candle opens, with five-minute resolution. A missing crossing is null, not proof that no dip occurred.

launch samples the last trade in the first second after the earliest returned trade, using at most 100 earliest trades. mayBeTruncated identifies samples reaching the cap. Its price and implied market cap follow the strategy engine's launch metric. No individual customer positions, strategy thresholds, wallets or private reports are included.

### Agent activity

The Orus API groups its data by subject: market, security, risk, agents and other indicators. agents describes trading-agent activity. scope=all_orus_agents includes desk and customer agents on the requested chain. Only counts and timestamps are returned, never agent/customer IDs, wallets, transaction hashes, amounts, PnL or strategy settings.

real and simulation each contain tradedAgents, holdingAgents, entries24h, exits24h, lastEntryAt and lastExitAt. tradedAgents counts distinct agents with eligible entries in retained history. holdingAgents counts distinct agents still holding according to the position book; it is a subset of tradedAgents, so do not add them. Multiple entries by the same agent count once in these two fields. Agents are not necessarily independent strategies or separate users.

Real entries use position statuses open, closed or sell_failed and require a non-empty recorded entry transaction hash. This excludes pre-broadcast placeholders and real rows without an entry hash, even if their bookkeeping is incomplete after an actual purchase. entry_pending never counts, even with a hash. Simulation uses simulated_open or simulated_closed and does not require a hash. Mode comes from the position, not the agent's current execution setting. Paused and stopped agents still count. Holding includes sell_failed because the book still records tokens held. No receipt or current wallet balance is rechecked.

entries24h counts eligible position entries, not distinct agents, with entry_at in the inclusive interval [asOf minus 24 hours, asOf]. exits24h counts eligible closed positions using exit_at in that same interval; failed exits do not count. A closure can be a simulated write-off and must not be described as proof of a successful on-chain sale. lastEntryAt and lastExitAt are the latest eligible recorded timestamps in retained history, not only the 24-hour window. Entry timestamps are bookkeeping times, not guaranteed block inclusion times. Future timestamps are excluded.

asOf is the observation time for agent activity. coverage=retained_history means currently retained records, not a guaranteed lifetime history: deleting an agent can remove its history. With status=available, zero means no matching records; a null lastEntryAt/lastExitAt means no eligible timestamp was found. With status=unavailable, asOf, all counts and all dates are null; availability.agents.status is unavailable and warnings includes agent_activity_unavailable. Never convert this failure to zero.

Rejection counts and acceptance rates are not exposed: existing decision logs mix strategy criteria with operational failures and do not capture every evaluation. Absence of an entry is not a refusal. Agent activity is not a consensus score, a safety verdict or a trading recommendation.

### Freshness and availability

checkedAt is the start of data collection, not the timestamp of an on-chain audit or the last trade. market.priceUpdatedAt is null because the exact quote timestamp is unavailable. A successful scan, including agents, is cached for at most 30 seconds from checkedAt. cache.ageSeconds reports its age; agents.asOf remains the original observation timestamp on a cache hit. Authentication and quotas are enforced even on cache hits; HTTP responses are private, no-store.

availability reports available, unavailable or not_requested for details, chart, launch and agents. Security has available, partial or unavailable coverage, with missingFields and conflictingFields. Security, chart, launch and agent activity may be incomplete while core token details succeed. When the scan cannot be served, the endpoint returns 503. The public token page refreshes observations for tokens already scanned or traded by Orus. It shows price candles, anonymous entry counts and clearly separated real/simulated agent activity. Refresh is requested every 30 seconds while visible; shared cached observations may be older. Collection timestamps and missing-data states are shown. The page uses a fixed 48-hour window and 30% dip threshold, without a partner key.

### Telegram integration

Render card.text immediately above your buy/sell controls and link the arrow or ‘checked by orus’ label to card.url. Use plain text, or escape all dynamic values for your Telegram parse mode. The URL deep-links to /token/4663/<address>, the public Orus token intelligence page without a partner key. Chart markers count entries in five-minute buckets, not execution prices; customer identities, sizes and rules remain private.

When retained public desk reports exist, the token page lists dated snapshots with their UTC collection time. Open a report to see its saved market figures, chart and available analysis. Historical data is not refreshed when opened; private customer reports and strategy context are excluded.

A typical line is: orus: no honeypot reported · tax 0/0 · bundled 4% · deployer 3 launches, rugs unknown · checked by orus ↗. This is an illustration, not a live scan. The API emits ‘honeypot unknown’, ‘tax unknown/unknown’ and ‘bundled unknown’ whenever the source lacks those fields.

card.text keeps its existing format. You may add a separate activity line when agents.status=available: ‘Agents (real): 8 traded · 3 holding · 5 entries / 24h’. These numbers are illustrative. Use agents.real.tradedAgents, agents.real.holdingAgents and agents.real.entries24h respectively; label simulated activity separately. Show the observation time and preserve attribution. If activity is unavailable, omit its counts or show ‘Agent activity unavailable’ while retaining the valid market scan.

If the scan fails, show ‘orus: scan unavailable’ or omit the line. Do not reuse a successful badge without its age. For the two-week pilot Orus can report admitted requests, distinct tokens, completed status codes, cache hits and median/p95 server time. The partner must measure card impressions and referral clicks; scan calls are not impressions.

### Limits and errors

Default quotas are 30 admitted requests per minute and 5,000 per UTC day, shared across all of a partner's keys and all server instances. Operators can configure them per partner. Validation failures and upstream failures consume admitted requests. X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Day-Remaining report quota state.

400: fix parameters. 401: missing, invalid, expired or revoked key, or inactive partner; stop and contact Orus. 404: token not indexed. 429: wait Retry-After. 503: retry with jitter after Retry-After, at most twice. An unindexed token is not necessarily an invalid contract. Unsupported methods return 405. Next.js also supports HEAD (same authentication and quota as GET) and automatic OPTIONS.

GET errors have { error: { code, message }, requestId }. Every GET response has X-Request-Id for support. Do not send your key to support. JSON additions may appear within v1; clients should ignore unknown fields and keep null handling. Breaking changes require a new API version.

## Machine-readable contract

- OpenAPI: https://www.orusagent.xyz/openapi/partner-v1.json
- Agent integration guide: https://www.orusagent.xyz/partner-api-agents.txt
