fix(shopinbit): regenerate expired invoice via PUT ?retry=true
What changed, and why it matters
This commit fixes a small integration bug in the Stack Wallet app's ShopInBit payment feature. Previously, when a user tried to refresh an expired invoice, the app called the server without the required retry=true flag. The fix adds that flag so the server regenerates the invoice instead of returning an error. There is no direct evidence this is a security vulnerability; it appears to be a normal bug fix for a broken user flow.
Treat as a routine functional bug fix. No immediate security action is indicated. If reviewing the broader ShopInBit integration, verify that retry=true cannot be abused to reset or invalidate another user's in-flight payment, since the existing comment notes that repeated calls regenerate the invoice and invalidate in-flight payments.
Security signals we found
No security-relevant keywords in commit title or message
Change is limited to adding a missing query parameter for an existing API endpoint
No changes to authentication, authorization, cryptography, or input validation
No vendor or researcher attribution to a security report
Evidence from the diff
The change adds a boolean retry parameter (default false) to ShopInBitClient.putPayment(). When retry is true, the HTTP request includes query parameter ?retry=true on the PUT /tickets/{ticketId}/payment endpoint. The UI’s invoice-refresh flow now passes retry: true. The diff shows only this API contract correction and no authentication, authorization, or input-validation changes.
Changed components
lib/services/shopinbit/src/client.dartlib/pages/shopinbit/shopinbit_payment_view.dartInspect captured patch +9 / −1
diff --git a/lib/pages/shopinbit/shopinbit_payment_view.dart b/lib/pages/shopinbit/shopinbit_payment_view.dart
index 43a5c99..c6b5b4b 100644
--- a/lib/pages/shopinbit/shopinbit_payment_view.dart
+++ b/lib/pages/shopinbit/shopinbit_payment_view.dart
@@ -188,7 +188,11 @@ class _ShopInBitPaymentViewState extends ConsumerState<ShopInBitPaymentView>
whileFuture: ref
.read(pShopinBitService)
.client
- .putPayment(widget.apiTicketId, customerKey: customerKey),
+ .putPayment(
+ widget.apiTicketId,
+ customerKey: customerKey,
+ retry: true,
+ ),
context: context,
message: "Refreshing invoice",
);
diff --git a/lib/services/shopinbit/src/client.dart b/lib/services/shopinbit/src/client.dart
index e5c15a9..19915cb 100644
--- a/lib/services/shopinbit/src/client.dart
+++ b/lib/services/shopinbit/src/client.dart
@@ -331,13 +331,17 @@ class ShopInBitClient {
/// shipping/billing, seen the Terms & Conditions, and explicitly clicked
/// PAY NOW. Repeated calls regenerate the invoice and invalidate any in-
/// flight payment.
+ /// Create a payment invoice, or regenerate an expired/invalid one with
+ /// [retry] = true (spec: PUT ...?retry=true).
Future<ApiResponse<PaymentInfo>> putPayment(
int ticketId, {
required String customerKey,
+ bool retry = false,
}) async {
return _request(
'PUT',
'/tickets/$ticketId/payment',
+ query: retry ? const {'retry': 'true'} : null,
parse: PaymentInfo.fromJson,
customerKey: customerKey,
);
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.