Skip to content

Conversation

Kitenite
Copy link
Contributor

@Kitenite Kitenite commented Aug 15, 2025

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Release
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes


Important

Introduces upgradeSubscription to handle subscription upgrades without proration and modifies Next.js config to ignore build errors.

  • Behavior:
    • Introduces upgradeSubscription in functions.ts to handle subscription upgrades without proration.
    • Replaces updateSubscription with upgradeSubscription in subscription.ts for immediate billing of price differences.
    • Prevents no-op upgrades by checking if the new price is the same as the current price.
  • Configuration:
    • Modifies next.config.mjs to ignore TypeScript and ESLint errors during builds.
  • Error Handling:
    • Adds error handling for missing subscription items and price amounts in upgradeSubscription.

This description was created by Ellipsis for af957d7. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Smoother subscription upgrades: switching to a higher-priced plan now applies without proration and bills any positive difference immediately.
    • Prevents no-op upgrades when the selected plan matches the current one.
    • Improved validation and clearer error messaging for invalid upgrade attempts.
  • Chores

    • Build config updated to ignore ESLint and TypeScript build errors during builds.

Copy link

supabase bot commented Aug 15, 2025

This pull request has been ignored for the connected project wowaemfasoptxrdjhilu because there are no changes detected in apps/backend/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

Copy link

vercel bot commented Aug 15, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
web Ready Ready Preview Comment Aug 15, 2025 9:54pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
docs Skipped Skipped Aug 15, 2025 9:54pm

Copy link

coderabbitai bot commented Aug 15, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new upgradeSubscription function in Stripe utilities and updates the web subscription router to call it for upgrades (no proration). Also replaces/removes a Next.js TypeScript config with a JS config enabling build-time ESLint/TS ignores.

Changes

Cohort / File(s) Summary of Changes
Subscription API Router
apps/web/client/src/server/api/routers/subscription/subscription.ts
Replaced usage of updateSubscription with upgradeSubscription for upgrade scenarios; kept updateSubscriptionNextPeriod. Updated import list; call signature unchanged ({ subscriptionId, subscriptionItemId, priceId }).
Stripe Billing Logic
packages/stripe/src/functions.ts
Added upgradeSubscription to update a subscription item to a new price with proration_behavior: 'none'. Validates subscription/item and price amounts, prevents no-op upgrades, computes positive price differences, creates an invoice item and immediately invoices/pays if needed, and returns the updated subscription.
Next.js Config
apps/web/template/next.config.mjs, apps/web/template/next.config.ts
Added next.config.mjs with eslint.ignoreDuringBuilds: true and typescript.ignoreBuildErrors: true. Removed next.config.ts which previously exported a NextConfig object (deleted file).

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant WebAPI as Web Subscription Router
  participant Billing as upgradeSubscription (Stripe utils)
  participant Stripe as Stripe API

  User->>WebAPI: Request upgrade (subscriptionId, subscriptionItemId, priceId)
  WebAPI->>Billing: upgradeSubscription({...})
  Billing->>Stripe: Retrieve subscription
  Stripe-->>Billing: Subscription details
  Billing->>Billing: Validate prices / compute difference
  Billing->>Stripe: Update subscription item (proration: none)
  Stripe-->>Billing: Updated subscription
  alt priceDifference > 0
    Billing->>Stripe: Create invoice item (+difference)
    Billing->>Stripe: Create invoice (immediate) & pay
    Stripe-->>Billing: Invoice created/paid
  end
  Billing-->>WebAPI: Return updated subscription
  WebAPI-->>User: Respond with result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I thump my paws—an upgrade hop!
No proration storms, a gentle stop.
If prices climb, I bill with care,
A tiny invoice hums in air.
Carrots tall, subscriptions bright—
Rabbit patch code, deployed tonight.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/disable-proration

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel vercel bot temporarily deployed to Preview – docs August 15, 2025 21:38 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
packages/stripe/src/functions.ts (1)

157-169: Derive currency from the item price and finalize/pay invoice for immediate charge

  • Currency: Avoid defaulting to 'usd' which can cause Stripe errors if the subscription is in another currency. Prefer the subscription’s currency, then the item’s price currency.
  • Immediate invoicing: Creating with auto_advance: true typically finalizes later (not instant). To charge immediately, finalize and pay the invoice.

Apply this diff:

-        await stripe.invoiceItems.create({
-            customer: updatedSubscription.customer as string,
-            amount: priceDifferenceAmount,
-            currency: updatedSubscription.currency || 'usd',
-            description: 'Price upgrade difference',
-        });
-
-        // Create invoice immediately
-        const invoice = await stripe.invoices.create({
-            customer: updatedSubscription.customer as string,
-            auto_advance: true,
-        });
+        await stripe.invoiceItems.create(
+            {
+                customer: updatedSubscription.customer as string,
+                amount: priceDifferenceAmount,
+                currency:
+                    updatedSubscription.currency ||
+                    newItem.price?.currency ||
+                    undefined,
+                description: `Price upgrade difference (${currentItem.price?.id} → ${newItem.price?.id})`,
+            }
+        );
+
+        // Create, finalize, and pay invoice immediately
+        const invoice = await stripe.invoices.create({
+            customer: updatedSubscription.customer as string,
+            collection_method: 'charge_automatically',
+            auto_advance: false,
+        });
+        await stripe.invoices.finalizeInvoice(invoice.id);
+        await stripe.invoices.pay(invoice.id);

Note:

  • If neither subscription nor price currency is present, consider throwing explicitly rather than relying on a default to avoid currency mismatches.
if (!currency) throw new Error('Currency not found on subscription or price');
🧹 Nitpick comments (4)
apps/web/client/src/server/api/routers/subscription/subscription.ts (1)

165-169: Confirm post-upgrade state sync and “immediate” invoicing semantics

  • This path no longer updates the DB (unlike the downgrade path which writes schedule info). If your webhook is responsible for syncing the new price into the DB, please confirm it covers this upgrade scenario and that the UI can render the new tier promptly without relying solely on webhook latency.
  • “Immediate” invoicing: upgradeSubscription currently creates an invoice with auto_advance: true, which is finalized automatically later (typically up to ~1 hour). If you need truly immediate charge/collection, consider finalizing and paying the invoice explicitly in upgradeSubscription (see suggestion in functions.ts review).
packages/stripe/src/functions.ts (3)

137-146: Optional: Add idempotency to write operations

Retries could double-charge (duplicate invoice items). Consider idempotency keys for invoice item and invoice creation.

Example:

await stripe.invoiceItems.create(data, { idempotencyKey: `upgrade-item-${subscriptionId}-${subscriptionItemId}-${priceId}` });
const invoice = await stripe.invoices.create(invoiceData, { idempotencyKey: `upgrade-invoice-${subscriptionId}-${subscriptionItemId}-${priceId}` });

137-146: Optional: Ensure price fields are available without expansions

In some API versions/setups, nested price objects may not include all fields unless expanded. If you encounter null unit_amount, retrieve the Price via stripe.prices.retrieve(priceId) or use expansions on the subscription update/retrieve.

Example:

const currentPriceObj = await stripe.prices.retrieve(currentPriceId!);
const newPriceObj = await stripe.prices.retrieve(priceId);

171-172: Return type and data shape

Consider returning both the updated subscription and invoice (if one is created) so callers can reflect immediate charges in the UI.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 51ce76f and 1ba8e8f.

📒 Files selected for processing (2)
  • apps/web/client/src/server/api/routers/subscription/subscription.ts (2 hunks)
  • packages/stripe/src/functions.ts (1 hunks)
🔇 Additional comments (1)
apps/web/client/src/server/api/routers/subscription/subscription.ts (1)

3-3: Switch to upgradeSubscription aligns with “disable proration” objective

Import change looks correct and matches the new Stripe utility. No concerns here.

@vercel vercel bot temporarily deployed to Preview – docs August 15, 2025 21:51 Inactive
@@ -4,5 +4,11 @@ const nextConfig = {
devIndicators: {
buildActivity: false,
},
eslint: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid ignoring ESLint/TypeScript build errors unless absolutely necessary. This may hide real issues in production.

if (priceDifferenceAmount > 0) {
await stripe.invoiceItems.create({
customer: updatedSubscription.customer as string,
amount: priceDifferenceAmount,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The currency field was removed from the invoiceItems.create call. Stripe typically requires a currency for invoice items; consider reinstating it.

Suggested change
amount: priceDifferenceAmount,
currency: 'usd',


const newItem =
updatedSubscription.items.data.find((i) => i.id === subscriptionItemId)
?? updatedSubscription.items.data[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Falling back to the first item if the matching subscription item isn't found may mask issues. It might be safer to throw an error instead.

Suggested change
?? updatedSubscription.items.data[0];
?? (() => { throw new Error('Subscription item not found on updated subscription'); })()

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
packages/stripe/src/functions.ts (3)

127-140: Good: targeting the correct subscription item and nullish-checking unit_amount

Using subscriptionItemId to locate the item and checking unit_amount with a nullish guard avoids multi-item and 0-amount pitfalls.


153-166: Good: reading updated item by id and incorporating quantity into the delta

This addresses under-billing when quantity > 1 and avoids relying on index 0.


176-185: Nice: invoice is paid immediately after creation

This addresses prior feedback to ensure the upgrade transaction completes in one operation.

🧹 Nitpick comments (1)
apps/web/template/next.config.mjs (1)

7-12: Turning off ESLint and TypeScript checks during builds can mask real issues—confirm intent or scope to non-CI builds

This will allow type and lint errors to ship unnoticed. If this is only to relax local template builds, gate it behind an env var so CI remains strict.

Apply this diff to enforce checks on CI while allowing local flexibility:

-    eslint: {
-        ignoreDuringBuilds: true,
-    },
-    typescript: {
-        ignoreBuildErrors: true,
-    },
+    eslint: {
+        // Keep CI strict; allow local templates to build even with lint errors
+        ignoreDuringBuilds: process.env.CI !== 'true',
+    },
+    typescript: {
+        // Keep CI strict; allow local templates to build even with TS errors
+        ignoreBuildErrors: process.env.CI !== 'true',
+    },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba8e8f and af957d7.

📒 Files selected for processing (3)
  • apps/web/template/next.config.mjs (1 hunks)
  • apps/web/template/next.config.ts (0 hunks)
  • packages/stripe/src/functions.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/template/next.config.ts
🔇 Additional comments (1)
packages/stripe/src/functions.ts (1)

164-166: Validate billing interval assumptions (monthly vs yearly) when computing delta

The delta assumes both prices share the same billing interval/granularity. If plan intervals differ (e.g., month vs year), this will be incorrect.

Would you like me to extend this to assert newPrice.recurring?.interval === currentItem.price.recurring?.interval (and factor interval_count) and throw if mismatched?

Comment on lines +142 to +185
const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
items: [
{
id: subscriptionItemId,
price: priceId,
},
],
// We don't want to prorate the price difference because it would be based on time remaining in the current period
proration_behavior: 'none',
});

const newItem =
updatedSubscription.items.data.find((i) => i.id === subscriptionItemId)
?? updatedSubscription.items.data[0];
if (!newItem) {
throw new Error('Subscription item not found on updated subscription');
}
const newPriceAmount = newItem.price?.unit_amount;
if (newPriceAmount == null) {
throw new Error('New price amount not found');
}

const quantity = newItem.quantity ?? 1;
const priceDifferenceAmount = (newPriceAmount - currentPriceAmount) * quantity;

// Create a one-off invoice item for the price difference if the new price is higher
if (priceDifferenceAmount > 0) {
await stripe.invoiceItems.create({
customer: updatedSubscription.customer as string,
amount: priceDifferenceAmount,
description: 'Onlook subscription upgrade',
});

// Create invoice immediately
const invoice = await stripe.invoices.create({
customer: updatedSubscription.customer as string,
auto_advance: true,
});

if (!invoice.id) {
throw new Error('Invoice not created');
}
await stripe.invoices.pay(invoice.id);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Prevent free upgrades on payment failure: charge first (with currency), then apply the subscription update

Currently the subscription is upgraded (Line 142) before charging the upgrade delta. If invoice creation or payment fails, the customer can receive a free upgrade. Also, the invoice item is created without a currency, which Stripe requires when specifying an amount.

Refactor to:

  • Compute the delta using the new Price object (no update yet).
  • Validate currency and include it when creating the invoice item.
  • Create and pay the invoice first; only then update the subscription.
  • Keep proration_behavior: 'none' as intended.

Apply this diff to the function body to fix ordering and currency handling:

-    const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
-        items: [
-            {
-                id: subscriptionItemId,
-                price: priceId,
-            },
-        ],
-        // We don't want to prorate the price difference because it would be based on time remaining in the current period
-        proration_behavior: 'none',
-    });
-
-    const newItem =
-        updatedSubscription.items.data.find((i) => i.id === subscriptionItemId)
-        ?? updatedSubscription.items.data[0];
-    if (!newItem) {
-        throw new Error('Subscription item not found on updated subscription');
-    }
-    const newPriceAmount = newItem.price?.unit_amount;
-    if (newPriceAmount == null) {
-        throw new Error('New price amount not found');
-    }
-
-    const quantity = newItem.quantity ?? 1;
-    const priceDifferenceAmount = (newPriceAmount - currentPriceAmount) * quantity;
-
-    // Create a one-off invoice item for the price difference if the new price is higher
-    if (priceDifferenceAmount > 0) {
-        await stripe.invoiceItems.create({
-            customer: updatedSubscription.customer as string,
-            amount: priceDifferenceAmount,
-            description: 'Onlook subscription upgrade',
-        });
-
-        // Create invoice immediately
-        const invoice = await stripe.invoices.create({
-            customer: updatedSubscription.customer as string,
-            auto_advance: true,
-        });
-
-        if (!invoice.id) {
-            throw new Error('Invoice not created');
-        }
-        await stripe.invoices.pay(invoice.id);
-    }
-
-    return updatedSubscription;
+    // Compute delta using the target Price (no subscription change yet)
+    const newPrice = await stripe.prices.retrieve(priceId);
+    const newPriceAmount = newPrice.unit_amount;
+    if (newPriceAmount == null) {
+        throw new Error('New price amount not found');
+    }
+
+    const quantity = currentItem.quantity ?? 1;
+    const currentCurrency = currentItem.price.currency;
+    const newCurrency = newPrice.currency;
+    if (currentCurrency && newCurrency && currentCurrency !== newCurrency) {
+        throw new Error('Cannot upgrade across different currencies');
+    }
+    const currency = newCurrency ?? currentCurrency;
+    if (!currency) {
+        throw new Error('Currency not found on price');
+    }
+
+    const priceDifferenceAmount = (newPriceAmount - currentPriceAmount) * quantity;
+
+    // Charge the delta first (if positive)
+    if (priceDifferenceAmount > 0) {
+        await stripe.invoiceItems.create({
+            customer: currentSubscription.customer as string,
+            amount: priceDifferenceAmount,
+            currency,
+            description: 'Onlook subscription upgrade',
+        });
+
+        const invoice = await stripe.invoices.create({
+            customer: currentSubscription.customer as string,
+            auto_advance: true,
+            collection_method: 'charge_automatically',
+        });
+        if (!invoice.id) {
+            throw new Error('Invoice not created');
+        }
+        await stripe.invoices.pay(invoice.id);
+    }
+
+    // Only after successful payment do we apply the subscription update without proration
+    const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
+        items: [
+            {
+                id: subscriptionItemId,
+                price: priceId,
+            },
+        ],
+        proration_behavior: 'none',
+    });
+
+    return updatedSubscription;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
items: [
{
id: subscriptionItemId,
price: priceId,
},
],
// We don't want to prorate the price difference because it would be based on time remaining in the current period
proration_behavior: 'none',
});
const newItem =
updatedSubscription.items.data.find((i) => i.id === subscriptionItemId)
?? updatedSubscription.items.data[0];
if (!newItem) {
throw new Error('Subscription item not found on updated subscription');
}
const newPriceAmount = newItem.price?.unit_amount;
if (newPriceAmount == null) {
throw new Error('New price amount not found');
}
const quantity = newItem.quantity ?? 1;
const priceDifferenceAmount = (newPriceAmount - currentPriceAmount) * quantity;
// Create a one-off invoice item for the price difference if the new price is higher
if (priceDifferenceAmount > 0) {
await stripe.invoiceItems.create({
customer: updatedSubscription.customer as string,
amount: priceDifferenceAmount,
description: 'Onlook subscription upgrade',
});
// Create invoice immediately
const invoice = await stripe.invoices.create({
customer: updatedSubscription.customer as string,
auto_advance: true,
});
if (!invoice.id) {
throw new Error('Invoice not created');
}
await stripe.invoices.pay(invoice.id);
}
// Compute delta using the target Price (no subscription change yet)
const newPrice = await stripe.prices.retrieve(priceId);
const newPriceAmount = newPrice.unit_amount;
if (newPriceAmount == null) {
throw new Error('New price amount not found');
}
const quantity = currentItem.quantity ?? 1;
const currentCurrency = currentItem.price.currency;
const newCurrency = newPrice.currency;
if (currentCurrency && newCurrency && currentCurrency !== newCurrency) {
throw new Error('Cannot upgrade across different currencies');
}
const currency = newCurrency ?? currentCurrency;
if (!currency) {
throw new Error('Currency not found on price');
}
const priceDifferenceAmount = (newPriceAmount - currentPriceAmount) * quantity;
// Charge the delta first (if positive)
if (priceDifferenceAmount > 0) {
await stripe.invoiceItems.create({
customer: currentSubscription.customer as string,
amount: priceDifferenceAmount,
currency,
description: 'Onlook subscription upgrade',
});
const invoice = await stripe.invoices.create({
customer: currentSubscription.customer as string,
auto_advance: true,
collection_method: 'charge_automatically',
});
if (!invoice.id) {
throw new Error('Invoice not created');
}
await stripe.invoices.pay(invoice.id);
}
// Only after successful payment do we apply the subscription update without proration
const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
items: [
{
id: subscriptionItemId,
price: priceId,
},
],
proration_behavior: 'none',
});
return updatedSubscription;

Comment on lines +169 to +173
await stripe.invoiceItems.create({
customer: updatedSubscription.customer as string,
amount: priceDifferenceAmount,
description: 'Onlook subscription upgrade',
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing currency on invoice item will cause a Stripe error

When creating invoice items with an explicit amount, Stripe requires a currency. If you don’t adopt the larger refactor above, minimally include the currency from the item’s price.

Apply this minimal diff:

         await stripe.invoiceItems.create({
             customer: updatedSubscription.customer as string,
             amount: priceDifferenceAmount,
+            currency: newItem.price?.currency || currentItem.price?.currency || 'usd',
             description: 'Onlook subscription upgrade',
         });

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/stripe/src/functions.ts around lines 169 to 173, the
invoiceItems.create call is missing the required currency when supplying an
explicit amount; add a currency property using the currency from the relevant
Price object (for example currency: item.price.currency or currency:
price.currency — whichever variable you used to compute priceDifferenceAmount),
or extract it from updatedSubscription items if needed, and pass that currency
into the invoiceItems.create payload.

@Kitenite Kitenite marked this pull request as draft August 15, 2025 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant