# Tequity free bets API

For operators whose wallet already speaks Tequity's wallet protocol. The wallet manages free bets on 232rgs with the same calls it makes to Tequity's platform ("Extra API": add, remove, available bets). The RGS runs them as its native free rounds, so they are budgeted, audited and settled like any other campaign. Design and rules: `docs/design/tequity-free-bets.md`.

## Base URL, signing and set-up

- **Base URL:** the wallet's platform base URL is `https://<rgs>/tequity`. Every call is `POST <base>/wallet/{wallet}/freeBets/{add|remove|availableBets}` with `Content-Type: application/json`.
- **Signing:** `X-Server-Authorization` is the lowercase or uppercase hex HMAC-SHA256 of the exact request body with the wallet's shared secret (Tequity's scheme: `echo -n $BODY | openssl dgst -sha256 -hmac $SECRET -hex`). It is compared in constant time.
- **Set-up, done by the RGS operator:**
  - **The wallet entry:** a name (`{wallet}`, `[a-z0-9][a-z0-9_-]{0,63}`), a secret of at least 32 characters, and an operator API key that holds the `campaigns` scope. They go in the file named by `TEQUITY_WALLETS_FILE`.
  - **The acting key:** every campaign and grant is audited under that key. Revoking the key, or letting it expire, stops the wallet.
- **Common fields:**
  - `operator` must equal that key's operator code.
  - `brand` is accepted and not used yet.
  - Game ids are the RGS game codes.
  - Currencies are three lowercase letters.

## Add free bets — `POST /wallet/{wallet}/freeBets/add`

| Field | Rule |
| --- | --- |
| `walletCampaignId` | 1–128 characters |
| `games` | 1–64 game ids |
| `nativeIds` | 1–1,000 player ids, each 1–256 characters |
| `bets` | Free bets per player, 1–10,000 |
| `amount` | Stake per free bet in major units. It must be one of the game's free-round amounts in that currency (see available bets). More decimals than the currency has are refused, not rounded. |
| `currency` | For example `eur`. |
| `start`, `end` | Optional Unix milliseconds. `start` defaults to now and `end` to 90 days after `start`; `end` must be after `start`. |
| `operator`, `brand` | As above. |

**What the RGS does:**
- **Campaigns:** one native campaign per game, with the stake as given, payouts as promotional money, and a liability budget that covers every grant's maximum payout.
- **Grants:** each player gets `bets` free rounds.
- **New players:** a player without an account in that currency gets one, as a first launch would. No money moves, and an active responsible-gaming block is inherited.

**Response:** `{"success": true}`.

**Repeats:** sending the same request again completes whatever is missing and creates nothing twice. A different request under the same `walletCampaignId` creates its own campaigns, and remove ends them all.

## Remove free bets — `POST /wallet/{wallet}/freeBets/remove`

- **Body:** `walletCampaignId`, `games`, `operator`, `brand`.
- **Effect:** ends every native campaign made for that `walletCampaignId` on those games. Removing again changes nothing.
- **Response:** `{"success": true}`.
- **Unknown campaign:** a `walletCampaignId` never added on a game is `409 {"error":"FREE_ROUNDS_UNAVAILABLE"}`.

## Available bets — `POST /wallet/{wallet}/freeBets/availableBets`

- **Body:** `games` (1–64), `currencies` (1–16), `operator`, `brand`.
- **Response:** each game's free-bet amounts in major units, per requested currency. `[]` where the game has none.

```json
{ "fruit-oasis": { "eur": [0.1, 1], "usd": [] } }
```

## Errors

| Status | Body | When |
| --- | --- | --- |
| 401 | `{"error":"OPERATOR_AUTHENTICATION_FAILED"}` | Bad or missing signature, unknown wallet, or the acting key revoked, expired, without the `campaigns` scope, or its operator inactive. |
| 400 | `{"error":"INVALID_REQUEST"}` | Body fails the rules above, `operator` does not match, the amount is not a free-bet amount of the game, too many decimals, or `end` not after `start`. |
| 409 | `{"error":"FREE_ROUNDS_UNAVAILABLE"}` | Removing a campaign that was never added; a game not enabled for the operator in that currency. |

These are the RGS's error bodies, not Tequity's `{"error":{"code","message"}}`.

## Not provided

- **`POST /wallet/{wallet}/availableGames`:** it needs a title and a type per game in the catalog.
- **Tequity's money calls:**
  - Launch, authenticate, balance, transaction and cancel are built ([tequity-wallet.md](tequity-wallet.md)).
  - Free bets play through a connector wallet: the free round's withdraw of 0 and its deposit carry `campaignType: freeBets`, the `walletCampaignId` and `campaignData` ([tequity-wallet.md](tequity-wallet.md), Free rounds). The operator needs the `free-rounds-external` module.
  - Jackpot fields on transactions are not built; jackpot games are refused on connector sessions. Design: `docs/design/tequity-wallet-connector.md`.
