feat(payments): VK Votes payment rail #224
Reference in New Issue
Block a user
Delete Branch "feature/payment-intake-vk"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
The VK Votes ("голоса") payment rail, end to end, reusing the intake engine from the direct
rail. The
wallet.orderendpoint branches by rail: a VK context opens a pending order (providervk) and returns its id; the client passes it toVKWebAppShowOrderBox.Mechanism. VK's two-phase payment callback is verified at the gateway with the app protected
key (
GATEWAY_VK_APP_SECRET, already deployed) and proxied to a backend intake handler:get_item→ returns the ordered pack's title and vote price;order_status_change→ the sameFund(sourcevk, currencyVOTE), idempotenton VK's own order id, and records a
succeededevent, so the dispatcher push refreshes thewallet in place.
VK self-handles the receipt (D41), so nothing is sent.
Tests
Unit: the VK signature verifier (
vkpay— MD5, sortedkey=value, secret appended; valid / tampered/ wrong-secret / missing). Integration (Postgres): a VK order → get_item lookup → credit the vk
segment once → a duplicate VK callback credits nothing. UI:
check/test/build/ wallet e2e(the direct path is unchanged; the VK branch is exercised on-device).
Review on the contour
In the VK Mini App, a chip pack shows priced in votes; buying opens VK's payment box; paying
credits the chips (via the push). VK vote-packs are seeded on the contour (50 → 10, 100 → 20 votes).
Owner setup
The VK app payment callback =
https://scrabble.iliadenisov.ru/pay/vk/callbackis set; thesecret is
GATEWAY_VK_APP_SECRET(already deployed). Nothing else to wire.⚠ Pre-prod: VK has no separate prod callback URL — the app callback points at the contour host,
so swap it to the prod host before deploying payments to prod (noted in the plan/memory).
Remaining (this stack)
The TG-Stars rail and refunds; plus hiding the ad banner on a no-ads purchase (a spend-path signal,
deferred with your agreement).
Add the vkpay package: verify a VK Mini Apps payment ("голоса") callback signature — MD5 (mandated by VK's payment protocol) of the sig-excluded parameters, sorted by name and concatenated key=value, with the app secret appended; case-insensitive over the hex digest. Unit-tested (valid / tampered / wrong-secret / missing). First piece of the VK rail; the two-phase callback handler, the VK order branch and the client bridge follow.Wire the VK Mini Apps ("голоса") rail end to end, reusing the intake engine. The wallet.order endpoint branches by rail: a VK context opens a pending order (provider vk) and returns its id, which the client passes to VKWebAppShowOrderBox. VK's two-phase payment callback is verified at the gateway with the app protected key (GATEWAY_VK_APP_SECRET) and proxied to a backend intake handler: get_item returns the ordered pack's title and vote price; a chargeable order_status_change credits the vk segment exactly once (the same Fund, idempotent on VK's own order id) and records a succeeded event, so the dispatcher push refreshes the wallet. Integration test for the VK order->credit path.Money purchases are not permitted in the VK iOS app (Apple ToS), and the backend already refuses them (the CreateOrder VK-iOS freeze). Show the pack "Buy" muted there and explain on tap ("purchases are not available on this platform"), instead of letting the tap hit a 403 and a generic error toast. The storefront still lists the packs.