Skip to content

Two APIs, running in opposite directions

Integrating an aggregator is usually described as one thing. It is two, and only one of them is a product. Understanding which is which is the whole reason this platform is sold without an aggregator attached.

The direction that is a client, and the direction that is a service

Games API — we call them

Four endpoints and a thin HTTP client. If one is slow, a page is slow. Nothing here can lose a transaction, and nothing here is hard.

  • POST /operator/generic/v2/game/url

    open a game session

  • POST /operator/generic/v2/game/list

    the catalog, rate-limited to one request a minute

  • POST /operator/generic/v2/game/round

    replay a settled round

  • POST /operator/generic/v2/products/list

    the providers enabled on your account

Wallet API — they call us

Five endpoints we host and operate, with no JWT on them. The signature and the IP allowlist are the entire authentication, and the signature is verified over the raw body — never over re-serialised JSON, which is a different string.

  • POST /user/info

    who this token belongs to

  • POST /user/balance

    the only endpoint exempt from idempotency

  • POST /transaction/bet

    debit, live token required

  • POST /transaction/win

    credit, an expired token is still valid

  • POST /transaction/rollback

    always answers RS_OK, even for a transaction never seen

The bet and the win never reach the player app. The balance moves server-side while the app is showing an iframe it cannot see into — which is why every balance on screen carries a refresh control and the app re-fetches when a game closes. A platform that does not account for this shows players a stale number after every spin.

Every callback answers HTTP 200, with the status in the body

A non-200 reads to an aggregator as “operator down”. Hub88 will retry a failed rollback up to five hundred times with backoff, so a server that answers 500 to a malformed request earns itself a retry storm on top of whatever was already wrong. The status goes in the body. All fifteen are implemented.

RS_OK

The only success value there is.

RS_ERROR_INVALID_SIGNATURE

The body did not verify against your public key.

RS_ERROR_INVALID_TOKEN

Unknown token, or a token belonging to a different player.

RS_ERROR_TOKEN_EXPIRED

Known, but past its life. Distinct from unknown, deliberately.

RS_ERROR_NOT_ENOUGH_MONEY

Refused, and the real balance is sent alongside it.

RS_ERROR_USER_DISABLED

The account is blocked or frozen.

RS_ERROR_INVALID_PARTNER

The operator id on the request is not one of ours.

RS_ERROR_INVALID_GAME

The game code is not in the catalog.

RS_ERROR_WRONG_CURRENCY

The wallet does not hold that currency.

RS_ERROR_DUPLICATE_TRANSACTION

Same id, different content. A conflict, not a retry.

RS_ERROR_TRANSACTION_DOES_NOT_EXIST

A win with no bet behind it, and no replay of its own.

RS_ERROR_WRONG_SYNTAX

The body is not the shape the contract describes.

RS_ERROR_WRONG_TYPES

Right fields, wrong types.

RS_ERROR_LIMIT_REACHED

An operator limit stopped it.

RS_ERROR_UNKNOWN

Implemented, and deliberately never sent — it is graded as an operator system failure.

Three token rules that are easy to implement backwards

Each of these has a failure that only shows up in production, on a real player, once.
A balance read and a bet need a live token
Nothing may be debited on a session that has ended.
live
A win and a rollback accept an expired one
A round can settle after the player has closed the game. Refusing a late win is how an operator ends up with unpaid players, which is the counter an aggregator grades hardest.
expired is fine
A token belonging to someone else is invalid, not expired
Reporting the wrong one sends the provider down the wrong recovery path.
invalid

What each callback does when it arrives twice

Retries are normal traffic, not an incident. Each endpoint has its own answer, and each answer is tested.
bet
A genuine retry returns the first result. A different transaction carrying an id that was already used is a conflict and is told so. Turnover accrual runs where it cannot fail the response, because by then the money has already moved.
duplicate is refused
win
Before refusing a win with no matching applied bet, the ledger checks whether this win’s own id was already applied — that is a legitimate replay, not an attack. Inventing money from an unreferenced win is the first thing a chaos suite tries.
needs a bet behind it
rollback
Including for a transaction never seen: a zero-amount tombstone is written so the retries stop. It reverses only an applied bet not already reversed by a different rollback id, gives back the turnover the bet actually contributed rather than a recomputation against today’s weights, and then zeroes it so a second rollback restores nothing.
always RS_OK

What the first week looks like

This is a sequence, so it is numbered. Dates move with your certification slot; the order does not.
  1. 01 · Day one

    Credentials and a staging pointing

    You create the Operator ID and key pair on your own Hub88 account — they are yours, and they stay yours. We take the public key, you take ours, and the wallet endpoints are pointed at a staging deployment.

  2. 02 · Day two

    Catalog sync and curation

    The game list is pulled once, categories are mapped, and anything that does not map is reported to you by name rather than filed under a default. You curate the lobby; a later re-sync cannot undo that, because a sync only overwrites provider-owned fields.

  3. 03 · Day three

    The chaos suite against your credentials

    A retried bet, a win with no bet, an unreferenced rollback, a late win on an expired token, a bad signature, a blocked-country game, an unmapped category. This runs before certification is requested, not after it fails.

  4. 04 · Day four

    Certification, under your Operator ID

    Hub88’s own certification tests, run twice — once on staging and once on production — per region you operate in. We drive the run; the account, the credentials and the pass are yours.

  5. 05 · Day five

    Brand, themes, content and staff accounts

    Brand name, theme, banners, promotions, bonus policies, VIP tiers, payment channels and the staff roles that can touch each of them. All of it is data, so none of it is a deploy.

Certification runs under your Operator ID and your key pair, per region, because those credentials belong to you and not to us. Each brand you launch is its own technical integration and each operating entity is invoiced separately by the aggregator — a two-brand, two-region plan is four integrations, not one. Worth knowing before anybody promises a date.

If you are not on Hub88

Nothing above is specific to one vendor except the names. Provider detail lives behind an interface with twelve members, and the core never contains an aggregator’s name. Writing a second adapter is bounded work against a contract that already exists, and it is proved by the fact that the entire test suite runs against a mock adapter implementing those same twelve members.
Identity and trust
The adapter key, and the IP allowlist inbound callbacks must come from.
2 members
Configuration
Taking the operator’s credentials, and refusing to run at all when it has not been given them. A half-configured adapter that answers anyway is worse than one that will not start.
2 members
Catalog
Reading the provider’s game list, and mapping their category onto ours. A category that does not map returns null and is reported — never defaulted.
2 members
Session and signature
Minting a launch URL for a player, and verifying an inbound signature over the raw request body.
2 members
Lookups the back office needs
A round, the product list, and a transaction search. These are what a desk uses to answer “what happened to this bet” without leaving the back office.
3 members
Freebets
Campaigns and rewards: create, list, inspect, bulk-create, cancel, and read prepaids. One member on the interface, eight functions behind it.
1 member, 8 calls

Tell us which aggregator you run and we will tell you what that adapter costs before you commit to anything.

Bring your Operator ID. We will show you the callbacks landing