Skip to content

End-to-end flows ​

Each payment path start to finish — who calls what, in what order, with example requests and responses. Endpoint paths and enums come from the code; the JSON bodies are illustrative — real values (ids, amounts, timestamps) differ, and only the fields shown are meaningful.

Paths use the mount points from Admin panel API and Player and provider API. In local dev the admin routes carry an /api prefix.

1. Player deposit through a gateway ​

The common case: a player deposits with an automated provider (card, UPI, crypto). No operator is involved; the provider confirms and the wallet is credited by a callback.

Player app ──create──▶ player-management ──▶ provider service ──▶ Provider
                                                                      │
                            wallet-management ◀──credit── player-management ◀──callback──┘

Step 1 — the player starts the deposit. The app creates a pending transaction.

http
POST /player/transactions/deposit
json
{
  "playerId": "665f0c2a9d1e4a0012ab34cd",
  "walletId": "665f0c2a9d1e4a0012ab7788",
  "amount": 1000,
  "provider": "PayZeasy",
  "method": "upi-collect",
  "idempotency_key": "0f8b1e2c-3d4a-4b5c-8e9f-1a2b3c4d5e6f"
}

The transaction is written with status: "pending" and handed to the provider service (POST /payzeasy/payin, which returns a payment page or QR to show the player).

Step 2 — the provider confirms. When the money lands, the provider calls its webhook, and the service forwards a normalised callback to player-management:

http
PUT /player/transactions/deposit/update-callback
json
{
  "id": "TXN-20260903-0042",
  "status": "success",
  "transactionAmount": 1000,
  "paymentMethod": "upi-collect"
}

Step 3 — the wallet is credited. player-management calls wallet-management:

http
POST /wallet/credit
json
{ "walletId": "665f0c2a9d1e4a0012ab7788", "amount": 1000, "type": "deposit" }

The deposit moves pending → success (or completed), and if it qualifies, a deposit bonus is evaluated. A declined payment arrives as status: "failed" instead and the wallet is untouched.

Provider status vocabularies are normalised

Each provider speaks its own language — YumGo sends needs_confirmation, AlphaPo sends confirmed, and so on. The callback handler maps these onto the internal enum (pending, success, failed, …) from Data model. You always read the internal value, never the provider's raw one.

2. Player deposit by manual bank transfer ​

Same start, but there is no automatic confirmation — an operator confirms the money against a bank reference, and that approval is what credits the wallet.

Player ──create──▶ pending ──(player transfers money in their bank app)──▶
Operator ──approve + bank reference──▶ /bank-payment/callback ──▶ wallet credit ──▶ success

Step 1 — the player picks a brand bank account and starts the deposit.

http
POST /bank-payment/deposit/:playerId        (player-side service)
json
{
  "wallet_id": "665f0c2a9d1e4a0012ab7788",
  "amount": 1000,
  "bank_account_id": "665f0c2a9d1e4a0012abbank",
  "idempotency_key": "a1b2c3d4-e5f6-4a5b-9c8d-7e6f5a4b3c2d"
}

The player transfers the money in their own banking app and the deposit sits pending.

Step 2 — the operator finds it in the manual bank deposit request list (GET /wallet-transactions/general-deposits/:adminId?provider=manual_bank) and approves it, entering the bank reference from the transfer. The panel resolves that to:

http
POST /bank-payment/callback        (admin-side service)
json
{
  "transaction_id": "TXN-20260903-0043",
  "status": "success",
  "amount": "1000",
  "bank_reference": "UTR9988776655"
}

The wallet is credited and the deposit becomes success. Reject instead sends status: "failed" with a reason (nothing is credited); refund on an already-credited deposit sends status: "refunded" with a reason and debits the money back out.

The approval is the credit

Until an operator confirms against the bank reference, the money is not in the wallet. See Reviewing withdrawals.

3. Player withdrawal — request, review, resolve ​

A withdrawal debits the wallet at request time, then waits for an operator.

Player app ──create (debits wallet)──▶ pending
Operator ──approve──▶ payout ──▶ success        OR
Operator ──reject──▶ refund to wallet ──▶ rejected

Step 1 — the player requests it. The wallet is debited immediately.

http
POST /player/transactions/create-withdrawal/:playerId
json
{
  "walletId": "665f0c2a9d1e4a0012ab7788",
  "amount": 500,
  "method": "manual_bank",
  "provider": "bank-payment",
  "bankAccountId": "665f0c2a9d1e4a0012abacct",
  "addressData": {
    "account_number": "<encrypted>",
    "ifsc_code": "<encrypted>",
    "account_holder": "<encrypted>"
  },
  "idempotency_key": "9c8d7e6f-5a4b-4c3d-8e2f-1a0b9c8d7e6f"
}

The transaction moves created → pending. If the wallet debit fails it becomes error instead.

Step 2a — the operator approves. For manual bank a bank reference is required:

http
POST /withdrawal-transactions/approve/:tx_id/:adminId
json
{ "bank_reference": "UTR1122334455" }
json
// 200
{ "message": "Transaction approved and sent to <Provider>", "payoutResponse": { } }

Only a pending transaction can be approved (else 400). Omitting the reference on a manual bank withdrawal returns 400 "bank_reference is required for approval". The payout executes and the transaction ends success.

Step 2b — or the operator rejects. The held money is returned automatically:

http
PUT /withdrawal-transactions/reject/:tx_id/:adminId
json
{
  "agentNote": "KYC documents could not be verified",
  "playerMessage": "Your withdrawal was declined because your verification is incomplete."
}
json
// 200
{
  "message": "Transaction rejected and wallet refunded",
  "transaction": { "status": "rejected" },
  "playerNotificationSent": true
}

The wallet is credited back, rejection.reject_reason_code is set to ADMIN_REJECTED, and the player is notified with playerMessage. Do not credit the player again — the refund already happened.

Step 3 (if it failed at the provider) — retry. A payout that errored can be retried while retry_count (default 5) remains:

http
PUT /withdrawal-transactions/approve/retry/:tx_id/:adminId

Only an error transaction is retryable; anything else returns 400.

4. Admin manual credit (top-up) ​

No provider, no callback — the wallet changes the instant the request returns.

http
PUT /wallets/:walletId/deposit/:adminId
json
{
  "amount": 50,
  "method": "correction",
  "type": "Admin",
  "note": "Goodwill credit — ticket #4821",
  "idempotency_key": "3c4d5e6f-7a8b-4c9d-8e1f-2a3b4c5d6e7f"
}
json
// 200
{
  "message": "Deposit successful",
  "wallet": { "total": "150.00" },
  "transaction": {
    "tx_id": "TXN-20260903-0044",
    "status": "success",
    "method": "correction",
    "provider": "Admin",
    "createdBy": { "name": "Jane Operator" }
  }
}

Note the mapping from what you send to what is stored: method: "fiat" → "cash", "correction" → "correction", "bonus" → "bonus"; and provider becomes the type you sent. The choice of method is the whole point — see Crediting and debiting a player.

5. Admin manual debit ​

http
PUT /wallets/:walletId/withdraw/:adminId
json
{
  "amount": 20,
  "method": "correction",
  "type": "Admin",
  "note": "Reversing mistaken credit — ticket #4822",
  "idempotency_key": "6f7a8b9c-0d1e-4f2a-8b3c-4d5e6f7a8b9c"
}
json
// 200
{ "message": "Withdrawal successful", "wallet": { "total": "130.00" }, "transaction": { "status": "success", "isApproved": true } }

Guards you will hit:

ConditionResponse
Wallet total below the amount400 { "error": "Insufficient funds" }
idempotency_key already used409 with the existing transaction
Wallet id not found404 { "error": "Wallet not found" }

6. Deposit reversal / chargeback ​

A confirmed deposit can be taken back — a provider chargeback, or an operator undoing it. The transaction flips success → reversed (guarded so it cannot double-flip), and the wallet is debited for the original amount with type: "rollback":

http
POST /wallet/debit
json
{ "walletId": "665f0c2a9d1e4a0012ab7788", "amount": 1000, "type": "rollback" }

A reversal does not undo the bonus or the play that followed the deposit — that is why chargebacks need investigating rather than clearing. See How players deposit.

7. Provider-specific variants ​

The generic flows above hold for every provider; these are the places a specific provider does something extra worth knowing.

AlphaPo — crypto deposit and withdrawal ​

A crypto deposit reuses a per-player, per-currency address rather than a hosted payment page. The app fetches (or creates) the address, shows it, and the deposit confirms when the chain does.

Player app ──GET .../deposit/address/:playerId/:currency──▶ (address + tag shown)
Player sends crypto to the address ──▶ blockchain confirms ──▶ alphapo service
                                     wallet credit ◀── player-management ◀── /alphapo/callback

The callback maps AlphaPo's vocabulary onto the internal enum: confirmed → success, processing → processing, not_confirmed/pending → pending, and cancelled/declined/failed/error → failed.

A crypto withdrawal debits the wallet up front (like any withdrawal), the provider pays out, and a callback confirms — but a failed payout triggers an explicit rollback that credits the wallet back:

Player app ──create (debits wallet)──▶ alphapo withdrawal-request
  success ──▶ /alphapo/withdrawal/callback ──▶ success
  failed  ──▶ /alphapo/withdrawal/callback ──▶ rollback ──▶ wallet credit (refund) ──▶ failed

TektikPay — approve, then execute (two steps) ​

TektikPay withdrawals are the one place approval and payout are separate calls. The player's request reserves funds and sits pending; an operator approves it in the review queue; and only then is the payout executed against TektikPay.

Player app ──create──▶ pending (funds reserved)
Operator ──approve──▶ player-management ──execute──▶ /tektikpay/withdrawal/execute
                                          callback ◀── tektikpay (Success | failed)

Contrast this with a gateway like Sansgetirsin, where approval and payout are the same call — approving sends the payout immediately.

Banco SANTS — PIX withdrawal ​

A PIX payout carries the destination key rather than bank-account fields:

http
POST /player/transactions/withdrawal/bancosants/:playerId
json
{
  "walletId": "665f0c2a9d1e4a0012ab7788",
  "amount": 250,
  "pixKey": "[email protected]",
  "pixKeyType": "email",
  "provider": "bancosants",
  "method": "pix",
  "idempotency_key": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"
}

The rest matches the generic withdrawal flow: debit on request, provider payout, /bancosants/withdrawal-callback confirms.

YumGo — the extra confirmation state ​

YumGo deposits can pass through a needs_confirmation provider status (3DS or a manual check), which the callback maps to the internal pending_confirmation. A deposit sitting there has not credited yet — it is waiting on the provider, not on an operator. It resolves to completed on success or failed/expired/cancelled otherwise; reversed/reversing cover a later reversal.

Status transitions at a glance ​

Deposit: pending → success (credited) · pending → failed (untouched) · success → refunded (manual bank refund) · success → reversed (chargeback).

Withdrawal: created → pending (held) · pending → processing → success (paid) · pending → rejected (refunded) · pending → error → success (retried).

The full enums, including the provider-oriented intermediate states, are in Data model.

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