# SVM Price Subscriptions

Subscribe to real-time price updates for Solana tokens. When a subscribed token's price changes, you receive a `priceUpdate` event on your Socket.IO connection with the latest price from the highest-liquidity pool.

> **Socket.IO only:** Price updates are delivered as server-emitted events on your Socket.IO connection. You must be connected via Socket.IO to receive them.

---

## Subscription Limits

Maximum active subscriptions per tier:

| Tier | Max Subscriptions |
| --- | --- |
| Free | 0 |
| Basic | 10 |
| Premium | 100 |
| Enterprise | 1,000 |

---

## Subscribe

Subscribe to price updates for one or more tokens.

**Endpoint:** `/svm/price/subscribe`

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `chain` | string | Yes | Always `sol` |
| `tokens` | string[] | Yes | Array of token mint addresses (min 1) |
| `ttlMs` | number | No | Subscription duration in milliseconds. Max: 604,800,000 (7d), default: 21,600,000 (6h) |

**Example:**

```typescript
socket.emit("/svm/price/subscribe", {
  chain: "sol",
  tokens: [
    "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "So11111111111111111111111111111111111111112",
  ],
  ttlMs: 21600000, // 6 hours
});
```

**Response:**

```json
{
  "success": true,
  "result": {
    "subscribed": [
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "So11111111111111111111111111111111111111112"
    ]
  }
}
```

Re-subscribing to an already-subscribed token refreshes its TTL without counting against the subscription limit.

---

## Unsubscribe

Unsubscribe from price updates for one or more tokens.

**Endpoint:** `/svm/price/unsubscribe`

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `chain` | string | Yes | Always `sol` |
| `tokens` | string[] | Yes | Array of token mint addresses to unsubscribe |

**Example:**

```typescript
socket.emit("/svm/price/unsubscribe", {
  chain: "sol",
  tokens: ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"],
});
```

**Response:**

```json
{
  "success": true,
  "result": {
    "unsubscribed": [
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
    ]
  }
}
```

---

## Active Subscriptions

List all active (non-expired) price subscriptions.

**Endpoint:** `/svm/price/active_subscriptions`

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `chain` | string | Yes | Always `sol` |

**Example:**

```typescript
socket.emit("/svm/price/active_subscriptions", {
  chain: "sol",
});
```

**Response:**

```json
{
  "success": true,
  "result": {
    "tokens": [
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "So11111111111111111111111111111111111111112"
    ]
  }
}
```

---

## Price Update Event

When a subscribed token's price changes, you receive a `priceUpdate` event. Updates are sourced from the highest-liquidity pool for the token and deduplicated so you only receive meaningful price changes.

```typescript
socket.on("priceUpdate", (data) => {
  console.log(data);
});
```

**Event payload:**

```json
{
  "chain": "sol",
  "token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "pool": {
    "type": "RaydiumV4",
    "lp": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2",
    "backingToken": "So11111111111111111111111111111111111111112",
    "rawPrice": 0.000034,
    "priceUsd": 0.0051,
    "tokenReserve": "1000000000000",
    "backingReserve": "34000000"
  },
  "slotNumber": 285000000,
  "timestamp": 1710979200
}
```

| Field | Type | Description |
| --- | --- | --- |
| `chain` | string | Always `sol` |
| `token` | string | Token mint address |
| `pool.type` | string | DEX type (e.g. `RaydiumV4`, `PumpSwap`, `MeteoraDLMM`) |
| `pool.lp` | string | Liquidity pool address |
| `pool.backingToken` | string | Backing token mint (e.g. SOL or USDC) |
| `pool.rawPrice` | number | Raw price ratio (token lamports / backing lamports) |
| `pool.priceUsd` | number | Price of 1 full token in USD |
| `pool.tokenReserve` | string | Token reserve amount in the pool |
| `pool.backingReserve` | string | Backing token reserve amount in the pool |
| `slotNumber` | number | Solana slot number of the update |
| `timestamp` | number | Unix timestamp in seconds |

---

## Subscription Expiring Event

You receive a `subscriptionExpiring` event shortly before a subscription expires, and again when it actually expires. Use this to re-subscribe if needed.

```typescript
socket.on("subscriptionExpiring", (data) => {
  console.log(data);
});
```

**Event payload:**

```json
{
  "chain": "sol",
  "token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "expiresAt": 1711065600,
  "expired": false
}
```

| Field | Type | Description |
| --- | --- | --- |
| `chain` | string | Always `sol` |
| `token` | string | Token mint address |
| `expiresAt` | number | Unix timestamp (seconds) when the subscription expires |
| `expired` | boolean | `false` when expiring soon, `true` when already expired |
