Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Pick a descriptive name per resource (e.g. `"prod-db"`, `"sessions-cache"`, `"ev
- Postgres: 10 MB storage, 2 simultaneous connections.
- Redis: 5 MB total.
- MongoDB: 5 MB storage, 2 connections per token (shared pod cap up to 20 across all anonymous tokens).
- NATS: 1024 MB JetStream storage.
- NATS: 64 MB JetStream storage.
- S3-compatible storage: 10 MB bucket prefix.
- Webhook: keeps last 100 received payloads.
- Deploy: not available on anonymous tier (requires Hobby or above — plans.yaml deployments_apps=0 for anonymous).
Expand Down Expand Up @@ -100,7 +100,7 @@ on `/api/v1/capabilities` for agent introspection.

> **Upgrading auto-promotes in-flight deployment TTLs.** When a team upgrades to any paid tier (Hobby / Hobby Plus / Pro / Growth / Team), the Razorpay subscription.charged webhook flips the team's `default_deployment_ttl_policy` from `auto_24h` to `permanent` (so every future `POST /deploy/new` defaults to no TTL) AND promotes every existing `auto_24h` non-terminal deploy to permanent (clearing `expires_at`). Per-deploy `ttl_policy='custom'` and `ttl_policy='permanent'` rows are never touched — only the `auto_24h` class is rolled forward. To restore the 24h-default behaviour after an upgrade, `PATCH /api/v1/team/settings {"default_deployment_ttl_policy":"auto_24h"}`.
- **Pro**: $49/mo. 10 GB Postgres, 512 MB Redis, 5 GB Mongo, 50 GB storage, 10 apps.
- **Team**: available soon — not yet self-serve. Planned at $199/mo with unlimited everything (Postgres / Redis / Mongo / queues / storage / deployments / vault entries), 50 custom domains, 90-day backups with self-serve restore, RBAC + audit log; SSO/SAML and a 99.9% SLA are also planned. Team cannot be purchased or claimed today — contact support@instanode.dev for onboarding.
- **Team**: available soon — not yet self-serve. Planned at $199/mo with high finite limits (50 GB Postgres, 1.5 GB Redis, 40 GB Mongo, 40 GB queues, 300 GB storage, 30 GB vector, 100 deployments, 1000 vault entries, 100k webhooks), 50 custom domains, 90-day backups with self-serve restore, RBAC + audit log; SSO/SAML and a 99.9% SLA are also planned. Capacity beyond these caps (or dedicated/isolated infra, multi-region, or compliance such as SOC2/BAA/SSO/SLA/DPA) is Enterprise — contact sales. Team cannot be purchased or claimed today — contact support@instanode.dev for onboarding.

## Conventions an LLM should follow when scripting against the platform

Expand Down
18 changes: 10 additions & 8 deletions src/components/PricingGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,11 @@ export const PRICING_GRID_TIERS: TierDefinition[] = [
upgradesTo: 'team',
},
{
// Team — launched 2026-05-20 (DOC-REALITY-DELTA sweep). plans.yaml:375
// has team at $199/mo, $1990/yr, every limit -1 (unlimited).
// CTA goes via buildCtaLabel('team') → "Contact sales" until the
// assisted-Razorpay self-serve flow ships.
// Team — $199/mo, $1990/yr. strict-80% margin redesign (2026-06-05):
// every Team limit is now a finite plans.yaml cap (was -1/unlimited).
// Above these caps = Enterprise (contact sales). CTA goes via
// buildCtaLabel('team') → "Contact sales" until the assisted-Razorpay
// self-serve flow ships.
key: 'team',
label: 'Team',
monthly: { price: '$199', sub: '/mo' },
Expand All @@ -182,11 +183,12 @@ export const PRICING_GRID_TIERS: TierDefinition[] = [
yearlyTotal: '$1990/yr',
},
features: [
{ text: 'unlimited Postgres · Redis · MongoDB · queues · storage' },
{ text: 'unlimited deployments · 50 custom domains' },
{ text: 'unlimited vault entries · multi-env' },
{ text: '50 GB Postgres · 1.5 GB Redis · 40 GB MongoDB' },
{ text: '40 GB queues · 300 GB object storage' },
{ text: '100 deployments · 50 custom domains' },
{ text: '1 000 vault entries · multi-env' },
{ text: '90-day backups · self-serve restore' },
{ text: 'RBAC + audit log' },
{ text: 'RBAC + audit log · need more? contact sales' },
{ text: 'SSO / SAML (coming soon)' },
{ text: '99.9% SLA (coming soon)' },
],
Expand Down
16 changes: 9 additions & 7 deletions src/pages/BillingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,22 +119,24 @@ const LIMITS: Record<string, { label: string; limits: PlanLimits; nextTier?: Tie
},
// D5 (2026-05-18): growth row was missing — a growth-tier team fell
// through to `LIMITS.hobby`, painting red over-quota bars on a plan they
// were well within. Numbers mirror api/plans.yaml growth: postgres 20480
// MB, redis 1024 MB, mongodb / webhooks unlimited (-1 in plans.yaml →
// Infinity here), 5 deployments, 10 team_members.
// were well within. strict-80% margin redesign (2026-06-05): growth's
// formerly-unlimited (-1) mongodb/webhooks are now finite; deployments
// corrected 5 → 50. Numbers mirror api/plans.yaml growth.
growth: {
label: 'Growth',
nextTier: 'team',
limits: {
postgres_mb: 20480, redis_mb: 1024, mongodb_mb: Infinity,
deployments: 5, webhooks: Infinity, team_seats: 10,
postgres_mb: 20480, redis_mb: 1024, mongodb_mb: 20480,
deployments: 50, webhooks: 100000, team_seats: 10,
},
},
// strict-80% margin redesign (2026-06-05): every Team limit is now finite
// (was Infinity, mirroring the retired -1 sentinel). Mirrors api/plans.yaml.
team: {
label: 'Team',
limits: {
postgres_mb: Infinity, redis_mb: Infinity, mongodb_mb: Infinity,
deployments: Infinity, webhooks: Infinity, team_seats: Infinity,
postgres_mb: 51200, redis_mb: 1536, mongodb_mb: 40960,
deployments: 100, webhooks: 100000, team_seats: 25,
},
},
}
Expand Down
22 changes: 12 additions & 10 deletions src/pages/MarketingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,23 +200,25 @@ const PLANS: Plan[] = [
cta: { label: 'Start pro →', href: ROUTES.signin, variant: 'primary' },
},
{
// Team tier — launched 2026-05-20 (DOC-REALITY-DELTA sweep).
// plans.yaml:375 has team at $199/mo, every limit -1 (unlimited).
// DOG-1: CTA is self-serve via /app/checkout?plan=team (Razorpay plan IDs
// are configured server-side as of api#168 + dashboard #106). Previous
// mailto Team CTA contradicted the "Self-serve at every tier. No sales
// call." H2 directly above this tile and leaked mid-funnel conversions
// on the $199/mo AOV path.
// Team tier — $199/mo. strict-80% margin redesign (2026-06-05): every
// Team limit is now a finite plans.yaml cap (was -1/unlimited). Above
// these caps = Enterprise (contact sales).
// NOTE (pre-existing, out of scope here): this CTA still points at the
// self-serve /app/checkout?plan=team path, which the server-side Team
// gate rejects with 400 tier_not_yet_available. The PricingPage Team CTA
// already uses a contact-sales mailto. This MarketingPage CTA should be
// reconciled with the gate in a follow-up (not changed here — the
// strict-margin task is explicitly copy-only and must not touch the gate).
id: 'team',
name: 'Team',
tagline: 'For the engineering org. Dedicated infra, RBAC + audit, with SSO & SLA on the way.',
price: '$199',
freq: '/ mo',
features: [
'unlimited Postgres · Redis · MongoDB',
'unlimited deployments · 50 custom domains',
'50 GB Postgres · 1.5 GB Redis · 40 GB MongoDB',
'100 deployments · 50 custom domains',
'90-day backups · self-serve restore · RBAC + audit',
'SSO/SAML · 99.9% SLA (coming soon)',
'Need more? Enterprise — contact sales',
],
cta: {
label: 'Start team →',
Expand Down
65 changes: 35 additions & 30 deletions src/pages/PricingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ const TIERS: {
ctaHrefYearly: '/app/checkout?plan=pro&frequency=yearly',
highlighted: true,
},
// Team tier — $199/mo, unlimited across the board; the upsell vs Pro is
// dedicated infra + 90-day backup retention + SLA + RBAC + SAML. Per
// api/plans.yaml:375 ($199/mo, $1990/yr).
// Team tier — $199/mo, high finite limits across the board (NOT unlimited
// as of the 2026-06-05 strict-margin redesign); the upsell vs Pro is
// dedicated infra + 90-day backup retention + SLA + RBAC + SAML + far
// higher caps. Anyone needing more than the finite Team caps is routed to
// Enterprise (contact sales). Per api/plans.yaml ($199/mo, $1990/yr).
{
key: 'team',
name: 'Team',
Expand Down Expand Up @@ -119,50 +121,52 @@ type Cell =
// lock-step with the TIERS array above.
type Row = { label: string; sub?: string; values: [Cell, Cell, Cell, Cell] }

// UNLIMITED — Team-tier marker. plans.yaml uses -1 sentinel for "no cap"
// on every Team limit; we render this as the visual "unlimited" cell.
// Kept as its own helper so a future redesign can swap in a richer
// visualisation (e.g. lightning-bolt icon) without rewriting every row.
const UNLIMITED: Cell = 'unlimited'
// strict-80% margin redesign (2026-06-05): Team is no longer "unlimited" —
// every Team limit is now a finite plans.yaml cap rendered directly in the
// Team column below. The former `UNLIMITED` cell helper was removed; anyone
// needing MORE than the finite Team caps is routed to Enterprise (contact
// sales), surfaced in the Team tier description + the section copy.

// Each row has 4 cells: [Anonymous, Hobby, Pro, Team]. Numbers come from
// api/plans.yaml. 2026-05-15: Hobby Plus column removed (the tier exists
// for upsell flows but is not part of the public ladder); Pro storage
// bumped per PRICING-AUDIT-2026-05-15.md (Postgres 5→10 GB, Redis
// 256→512 MB, Mongo 2→5 GB, object 10→50 GB). 2026-05-20: Team tier
// launched — every limit -1 in plans.yaml becomes 'unlimited' here.
// 256→512 MB, Mongo 2→5 GB, object 10→50 GB).
// strict-80% margin redesign (2026-06-05): every Team -1 ("unlimited")
// replaced with the finite plans.yaml cap (Postgres 50 GB / 100 conn,
// Redis 1.5 GB, Mongo 40 GB / 50 conn, Queue 40 GB, Vector 30 GB, Storage
// 300 GB, Webhooks 100k, Deploy apps 100, Vault 1000). Pro queue trimmed
// 10 GB → 5 GB in the same pass. Above Team = Enterprise (contact sales).
const ROWS: Row[] = [
{ label: 'Postgres', values: ['10 MB / 2 conn / 24h TTL', '1 GB / 8 conn', '10 GB / 20 conn', UNLIMITED] },
{ label: 'Redis', values: ['5 MB / 24h TTL', '50 MB', '512 MB', UNLIMITED] },
{ label: 'MongoDB', values: ['5 MB / 2 conn / 24h TTL', '100 MB / 5 conn', '5 GB / 20 conn', UNLIMITED] },
{ label: 'Postgres', values: ['10 MB / 2 conn / 24h TTL', '1 GB / 8 conn', '10 GB / 20 conn', '50 GB / 100 conn'] },
{ label: 'Redis', values: ['5 MB / 24h TTL', '50 MB', '512 MB', '1.5 GB'] },
{ label: 'MongoDB', values: ['5 MB / 2 conn / 24h TTL', '100 MB / 5 conn', '5 GB / 20 conn', '40 GB / 50 conn'] },
// FIX-G (2026-05-14): the column used to advertise "1 000 / 5 000 / 100k
// msg/d" but there's no backing queue_messages_per_day field on the
// plans.yaml side — quota enforcement is on queue_storage_mb. Shipping
// a per-day-msg counter is real scope and not in flight, so the copy
// moves to the field we actually enforce. Numbers mirror plans.yaml
// queue_storage_mb (anonymous=1024, hobby=5120, pro=10240).
{ label: 'Queue', sub: 'NATS storage', values: ['1 GB / 24h TTL', '5 GB', '10 GB', UNLIMITED] },
// Vector — added 2026-05-20 to surface /vector/new alongside the other
// services. plans.yaml vector_storage_mb: anon=10, hobby=500, pro=10240,
// team=-1 (unlimited).
{ label: 'Vector', sub: 'pgvector', values: ['10 MB / 24h TTL', '500 MB', '10 GB', UNLIMITED] },
// plans.yaml side — quota enforcement is on queue_storage_mb. Numbers
// mirror plans.yaml queue_storage_mb (anon=64 MB, hobby=2 GB, pro=5 GB,
// team=40 GB) after the 2026-06-05 strict-margin trim.
{ label: 'Queue', sub: 'NATS storage', values: ['64 MB / 24h TTL', '2 GB', '5 GB', '40 GB'] },
// Vector — plans.yaml vector_storage_mb: anon=10 MB, hobby=500 MB,
// pro=10 GB, team=30 GB (strict-margin 2026-06-05).
{ label: 'Vector', sub: 'pgvector', values: ['10 MB / 24h TTL', '500 MB', '10 GB', '30 GB'] },
// Anonymous storage: plans.yaml storage_storage_mb=10 (anonymous tier).
// PB04 P1 (2026-05-21): cell used to render '—' which contradicted the
// shipped backend — anonymous /storage/new returns a real 10 MB bucket.
{ label: 'Storage', values: ['10 MB / 24h TTL', '512 MB', '50 GB', UNLIMITED] },
{ label: 'Webhook stored', values: ['100', '1 000', '10k', UNLIMITED] },
{ label: 'Storage', values: ['10 MB / 24h TTL', '512 MB', '50 GB', '300 GB'] },
{ label: 'Webhook stored', values: ['100', '1 000', '10k', '100k'] },
// 2026-05-20: dropped "small / medium" pod-size adjectives — there is no
// deployment_size field on api/internal/handlers/deploy.go. Numbers map
// to plans.yaml deployments_apps (hobby=1, pro=10, team=-1 → unlimited).
{ label: 'Deploy apps', values: [{ mark: 'dash' }, '1', '10', UNLIMITED] },
// to plans.yaml deployments_apps (hobby=1, pro=10, team=100 finite).
{ label: 'Deploy apps', values: [{ mark: 'dash' }, '1', '10', '100'] },
{ label: 'Domains', values: [{ mark: 'dash' }, '*.deployment.instanode.dev', 'custom domain', '50 custom domains'] },
// Multi-env workflows (stack promotion + vault copy across envs) is a
// shipped Pro-tier feature: POST /api/v1/stacks/:slug/promote and
// POST /api/v1/vault/copy are live (RETRO-2026-05-12 §10.17). Hobby is
// single-env (production only).
{ label: 'Multi-env workflows', sub: 'stack promotion + vault copy', values: [{ mark: 'dash' }, { mark: 'dash' }, 'dev / staging / prod', 'dev / staging / prod'] },
{ label: 'RBAC + audit', values: [{ mark: 'dash' }, { mark: 'dash' }, { mark: 'dash' }, { mark: 'check' }] },
{ label: 'Vault entries', values: [{ mark: 'dash' }, '20', '200', UNLIMITED] },
{ label: 'Vault entries', values: [{ mark: 'dash' }, '20', '200', '1 000'] },
{ label: 'Vault envs', values: [{ mark: 'dash' }, 'production only', 'multi-env', 'multi-env'] },
{ label: 'Backups', values: [{ mark: 'dash' }, '7-day · no restore', '30-day · 1-click restore', '90-day · self-serve restore'] },
// SSO/SAML + SLA have no backend yet — shown as not-yet-available everywhere
Expand Down Expand Up @@ -467,9 +471,10 @@ export function PricingPage() {
"outgrew Hobby's Mongo" step.
</li>
<li data-testid="intermediate-tier-growth">
<strong>Growth · $99/mo.</strong> Unlimited MongoDB, unlimited webhooks, 1 GB Redis,
20 GB Postgres. Pro-tier supporting services without committing to Pro's deployment
ladder. Yearly billing not yet offered on this tier.
<strong>Growth · $99/mo.</strong> 20 GB MongoDB, 100k webhook receivers, 1 GB Redis,
20 GB Postgres, 20 GB queue, 150 GB object storage. Pro-tier supporting services
without committing to Pro's deployment ladder. Yearly billing not yet offered on
this tier.
</li>
</ul>
</section>
Expand Down
Loading