Docs
Plans, quotas & billing
Exactly what Free, Basic, and Pro include, the quota counters that govern each kind of run, what you see when you hit a wall, and how an upgrade takes effect.
RealSiteWorth has three plans: Free, Basic, and Pro. Every number on this page comes from a constant in the codebase, not from marketing copy. Where a value is configurable, this page says so.
Prices
| Plan | Monthly | Annual | Annual per month | Annual saving |
|---|---|---|---|---|
| Free | $0 | $0 | — | — |
| Basic | $39/mo | $399/yr | $33.25/mo | Save $69/yr — ~15% |
| Pro | $99/mo | $999/yr | $83.25/mo | Save $189/yr — ~16% |
Annual savings are computed from the monthly price, not typed in. The shared toggle label is Save ~15–16%. There are two marketing promo codes, RSW10 (Basic) and RSW20 (Pro). They are never auto-applied at checkout.
Only four Stripe prices can be bought. The checkout API rejects anything else outright: rsw_basic_monthly, rsw_basic_annual, rsw_pro_monthly, rsw_pro_annual.
What each plan includes
This table follows the feature matrix in the code, with the free monthly allowance resolved to its configured default. It is deliberately narrower than the roadmap. A feature appears here only when its tier placement is real and enforced.
| Free | Basic | Pro | |
|---|---|---|---|
| Valuation range + confidence | Yes | Yes | Yes |
| Asset classification | Yes | Yes | Yes |
| Website valuations | 15 / month (default) | 250 / month | 1,250 / month |
| Advanced valuations | No | 10 / month — in-app trigger rolling out | 50 / month via MCP/agent access |
| AI Memo + Value-Gap Roadmap | Preview | Full | Full |
| RSW Auth + Trust | Scores | Full breakdowns | Full breakdowns |
| Evidence review | Standard | Expanded | Expanded + advanced depth |
| Social valuation sections | Standard | Full engagement + demographics | Full + monetization depth |
| Store / business valuations | No | Yes | Yes |
| Domain vs. Business mode | No | No | Yes |
| Watchlist | 5 slots | 10 slots, manual refresh | 50 slots |
| Report export (print-ready) | Watermarked | Watermark-free | Watermark-free + CSV |
| MCP/agent API | No | No | Included. Bearer auth, 5 requests/sec |
Three notes on that table.
Pro's 50 advanced valuations are metered on their own monthly counter, separate from the 1,250 standard runs. Both are included in Pro at no extra charge, and advanced runs are reachable through the included MCP/agent access.
Basic includes 10 advanced valuations per month, and the in-app way to run them is rolling out. The allowance is real and metered, but advanced runs currently enter only through the agent/API transports, and the MCP/agent transport is Pro-only. There is no button in the dashboard that spends this allowance on Basic yet. It is documented here because it is what the plan includes, not because you can trigger it from the app today.
Basic's watchlist slots refresh when you ask them to.
Three counters, not one
Your ability to run a valuation is governed by three independent counters. You have to pass all of them.
1. Burst limit. 8 requests per IP per minute, on every valuation surface. This is checked first, before anything else. Exceeding it returns 429 and consumes no quota.
2. Daily or monthly bucket. Which bucket you land in depends on who you are.
3. Tier quota. The monthly allowance for your plan, counted per UTC calendar month.
Anonymous (not signed in)
You get 3 website valuations per UTC day, shared across every valuation surface. It is one combined bucket, not three per surface.
Two buckets enforce this together. One is keyed to your IP. The other is keyed to an rsw_anon_quota cookie (HttpOnly, SameSite=Lax, one-year max age). Clearing cookies still hits the IP bucket. Rotating IPs still hits the cookie bucket. The response reports whichever of the two has less left, so the remaining count is never overstated.
The bucket resets at 00:00 UTC.
Signed-in Free account
You get 15 website valuations per UTC calendar month by default. This value is configurable via the FREE_MONTHLY_QUOTA environment variable and falls back to 15 when unset.
Free accounts also get 5 social/creator valuations per UTC day and 5 watchlist slots.
The monthly window is the UTC calendar month. It resets at the first instant of the next month, and the API tells you the exact timestamp in x-quota-reset.
A note on the free tier's basicPerMonth: 90 constant: it does not govern you. Signed-in free accounts get a quota override of 50, and the binding wall for website valuations is the 15/month bucket above. Anonymous callers never reach the monthly check at all because the daily IP cap returns first. Treat 90 as dormant.
Basic and Pro
Paid tiers skip the daily bucket entirely. Your cap is the monthly tier quota: 250/month plus 10 advanced on Basic, 1,250/month plus 50 advanced on Pro, counted per UTC calendar month.
Because the daily bucket does not apply, x-quota-limit carries a non-numeric sentinel rather than a count on paid accounts. That describes the daily bucket only. Your real cap is the monthly quota in the table above.
When any meter reaches 80% of its monthly limit, the account page shows a soft warning. The hard stop is at 100%.
What counts as a run
A unit is reserved before the engine starts, and it is charged only if the run produces something usable.
Charged:
- Any valuation that returns a result.
Not charged:
- Requests rejected by the burst limiter. The limiter runs before any reservation.
- Requests rejected by a tier gate. On the store/business surface the tier check fires before the body is even parsed, specifically so a denied caller never consumes a unit.
- Requests rejected by the quota wall itself.
- Invalid input (
400), oversized bodies (413). - Runs that fail before producing a usable response. A 5xx or a thrown error refunds the reservation.
- Runs that come back fully degraded, meaning every core signal was null. Those refund too.
Refunds are bounded. A subject can reclaim at most 6 daily units per day and 15 monthly units per month. Past that cap the original charge stands. This exists so a caller who can reliably force failures cannot mint unbounded engine attempts, since each attempt can cost real vendor spend.
Refunds are idempotent and floor at zero. A duplicate or unmatched refund can never create quota.
Store and business valuations require Basic
Store and business (ecommerce) valuations are a paid feature. You need tier basic or higher.
Anonymous callers and signed-in free accounts get a 403:
{
"error": {
"code": "TIER_FORBIDDEN",
"reason": "ecommerce_requires_basic",
"tier": null,
"message": "Store and business valuations are part of Basic ($39/mo). Sign in with a Basic or Pro account to run one.",
"request_id": "a1b2c3d4e5f6a7b8"
}
}
The gate sits after the burst limiter and before the body parse, so a denied request costs you nothing.
One exception matters. If the account lookup itself fails, for example a database blip, you get a retryable 503 instead of a tier denial:
{
"error": {
"code": "AUTH_UNAVAILABLE",
"reason": "auth-lookup-failed",
"message": "We could not verify your account just now. Please retry in a moment.",
"request_id": "a1b2c3d4e5f6a7b8"
}
}
A paying customer is never 403'd because of an infrastructure hiccup. Retry the request.
This surface takes financial inputs, not a URL. Monthly revenue is required and is never inferred.
curl -X POST https://realsiteworth.com/api/value-ecommerce \
-H 'Content-Type: application/json' \
-d '{"monthlyRevenue": 42000, "monthlyCogs": 18000, "platform": "shopify"}'
What you see at the wall
The denial shape differs by surface. Read the reason field, not the HTTP status.
Website valuations (/api/value)
curl -X POST https://realsiteworth.com/api/value \
-H 'Content-Type: application/json' \
-d '{"url": "example.com"}'
Quota walls on this surface return HTTP 200 with allowed: false in the body. Do not branch on the status code here. Branch on allowed and reason.
Anonymous daily cap:
{
"allowed": false,
"tier": "free",
"kind": "basic",
"reason": "free_daily_ip_cap",
"message": "Anonymous use is capped at 3 valuations per day. Sign in free to keep report history.",
"quota": { "limit": 3, "remaining": 0, "reset": "daily_utc", "subject": "anonymous" },
"request_id": "a1b2c3d4e5f6a7b8"
}
Signed-in free monthly cap:
{
"allowed": false,
"tier": "free",
"kind": "basic",
"reason": "free_signed_in_monthly_cap",
"message": "Free account monthly website limit reached (15 valuations). Basic includes 250 website valuations each month — or come back on 2026-09-01T00:00:00Z.",
"quota": { "limit": 15, "remaining": 0, "reset": "2026-09-01T00:00:00Z", "subject": "user" },
"request_id": "a1b2c3d4e5f6a7b8"
}
The two reasons are deliberately distinct so a client can pick the right prompt (sign up versus upgrade) without inspecting quota.subject.
Store valuations (/api/value-ecommerce)
Free and anonymous callers never reach a quota wall on this surface, because the 403 tier gate (ecommerce_requires_basic) fires first. The wall you can actually hit here is the paid monthly allowance, described next.
Monthly tier quota exhausted (Basic and Pro)
When a paid account burns through its monthly allowance, the tier gate returns 403 with reason tier_basic_cap:
You've used your monthly Basic allowance. Upgrade or wait until September 1.
Burst limit
Every surface, 429:
{
"error": {
"code": "RATE_LIMITED",
"reason": "rate-limited",
"message": "Too many requests. Try again in a minute.",
"request_id": "a1b2c3d4e5f6a7b8"
}
}
Quota headers
Every valuation response, allowed or denied, carries the same three headers:
x-quota-limit: 15
x-quota-remaining: 11
x-quota-reset: 2026-09-01T00:00:00Z
x-quota-reset is daily_utc for the anonymous bucket and an ISO timestamp for monthly buckets. Read these to show a remaining count before the user hits the wall, rather than discovering the wall by hitting it.
How upgrading takes effect
Checkout goes through Stripe. Your tier flips when Stripe tells us it did, not when you land back on the site.
- You start checkout for one of the four allowed lookup keys. Anything else is rejected before a Stripe session is created.
- Stripe processes payment and sends a webhook. The webhook verifies the Stripe signature and rejects anything unsigned or mismatched with
400. Events are deduplicated on the event ID. - On
checkout.session.completed, the lookup key is mapped to a tier and stamped in two places: the Stripe customer's metadata, and yourprofiles.tierrow.
That second write is the one that matters for your limits. It happens at payment time, not when you visit your account page. If you close the tab immediately after paying, your new limits are already live.
Plan changes and cancellations follow the same path:
customer.subscription.updatedre-stamps the new tier on both stores.- A
canceledstatus drops you tofreeimmediately. past_duekeeps your paid tier. That is deliberate dunning grace, so a failed card retry does not lock you out mid-cycle.customer.subscription.deleteddrops you tofree.
The gate reads tier from that stamped metadata. It never trusts a tier supplied by the client.
Where these numbers live
If you are reading the source, these are the files that own each value. Nothing else should hardcode them.
| Value | Constant | File |
|---|---|---|
| Per-tier monthly quotas | TIER_QUOTAS | src/lib/billing/limits.ts |
| Soft-warning threshold (0.8) | SOFT_WARN_FRACTION | src/lib/billing/limits.ts |
| Free account allowances | FREE_ACCOUNT_LIMITS | src/lib/access/entitlements.ts |
| Prices and billing intervals | BASIC_MONTHLY_TIER etc. | src/lib/pricing-tiers.ts |
| Public feature copy | FEATURE_MATRIX | src/lib/billing/features.ts |
| Anonymous daily cap, burst limit | DAILY_QUOTA_PER_IP, MAX | src/lib/valuation/ratelimit.ts |
| Which bucket a caller uses | reserveAccountlessValuationQuota | src/lib/valuation/quota.ts |
| Watchlist slots | watchlistLimit | src/lib/billing/tier.ts |
