Skip to content

Wallet API reference

@moose/provider-sdk's ProviderClient wraps all four of these endpoints — most providers should use it rather than calling the HTTP API directly. All endpoints require a valid provider signature and are rate-limited per tenant. Errors from the endpoint itself share the body shape { "error": "<message>" }; a 401 from a bad/missing/expired signature is a plain-text body (invalid signature), not JSON — that check happens before the request reaches the endpoint. See Errors & retry for the full status code reference shared across every endpoint below.

Exceeding your tenant's rate limit returns 429 with a Retry-After header (seconds to wait) and body { "error": "rate limit exceeded" }.

POST /v1/wallet/session/verify

Request:

json
{ "sessionToken": "..." }

Response: see VerifySessionResponse in the SDK reference.

Error responses: 400 (missing/empty sessionToken), 401 (no provider identity resolved — bad/missing signature; or the session token is invalid or expired), 403 (the session belongs to a different provider), 429 (rate limit exceeded), 500 (Central Config resolution failed).

POST /v1/wallet/transaction

Requires a session token — obtained from the session the operator's launch call created, which this endpoint resolves server-side (there's no separate operatorId field on the wire). Submits a canonical BET / WIN / ROLLBACK transaction. ADJUSTMENT is rejected on this endpoint — that's admin-only.

Status code mapping:

  • 400 — invalid request body (validation failure, e.g. malformed currency), or the request doesn't match the session it references (playerRef/gameId/currency mismatch)
  • 401 — no provider identity resolved (bad/missing signature), or the session token is invalid or expired
  • 403 — the session belongs to a different provider than the one that signed this request
  • 409 — another attempt for this transactionId is in flight, don't retry yet
  • 429 — rate limit exceeded
  • 503 — game/operator not configured
  • 500 — retryable platform-side failure (includes a TIMED_OUT resolution)

A 200 with status: "DECLINED" is a normal business outcome, not an error.

Request/response shapes: see TransactionRequest / TransactionResponse in the SDK reference for the exact wire schema. currency must be a 3-letter, uppercase ISO-4217 code (e.g. "USD", not "usd") — a malformed code is rejected with 400.

POST /v1/wallet/balance

Queries the player's current balance on demand, without moving any money. Requires only a session token — playerRef is resolved from the session server-side, so a provider can never query the balance of a player under a session it doesn't own. The operator's wallet remains the source of truth: this is a pass-through query, not a cached or platform-computed value.

Request:

json
{ "sessionToken": "..." }

Response:

json
{ "balance": 4200 }

balance is in minor currency units (e.g. cents), matching TransactionResponse.balance.

For a DEMO session, this returns the in-memory fun-play balance instead of querying a real operator.

Status code mapping:

  • 400 — missing/empty sessionToken
  • 401 — no provider identity resolved (bad/missing signature), or the session token is invalid or expired
  • 403 — the session belongs to a different provider than the one that signed this request
  • 429 — rate limit exceeded
  • 503 — operator not configured
  • 500 — the operator's balance endpoint errored or timed out

Unlike POST /v1/wallet/transaction, this call is not idempotent-tracked and not retried by the platform on your behalf beyond what ProviderClient.getBalance does client-side — it's a read, so a failed attempt can simply be retried.

Bot-detection telemetry isn't on this API

There's no POST /v1/rgs/behavior here — bot-detection digests are posted straight from the game client's browser to a separate, dedicated behavior-ingestion endpoint, authenticated by session token rather than a provider signature (a browser can't hold your HMAC secret). See BehaviorReporter and the behavior-ingestion endpoint.