max / makenotwork
11 files changed,
+288 insertions,
-56 deletions
| @@ -293,3 +293,19 @@ support = 5.00 | |||
| 293 | 293 | engineering = 6.00 | |
| 294 | 294 | reserves = 7.50 | |
| 295 | 295 | earnback = 33.46 | |
| 296 | + | ||
| 297 | + | ||
| 298 | + | # ─── Runway disclosure (transparency block on /docs/about/economics) ───── | |
| 299 | + | # | |
| 300 | + | # Operator-set. Refreshed quarterly at sprint close, alongside the | |
| 301 | + | # /changelog recap. The paying-creator count on the page is pulled live | |
| 302 | + | # from the DB; this number is the cash-runway bucket. | |
| 303 | + | # | |
| 304 | + | # Units: quarters at current burn (whole-number bucket; we round down | |
| 305 | + | # rather than mislead in either direction). | |
| 306 | + | # | |
| 307 | + | # A value of 0 means "not yet published" — the page renders without a | |
| 308 | + | # number until the first quarterly refresh sets it. | |
| 309 | + | [runway] | |
| 310 | + | quarters = 0 | |
| 311 | + | last_updated_iso = "2026-06-03" |
| @@ -1,56 +0,0 @@ | |||
| 1 | - | # Platform Economics | |
| 2 | - | ||
| 3 | - | *As of 2026-05-16.* | |
| 4 | - | ||
| 5 | - | What you pay, what it covers, and what we commit to. | |
| 6 | - | ||
| 7 | - | --- | |
| 8 | - | ||
| 9 | - | ## What You Pay | |
| 10 | - | ||
| 11 | - | See [Pricing](./pricing.md) for the current tier prices, the founding-creator rate, and the provisional standard rate. | |
| 12 | - | ||
| 13 | - | --- | |
| 14 | - | ||
| 15 | - | ## What It Covers | |
| 16 | - | ||
| 17 | - | Your subscription funds three things, at a high level: | |
| 18 | - | ||
| 19 | - | **Cost to deliver.** The infrastructure that hosts your content (application servers, database, object storage, bandwidth) and the payment processing fee Stripe charges on each transaction. | |
| 20 | - | ||
| 21 | - | **Platform overhead.** Ongoing development, day-to-day operations, legal and compliance work, and reserves held against unexpected costs so a bad month doesn't force a price increase or a shutdown. | |
| 22 | - | ||
| 23 | - | **Returned to creators.** Surplus beyond what cost-to-deliver and platform overhead require is earmarked to come back to you as earn-back credit. We've committed to launching that program no later than 2027-01-01. | |
| 24 | - | ||
| 25 | - | See the full breakdown on the [pricing page](/pricing#cost-allocation) — every tier fee broken into Stripe processing, storage, human support time, product engineering, reserves, and earn-back surplus. | |
| 26 | - | ||
| 27 | - | No surplus goes to investors, shareholders, dividends, executive bonuses, paid acquisition, or marketing spend. We have none of those things. | |
| 28 | - | ||
| 29 | - | --- | |
| 30 | - | ||
| 31 | - | ## What We Commit To | |
| 32 | - | ||
| 33 | - | The binding commitments live in [What We Guarantee](./guarantees.md). The short version: | |
| 34 | - | ||
| 35 | - | - No surprise raises. Prices only change under conditions stated in writing. | |
| 36 | - | - At least 90 days notice on any change. | |
| 37 | - | - Existing creators are grandfathered at their current rate for at least 12 months when standard rates rise. | |
| 38 | - | - When our cost structure permits, the direction is downward. Cost-favorable changes apply retroactively to active subscriptions. | |
| 39 | - | ||
| 40 | - | --- | |
| 41 | - | ||
| 42 | - | ## What We Won't Do | |
| 43 | - | ||
| 44 | - | - **Percentage cuts.** We will not skim a percentage of what fans pay you. | |
| 45 | - | - **Per-transaction fees on top of Stripe.** The only deduction is Stripe's processing fee, which goes to Stripe. | |
| 46 | - | - **Surge pricing.** Tier prices do not move based on demand, time of day, or who you are. | |
| 47 | - | - **Quiet plan-gating.** Features won't migrate between tiers without notice and grandfathering. | |
| 48 | - | - **Paid acquisition or marketing.** We don't fund growth by spending your subscription on ads. | |
| 49 | - | ||
| 50 | - | --- | |
| 51 | - | ||
| 52 | - | ## See Also | |
| 53 | - | ||
| 54 | - | - [Pricing](./pricing.md): Current rates, founding-creator rate, standard rate | |
| 55 | - | - [What We Guarantee](./guarantees.md): Binding commitments in writing | |
| 56 | - | - [How We Work](./how-we-work.md): Business model and operating principles |
| @@ -472,6 +472,47 @@ pub async fn mark_grace_enforced(pool: &PgPool, user_id: UserId) -> Result<()> { | |||
| 472 | 472 | Ok(()) | |
| 473 | 473 | } | |
| 474 | 474 | ||
| 475 | + | /// Count fully-paying creators — `status = 'active'` only. | |
| 476 | + | /// | |
| 477 | + | /// Excludes trialing (free trial), past_due (payment failed but not yet | |
| 478 | + | /// canceled), canceled-in-grace (winding down), and incomplete states. | |
| 479 | + | /// This is the number that goes on the runway disclosure as "paying | |
| 480 | + | /// creators today": revenue-bearing seats, no fudge. | |
| 481 | + | #[tracing::instrument(skip_all)] | |
| 482 | + | pub async fn count_active_paying(pool: &PgPool) -> Result<i64> { | |
| 483 | + | let count: (i64,) = sqlx::query_as( | |
| 484 | + | "SELECT COUNT(*) FROM creator_subscriptions WHERE status = 'active'", | |
| 485 | + | ) | |
| 486 | + | .fetch_one(pool) | |
| 487 | + | .await?; | |
| 488 | + | Ok(count.0) | |
| 489 | + | } | |
| 490 | + | ||
| 491 | + | /// Count creators in a trial or 30-day cancellation grace period. | |
| 492 | + | /// | |
| 493 | + | /// These are not revenue-bearing today but represent the near-term | |
| 494 | + | /// pipeline: trialing seats may convert, grace seats may resubscribe | |
| 495 | + | /// before enforcement. Disclosed as a secondary number on the runway | |
| 496 | + | /// surface so the headline `count_active_paying` stays strict. | |
| 497 | + | #[tracing::instrument(skip_all)] | |
| 498 | + | pub async fn count_trialing_or_grace(pool: &PgPool) -> Result<i64> { | |
| 499 | + | let count: (i64,) = sqlx::query_as( | |
| 500 | + | r#" | |
| 501 | + | SELECT COUNT(*) FROM creator_subscriptions | |
| 502 | + | WHERE status = 'trialing' | |
| 503 | + | OR ( | |
| 504 | + | status = 'canceled' | |
| 505 | + | AND canceled_at IS NOT NULL | |
| 506 | + | AND canceled_at > NOW() - INTERVAL '30 days' | |
| 507 | + | AND grace_enforced_at IS NULL | |
| 508 | + | ) | |
| 509 | + | "#, | |
| 510 | + | ) | |
| 511 | + | .fetch_one(pool) | |
| 512 | + | .await?; | |
| 513 | + | Ok(count.0) | |
| 514 | + | } | |
| 515 | + | ||
| 475 | 516 | /// Check whether a user is in the 30-day cancellation grace period. | |
| 476 | 517 | /// | |
| 477 | 518 | /// Returns `true` if the subscription is canceled but within 30 days of cancellation |
| @@ -76,6 +76,7 @@ pub struct AppState { | |||
| 76 | 76 | pub docs: Arc<DocLoader>, | |
| 77 | 77 | pub tier_prices: tier_prices::TierPrices, | |
| 78 | 78 | pub cost_allocation: tier_prices::CostAllocation, | |
| 79 | + | pub runway_config: tier_prices::RunwayConfig, | |
| 79 | 80 | pub scanner: Option<Arc<ScanPipeline>>, | |
| 80 | 81 | pub webauthn: Arc<Webauthn>, | |
| 81 | 82 | pub syntax: Option<Arc<git::SyntaxHighlighter>>, |
| @@ -322,6 +322,7 @@ async fn main() { | |||
| 322 | 322 | let tp = makenotwork::tier_prices::TierPrices::from_assumptions(&assumptions); | |
| 323 | 323 | makenotwork::tier_prices::CostAllocation::from_assumptions(&assumptions, &tp) | |
| 324 | 324 | }, | |
| 325 | + | runway_config: makenotwork::tier_prices::RunwayConfig::from_assumptions(&assumptions), | |
| 325 | 326 | scanner, | |
| 326 | 327 | webauthn, | |
| 327 | 328 | syntax, |
| @@ -360,6 +360,33 @@ pub(super) async fn pricing_page( | |||
| 360 | 360 | } | |
| 361 | 361 | } | |
| 362 | 362 | ||
| 363 | + | /// Render the platform-economics + runway disclosure page. | |
| 364 | + | /// | |
| 365 | + | /// Shadows the catch-all `/docs/{slug}` so this URL keeps the | |
| 366 | + | /// `/docs/economics` shape inbound links already use, but the page | |
| 367 | + | /// renders as Askama (not docengine markdown) so it can carry live | |
| 368 | + | /// figures from the database. The two count queries are cheap (each | |
| 369 | + | /// is a single `SELECT COUNT(*)` against an indexed status column); | |
| 370 | + | /// no caching needed at current load. | |
| 371 | + | #[tracing::instrument(skip_all, name = "landing::economics_page")] | |
| 372 | + | pub(super) async fn economics_page( | |
| 373 | + | State(state): State<AppState>, | |
| 374 | + | session: Session, | |
| 375 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 376 | + | ) -> Result<impl IntoResponse> { | |
| 377 | + | let paying_creators = | |
| 378 | + | crate::db::creator_tiers::count_active_paying(&state.db).await?; | |
| 379 | + | let trialing_or_grace = | |
| 380 | + | crate::db::creator_tiers::count_trialing_or_grace(&state.db).await?; | |
| 381 | + | Ok(EconomicsTemplate { | |
| 382 | + | csrf_token: get_csrf_token(&session).await, | |
| 383 | + | session_user: maybe_user, | |
| 384 | + | runway_config: state.runway_config.clone(), | |
| 385 | + | paying_creators, | |
| 386 | + | trialing_or_grace, | |
| 387 | + | }) | |
| 388 | + | } | |
| 389 | + | ||
| 363 | 390 | /// Lightweight checkout success page for app-initiated Stripe flows. | |
| 364 | 391 | /// No auth required; the app polls for subscription status independently. | |
| 365 | 392 | #[tracing::instrument(skip_all, name = "landing::checkout_complete")] |
| @@ -90,6 +90,10 @@ pub fn public_routes() -> CsrfRouter<AppState> { | |||
| 90 | 90 | .route_get("/creators", get(creators_page)) | |
| 91 | 91 | .route_get("/docs", get(docs::docs_index)) | |
| 92 | 92 | .route_get("/docs/search.json", get(docs::docs_search_index)) | |
| 93 | + | // Static-slug routes must register BEFORE the catch-all `/docs/{slug}` | |
| 94 | + | // so axum's router prefers the exact match. /docs/economics renders | |
| 95 | + | // as Askama (live runway disclosure); the markdown source is gone. | |
| 96 | + | .route_get("/docs/economics", get(landing::economics_page)) | |
| 93 | 97 | .route_get("/docs/{slug}", get(docs::doc_page)) | |
| 94 | 98 | // Two-factor authentication | |
| 95 | 99 | .route_get("/auth/2fa", get(two_factor::two_factor_page)) |
| @@ -87,6 +87,8 @@ impl_into_response!( | |||
| 87 | 87 | DocIndexTemplate, | |
| 88 | 88 | // Pricing calculator | |
| 89 | 89 | PricingTemplate, | |
| 90 | + | // Platform economics + runway disclosure | |
| 91 | + | EconomicsTemplate, | |
| 90 | 92 | // Use cases | |
| 91 | 93 | UseCasesTemplate, | |
| 92 | 94 | // Team |
| @@ -771,6 +771,29 @@ pub struct PricingTemplate { | |||
| 771 | 771 | pub cost_allocation: crate::tier_prices::CostAllocation, | |
| 772 | 772 | } | |
| 773 | 773 | ||
| 774 | + | /// Platform economics + runway disclosure page. Renders at | |
| 775 | + | /// `/docs/about/economics` and shadows the catch-all docs route so the | |
| 776 | + | /// URL stays the same as the retired markdown page. See the doc comment | |
| 777 | + | /// on `templates/pages/economics.html` for the maintenance contract. | |
| 778 | + | #[derive(Template)] | |
| 779 | + | #[template(path = "pages/economics.html")] | |
| 780 | + | #[allow(dead_code)] // Fields used by Askama template | |
| 781 | + | pub struct EconomicsTemplate { | |
| 782 | + | pub csrf_token: CsrfTokenOption, | |
| 783 | + | pub session_user: Option<SessionUser>, | |
| 784 | + | /// `quarters` + `last_updated_iso` from `[runway]` in | |
| 785 | + | /// `assumptions.toml`. Operator-edited; refreshed quarterly. | |
| 786 | + | pub runway_config: crate::tier_prices::RunwayConfig, | |
| 787 | + | /// Live count of `status='active'` creator subscriptions. Pulled at | |
| 788 | + | /// request time so the page never lies about how many seats are | |
| 789 | + | /// revenue-bearing right now. | |
| 790 | + | pub paying_creators: i64, | |
| 791 | + | /// Live count of `status='trialing'` plus canceled-with-grace | |
| 792 | + | /// creators. Disclosed only when non-zero (the template hides the | |
| 793 | + | /// bullet otherwise so a quiet platform doesn't show "0 in trial"). | |
| 794 | + | pub trialing_or_grace: i64, | |
| 795 | + | } | |
| 796 | + | ||
| 774 | 797 | /// Use cases page showcasing creator types. | |
| 775 | 798 | #[derive(Template)] | |
| 776 | 799 | #[template(path = "pages/use_cases.html")] |
| @@ -255,6 +255,38 @@ fn build_aria_label(tier_label: &str, price: i32, segments: &[CostSegment]) -> S | |||
| 255 | 255 | s | |
| 256 | 256 | } | |
| 257 | 257 | ||
| 258 | + | /// Operator-edited runway figures, loaded once at startup. The | |
| 259 | + | /// live paying-creator counts come from the DB at request time and | |
| 260 | + | /// are NOT in this struct — see `db::creator_tiers::count_active_paying` | |
| 261 | + | /// and `count_trialing_or_grace`. | |
| 262 | + | /// | |
| 263 | + | /// `quarters` is the cash-runway bucket in whole quarters (rounded down). | |
| 264 | + | /// A value of `0` means "not yet published" and the template should | |
| 265 | + | /// suppress the line rather than render "0 quarters". | |
| 266 | + | /// | |
| 267 | + | /// `last_updated_iso` is the date the operator last refreshed the figure, | |
| 268 | + | /// in ISO 8601 (`YYYY-MM-DD`). Rendered verbatim into the "Last updated" | |
| 269 | + | /// stamp on the disclosure surface. | |
| 270 | + | #[derive(Clone, Debug, Default)] | |
| 271 | + | pub struct RunwayConfig { | |
| 272 | + | pub quarters: i32, | |
| 273 | + | pub last_updated_iso: String, | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | impl RunwayConfig { | |
| 277 | + | pub fn from_assumptions(a: &Assumptions) -> Self { | |
| 278 | + | Self { | |
| 279 | + | quarters: int_at(a, "runway.quarters"), | |
| 280 | + | last_updated_iso: str_at(a, "runway.last_updated_iso"), | |
| 281 | + | } | |
| 282 | + | } | |
| 283 | + | /// True iff the operator has published a runway figure. Suppress the | |
| 284 | + | /// "X quarters at current burn" line when this is false. | |
| 285 | + | pub fn is_published(&self) -> bool { | |
| 286 | + | self.quarters > 0 | |
| 287 | + | } | |
| 288 | + | } | |
| 289 | + | ||
| 258 | 290 | fn float_at(a: &Assumptions, key: &str) -> f64 { | |
| 259 | 291 | match a.get(key) { | |
| 260 | 292 | Some(LookupValue::Float(x)) => *x, | |
| @@ -332,6 +364,34 @@ mod tests { | |||
| 332 | 364 | } | |
| 333 | 365 | ||
| 334 | 366 | #[test] | |
| 367 | + | fn runway_config_loads_from_canonical_assumptions() { | |
| 368 | + | // The presence of the [runway] block is the only enforced thing — | |
| 369 | + | // the values inside are operator-edited. We pin the keys so a | |
| 370 | + | // future toml edit that renames `quarters` or `last_updated_iso` | |
| 371 | + | // is caught at PR time, not at boot. | |
| 372 | + | let a = Assumptions::load(ASSUMPTIONS_PATH).expect("load canonical toml"); | |
| 373 | + | let r = RunwayConfig::from_assumptions(&a); | |
| 374 | + | assert!(r.quarters >= 0, "quarters must be a non-negative integer"); | |
| 375 | + | assert!(!r.last_updated_iso.is_empty(), "last_updated_iso must be set"); | |
| 376 | + | // ISO 8601 date format: YYYY-MM-DD. | |
| 377 | + | assert_eq!(r.last_updated_iso.len(), 10); | |
| 378 | + | assert!(r.last_updated_iso.chars().nth(4) == Some('-')); | |
| 379 | + | assert!(r.last_updated_iso.chars().nth(7) == Some('-')); | |
| 380 | + | } | |
| 381 | + | ||
| 382 | + | #[test] | |
| 383 | + | fn runway_config_is_published_only_when_quarters_nonzero() { | |
| 384 | + | // The disclosure template hides the cash-runway bullet when this | |
| 385 | + | // returns false, so a freshly-deployed instance with quarters=0 | |
| 386 | + | // doesn't display "0 quarters at current burn" — which would be | |
| 387 | + | // both wrong and alarming. | |
| 388 | + | let r = RunwayConfig { quarters: 0, last_updated_iso: "2026-06-03".into() }; | |
| 389 | + | assert!(!r.is_published()); | |
| 390 | + | let r = RunwayConfig { quarters: 4, last_updated_iso: "2026-06-03".into() }; | |
| 391 | + | assert!(r.is_published()); | |
| 392 | + | } | |
| 393 | + | ||
| 394 | + | #[test] | |
| 335 | 395 | fn cost_allocation_aria_label_names_every_segment() { | |
| 336 | 396 | // Screen readers get the full breakdown via aria-label since the | |
| 337 | 397 | // colored bar carries no native semantics. Pin the format. |
| @@ -0,0 +1,113 @@ | |||
| 1 | + | {# Platform Economics — Askama page, NOT a docengine markdown surface. | |
| 2 | + | ||
| 3 | + | This page carries live disclosure (paying-creator counts pulled from | |
| 4 | + | the DB at request time) which docengine's static markdown pipeline | |
| 5 | + | can't express. It shadows the catch-all /docs/{slug} route so the | |
| 6 | + | URL stays at /docs/about/economics for backwards-compatibility with | |
| 7 | + | inbound links. | |
| 8 | + | ||
| 9 | + | Prose mirrors the previous economics.md content (deleted in the same | |
| 10 | + | commit). To edit prose, edit this file. To edit the cost-allocation | |
| 11 | + | model or the runway figure, edit docs/business/assumptions.toml. #} | |
| 12 | + | {% extends "base.html" %} | |
| 13 | + | ||
| 14 | + | {% block title %}Platform Economics - Makenot.work{% endblock %} | |
| 15 | + | ||
| 16 | + | {% block head %}{% endblock %} | |
| 17 | + | ||
| 18 | + | {% block content %} | |
| 19 | + | {% include "partials/site_header.html" %} | |
| 20 | + | ||
| 21 | + | <article class="doc-container"> | |
| 22 | + | <nav class="doc-breadcrumb"> | |
| 23 | + | <a href="/docs">Docs</a> / <span>About</span> | |
| 24 | + | <div class="docs-search-container docs-search-inline"> | |
| 25 | + | <input type="text" class="docs-search-input" placeholder="Search docs..." autocomplete="off" /> | |
| 26 | + | <div class="docs-search-results hidden"></div> | |
| 27 | + | </div> | |
| 28 | + | </nav> | |
| 29 | + | ||
| 30 | + | <h1 class="doc-title">Platform Economics</h1> | |
| 31 | + | ||
| 32 | + | <div class="doc-body"> | |
| 33 | + | <p><em>As of {{ runway_config.last_updated_iso }}.</em></p> | |
| 34 | + | ||
| 35 | + | <p>What you pay, what it covers, the position we're operating from, and what we commit to.</p> | |
| 36 | + | ||
| 37 | + | <hr> | |
| 38 | + | ||
| 39 | + | <h2>What You Pay</h2> | |
| 40 | + | <p>See <a href="/docs/pricing">Pricing</a> for the current tier prices, the founding-creator rate, and the provisional standard rate.</p> | |
| 41 | + | ||
| 42 | + | <hr> | |
| 43 | + | ||
| 44 | + | <h2>What It Covers</h2> | |
| 45 | + | <p>Your subscription funds three things, at a high level:</p> | |
| 46 | + | ||
| 47 | + | <p><strong>Cost to deliver.</strong> The infrastructure that hosts your content (application servers, database, object storage, bandwidth) and the payment processing fee Stripe charges on each transaction.</p> | |
| 48 | + | ||
| 49 | + | <p><strong>Platform overhead.</strong> Ongoing development, day-to-day operations, legal and compliance work, and reserves held against unexpected costs so a bad month doesn't force a price increase or a shutdown.</p> | |
| 50 | + | ||
| 51 | + | <p><strong>Returned to creators.</strong> Surplus beyond what cost-to-deliver and platform overhead require is earmarked to come back to you as earn-back credit. We've committed to launching that program no later than 2027-01-01.</p> | |
| 52 | + | ||
| 53 | + | <p>See the full breakdown on the <a href="/pricing#cost-allocation">pricing page</a> — every tier fee broken into Stripe processing, storage, human support time, product engineering, reserves, and earn-back surplus.</p> | |
| 54 | + | ||
| 55 | + | <p>No surplus goes to investors, shareholders, dividends, executive bonuses, paid acquisition, or marketing spend. We have none of those things.</p> | |
| 56 | + | ||
| 57 | + | <hr> | |
| 58 | + | ||
| 59 | + | <h2>Where We Are</h2> | |
| 60 | + | <p>Numbers refresh at the close of every two-month sprint, alongside the <a href="/changelog">changelog</a> recap. The paying-creator count is read live from the database at the time you load this page.</p> | |
| 61 | + | ||
| 62 | + | <ul> | |
| 63 | + | <li>Paying creators today: <strong>{{ paying_creators }}</strong></li> | |
| 64 | + | {% if trialing_or_grace > 0 %} | |
| 65 | + | <li>In trial or 30-day cancellation grace: <strong>{{ trialing_or_grace }}</strong></li> | |
| 66 | + | {% endif %} | |
| 67 | + | <li>Break-even at the assumed tier mix: approximately <strong>22.5</strong> paying creators at the standard rate, <strong>46.8</strong> at the founding rate. (Derivation in the build's <code>assumptions.toml</code>.)</li> | |
| 68 | + | {% if runway_config.is_published() %} | |
| 69 | + | <li>Cash runway at current burn: <strong>{{ runway_config.quarters }}</strong> quarter{% if runway_config.quarters != 1 %}s{% endif %}.</li> | |
| 70 | + | {% endif %} | |
| 71 | + | </ul> | |
| 72 | + | ||
| 73 | + | <p>Reserve capacity (twelve months of fixed costs plus a legal reserve and a single-incident shock reserve) is approximately <strong>$62k</strong>, derived from the build's assumptions. Reserves shrink before prices change; a single bad month doesn't move the headline rate.</p> | |
| 74 | + | ||
| 75 | + | <hr> | |
| 76 | + | ||
| 77 | + | <h2>What We Commit To</h2> | |
| 78 | + | <p>The binding commitments live in <a href="/docs/guarantees">What We Guarantee</a>. The short version:</p> | |
| 79 | + | <ul> | |
| 80 | + | <li>No surprise raises. Prices only change under conditions stated in writing.</li> | |
| 81 | + | <li>At least 90 days notice on any change.</li> | |
| 82 | + | <li>Existing creators are grandfathered at their current rate for at least 12 months when standard rates rise.</li> | |
| 83 | + | <li>When our cost structure permits, the direction is downward. Cost-favorable changes apply retroactively to active subscriptions.</li> | |
| 84 | + | </ul> | |
| 85 | + | ||
| 86 | + | <hr> | |
| 87 | + | ||
| 88 | + | <h2>What We Won't Do</h2> | |
| 89 | + | <ul> | |
| 90 | + | <li><strong>Percentage cuts.</strong> We will not skim a percentage of what fans pay you.</li> | |
| 91 | + | <li><strong>Per-transaction fees on top of Stripe.</strong> The only deduction is Stripe's processing fee, which goes to Stripe.</li> | |
| 92 | + | <li><strong>Surge pricing.</strong> Tier prices do not move based on demand, time of day, or who you are.</li> | |
| 93 | + | <li><strong>Quiet plan-gating.</strong> Features won't migrate between tiers without notice and grandfathering.</li> | |
| 94 | + | <li><strong>Paid acquisition or marketing.</strong> We don't fund growth by spending your subscription on ads.</li> | |
| 95 | + | </ul> | |
| 96 | + | ||
| 97 | + | <hr> | |
| 98 | + | ||
| 99 | + | <h2>See Also</h2> | |
| 100 | + | <ul> | |
| 101 | + | <li><a href="/docs/pricing">Pricing</a>: Current rates, founding-creator rate, standard rate</li> | |
| 102 | + | <li><a href="/docs/guarantees">What We Guarantee</a>: Binding commitments in writing</li> | |
| 103 | + | <li><a href="/docs/how-we-work">How We Work</a>: Business model and operating principles</li> | |
| 104 | + | </ul> | |
| 105 | + | </div> | |
| 106 | + | </article> | |
| 107 | + | ||
| 108 | + | <footer class="text-reader-footer"> | |
| 109 | + | <a href="/">Makenot<span class="dot">.</span>work</a> | |
| 110 | + | </footer> | |
| 111 | + | ||
| 112 | + | <script src="/static/docs-search.js"></script> | |
| 113 | + | {% endblock %} |