Wallet
End users
Freeze

Freeze an End User

Who calls these endpoints?External API (s2s)
Base path
/api/v1/wallet
Identity
Ed25519 request signature — X-Key-Id, X-Date, X-Nonce, Digest (when there is a body), X-Signature. ±5 min clock window, single-use nonce, optional per-key IP allow-list.
Authorization
The key must carry the wallet product and the wallet permission the call requires; a call without it gets 403 WALLET_INSUFFICIENT_SCOPE. Permissions per endpoint: Key permissions.
Cross-surface
Freeze exists in both s2s and the merchant panel. Unfreezing and closing are panel-only: Panel — End Users. This endpoint requires wallet:enduser:manage or wallet:program:manage on your key.
POST /api/v1/wallet/end-users/{id}/freeze

Moves the user from ACTIVE to FROZEN. Use it for a suspicious transaction, a suspected account takeover, or your own risk decision. Freezing is reversible; the balance is kept.

Request

HeaderRequiredRule
Signature headers✅Authentication
Idempotency-Key✅1–128 characters
Body fieldTypeRequiredRule
reasonstring—Reason for freezing, up to 240 characters.

If you have nothing to send, send an empty JSON object ({}).

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/end-users/8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34/freeze" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: freeze-crm-88213-20261011" \
  -H "X-Key-Id: …" -H "X-Date: …" -H "X-Nonce: …" -H "Digest: …" -H "X-Signature: …" \
  -d '{"reason":"Customer reported a lost phone"}'
{
  "status": "success",
  "code": "SUCCESS",
  "message": "…",
  "data": {
    "endUser": {
      "id": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34",
      "programId": "5b9e2f3a-7c41-4d8e-a6f2-9e1b3c4d5f60",
      "accountType": "PERSONAL",
      "externalCustomerId": "crm-88213",
      "phoneMasked": "9053******67",
      "displayNameMasked": "A*** Y*****",
      "status": "FROZEN",
      "updatedAt": "2026-10-11T11:20:37.912Z"
    }
  },
  "requestId": "…"
}

The response returns the full endUser view; the fields are on Detail & Lookup (the example is shortened).

A frozen user

Result
Wallet-to-wallet transfer as sender, transfer to IBAN, withdrawal, top-upCannot be started — 409 WALLET_STATE_INVALID
Being the payer in a wallet paymentThe user is treated as not found — 404 WALLET_NOT_FOUND
Being the recipient of a wallet-to-wallet transferThe recipient is treated as not found — 404 WALLET_NOT_FOUND
Wallet lookupReturns exists: false
Opening a new wallet409 WALLET_STATE_INVALID
BalanceKept; no money moves
Reads (detail, balances, limit status, list)Work

Freezing does not reverse operations that have already started. Before deciding, check the user's open operations through Operations.

Repeated calls

  • If the user is already FROZEN, the call succeeds and returns the user unchanged.
  • Repeating with the same Idempotency-Key returns the first response. The comparison uses the user id only; the first response is returned even if reason differs.
  • A CLOSED user cannot be frozen: 409 WALLET_STATE_INVALID.

Unfreezing and closing

These two actions are not in the s2s API; your operations team performs them in the merchant panel:

  • Unfreeze returns the user to ACTIVE.
  • Close sets the user and all their wallets and accounts to CLOSED and cannot be undone. If any account has a balance, closing is rejected with 409 WALLET_BALANCE_NOT_ZERO.

Details: Panel — End Users.

Errors

HTTPCodeWhen
400VALIDATION_ERRORreason is longer than 240 characters or the body contains an undefined field
400—{id} is not a UUID; Idempotency-Key missing, empty or longer than 128 characters
403WALLET_INSUFFICIENT_SCOPEThe key lacks wallet:enduser:manage or wallet:program:manage
404WALLET_NOT_FOUNDThe user does not exist or is not yours
409WALLET_STATE_INVALIDThe user is CLOSED
409WALLET_IDEMPOTENCY_IN_PROGRESSThe first request sent with the same key is still being processed