Overview
Overview
Wallet adapter is operator-owned server-to-server API used by OpenPoly to read balances and execute wallet mutations.
Ownership split
OpenPoly owns:
- Mini App UI
- quote and execution pipeline
- trade and redemption state
- webhook dispatch
Operator owns:
- wallet balances
- debit and credit execution
- wallet auth secret
- wallet operation observability
Required contract paths
GET /balancePOST /debitPOST /creditPOST /debit-reversal
REST v1 has path-based mutation direction. OpenPoly selects the endpoint from the operation type; the JSON request body does not include a direction field.
The shared adapter config also has a credit_reversal_path field for compatibility with the internal direction enum, but the current Mini App trade/redemption processor does not call POST /credit-reversal in production flows.
Mutation request body
All mutation endpoints use the same JSON body shape:
{
"external_user_id": "operator-user-123",
"amount_minor": 10000,
"currency_code": "IDR",
"idempotency_key": "mini_app_order:1:debit",
"reason": "mini_app_buy_order",
"metadata": {}
}
OpenPoly sends every field below on every mutation request.
| Field | Type | Requirement | Notes |
|---|---|---|---|
external_user_id | string | Required | Stable operator-side user ID. |
amount_minor | integer | Required | Amount in the currency's minor unit. Current REST v1 operators use IDR. |
currency_code | string | Required | Current production value: IDR. |
idempotency_key | string | Required | Durable deduplication key. |
reason | string | Required | Business reason such as mini_app_buy_order, mini_app_sell_order, mini_app_redemption, or mini_app_buy_compensation. |
metadata | object | Required | Always sent; may be empty. Fields vary by flow and must be treated as additive. |
external_user_id is required for debit, credit, and reversal paths. OpenPoly resolves it from the Mini App launch/session user and sends it again on each wallet mutation.
Required metadata by flow
Metadata is part of the production contract. Operators must accept additional fields without rejecting the request.
| Flow | Reason | Required metadata | Optional additive metadata |
|---|---|---|---|
| Buy debit | mini_app_buy_order | orderId, marketId | outcome |
| Buy compensation | mini_app_buy_compensation | orderId, marketId | balanceOperationId |
| Sell credit | mini_app_sell_order | orderId, marketId | outcome |
| Redemption credit | mini_app_redemption | redemptionItemId, marketId | None currently |
The full-contract adapter test uses mini_app_wallet_adapter_test with test-only metadata. It is not a market trade or redemption and is exempt from this production matrix.
Core rules
- Every mutation must be idempotent.
- Direct mutation response
statusis required and must besucceeded,failed, orpending. Other response fields are optional unless an endpoint page says otherwise. - A timeout, network failure,
pending, HTTP408, HTTP429, or HTTP5xxleaves the primary mutation outcome ambiguous and sends the order to manual review. - Do not retry an ambiguous primary debit or credit automatically. An operator may already have applied it.
- Buy compensation may retry with its original idempotency key because the repeated request must return the original effective result.
- Unknown wallet state must not be reported as success.
- OpenPoly order state and wallet state are not one atomic transaction.
- Manual review may be required when remote wallet result is unknown.
Recommended headers
Authorization: Bearer {opera...ken}
X-Polynion-Request-Id: req_...
X-Polynion-Timestamp: 2026-06-18T00:00:00.000Z
Optional request signing may also be enabled with X-Polynion-Signature.
Dashboard setup
Operator admins configure the adapter in Operator Dashboard → Integrations → Wallet Adapter.
The dashboard stores:
- base URL;
- bearer token;
- optional signing secret;
- timeout and path overrides.
Bearer and signing secrets are encrypted before storage. After saving, OpenPoly only shows whether a secret is configured; plaintext and encrypted payloads are never returned by the API.
Validation tests
The dashboard exposes two validation modes:
- Connection test — calls only
GET /balancefor a supplied external user ID. It does not mutate wallet state. - Full contract test — performs real wallet mutations against a dedicated test user and small amount. It validates balance, debit, debit reversal, credit, a second debit, and final balance. The final balance must equal the initial balance.
Full contract tests require explicit confirmation because compensation can fail or become unknown. If a compensation step fails, OpenPoly reports requires_manual_review so the operator can inspect and reconcile the remote wallet manually.
