Monetization¶
SectorWars 2102 is free-to-play with optional subscriptions. The base game (sign-up, single-region play, all core gameplay) is free forever. Real money buys cross-region travel, region ownership, and (future) cosmetic / convenience perks — never a competitive ceiling.
Source files:
- services/gameserver/src/services/paypal_service.py — PayPal API integration, plan IDs, webhook handling.
- services/gameserver/src/models/user.py — subscription_tier, subscription_status, paypal_subscription_id columns on User.
- services/gameserver/src/models/region.py — subscription_tier, paypal_subscription_id on Region (for Region Owner billing).
- services/gameserver/src/services/regional_auth_service.py — RegionalRole.GALACTIC_CITIZEN, role permissions.
1. Subscription tiers¶
Three tiers are defined in paypal_service.py:SubscriptionTier. The first two are live; the third is reserved for future expansion.
1.1 Free¶
Price: $0.
Identity: Default for every new account. User.subscription_tier = NULL.
Includes: - Full character creation and play within a single home region. - All core gameplay: trading, combat, planet ownership, colonization, faction missions, team membership, ranking progression. - ARIA companion at base consciousness tier. - Access to leaderboards and cross-team chat within the home region.
Excludes:
- Cross-region travel (cannot leave home region except to visit Central Nexus as a visitor membership).
- Region ownership.
- (Future) cosmetic ship skins and ARIA voice packs.
1.2 Galactic Citizen — $5 / month¶
Identity: User.subscription_tier = "galactic_citizen". PayPal plan ID configured via PAYPAL_GALACTIC_CITIZEN_PLAN_ID env var (services/gameserver/src/core/config.py:73).
When a Galactic Citizenship subscription activates, Player.is_galactic_citizen is set to true (paypal_service.py:_activate_galactic_citizenship, line 412).
Unlocks:
- Cross-region travel via Central Nexus warp gates (the Player.can_travel_between_regions property gates this — models/player.py:147).
- Auto-elevation to RegionalRole.GALACTIC_CITIZEN in any visited region, granting GALACTIC_CITIZEN_BENEFITS permission (regional_auth_service.py:179).
- A small monthly in-game credit stipend (target: 5,000 cr/month — see FEATURES/economy/lifecycle.md).
- Faster ARIA relationship score growth and elevated initial consciousness tier.
- Cosmetic citizenship badge on player profile.
1.3 Region Owner — $25 / month¶
Identity: Region.subscription_tier = "regional_owner", Region.paypal_subscription_id set, Region.owner_id linked to the User. PayPal plan ID via PAYPAL_REGIONAL_OWNER_PLAN_ID.
Activation: paypal_service.py:_activate_regional_ownership (line 426). On subscription approval, the system either creates a new Region row or transfers ownership of an existing one.
Unlocks:
- Ability to create and own a player-owned region (100–1,000 sectors, per valid_region_type_sector_count constraint in models/region.py:138).
- Configure governance_type (autocracy / democracy / council).
- Set tax_rate (5% to 25%, constraint in models/region.py:134).
- Set starting_credits for new players spawning in the region.
- Customize language_pack, aesthetic_theme, traditions (cultural identity).
- Receive a share of regional tax revenue (📐 Design-only — payout share %).
- Issue regional bounties from treasury.
- Includes Galactic Citizen benefits for the owning user.
1.4 Nexus Premium — $50 / month (future)¶
Identity: User.subscription_tier = "nexus_premium". Plan ID PAYPAL_NEXUS_PREMIUM_PLAN_ID.
Reserved tier (paypal_service.py:30 annotates "future expansion"). Intended for power users who want Galactic Citizen + a permanent presence in the Central Nexus + enhanced ARIA features. Specifics to be defined.
2. PayPal billing flow¶
End-to-end topology of a subscription purchase. Source: paypal_service.py:create_galactic_citizen_subscription (line 166) and create_regional_ownership_subscription (line 206).
2.1 Subscription create¶
Player-client gameserver PayPal
│ │ │
│ POST /api/v1/subscriptions/ │ │
│ galactic-citizen │ │
│ ─────────────────────────► │ │
│ │ POST /v1/billing/ │
│ │ subscriptions │
│ │ ──────────────────────────► │
│ │ ◄────── subscription.id + │
│ │ approval_url │
│ ◄─── { approval_url } ───── │ │
│ │ │
│ user redirected to PayPal approval page │
│ ─────────────────────────────────────────────────────────►│
│ user completes PayPal flow │
│ ◄──── return_url with subscription_id ─────────────────── │
2.2 Webhook activation¶
PayPal calls back to the gameserver webhook endpoint when the subscription state changes. Source: paypal_service.py:handle_subscription_webhook (line 294).
PayPal gameserver database
│ │ │
│ POST /webhooks/paypal │ │
│ { event_type: │ │
│ BILLING.SUBSCRIPTION │ │
│ .ACTIVATED } │ │
│ ─────────────────────────────► │ │
│ │ verify signature │
│ │ (validate_webhook_signature)│
│ │ ─────────────────────────► │
│ │ parse custom_id │
│ │ → "galactic_citizen_<uid>" │
│ │ or "regional_owner_<uid>_<region>"
│ │ │
│ │ User.paypal_subscription_id│
│ │ User.subscription_tier │
│ │ Player.is_galactic_citizen │
│ │ = true │
│ │ ─────────────────────────► │
│ ◄── 200 OK ────────────────────│ │
2.3 Feature flag flip¶
After the webhook commits, gated features become available immediately:
- Player.can_travel_between_regions returns true (gates inter-region travel API).
- Player.is_galactic_citizen = true (gates Galactic-Citizen-only UI elements).
- For Region Owner: Region.status = "active", Region.owner_id set — region governance UI unlocks.
No client-side cache flush is required; the player-client checks these flags on each session and on key UI transitions.
3. Webhook event handling¶
Source: paypal_service.py:handle_subscription_webhook (line 294). Mapping of PayPal event → action:
| PayPal event | Handler | Effect |
|---|---|---|
BILLING.SUBSCRIPTION.ACTIVATED |
_handle_subscription_activated |
Set is_galactic_citizen = true or activate region |
BILLING.SUBSCRIPTION.CANCELLED |
_handle_subscription_cancelled |
Clear is_galactic_citizen; suspend region (Region.status = "suspended") |
BILLING.SUBSCRIPTION.SUSPENDED |
_handle_subscription_suspended |
Suspend region access |
BILLING.SUBSCRIPTION.PAYMENT.FAILED |
_handle_payment_failed |
Log warning; failure-counter for eventual suspension |
PAYMENT.SALE.COMPLETED |
_handle_payment_completed |
Confirm renewal; reactivate suspended region if applicable |
Webhook signature validation is mandatory in production (validate_webhook_signature, line 507) — calls PayPal's verification API with the configured PAYPAL_WEBHOOK_ID. The bypass PAYPAL_SKIP_WEBHOOK_VALIDATION env var exists only for local development and emits a warning when used.
4. Refund, suspension, termination¶
4.1 Suspension¶
Triggered by:
- Repeated payment failures (PayPal sends BILLING.SUBSCRIPTION.SUSPENDED after configured retry attempts).
- Operator-initiated suspension via admin UI.
- Direct PayPal API call: paypal_service.suspend_subscription(subscription_id, reason) (line 266).
Effect:
- Region.status = "suspended" for region subscriptions — the region remains in the database, citizens cannot enter/leave, owner cannot configure.
- Player.is_galactic_citizen unset for citizenship subscriptions — cross-region travel blocked, but in-game character data is untouched.
A suspended subscription auto-reactivates when payment resumes (_handle_payment_completed, line 393, sets region.status = "active").
4.2 Cancellation¶
User-initiated:
- Player cancels via PayPal account or via in-game UI (which calls paypal_service.cancel_subscription, line 252).
Effect:
- Subscription becomes CANCELLED at PayPal.
- Webhook fires BILLING.SUBSCRIPTION.CANCELLED.
- _handle_subscription_cancelled (line 340) clears Region.paypal_subscription_id, sets region.status = "suspended", or clears player.is_galactic_citizen.
4.3 Refunds¶
Refund handling is operator-driven — there is no in-app "request refund" button. An operator reviews the case and:
1. Issues the PayPal refund out-of-band via the PayPal merchant dashboard.
2. Cancels the subscription via paypal_service.cancel_subscription.
3. Logs an audit entry via services/audit_service.py.
Target policy: pro-rata refunds within 7 days of charge for Galactic Citizen; pro-rata only on first month for Region Owner; no refund after the first month of a region subscription (since the universe state has been altered by the player's ownership actions).
4.4 Termination¶
Permanent termination beyond cancellation:
- Region subscriptions: after 30 days of suspended status, the region becomes eligible for Region.status = "terminated". Resident players are migrated to a default region. Region records retained for audit.
- Galactic Citizen: cancellation is termination — the user simply returns to free tier.
The RegionStatus.TERMINATED enum (models/region.py:RegionStatus) reserves the state; the migration job is 📐 Design-only.
5. Pricing rationale¶
| Tier | Price | Marginal cost | Target audience | Conversion goal |
|---|---|---|---|---|
| Free | $0 | Hosting share | Everyone | Onboard, retain ≥ 10 hours |
| Galactic Citizen | $5 | Trivial | Hour-50+ players | 5–10% of active players |
| Region Owner | $25 | Operator cost dominant (region creation, persistence, governance UI) | Hour-300+ committed players | 0.5–1% of active players |
| Nexus Premium | $50 | (future) | Power users, content creators | <0.1% (luxury tier) |
The price ladder is deliberately steep — Region Owner is 5x Galactic Citizen — because region ownership is a creator role, not a consumer role, and pricing it close to Galactic Citizen would devalue regional politics.
6. Identity-state lookup¶
A user's combined subscription state can be queried via paypal_service.get_user_subscriptions(user_id) (line 459), which returns all active subscriptions across both Galactic Citizen and any owned regions. The function consults both User.paypal_subscription_id and the joined Region.paypal_subscription_id rows.
For internal feature-gating, services should consult:
- User.subscription_tier (string column) — fast in-process check.
- User.subscription_status — must equal "active" (or PayPal's "ACTIVE").
- Player.is_galactic_citizen — derived flag for cross-region permissions.
- Region.owner_id == user.id AND Region.status == "active" — region ownership check.
7. Audit and compliance¶
All subscription state changes log to services/audit_service.py. Webhooks include:
- Inbound webhook payload (full body) with redacted PayPal access tokens.
- Resulting database mutations.
- Operator who initiated any direct cancellation/suspension.
Retention: 7 years for billing-related audit entries (financial-services standard).
8. Cross-references¶
- multi-regional.md — what region ownership unlocks at the gameplay level.
- aria.md — ARIA tier benefits for paid subscribers.
- FEATURES/economy/lifecycle.md — subscription perks as economy faucets.
- FEATURES/gameplay/player-journey.md — when in the player lifecycle each tier becomes attractive.