Skip to content

POST /freespins/finish

Beexar → Operator

Beexar sends this request when a freespins issue is over, with the total its free rounds won, for you to credit to the player you issued them to. It is the only wallet request freespins make: the free rounds themselves send no /betwin and no /finish.

Only operators that issue freespins receive it. It goes to the operator’s Freespins finish URL — a fifth callback URL, separate from the four round callbacks.


POST {freespins_finish_url}

Header Value
Content-Type application/json
X-REQUEST-SIGN HMAC-SHA256 signature of request body
Field Type Required Description
issue_id string Yes Your identifier of the issue — the issue_id you sent to Freespins/Issue
amount string Yes Total won on the issue’s free rounds, a decimal string in the issue’s currency, at that currency’s scale — zero when they won nothing ("0.00" in EUR, "0" in JPY)

The request names neither the player nor the currency: they are the ones you recorded for issue_id when you issued it.

{
"issue_id": "fs-2026-000123",
"amount": "12.50"
}

Field Type Required Description
balance string Yes The player’s balance after the credit
{
"balance": "512.50"
}
HTTP Status Twirp Code api_code Description
400 invalid_argument 610 Unknown issue_id — you never issued it
400 invalid_argument 605 Only for an issue whose Freespins/Cancel Beexar accepted — it never sends a Finish for one
400 invalid_argument 400 Invalid request
400 invalid_argument 403 Invalid or missing signature
500 internal 500 Internal server error

Terminal window
curl -X POST https://casino.example.com/wallet/freespins/finish \
-H "Content-Type: application/json" \
-H "X-REQUEST-SIGN: abc123def456..." \
-d '{
"issue_id": "fs-2026-000123",
"amount": "12.50"
}'

  • Sent once per issue, when the issue is over: every free round has been played, or valid_until passed after at least one was played. Never for an issue that expired with no round played, and never for a canceled one.
  • Retried until accepted: after 1, 3 and 5 minutes, then every 5 minutes, until you answer 200. Every retry carries the same body, byte for byte. Each attempt has 15 seconds; a slower answer counts as no answer.
  • Idempotent on issue_id: credit amount once, store the balance you answered, and answer a repeat with that stored balance — not today’s, and without crediting again. Do the check and the credit in one database transaction, as for id_provider on /betwin.
  • Zero is valid ("0.00", or "0" in a currency without decimals): the free rounds won nothing. Accept it and close the issue; unlike a /betwin amount, zero is not an error here.
  • The amount is final: what the issue’s rounds won in total, frozen when the issue ended.
Issue ended by Sent?
Every free round played Yes — the total won
valid_until passed after at least one round Yes — what the played rounds won
valid_until passed with no round played No
Freespins/Cancel No — the winnings are forfeited

sequenceDiagram
    participant Beexar
    participant Wallet as Operator Wallet

    Note over Beexar: the issue's last free round ends
    Beexar->>Wallet: POST /freespins/finish { issue_id, amount }
    Wallet--xBeexar: timeout
    Note right of Beexar: retried after 1 minute, same body
    Beexar->>Wallet: POST /freespins/finish { issue_id, amount }
    Wallet->>Wallet: issue_id not credited yet: credit, store balance
    Wallet-->>Beexar: 200 { balance }
    Note right of Wallet: a later repeat answers the stored balance