Skip to main content

max / makenotwork

3.0 KB · 57 lines History Blame Raw
1 //! Stripe Connect, Checkout, and webhook routes.
2 //!
3 //! See also: `/docs/guide/03-selling`
4
5 mod checkout;
6 mod connect;
7 mod webhook;
8 mod webhook_v2;
9
10 pub(crate) use checkout::grant_bundle_items;
11 pub(crate) use webhook::process_webhook_event;
12
13 use axum::routing::get;
14
15 use crate::{
16 csrf::{post_csrf, post_csrf_manual, post_csrf_skip, CsrfRouter},
17 AppState,
18 };
19
20 /// Reason string for routes that only construct a Stripe Checkout Session URL.
21 /// State mutation happens server-side via the Stripe webhook, not in these
22 /// handlers. The `tip` route is the documented exception — it inserts a
23 /// `pending_tip` row BEFORE the Stripe call, so it uses Manual posture.
24 const STRIPE_SESSION_SKIP: &str =
25 "Stripe Checkout Session constructor — no mutation until webhook";
26
27 /// Register Stripe Connect, Checkout, and webhook routes.
28 pub fn stripe_routes() -> CsrfRouter<AppState> {
29 CsrfRouter::new()
30 // Creator onboarding (Account Links flow)
31 .route_get("/stripe/connect", get(connect::stripe_connect_disclaimer))
32 .route("/stripe/connect/proceed", post_csrf(connect::stripe_connect_proceed))
33 .route_get("/stripe/connect/return", get(connect::stripe_connect_return))
34 .route_get("/stripe/connect/refresh", get(connect::stripe_connect_refresh))
35 // Checkout flow (idempotency handled by global middleware in metrics.rs)
36 .route("/stripe/fan-plus", post_csrf(checkout::create_fan_plus_checkout))
37 .route("/stripe/fan-plus/cancel", post_csrf(checkout::cancel_fan_plus))
38 .route("/stripe/fan-plus/resume", post_csrf(checkout::resume_fan_plus))
39 .route("/stripe/billing-portal", post_csrf(checkout::open_billing_portal))
40 .route("/stripe/creator-tier", post_csrf(checkout::create_creator_tier_checkout))
41 .route("/stripe/checkout/{item_id}", post_csrf_skip(STRIPE_SESSION_SKIP, checkout::create_checkout))
42 .route("/stripe/checkout/{item_id}/cancel-pending", post_csrf(checkout::cancel_pending_item_checkout))
43 .route("/stripe/checkout/project/{project_id}", post_csrf_skip(STRIPE_SESSION_SKIP, checkout::create_project_checkout))
44 .route("/stripe/subscribe/{tier_id}", post_csrf_skip(STRIPE_SESSION_SKIP, checkout::create_subscription_checkout))
45 .route("/stripe/checkout/tip/{recipient_id}", post_csrf_manual(
46 "inserts pending_tip row before Stripe call — handler validates _csrf",
47 checkout::create_tip_checkout,
48 ))
49 .route("/stripe/checkout/cart", post_csrf_skip(STRIPE_SESSION_SKIP, checkout::create_cart_checkout))
50 .route("/stripe/checkout/cart/all", post_csrf_skip(STRIPE_SESSION_SKIP, checkout::create_cart_checkout_all))
51 .route_get("/stripe/success", get(checkout::checkout_success))
52 .route_get("/stripe/cancel", get(checkout::checkout_cancel))
53 // Webhooks
54 .route("/stripe/webhook", post_csrf_skip("webhook: stripe signature verified in handler", webhook::webhook))
55 .route("/stripe/webhook/v2", post_csrf_skip("webhook: stripe signature verified in handler", webhook_v2::webhook_v2))
56 }
57