Wallet adapter
Wallet adapter
Manage the REST v1 wallet adapter configuration used by Mini App balance reads and wallet mutations.
Paths
GET /api/operator/wallet-adapter
PUT /api/operator/wallet-adapter
POST /api/operator/wallet-adapter/test
Required scopes
wallet_adapter:readforGETwallet_adapter:writeforPUTandPOST /test
GET response
The response is masked. Secrets are never returned.
GET has no query parameters or body; only the bearer header and wallet_adapter:read scope are required.
Fields:
balance_adapter_typeauth_mode:env_var,encrypted, ornonebase_urltimeout_msbalance_pathdebit_pathcredit_pathdebit_reversal_pathhas_bearer_tokenhas_signature_secretcurrency_codeupdated_at
PUT body
Typical body:
{
"base_url": "https://wallet.operator.example",
"bearer_token": "operator-wallet-token",
"signature_secret": "optional-signing-secret",
"timeout_ms": 10000,
"balance_path": "/balance",
"debit_path": "/debit",
"credit_path": "/credit",
"debit_reversal_path": "/debit-reversal"
}
A configured secret may be omitted when updating non-secret fields. Sending a new secret replaces the stored encrypted value.
| Field | Type | Requirement | Values/default |
|---|---|---|---|
base_url | string | Required on first setup | May be omitted on later updates to keep the current URL. HTTPS required except localhost/127.0.0.1. |
bearer_token | string | Required on first setup | May be omitted later to keep the encrypted credential. |
signature_secret | string | Optional | Enables request signing. Omit to keep an existing secret; an empty value does not clear it. |
timeout_ms | integer | Optional | Default 10000; clamped to 1000–30000. |
balance_path | string | Optional | Default /balance. A leading / is added when missing. |
debit_path | string | Optional | Default /debit. |
credit_path | string | Optional | Default /credit. |
debit_reversal_path | string | Optional | Default /debit-reversal. |
credit_reversal_path | string | Optional | Accepted by the API, default /credit-reversal; not used by current production trade/redemption flows. |
Current dashboard-managed production paths are balance, debit, credit, and debit reversal. The backend config parser also accepts credit_reversal_path for compatibility with the shared direction enum, but the current trade/redemption processor does not call credit reversal in production flows and the masked GET response does not expose that field.
The current API supports REST v1 only for IDR operators. Unsupported currency returns 400 REST_V1_UNSUPPORTED_CURRENCY.
Test body
Common and mode-specific fields:
| Field | Type | Requirement | Values/default |
|---|---|---|---|
external_user_id | string | Required | Dedicated operator-side test user. |
mode | string | Optional | connection (default) or full_contract. |
amount_minor | positive integer | Required for full_contract | Small real mutation amount in operator currency minor units. |
confirmation | boolean | Required for full_contract | Must be exactly true. |
| Adapter config fields | mixed | Optional | May temporarily override or complete the saved config for this test. The resulting config must contain base_url and a bearer token. |
product | string | Optional | opinion (default) or polyflight for a Polyflight full-contract drill. |
dedicated_test_user_confirmation | boolean | Required for Polyflight full_contract | Must be exactly true; confirms the external user is isolated test infrastructure. |
scenario | string | Optional for Polyflight | normal, debit_applied_then_timeout, credit_applied_then_timeout, definite_rejection, duplicate_same, or duplicate_conflict. |
Connection test:
{
"mode": "connection",
"external_user_id": "operator-user-123",
"base_url": "https://wallet.operator.example",
"bearer_token": "operator-wallet-token"
}
Full contract test:
{
"mode": "full_contract",
"external_user_id": "operator-user-123",
"amount_minor": 1000,
"confirmation": true
}
Polyflight full-contract drill:
{
"mode": "full_contract",
"product": "polyflight",
"external_user_id": "dedicated-polyflight-test-user",
"amount_minor": 1000,
"confirmation": true,
"dedicated_test_user_confirmation": true,
"scenario": "debit_applied_then_timeout"
}
Polyflight test amounts must be a 1,000-IDR step and no more than 10,000 IDR. These drills use production Polyflight reasons, keys, and metadata plus dedicated-test context; the normal sequence also uses a test-only cleanup debit. Use only dedicated staging/test wallet infrastructure. The API is not a simulator-only endpoint: submitted configuration overrides can direct real HTTP mutations, and the safety confirmation is not an environment lock.
The full contract test performs real wallet mutations against the configured or submitted adapter config. Use a dedicated test user and a small amount.
The Opinion full-contract sequence is: balance, debit, debit reversal, credit, second debit, final balance. A successful sequence must return to its initial balance; a mismatch requires manual review.
All mutation test requests include external_user_id, amount_minor, currency_code, idempotency_key, reason, and metadata. They do not include direction; the path selected for the step is the direction.
Polyflight scenario behavior
The receiving test wallet must implement the requested fault. Merely selecting a scenario does not make an arbitrary operator wallet reject or time out.
| Scenario | Expected behavior |
|---|---|
normal | Purchase debit and compensation; separate setup debit and full refund; win credit and test cleanup debit; zero-amount loss credit and its identical duplicate; final balance equals initial balance. |
duplicate_same | Repeat the purchase key/payload successfully without a second debit, compensate, then verify final balance. |
duplicate_conflict | Repeat the purchase key with a different amount and expect HTTP 409, compensate the original debit, then verify final balance. |
definite_rejection | Expect HTTP 422; no automatic compensation/final-balance sequence. |
debit_applied_then_timeout | Expect HTTP 504 after debit; manual review, no blind compensation or final-balance check. |
credit_applied_then_timeout | Expect HTTP 504 after win credit; manual review, no cleanup or final-balance check. |
Polyflight test mutations include top-level dedicated_test_user_confirmation: true, in addition to metadata test context. Generated purchase/ticket IDs are contract-test correlations, not admitted product records. A simulator-only result does not certify the real HTTP wallet contract.
Non-null mutation receipt echoes of external_user_id, idempotency_key, amount_minor, and currency_code must match the request; identity conflicts fail the step. Production processing treats conflicting receipts as unknown. Inspect actual steps and ledger evidence even if a test result is labelled failed rather than unknown; that label alone does not prove a wallet write never happened.
Test response
{
"mode": "connection",
"success": true,
"requires_manual_review": false,
"steps": [
{
"step": "balance",
"method": "GET",
"path": "/balance",
"status": "success",
"latency_ms": 42,
"remote_status": "succeeded",
"external_user_id": "operator-user-123"
}
]
}
Step status can be success, failed, or unknown.
requires_manual_review = true means a mutation or compensation step reached a state that needs operator follow-up before the test user should be reused.
Full-contract responses additionally include product, scenario, test_run_id, nullable contract_expectation_met, and Polyflight safeguards. A deliberate fault can return success: true / contract_expectation_met: true together with requires_manual_review: true: the expected fault was observed, but the applied wallet effect still needs reconciliation. Do not reuse that user or repeat the whole test to “clear” it.
In the dashboard, Wallet Settings saves configuration, Integration UAT exposes saved-config connection checks, and API Playground → Wallet Adapter exposes the test API where a confirmed full-contract body can be submitted.
