From a13e45e0f9a7d3baf60ba82469cc0c4307a87938 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 6 Sep 2026 12:35:49 +0300 Subject: [PATCH] chore(billing): claim the Play purchase hand-over The endpoint was written before the idempotency plugin was on main and carried a note to come back for it. A retried hand-over was already harmless - the sync writes absolute state onto one row per account - but the claim spares a second verification round trip to Google, and this is exactly the call a phone retries: it fires the moment the app comes back from the Play sheet. --- src/http/routes/billing.routes.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/http/routes/billing.routes.ts b/src/http/routes/billing.routes.ts index 1278ba5..27cbd1c 100644 --- a/src/http/routes/billing.routes.ts +++ b/src/http/routes/billing.routes.ts @@ -53,12 +53,16 @@ export default function billingRoutes(fastify: FastifyInstance): void { tags: ["Billing"], }, onRequest: [fastify.authenticate], - // A retried hand-over is already harmless: the sync writes the - // provider's absolute state onto one row per account, so reporting - // the same purchase twice lands in the same place. It should still - // carry `idempotency: true` once that plugin is on main, to save - // the second verification round trip. - config: { rateLimit: RateLimitPolicies.SENSITIVE }, + config: { + // A retried hand-over is already harmless - the sync writes + // the provider's absolute state onto one row per account - but + // the claim spares a second verification round trip to Google, + // and this is exactly the call a phone retries: it fires right + // after a purchase, when the app has just come back from the + // Play sheet. + idempotency: true, + rateLimit: RateLimitPolicies.SENSITIVE, + }, }, playBillingController.registerPurchase.bind(playBillingController), );