9 min read

Cloudbet API automation — patterns the docs don't tell you about

Cloudbet's v3 API is mature but the docs cover happy paths. Bet placement idempotency, settlement query timing, balance polling intervals, and rate-limit shape — the patterns operators actually need.

  • Cloudbet API
  • Automation

Cloudbet’s v3 API is a mature REST + WebSocket surface — bet placement, settlement queries, balance card, history endpoints all work as described. What the docs don’t cover is the operational pattern: how to make bet placement idempotent, when to poll settlement vs subscribe to push, how often to refresh the balance card, and the rate-limit shape that catches most first-time automation builders. This post is the operational layer between the public docs and a production-grade bet placer.

The asynchronous shape

Most retail betting platforms behave synchronously: you click “place bet” and the server replies with “placed” or “rejected.” Cloudbet’s v3 API behaves asynchronously: you submit, you get an acceptance receipt with a bet_id, and the actual placement happens behind the scenes. The status endpoint resolves to one of: pending, accepted, rejected, settled.

The implication for automation: a 200 OK from POST /v3/bets is necessary but not sufficient. You need a follow-up GET /v3/bets/{bet_id} to confirm the placement succeeded. The typical resolution time is 200ms–2s; the timeout you should configure is 10–30s before treating the placement as failed.

Idempotency — the non-obvious requirement

The docs mention idempotency keys briefly. The operational pattern: every bet placement should include a UUID-shaped Idempotency-Key header generated by your client. If the network drops between your submit and the server’s acceptance, you retry with the same key — Cloudbet returns the original acceptance receipt rather than placing the bet twice.

Without this pattern, transient network errors cause double-placement. With it, retries are safe up to ~24 hours.

// Pseudocode shape — production-style placement with idempotency
async function placeBet(stake: number, marketId: string, outcome: string): Promise<BetReceipt> {
  const idempotencyKey = crypto.randomUUID();
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      const res = await fetch(`${BASE}/v3/bets`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${apiKey}`,
          'Idempotency-Key': idempotencyKey,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ stake, marketId, outcome }),
      });
      if (res.status === 200) return await res.json();
      if (res.status === 409) {  // Duplicate — same key already accepted
        return await fetchExistingByKey(idempotencyKey);
      }
      if (res.status >= 500) {
        await sleep(1000 * (attempt + 1));
        continue;
      }
      throw new BetError(res.status, await res.text());
    } catch (e) {
      if (attempt === 2) throw e;
      await sleep(1000 * (attempt + 1));
    }
  }
  throw new BetError(500, 'exhausted retries');
}

Settlement query timing

Cloudbet settles bets via two paths: push (WebSocket subscription to bet status changes) and pull (HTTP GET on the bet status endpoint). The pattern that works in production: subscribe to push for primary notification, fall back to pull on a 30-minute cadence for bets in accepted state.

Why fall back? WebSockets disconnect occasionally. A bet that settled while your socket was disconnected gets missed. The pull cadence catches these without spamming the API.

Bet placed → status: accepted

WebSocket subscription notifies on settlement
  ↓ (or, every 30 min:)
GET /v3/bets/{bet_id} → if status changed, update ledger

Balance polling intervals

The balance card endpoint (GET /v3/account/balance) is rate-limited at roughly 1 req/sec per account. The operational pattern: poll every 60 seconds during active trading, every 5 minutes when idle. Higher frequency than 1/sec returns 429 and forces a back-off.

If you place bets, the balance updates immediately — you can read it back ~100ms after a bet acceptance to confirm the stake was debited. Don’t rely on this read as the placement confirmation, though — use the bet status endpoint for that.

The rate-limit shape

Cloudbet’s rate limits aren’t a single bucket. From operational observation:

Endpoint familyRateBurst
GET /v3/markets/*10 req/sec30
GET /v3/bets/*5 req/sec15
POST /v3/bets2 req/sec5
GET /v3/account/balance1 req/sec3
WebSocket subscriptionsup to 50 active

The burst capacity matters: you can fire 5 bet placements simultaneously without hitting the limit, but the 6th will queue or 429. Spread bet placements across a few hundred ms when possible.

429 responses include a Retry-After header — respect it. Repeated 429s without backoff can trigger temporary IP-level throttling.

Bet status state machine

The lifecycle of a placed bet:

pending (transient, sub-second usually)

accepted (in the book, awaiting settlement)

settled (resolved: won, lost, void, or push)

Plus rejection paths:

rejected (book declined — usually market closed or limit exceeded)

The settled status carries a settlement sub-object with result (won/lost/void/push) and payout (for wins). Your ledger updates on settled, not on accepted.

What’s NOT in the public docs

Three patterns operational users learn the hard way:

  • Market suspension. Cloudbet suspends markets briefly during the seconds around line moves. A bet submitted during suspension returns 400 with market_suspended. The pattern is to back off 500ms–2s and resubmit; if still suspended after 3 retries, abandon the bet.
  • Currency mismatch. Your account is denominated in one currency (BTC, USDT, or fiat-pegged). Bets must be in account currency; the API returns 400 if you submit a different currency code. The brand-config schema should hard-code the account currency.
  • Min/max stake per market. Each market has a min and max stake. Submitting outside the range returns 400. The pattern is to query the market detail endpoint before placement to get current min/max; cache for 60 seconds.

What Glitch Edge handles for you

If you’d rather not build this layer yourself, Glitch Edge ships a Cloudbet integration that wraps all of the above:

  • Idempotency keys generated and tracked automatically
  • WebSocket + 30-min poll fallback for settlement
  • Balance polling at the right cadence
  • Rate-limit aware request scheduling
  • Market suspension retry with bounded backoff
  • Currency + min/max validation before placement

The thin client wouldn’t take weeks to write yourself, but the operational patterns above are most of the engineering work. The boilerplate exists if you want to skip that work and focus on your strategy.

Frequently asked questions

Does Cloudbet’s API support all markets the web UI shows?

Mostly yes, with some lag — new market types sometimes appear in the web UI 1–2 weeks before they’re documented in the API. Production strategies should target documented market types only.

Can I use a single Cloudbet account for multiple strategies?

Yes — that’s the typical pattern. The API doesn’t segregate strategies; you tag bets in your own ledger with a strategy ID. Glitch Edge does this automatically.

What about WebSocket reconnection logic?

The pattern that works: exponential backoff on disconnect, max 30s between retries. On reconnect, resubscribe to your topics and run a pull-based reconciliation against bets in accepted state to catch missed settlements.

Are there sandbox / staging credentials for testing?

Cloudbet offers a sandbox environment with documented test accounts. Use it for integration testing — never run automated bet placement against production without first validating against sandbox.

How does Glitch Edge handle key rotation?

Operator rotates the key in their Cloudbet account; updates the encrypted-at-rest copy in Glitch Edge. The platform’s request scheduling handles the cutover without dropping in-flight bets.

Further reading