Skip to content

feat: Tracking & Billing, Polar - #6924

Merged
andrecalil merged 14 commits into
mainfrom
feat/billing-phase-4-5-and-6-polar
Aug 28, 2026
Merged

andrecalil merged 14 commits into
mainfrom
feat/billing-phase-4-5-and-6-polar

Conversation

@andrecalil

Copy link
Copy Markdown
Collaborator

Summary

This change lets organizations buy SuperPlane-hosted LLM credit and control which models each factory can use.

  • Polar runs checkout, tax, and invoices. SuperPlane keeps the usage ledger and remaining-credit wallet.
  • Owners add prepaid credit packs and open invoices from LLM spend. Self-hosted installs hide those actions.
  • Organizations select BYOK models from connected Anthropic, OpenAI, and OpenRouter keys. Factories can use a subset.
  • Factories can set a hosted spend limit. Hosted runs stop when org credit or that limit is empty. BYOK is not billed.
  • Organization settings move to /{org}/organization/{tab}. LLM spend and Integrations live there. Old LLM spend URLs redirect.

Test plan

  • Open /{org}/organization/llm-spend and confirm remaining credit and model spend.
  • If Polar is configured, buy a credit pack and return with ?credit=added.
  • After a purchase, open Manage invoices.
  • Connect a BYOK integration and select models for the organization.
  • On factory Models, subset the org list. Confirm the picker uses that list.
  • Set a factory hosted spend limit on Usage.
  • Confirm hosted runs stop when credit or the factory limit is empty.
  • Confirm /{org}/settings/llm-spend redirects to organization LLM spend.
  • Confirm /{org}/settings/integrations still opens the old catalog.

Made with Cursor

Organizations need self-serve hosted credit, BYOK model lists, and
factory spend limits. Polar handles checkout and invoices. SuperPlane
keeps the usage ledger and remaining-credit wallet.

Organization settings now live at /{org}/organization so LLM spend and
Integrations sit next to workspaces instead of inside a factory URL.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
@superplanehq-integration

Copy link
Copy Markdown
Contributor

👋 Commands for maintainers:

  • /sp start - Start an ephemeral machine (takes ~30s)
  • /sp stop - Stop a running machine (auto-executed on pr close)

@superplanehq-integration

Copy link
Copy Markdown
Contributor

Storybook available at https://pr-6924-storybook.superplane.workers.dev

Comment thread pkg/billing/polar/webhook.go Outdated
Comment thread pkg/billing/polar/webhook.go Outdated
Comment thread pkg/grpc/actions/factories/factory_llm_models.go
Comment thread pkg/grpc/actions/organizations/hosted_credit_billing.go Outdated
andrecalil and others added 2 commits August 26, 2026 15:56
Polar signs with the full secret bytes. An empty secret or a non-pack
checkout can grant credit incorrectly or charge without a wallet grant.
This change rejects those cases, keeps factory models in the parent
list, and splits duplicated settings UI so lint stays in budget.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread pkg/components/runner/hosted.go
andrecalil and others added 2 commits August 26, 2026 18:25
Turning off No limit seeded $0.00 and mapped empty input to zero, so
Save could block all SuperPlane-hosted runs. Empty BYOK models skipped
the allowlist. Also add billing and model tests so coverage stays in
budget.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread web_src/src/hooks/useLLMModelAllowlists.ts
Comment thread web_src/src/ui/configurationFieldRenderer/HostedModelFieldRenderer.tsx Outdated
Comment thread pkg/grpc/actions/organizations/hosted_credit_billing.go Outdated
andrecalil and others added 4 commits August 26, 2026 20:45
…5-and-6-polar

Co-authored-by: Cursor <cursoragent@cursor.com>
Factory allowlist saves left the canvas model picker stale.
Checkout accepted a customer IP from the request body.
The credit return page showed success after one fetch.

Invalidate picker queries after model saves. Wait for the
canvas factory before the list. Use only proxy headers for
checkout IP. Snapshot the grant and poll until it increases.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
The credit return hook listed a whole args object in an effect
dependency check. The canvas factory mock failed TypeScript.

Destructure the hook inputs for the effect deps. Type the canvas
mock so the factory wait tests compile.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
A second org for the same owner failed Polar unique-email checks.
Permanent webhook errors returned 500 and Polar disabled the
endpoint. Refunds left SuperPlane credit in place.

Give each org a unique Polar team email. Accept poison-pill
events with 202. Reverse Polar grants on order.refunded.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread pkg/billing/polar/apply.go Outdated
Comment thread pkg/billing/polar/apply.go
Comment thread pkg/grpc/actions/organizations/hosted_credit_billing.go
andrecalil and others added 3 commits August 26, 2026 22:30
A refund could skip a grant when pack metadata was missing.
A refund that arrived before order.paid returned 202, so Polar
did not retry. grpc-gateway hid Cloudflare client IPs from tax.

Reverse an existing Polar grant even without pack metadata.
Return 500 until the grant exists. Read gateway Cloudflare IPs.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
The spend page labeled Polar packs as SuperPlane grant. Polar team
portal sessions failed without a member id.

Keep SuperPlane grant as welcome plus admin credit. Show purchased
credit from Polar packs. List Polar orders. Open the Polar portal
with the organization external id and the owner member.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
…5-and-6-polar

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	db/structure.sql
#	web_src/src/App.tsx
#	web_src/src/lib/startDirectGitHubConnect.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5efc7a7. Configure here.

Comment thread pkg/billing/polar/apply.go Outdated
Comment thread pkg/components/runner/hosted.go
andrecalil and others added 2 commits August 27, 2026 21:45
Concurrent Polar refunds with different ids could reverse more
than the purchase grant. Hosted runs now use the same factory
model list as BYOK. Split HostedCreditSummaryCard so ESLint
complexity stays inside the budget.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
golang-migrate records only the newest version. Three Polar
migrations were older than work-order origin from main, so
production would skip them. Recreate those files with later
timestamps so they apply after the merge.

Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: Cursor <cursoragent@cursor.com>
@andrecalil
andrecalil merged commit bd0b619 into main Aug 28, 2026
5 of 6 checks passed
@andrecalil
andrecalil deleted the feat/billing-phase-4-5-and-6-polar branch August 28, 2026 01:08
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