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

# Callout competitions

> Competitions ranked on callouts instead of trades: kind callouts, metrics avg_peak_x, best_peak_x, sum_peak_x, hit_rate and callouts, with min_callouts, hit_x and chain all.

> [!NOTE]
>
> Callouts are switched on per instance on request. Contact us ([contact@cabalspy.xyz](mailto:contact@cabalspy.xyz)) to enable them. Without them every endpoint answers 403 [feature\_not\_enabled](https://docs.cabalspy.xyz/cabalspy-id/errors.md#feature_not_enabled).

A callout competition ranks your platform users on the [callouts](https://docs.cabalspy.xyz/cabalspy-id/callouts.md) they make while it runs, instead of on their trades. It is a [competition](https://docs.cabalspy.xyz/cabalspy-id/competitions.md) like any other: the same endpoints, lifecycle, enrollment, participant limits, rule changes, standings every 5 minutes and webhooks. Only what counts and how it is scored differ.

Create one with [POST /v1/competitions](https://docs.cabalspy.xyz/cabalspy-id/competitions-create.md) and `"kind": "callouts"`. `kind` cannot be changed later. Without callouts switched on, the request is refused with `feature_not_enabled`. Callout competitions count towards the same limit of 5 open competitions.

## What counts

Every callout a participant makes **on your instance while the competition runs**, from `started_at` to `ends_at`, on the competition's chain, or on any chain with `"chain": "all"`. A participant who joined after the start counts only the callouts made after joining, so earlier callouts do not count for late joiners. Removed callouts do not count.

Each callout is counted with its current [score](https://docs.cabalspy.xyz/cabalspy-id/callouts.md#scoring), its peak multiple so far. A callout made during the competition keeps improving its participant's score while its token makes new highs, until the competition ends. At the end the standings are frozen, later highs no longer change the results.

Wallets play no part: `wallet_trust` has no effect on a callout competition.

## Metrics

| metric | Score |
| - | - |
| `avg_peak_x` | Average score of the participant's callouts. |
| `best_peak_x` | Best score of a single callout. |
| `sum_peak_x` | Sum of the scores. |
| `hit_rate` | Callouts that reached `hit_x`, as a percentage of the participant's callouts (0 to 100). |
| `callouts` | Number of callouts. |

Highest score ranks first. Ties are broken by more callouts, then by who joined first.

## Fields

Callout competitions take the fields of [Create a competition](https://docs.cabalspy.xyz/cabalspy-id/competitions-create.md), with these differences:

| Field | Callout competitions |
| - | - |
| `kind` | `"callouts"`. Default `"trading"`. Only on create. |
| `metric` | One of the callout metrics above. |
| `chain` | solana, bnb, base, eth, rh, or `all` for callouts on any chain. |
| `min_callouts` | Callouts a participant needs to be ranked, 0 to 100,000. Default 0. A participant needs at least one callout either way. |
| `hit_x` | The multiple that counts as a hit for `hit_rate`, above 1 and at most 1000. Default 2. |
| `min_trades`, `min_volume_usd` | Do not apply. Sending them is refused with `invalid_parameter`. |
| `wallet_trust` | Accepted, but has no effect. |

`min_callouts` and `hit_x` in turn are refused on trading competitions. Both can be changed at any time with [Update](https://docs.cabalspy.xyz/cabalspy-id/competitions-update.md), like every other rule. If callouts were switched off for your instance in the meantime, updating a callout competition is refused with `403 feature_not_enabled`.

The competition object returns `kind`, plus `min_callouts` and `hit_x` in place of `min_trades` and `min_volume_usd`. With `"chain": "all"`, `chain_name` is `All chains`.

## Create one

```bash cURL theme={null}
curl -X POST "https://api-id.cabalspy.xyz/v1/competitions" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Caller of the Week",
    "kind": "callouts",
    "chain": "all",
    "metric": "avg_peak_x",
    "duration_hours": 168,
    "enrollment": "all_users",
    "min_participants": 2,
    "min_callouts": 3,
    "hit_x": 2,
    "prizes": [{"rank": 1, "prize": "Caller of the Week badge"}]
  }'
```

```python Python theme={null}
import requests

r = requests.post("https://api-id.cabalspy.xyz/v1/competitions", json={
    "name": "Caller of the Week", "kind": "callouts", "chain": "all",
    "metric": "avg_peak_x", "duration_hours": 168, "min_callouts": 3,
}, headers={"Authorization": "Bearer YOUR_KEY"})
c = r.json()["data"]
print(c["id"], c["kind"], c["status"])
```

```javascript JavaScript theme={null}
const res = await fetch("https://api-id.cabalspy.xyz/v1/competitions", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    name: "Solana 5x Hunt", kind: "callouts", chain: "solana",
    metric: "hit_rate", hit_x: 5, min_callouts: 5, duration_hours: 72,
  }),
});
const { data } = await res.json();
console.log(data.id, data.metric, data.hit_x);
```

```json Response theme={null}
{
  "success": true,
  "data": {
    "id": "2e7a9c4b-1d3f-4b5a-8c6d-9e0f1a2b3c4d",
    "name": "Caller of the Week",
    "description": null,
    "chain": "all",
    "chain_name": "All chains",
    "metric": "avg_peak_x",
    "wallet_trust": "all",
    "enrollment": "all_users",
    "status": "scheduled",
    "starts_at": null,
    "duration_hours": 168.0,
    "started_at": null,
    "ends_at": null,
    "ended_at": null,
    "min_participants": 2,
    "max_participants": null,
    "kind": "callouts",
    "participants": 148,
    "min_callouts": 3,
    "hit_x": 2.0,
    "late_join": true,
    "prizes": [{ "rank": 1, "prize": "Caller of the Week badge" }],
    "rules_version": 1,
    "standings_updated_at": null,
    "created_at": "2026-11-01T18:00:00Z",
    "updated_at": "2026-11-01T18:00:00Z",
    "changes": [],
    "changed_while_running": false
  },
  "meta": {
    "request_id": "req_5162c7cf7f87",
    "cached": false,
    "cache_age_seconds": 0,
    "version": "v1",
    "timestamp": "2026-11-01T18:00:00Z"
  }
}
```

## Standings

[Standings](https://docs.cabalspy.xyz/cabalspy-id/competitions-standings.md) of a callout competition carry callout stats instead of trading stats in each entry:

| Field | Meaning |
| - | - |
| `score` | The value of the competition's metric. |
| `callouts` | Callouts counted. |
| `avg_peak_x`, `median_peak_x`, `best_peak_x` | Average, median and best score. Null without callouts. |
| `sum_peak_x` | Sum of the scores. |
| `hits`, `hit_rate` | Callouts that reached `hit_x`, and their percentage (0 to 100). |
| `best_call` | The participant's best callout: id, chain, mint, symbol and peak\_x. Null without callouts. |

Participants below `min_callouts`, or without any callout, are listed after the ranked ones with `rank: null` and `ranked: false`. The same entries appear in `top` of `competition.standings` and `results` of `competition.ended`.

```json Standings entry theme={null}
{
  "rank": 1,
  "ranked": true,
  "external_id": "user_8412",
  "csid_id": "3f9a1c2e-5b7d-4e8f-a1b2-c3d4e5f60718",
  "score": 2.3911,
  "callouts": 4,
  "avg_peak_x": 2.3911,
  "median_peak_x": 1.8273,
  "best_peak_x": 4.48,
  "sum_peak_x": 9.5644,
  "hits": 2,
  "hit_rate": 50.0,
  "best_call": {
    "id": "5b0e7c3a-2d4f-4a6b-9c8d-1e2f3a4b5c6d",
    "chain": "solana",
    "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
    "symbol": "invisibull",
    "peak_x": 4.48
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.