Skip to content

Data model ​

The transaction schemas and the status / method enums the two backends share. Enum values are quoted verbatim from the admin mono-backend Mongoose models (models/DepositTransaction.js, models/WithdrawalTransaction.js, models/BankAccount.js, models/PaymentSetting.js).

Deposit transaction ​

Collection deposittransactions. tx_id format TXN-YYYYMMDD-NNNN.

Status ​

Default created. Full enum:

created, pending, intent, started, authorized, received, settled,
completed, success, failed, expired, disputed, pending_confirmation,
refunded, confirmed, canceled, reversing, reversed

The inline comments in the model explain the provider-oriented ones: intent (payment process started), started (player on the payment page), authorized (card authorized), received (fiat received by the provider), settled (crypto sent), completed (final success), success (legacy/alternative success), pending_confirmation (awaiting 3DS or a manual check), disputed (chargeback).

success vs completed

Both success and completed are terminal success states — success is the legacy one and is what manual admin credits are written as. Treat either as "the money is in." Don't assume a single canonical success value.

Method ​

Required. Enum:

crypto, bank, manual_bank, card, correction, bonus, bank_account,
upi, voucher, admin, pix, mobile_money, neteller, skrill, cash,
apple_pay, google_pay

A manual admin Fiat credit is stored as cash (not fiat); Correction Up as correction; Bonus as bonus. See Admin panel API.

Notable fields ​

FieldNotes
amountDecimal128
afterBalanceWallet total after the credit
providerFree string; "Admin" for manual credits
paymentType / paymentSystemNameAlternative provider fields used by some gateways
external_tx_idProvider's own id
bonusEligibleBoolean, default false
rejection{ rejectedAmount, rejectedAt, rejectedBy, reasonCode, reason, rejectedTransactionRefId }
refund{ refundedAmount, refundedAt, refundedBy, reason, refundedTransactionRefId }
idempotency_keyUnique, sparse
createdBy{ adminId, name } — who ran a manual credit
noteInternal note
confirmed_at / failed_at / refunded_atTimestamps

Index: { playerId, status, currency }.

Withdrawal transaction ​

Collection withdrawaltransactions. tx_id format WDR-YYYYMMDD-NNNN.

Status ​

Default created. Enum:

created, pending, processing, confirmed, rejected, success, error, refunded

created is the pre-finalisation state; pending means held and awaiting review/payout; processing means a provider is paying it out; error is a failed payout that can be retried (up to retry_count, default 5).

Method ​

Enum (note: no manual_bank here, unlike deposits — and it does include cash):

crypto, correction, bank, card, upi, voucher, admin, pix,
mobile_money, neteller, skrill, cash, apple_pay, google_pay

A manual admin Fiat debit is stored as cash; Correction Down as correction.

Rejection reasons ​

rejection.reject_reason_code enum:

KYC_INCOMPLETE, FRAUD_SUSPECTED, BALANCE_TOO_LOW, LIMIT_EXCEEDED, ADMIN_REJECTED

A manual rejection from the review queue is recorded as ADMIN_REJECTED. The rejection object also holds rejected_by, rejected_at, reject_reason, player_message, and player_notification_id.

Notable fields ​

FieldNotes
amountDecimal128, required
isApprovedBoolean, default false; true for manual admin debits and approved payouts
approved{ approved_at, approved_by }
retry_countDefault 5, min 0
addressData{ crypto_address, network, account_number, ifsc_code, account_holder } — bank fields encrypted; null for manual admin debits
cryptoDetails{ payment_id, network, wallet_address, wallet_type }
rollback_finalized_atWhen the refund-on-failure completed
createdBy{ adminId, name }
confirmed_atSuccess timestamp

Bank account ​

Collection for manual bank accounts (models/BankAccount.js). One per brand + currency, typically.

FieldNotes
brandRequired
bank_nameRequired
account_number, account_holder_name, ifsc_codeRequired; encrypted at the application layer
currencyRequired, uppercased
deposit_min_amount / deposit_max_amountDefault null; max ≥ min
withdrawal_min_amount / withdrawal_max_amountDefault null; max ≥ min
instructionsShown to the player
orderDisplay order, default 0
isActiveDefault true
isDeletedSoft-delete flag

Payment setting ​

Singleton keyed global (models/PaymentSetting.js). All toggles default true.

deposit.cryptoEnabled          → enableCryptoDeposit
deposit.localCurrencyEnabled   → enableLocalCurrencyDeposit
deposit.manualBankEnabled      → enableManualBankDeposit
withdraw.cryptoEnabled         → allowCryptoWithdraw
withdraw.localCurrencyEnabled  → enableLocalCurrencyWithdraw

The right-hand column is the player-app flag each maps to, surfaced through GET /player/payment-config.

Permissions ​

The permission strings gating payment actions, gathered from the route files:

PermissionGates
management.payment.viewRead payment settings and the method catalogue
management.payment.createSync the method catalogue
management.payment.editUpdate settings, reorder / toggle methods
management.payment.manualBank.viewList manual bank accounts
management.payment.manualBank.createCreate a bank account
management.payment.manualBank.editEdit accounts; approve/reject/refund manual bank requests
management.payment.manualBank.deleteDelete a bank account
players.list.detail.payment.deposit.createManually credit a player (panel)
players.list.detail.payment.withdrawal.createManually debit a player (panel)

Permissions are modelled as { resource, action, category, description } and grouped into roles ({ roleName, permissions[] }). See Roles and access.

Internal documentation. Every page states what has been verified and what has not.