Skip to content

Commit 5ffa778

Browse files
committed
fix: create real Stripe customer before checkout session
The checkout was failing because we passed the user's namespace (e.g., "janos") as the Stripe customer ID. Stripe expects a real customer ID (cus_...). Flow now: 1. Check cloud_billing table for existing Stripe customer_id 2. If none → create via Stripe API (POST /v1/customers) 3. Store customer_id in cloud_billing 4. Use real customer_id for Checkout session creation
1 parent 0104034 commit 5ffa778

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

crates/warpd/src/cloud/routes.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1031,12 +1031,71 @@ async fn billing_checkout(
10311031
}
10321032
};
10331033

1034+
// Step 1: Find or create a Stripe customer for this user.
1035+
// Check cloud_billing table for existing customer_id.
1036+
let customer_id = {
1037+
let mut rows = state
1038+
.cloud_db
1039+
.query(
1040+
"SELECT customer_id FROM cloud_billing WHERE team_id = ?",
1041+
libsql::params![user.namespace.clone()],
1042+
)
1043+
.await
1044+
.ok();
1045+
1046+
let existing = if let Some(ref mut r) = rows {
1047+
r.next()
1048+
.await
1049+
.ok()
1050+
.flatten()
1051+
.and_then(|row| row.get::<String>(0).ok())
1052+
} else {
1053+
None
1054+
};
1055+
1056+
match existing {
1057+
Some(cid) if !cid.is_empty() => cid,
1058+
_ => {
1059+
// Create a new Stripe customer.
1060+
match state
1061+
.billing
1062+
.create_customer(&user.email, &user.namespace)
1063+
.await
1064+
{
1065+
Ok(cid) => {
1066+
// Store in cloud_billing table.
1067+
let now = std::time::SystemTime::now()
1068+
.duration_since(std::time::UNIX_EPOCH)
1069+
.unwrap_or_default()
1070+
.as_secs() as i64;
1071+
let _ = state
1072+
.cloud_db
1073+
.execute(
1074+
"INSERT OR REPLACE INTO cloud_billing (customer_id, team_id, plan, created_at) VALUES (?, ?, 'free', ?)",
1075+
libsql::params![cid.clone(), user.namespace.clone(), now],
1076+
)
1077+
.await;
1078+
cid
1079+
}
1080+
Err(e) => {
1081+
return error_response(
1082+
StatusCode::INTERNAL_SERVER_ERROR,
1083+
&format!("Failed to create Stripe customer: {e}"),
1084+
)
1085+
.into_response();
1086+
}
1087+
}
1088+
}
1089+
}
1090+
};
1091+
1092+
// Step 2: Create a Checkout session with the real Stripe customer ID.
10341093
let success_url = "https://warpgrid.dev/console/settings?checkout=success";
10351094
let cancel_url = "https://warpgrid.dev/pricing";
10361095

10371096
match state
10381097
.billing
1039-
.create_checkout_session(&user.namespace, plan, success_url, cancel_url)
1098+
.create_checkout_session(&customer_id, plan, success_url, cancel_url)
10401099
.await
10411100
{
10421101
Ok(url) => CloudResponse::ok(CheckoutResponse { url }).into_response(),

0 commit comments

Comments
 (0)