{"record":{"id":"ea0f869c6ffad410","repo":"Stirling-Tools/Stirling-PDF","slug":"create-payg-bundle-quote-failed","errorCode":null,"errorMessage":"create-payg-bundle-quote failed","messagePattern":"create-payg-bundle-quote failed","errorType":"exception","errorClass":"StripeFunctionError","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/portal/billing/stripe.ts","lineNumber":347,"sourceCode":"/**\n * Create + finalize the Stripe QUOTE backing a persisted quote row, via {@code create-payg-bundle-quote}.\n * The customer-facing quote number + PDF are Stripe's. On edit the server cancels the prior Stripe quote\n * and issues a new one. Capacity is credited only when the accepted quote's invoice is PAID (the webhook).\n */\nexport async function createBundleStripeQuote(\n  req: BundleStripeQuoteRequest,\n): Promise<BundleStripeQuote> {\n  const res = await invoke<BundleStripeQuoteResponse>(\n    \"create-payg-bundle-quote\",\n    {\n      team_id: req.teamId,\n      quote_id: req.quoteId,\n      ...(req.poNumber ? { po_number: req.poNumber } : {}),\n      ...(req.daysUntilDue != null ? { days_until_due: req.daysUntilDue } : {}),\n    },\n  );\n  if (!res.success || !res.stripe_quote_id) {\n    throw new StripeFunctionError(\n      res.error ?? \"create-payg-bundle-quote failed\",\n    );\n  }\n  return {\n    stripeQuoteId: res.stripe_quote_id,\n    stripeQuoteNumber: res.stripe_quote_number ?? null,\n  };\n}\n\n/** A raised Stripe invoice — the {@code accept-payg-bundle-quote} result. */\nexport interface BundleInvoice {\n  invoiceId: string;\n  /** Stripe-hosted page where the buyer pays / downloads the invoice. */\n  hostedInvoiceUrl: string | null;\n  invoicePdf: string | null;\n  status: string | null;\n}\n","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/portal/billing/stripe.ts#L329-L365","documentation":"Fallback thrown by createBundleStripeQuote when the create-payg-bundle-quote edge function returns success === false OR omits stripe_quote_id. A real Stripe quote handle is mandatory to proceed, so an absent stripe_quote_id is a hard failure even if success was true.","triggerScenarios":"create-payg-bundle-quote responds with success:false, or with success:true but no stripe_quote_id — e.g. Stripe rejected the quote creation, the team/quote row was invalid, or the function's Stripe call failed and it returned success without the handle.","commonSituations":"Stripe API key misconfigured in the function; the quote row referenced by quote_id does not exist or belongs to another team; Stripe-side error (invalid customer, currency mismatch) swallowed by the function; response shape changed after a function deploy.","solutions":["Read the res.error if present in the function logs; if absent, fix the function to return it.","Verify quoteId corresponds to a valid open quote (see getLatestBundleQuote) for the team.","Confirm the Stripe secret key + connected-account config the function uses.","Catch StripeFunctionError at the call site and show a retry-able error to the admin."],"exampleFix":"// edge function — before\nif (quoteNotFound) return json({ success: true });\n\n// after\nif (quoteNotFound) {\n  return json({ success: false, error: 'quote_not_found' });\n}\nreturn json({ success: true, stripe_quote_id: stripeQuote.id });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isBundleQuoteResponse(res: BundleStripeQuoteResponse | null): res is BundleStripeQuoteResponse & { success: true; stripe_quote_id: string } {\n  return res != null && res.success === true && typeof res.stripe_quote_id === \"string\";\n}","tryCatchPattern":"try {\n  const { stripeQuoteId } = await createBundleStripeQuote(req);\n  proceedToAccept(stripeQuoteId);\n} catch (e) {\n  if (e instanceof StripeFunctionError) {\n    notifications.show({ message: `Could not create quote: ${e.message}`, color: \"red\" });\n  } else throw e;\n}","preventionTips":["Verify quoteId is a valid open quote for the team before requesting a Stripe quote.","Ensure create-payg-bundle-quote returns stripe_quote_id on success and a clear error otherwise.","Confirm the Stripe secret key the function uses is valid."],"tags":["billing","stripe","supabase","edge-function","quote","contract"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}