feat(billing): make finishing the trial discoverable (billing button + API/MCP error hint) - #2113
Open
giladresisi wants to merge 2 commits into
Open
giladresisi wants to merge 2 commits into
giladresisi wants to merge 2 commits into
Conversation
Add a "Finish trial" button to the billing page for trialing orgs, behind a confirmation, and point the video and clipping trial gate errors at the billing page so API and MCP callers know how to unblock themselves. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Strix Security ReviewNo security issues found. Updated for Reviewed by Strix |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What kind of change does this PR introduce?
Feature (frontend billing page, backend trial gate messages). Adds a "Finish trial" button to
main.billing.component.tsx, shown only whileuser.isTrailingis true. Clicking it opens adeleteDialogconfirmation, and only on confirm mounts the existingFinishTrialmodal. Closing that modal now also revalidates/user/selfso the button disappears once the trial has ended. On the backend, the 406 trial gate messages inMediaService(generateVideoAllowed,validateVideoRequest) andClippingService.startClippingkeep their original first sentence and append where to finish the trial: the plain/billingpage and the button name.What deliberately stayed the same: who is gated (
!video.trial && org.isTrailingfor videos,org.isTrailingfor clipping), the 406 status, the plain string body,POST /billing/finish-trial,StripeService.finishTrial,/billing/is-trial-finished, and the existing/billing?finishTrial=trueentry point used by the web 406 dialog. No workflow, activity, DTO or schema changes.Why was this change needed?
A Cloud customer on a trial tried to generate a Seedance video through the API and got "This video is not available in trial mode". The gate is intentional (paid-only generators have
trial: false), but the customer had no way to unblock themselves: the error gave no next step, and the billing page had no visible control for ending the trial early. The only entry points to finishing a trial were the web app's 406 dialog and the precondition modal, which API and MCP callers never see.The error text points at the plain
/billingpage on purpose and never at/billing?finishTrial=true. That URL mountsFinishTrial, which charges immediately with no confirmation of its own, so it must not be handed out in API or MCP error text where an agent, a link previewer or a careless click could trigger a charge. The user opens/billingand clicks the new button, which confirms first. That makes the button a prerequisite of the message, so both ship together here.Clipping gets the same hint because its trial gate is reachable only from the public API and the MCP
clippingTool. It has no web screen, so the web 406 dialog never covers it.Other information:
Independent of #2062, which only adds frontend copy in the video generator UI and does not touch the billing page or the backend messages.
The four new translation keys (
finish_trial,finish_trial_confirmation,finish_trial_charge_me_now,trial) are added to the English source and translated for the other locales with lingo.dev in a second commit.Testing done on this branch:
/billing/finish-trial(checked in the browser network log and the backend log).POST /public/v1/generate-videowithtype: "seedance"returns 406 with the original sentence, the plain/billingURL and the button name, and nofinishTrial=true.generateVideoToolwithseedancereturns the new message inside the existing wrapper, ending with the credit-not-used sentence and reading cleanly.Not tested:
/user/selfrevalidation). It needs a real Stripe test-mode trial subscription.QA
/billing. Expected: a "Finish trial" button next to "Update Payment Method / Invoices History"./billing/finish-trialis sent./billingon a paid org that is not on a trial, on a FREE org, and on a lifetime org. Expected: no "Finish trial" button./billing?finishTrial=trueon a trialing org in Stripe test mode. Expected: same behavior as before this PR, the "Finishing Trial" modal mounts right away.POST /public/v1/generate-videowith{"type":"seedance","output":"vertical","customParams":{"prompt":"a cat"}}(requiresEVOLINK_API_KEYso Seedance is registered). Expected: 406, andmessagestarts with "This video is not available in trial mode." followed by the/billingURL and the "Finish trial" button name, withoutfinishTrial=true."type":"image-text-slides"and valid params. Expected: no 406, generation starts as before.generateVideoToolwith identifierseedance. Expected: theerrorstring contains the same message and ends with "The user's video credit was not used."POST /public/v1/clippingwith a YouTube URL. Expected: 406 with "Clipping is not available in trial mode." followed by the same/billinghint.Checklist:
Put a "X" in the boxes below to indicate you have followed the checklist;
🤖 Generated with Claude Code