CRYPREX API v1

Build trading bots that place price predictions programmatically. All amounts are in USDT.

Getting started

  1. Log in to your account and open Profile → 🔑 API.
  2. Create an API key. It is shown once — copy and store it safely.
  3. Send the key in the Authorization header on every request.
Authorization: Bearer cpx_your_api_key_here

Keys grant access to your account only (balance, your bets, placing bets). They cannot withdraw, deposit, or access other users. Keep your key secret; revoke it anytime in your Profile.

Rate limits

  • Read endpoints (GET): 120 requests / minute per key
  • Placing bets (POST /bet): 10 requests / minute per key
  • /api/v1/leaderboard-bets (no key needed): 900 usernames / minute per IP — batching with usernames= doesn't raise this, it just means fewer round trips
  • /api/v1/symbols (no key needed): 60 requests / minute per IP — the list is cached for 5 minutes, so polling it faster than that returns the same payload

Exceeding a limit returns 429 with a Retry-After header (in seconds). The rounds endpoint is cached for ~2s, so polling it frequently is fine.

Endpoints

Base URL: https://cryprex.com

GET/api/v1/leaderboard-bets

Public, no API key required — recent bets of any user(s) by username. Built for copy-trading bots that need to detect when a leader places a new bet.

Query: username (one user) or usernames (comma-separated, up to 100 — batch instead of one request per user), since (ISO timestamp, optional), limit (per-user, 1–100, default 50).

since is a cursor, not a general date filter — pass it for polling. Without it, results start from the oldest bet still inside the retention window (ascending order), not the user's most recent activity. To poll for new bets: store the createdAt of the last bet you processed, then pass it back as since on the next call to get only what happened after it.

Retention: only the last 40 days of bets are returned. A since older than that is clamped to the window start. This has no effect on copy-trading, which polls the tail.

Rate limit is counted in usernames requested, not HTTP requests — a batch of 20 costs the same as 20 separate calls, it just costs one round trip. With usernames, the response is a flat list with a username field on each bet; with a single username, the shape matches the other endpoints (top-level username, no per-bet field).

GET/api/v1/account

Your account: id, username, balance, statusText, statusLocked.

POST/api/v1/account/status

Set your status text — shown as a speech bubble next to your username on the leaderboard. Body: { "statusText": "..." } (max 34 chars, empty/omitted clears it). Fails with 403 if an admin has locked your status.

GET/api/v1/symbols

Public, no API key required — every pair you can bet on. Use it to validate a symbol before calling /api/v1/bet.

Query (optional): exchange (futures|spot, default futures).

Returns { symbol, pair } per entry, sorted alphabetically — no prices, no volumes. Live quotes belong to the round you are betting on, not to this list.

/api/v1/bet only checks a symbol against the pattern ^[A-Z0-9]{2,20}USDT$. A well-formed but non-existent pair is not rejected as unknown — it fails later with 503 when no opening price can be fetched. Checking against this list avoids that.

Cached for 5 minutes. If Binance is unreachable the last good list is served with stale: true rather than an empty array.

GET/api/v1/rounds

Current rounds and period info (start/end, betting deadline, whether betting is open).

Query (optional): period (5m|15m|1h|1d|1w|1m|1y), exchange (futures|spot, default futures), symbol (e.g. BTCUSDT).

GET/api/v1/bets

Your bets, newest first.

Query (optional): status (active|won|lost|cancelled), limit (1–200, default 50), offset.

POST/api/v1/bet

Place a prediction. Body (JSON):

{
  "symbol": "BTCUSDT",
  "period": "1h",
  "direction": "UP",
  "amount": 5,
  "exchange": "futures"
}

direction: UP or DOWN. amount: min 1 USDT. exchange optional (default futures). The start price, round and betting deadline are determined by the server — you cannot bet after a round's deadline.

Supported symbols are not a fixed whitelist: any USDT pair Binance currently lists as trading works — around 695 on futures and 480 on spot (BTCUSDT, ETHUSDT, BNBUSDT, SOLUSDT, XRPUSDT and so on). Call /api/v1/symbols for the exact live list.

Don't use /api/v1/rounds for this — it returns rounds that already exist, and a round is only created by the first bet on that pair, so at any moment most supported symbols are simply absent from it. You can bet on a pair that has no round yet; the round is opened by your bet.

How predictions work

You predict whether a coin price will be UP or DOWN at the end of a period (1 hour, day, week, month, year). Each period has a betting window; after the deadline no new bets are accepted, but the round runs until it ends. Winners split the losing pool proportionally (a 20% commission applies to the losing pool). /api/v1/bets?status=won

Example bot — Python

import requests

BASE = "https://cryprex.com"
API_KEY = "cpx_your_api_key_here"
headers = {"Authorization": f"Bearer {API_KEY}"}

# 1. Check balance
acc = requests.get(f"{BASE}/api/v1/account", headers=headers).json()
print("Balance:", acc["account"]["balance"])

# 2. Look at the 1h round for BTC and bet if betting is open
r = requests.get(f"{BASE}/api/v1/rounds",
                 params={"period": "1h", "symbol": "BTCUSDT"},
                 headers=headers).json()

can_bet = r["periods"][0]["canBet"]
if can_bet:
    resp = requests.post(f"{BASE}/api/v1/bet", headers=headers, json={
        "symbol": "BTCUSDT",
        "period": "1h",
        "direction": "UP",
        "amount": 5,
    }).json()
    print("Bet result:", resp)
else:
    print("Betting window for this round is closed")

# 3. Review recent bets
bets = requests.get(f"{BASE}/api/v1/bets",
                    params={"limit": 5}, headers=headers).json()
for b in bets["bets"]:
    print(b["symbol"], b["direction"], b["amount"], b["status"])

Example bot — Node.js

const BASE = "https://cryprex.com";
const API_KEY = "cpx_your_api_key_here";
const headers = {
  "Authorization": `Bearer ${API_KEY}`,
  "Content-Type": "application/json",
};

async function main() {
  // 1. Balance
  const acc = await fetch(`${BASE}/api/v1/account`, { headers }).then(r => r.json());
  console.log("Balance:", acc.account.balance);

  // 2. Check the 1h BTC round
  const r = await fetch(`${BASE}/api/v1/rounds?period=1h&symbol=BTCUSDT`, { headers })
    .then(r => r.json());

  if (r.periods[0].canBet) {
    const resp = await fetch(`${BASE}/api/v1/bet`, {
      method: "POST",
      headers,
      body: JSON.stringify({
        symbol: "BTCUSDT",
        period: "1h",
        direction: "UP",
        amount: 5,
      }),
    }).then(r => r.json());
    console.log("Bet result:", resp);
  } else {
    console.log("Betting window is closed");
  }
}

main();

Responses & errors

Every response is JSON with a success boolean. On error, error holds a message.

  • 401 — invalid or missing API key
  • 400 — bad parameters (see error message)
  • 429 — rate limit exceeded (retry after header)
  • 503 — start price temporarily unavailable, retry

POST /api/v1/bet also returns a stable code next to the message: BETTING_CLOSED, INSUFFICIENT_FUNDS, MIN_AMOUNT, PRICE_UNAVAILABLE, ACCOUNT_BANNED, INVALID_PERIOD, INVALID_DIRECTION, INVALID_EXCHANGE, INVALID_AMOUNT, INVALID_INPUT, USER_NOT_FOUND, BET_FAILED. Branch on code, not on the message text — wording may change, codes will not.

Partner bots — for developers publishing on CRYPREX

Everything above uses a user API key: it acts as one account and can place bets for it. Publishing your own bot on CRYPREX is a separate track with a separate credential — a bot secret — and the two are not interchangeable.

User API keyBot secret
Issued in your profile, by yourselfIssued by CRYPREX after your bot is approved
Authorization: Bearer cpx_…Authorization: Bearer bot_…
Acts as one user accountActs as your bot: its own wallet only, never someone else's account
120 reads/min, 10 bets/min per key60 reads/min, 20 writes/min per bot
Endpoints above/api/v1/bot/*

Where your bot runs

On your own server. We do not host your code and there is no iframe. cryprex.com/bots/<your-slug>/* is reverse-proxied to the origin URL you give us, so your bot lives under our domain while running on your infrastructure.

  • The full original path is forwarded, prefix included — your app receives /bots/<slug>/page, not /page. Set that prefix as your framework's basePath (Next.js basePath) so your own links and fetches line up.
  • Query strings are preserved. All headers pass through except hop-by-hop ones; we add x-forwarded-host and x-forwarded-proto.
  • Your origin unreachable → visitors get 502. Suspended or unconfigured bot → our own page for that slug, not a proxy.
  • Routing is a database row, so a new slug goes live without a deploy on our side.

Origin requirements. An absolute http:// or https:// URL; use HTTPS in production. You may point it at anything reachable from the internet while developing, including a tunnel to your laptop. The origin can be changed later — ask support; the proxy picks it up within 15 seconds, no redeploy on either side. We do not health-check your origin and we do not require you to allowlist us, though you may: all traffic reaches you from our server.

Verifying traffic came through us. Anyone who learns your origin URL can call it directly, bypassing the proxy and your billing. Every proxied request carries x-cryprex-proxy, set to the SHA-256 of your bot secret. Compare it against sha256(your_secret) and reject requests without it. We overwrite any incoming header of that name, so it cannot be forged from outside. Sending the hash rather than the secret is deliberate — the hash is useless for authenticating against our API.

Charging a user for your plan

You never touch a user's balance directly. You create an intent, the user confirms it on CRYPREX, you verify the result server-side.

  1. POST /api/v1/bot/charge-intent with { cryprexUserId, amount, description, planDays } → returns intentId, confirmUrl, expiresAt (15 minutes).planDays is the term being sold, in whole days — send it for every dated plan, omit it for lifetime. We do not track subscriptions, so it is the only way we can work out a buyer's unused days if your bot is ever suspended. Without it they cannot be compensated.
  2. Send the user to confirmUrl. Whoever is logged in there pays — cryprexUserId is a UI hint, not the source of truth.
  3. GET /api/v1/bot/charge/<intentId>pending | completed | expired, plus payerUserId. Always confirm here; never trust redirect parameters in the browser, they are trivially forged.
  4. Your share lands in your bot wallet. POST /api/v1/bot/payout with { toUsername, amount, reason } moves money out of that wallet — to yourself or to a user, e.g. a refund. It spends only what your bot earned.

Auto-renewal

Pass recurring: true to charge-intent (alongside planDays — a lifetime plan has nothing to renew). That does not create a mandate; it puts a checkbox on the checkout page, unticked by default. The mandate exists only if the user ticks it, because from then on the charge happens without them.

  • Renewal charges the same amount every planDays days, on the ladder prices — auto-renewal is not a separate plan.
  • GET /api/v1/bot/subscriptions lists yours (filter by cryprexUserId or status). pastDue: true means the last charge failed and the grace period is running.
  • DELETE /api/v1/bot/subscriptions/:id cancels. Calling it twice is fine — a cancelled mandate answers success rather than an error.
  • You must give the user a way to cancel inside your bot. There is no cancel button on CRYPREX for this, so yours is the only one. A plan the buyer cannot stop is grounds for suspension.
  • Out of balance: we retry for 3 days and tell the user, then cancel the mandate. The bot is not charged for the attempts.
  • We stop the mandate ourselves if your bot is suspended — nobody keeps paying for something that has been turned off.
  • The user gets a message 2 days before each charge, and again if one fails. It is sent in whatever language their interface is set to.

Cancelling stops future charges only. The period already paid for runs to its end and is not refunded — see the sales-are-final rule below.

Commercial terms

  • Onboarding fee — 1000 USDT, one-off. Covers listing your bot on /bots, registering the slug and origin, wiring up billing, and issuing the secret. Charged before the bot goes live and not refundable once the secret is issued.
  • Revenue share — 50%. CRYPREX keeps half of every plan purchase made through charge-intent.Your half is released in 30-day instalments across the term the buyer paid for, not all at once: a 30-day plan pays out once after 30 days, a 90-day plan in three parts, a year in twelve. Instalments are whole cents, with the last one carrying the remainder — a $365 plan releases eleven times at $15.20 and once at $15.30. Released money appears in your bot wallet; you can see what is still locked in your CRYPREX profile. This exists so that a suspension has a cost: it is what buyers are compensated from when a bot is pulled mid-term.
  • Plan prices are fixed by CRYPREX and identical for every partner. You may not price below them, run private discounts, or move a paid feature outside our billing to avoid the share. Undercutting is grounds for suspension.
  • Optional loyalty discount — 20%. You may offer it to users who display I use <botname> as their CRYPREX status. It is earned by keeping the status for 30 continuous days and applies to the next purchase. Offering it is your choice; its terms are not — 20% and 30 days, so the same offer means the same thing on every bot.

The plan ladder, identical for every partner:

PlanPriceYour half
30 days$50$25
90 days$120$60
180 days$210$105
365 days$365$182.50
Lifetime$500$250

Every plan is a one-time payment, no recurring charges. You may offer fewer plans than this, but not different prices.

All sales are final. Plans cannot be paused, cancelled or refunded — not by the user, not by you, not partway through. State this plainly on your own pages before checkout so buyers are not surprised by it afterwards. Auto-renewal is the one thing that can be stopped, and stopping it only prevents the next charge: the period already paid for still runs to its end.

All money moves through CRYPREX balances. Taking payment for a plan outside the platform is a breach of these terms.

Getting a secret, and how to test

  1. Apply at /bots/apply. You can apply with any balance — nothing is checked at this step. We answer within 72 hours.
  2. On approval the 1000 USDT is deducted from the CRYPREX balance of the account you named as owner, so top it up beforehand. There is no invoice and no external transfer.
  3. The slug and origin are registered and the secret is issued. It is shown once — only its hash is stored, so it can be regenerated but never recovered.
  4. You build and test against the live API with the secret in hand. Your bot is not listed on /bots yet.
  5. Listing on /bots happens last, after the bot is finished and we have tested it.

Working and listed are two separate states. From the moment your bot is created it is fully working: the key authenticates, and cryprex.com/bots/<your-slug> serves your app. It is simply not in the catalogue, and the link is published nowhere — you use it to build against the real address, we use it to review. Listing only makes it visible to users; nothing about how it runs changes. Being unlisted is not a penalty and never affects your key.

There is no sandbox. Billing is exercised against real balances, so debug it with small amounts — charge-intent accepts any amount above zero, and $1 walks the whole path. Because the secret is issued before listing, you can do all of this without anything being visible to users.

A suspended bot stops authenticating immediately and its slug stops proxying. Suspension is for breach of these terms, not something a user can trigger.

If we suspend or remove your bot, its buyers are made whole. Users holding a plan that has not run out are credited the unused days back to their CRYPREX balance, pro rata. That is CRYPREX honouring the purchase on your behalf — it is not a refund the buyer can ask for, and it does not change the rule that sales are final. Keep this in view when weighing whether a shortcut is worth it: the cost of a suspension lands on you.

The API is provided as-is for building bots on CRYPREX. We may adjust limits to keep the platform stable. Abuse or attempts to overload the service will result in key revocation.