Skip to main content

Callback Specification

This page documents the four HTTP endpoints that your server must implement to support Seamless Wallet integration. Ruby calls these endpoints in real time for every game event.


Overview

All four endpoints share the following properties:

  • Method: POST
  • Base URL: your configured callback_url
  • Content-Type: application/json (request and response)
  • Authentication: HMAC-SHA256 signature headers (see Callback Authentication)
  • Timeout: 5 seconds hard cutoff; target < 3 seconds
  • Success criteria: any HTTP 2xx response code
  • Failure behavior: non-2xx or timeout → immediate error, no automatic retry

URL Construction

Ruby strips any trailing slash from your callback_url before appending the path:

callback_url = "https://wallet.example.com/ruby"
→ POST https://wallet.example.com/ruby/balance
→ POST https://wallet.example.com/ruby/debit
→ POST https://wallet.example.com/ruby/credit
→ POST https://wallet.example.com/ruby/rollback

It is recommended to register your callback_url without a trailing slash, though either form will work.


POST /balance

Query a player's current balance. This is a stateless read — no funds are moved and no side effects are expected.

Request

{
"player_id": 12345,
"username": "player_handle",
"provider_code": "evo"
}
FieldTypeRequiredDescription
player_idintegerYesRuby's internal player identifier
usernamestringNoPlayer's display name, if available
provider_codestringNoGame provider code (e.g., "evo", "pg")

Response

{
"balance": "1250.00"
}
FieldTypeDescription
balancestringCurrent player balance as a decimal string (e.g., "1250.00")

Notes

  • balance is a stateless query. There is no transaction_id and no idempotency requirement.
  • Always return the current real-time balance for the player.

POST /debit

Deduct funds from a player's wallet. Called when a player places a bet.

Request

{
"player_id": 12345,
"amount": "100.50",
"transaction_id": "txn_bet_abc123",
"username": "player_handle",
"provider_code": "evo",
"round_id": "round_xyz",
"game_code": "baccarat_classic",
"ref_id": "external_ref_001",
"memo": "Bet on Baccarat round 7"
}
FieldTypeRequiredDescription
player_idintegerYesRuby's internal player identifier
amountstringYesAmount to deduct, as a decimal string (e.g., "100.50")
transaction_idstringYesUnique transaction identifier — use this for idempotency
usernamestringNoPlayer's display name
provider_codestringNoGame provider code
round_idstringNoGame round identifier
game_codestringNoGame identifier within the provider
ref_idstringNoExternal reference ID from the game provider
memostringNoHuman-readable description of the transaction

Response

{
"balance": "1149.50",
"balance_before": "1250.00"
}
FieldTypeDescription
balancestringPlayer's balance after the debit
balance_beforestringPlayer's balance before the debit

Idempotency

If you receive a POST /debit request with a transaction_id you have already successfully processed, return the same response as the original call. Do not deduct funds again.

If the original transaction is still in progress (e.g., due to a race condition), serialize access to prevent double-debit.

Error Cases

ScenarioRecommended HTTP Status
Insufficient funds402 Payment Required or 422 Unprocessable Entity
Player not found404 Not Found
Player account suspended403 Forbidden
Internal server error500 Internal Server Error

Any non-2xx response is treated as a failure by Ruby.


POST /credit

Add funds to a player's wallet. Called when a player wins or a settlement occurs.

Request

{
"player_id": 12345,
"amount": "200.00",
"transaction_id": "txn_win_def456",
"username": "player_handle",
"provider_code": "evo",
"round_id": "round_xyz",
"game_code": "baccarat_classic",
"ref_id": "external_ref_002",
"memo": "Win payout for Baccarat round 7"
}
FieldTypeRequiredDescription
player_idintegerYesRuby's internal player identifier
amountstringYesAmount to credit, as a decimal string
transaction_idstringYesUnique transaction identifier — use this for idempotency
usernamestringNoPlayer's display name
provider_codestringNoGame provider code
round_idstringNoGame round identifier
game_codestringNoGame identifier within the provider
ref_idstringNoExternal reference ID from the game provider
memostringNoHuman-readable description of the transaction

Response

{
"balance": "1349.50",
"balance_before": "1149.50"
}
FieldTypeDescription
balancestringPlayer's balance after the credit
balance_beforestringPlayer's balance before the credit

Idempotency

If you receive a POST /credit request with a transaction_id you have already successfully processed, return the same response as the original call. Do not credit funds again.


POST /rollback

Reverse a prior debit transaction. Called when a round is voided or cancelled after a bet was already placed.

Request

{
"player_id": 12345,
"amount": "100.50",
"transaction_id": "txn_rollback_ghi789",
"username": "player_handle",
"provider_code": "evo",
"round_id": "round_xyz",
"ref_id": "external_ref_003"
}
FieldTypeRequiredDescription
player_idintegerYesRuby's internal player identifier
amountstringYesAmount to restore, as a decimal string
transaction_idstringYesUnique transaction identifier for this rollback — use this for idempotency
usernamestringNoPlayer's display name
provider_codestringNoGame provider code
round_idstringNoGame round identifier
ref_idstringNoExternal reference ID from the game provider

Note: game_code and memo are not included in rollback requests.

Response

{
"balance": "1250.00"
}
FieldTypeDescription
balancestringPlayer's balance after the rollback

Note: balance_before is not included in the rollback response.

Idempotency

If you receive a POST /rollback request with a transaction_id you have already successfully processed, return the same response as the original call. Do not restore funds again.


Field Types Reference

FieldTypeNotes
player_idintegerAlways present in all four callbacks
amountstringDecimal representation, e.g. "100.50". Parse with Decimal or equivalent — do not use floating-point
balancestringDecimal representation of balance after transaction
balance_beforestringDecimal representation of balance before transaction (debit/credit only)
transaction_idstringOpaque unique string; use as a deduplication key
usernamestringMay be absent; do not depend on it for player lookup
provider_codestringShort code identifying the game provider
round_idstringGame-level round identifier
game_codestringProvider-specific game identifier (not present in rollback)
ref_idstringExternal reference from the game provider; may be absent
memostringHuman-readable note; may be absent (not present in rollback)

Idempotency Summary

Endpointtransaction_idIdempotency Required
/balanceNoNo — stateless read
/debitYesYes
/creditYesYes
/rollbackYesYes

Ruby records a successful response for each transaction_id. If Ruby calls you again with the same transaction_id (due to network uncertainty), your server must return the original result. Ruby does not rely on re-processing to be safe — but your server must defend against it independently.


Retry Policy

There is currently no automatic retry for failed callbacks. If a callback returns a non-2xx status code, or if the request times out (> 5 seconds), Ruby propagates the error immediately back to the game provider. No re-attempt is made.

Plan your error handling accordingly:

  • Return 5xx only for transient errors you expect to be retried manually
  • Return 4xx for permanent business errors (insufficient funds, player suspended)
  • Ensure your server can respond within 5 seconds under load