diff --git a/content/docs/android/guides/web-checkout/using-revenuecat.mdx b/content/docs/android/guides/web-checkout/using-revenuecat.mdx
index a7f6e961..9002e7de 100644
--- a/content/docs/android/guides/web-checkout/using-revenuecat.mdx
+++ b/content/docs/android/guides/web-checkout/using-revenuecat.mdx
@@ -30,9 +30,10 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.RequestBody.Companion.toRequestBody
-import org.json.JSONObject
+ import okhttp3.Request
+ import okhttp3.RequestBody.Companion.toRequestBody
+ import org.json.JSONObject
+ import java.io.IOException
class SWDelegate : SuperwallDelegate {
private val client = OkHttpClient()
@@ -60,8 +61,8 @@ class SWDelegate : SuperwallDelegate {
// In the background using coroutines...
coroutineScope.launch {
- // For each subscription id, link it to the user in RevenueCat
- stripeSubscriptionIds.forEach { stripeSubscriptionId ->
+ // For each subscription id, link it to the user in RevenueCat
+ stripeSubscriptionIds.forEach { stripeSubscriptionId ->
try {
val json = JSONObject().apply {
put("app_user_id", appUserId)
@@ -80,14 +81,15 @@ class SWDelegate : SuperwallDelegate {
.addHeader("Authorization", "Bearer $revenueCatStripePublicAPIKey")
.build()
- val response = client.newCall(request).execute()
- val responseBody = response.body?.string()
-
- if (response.isSuccessful) {
- Log.d("Superwall", "[!] Success: linked $stripeSubscriptionId to user $appUserId: $responseBody")
- } else {
- Log.e("Superwall", "[!] Error: unable to link $stripeSubscriptionId to user $appUserId. Response: $responseBody")
- }
+ client.newCall(request).execute().use { response ->
+ val responseBody = response.body?.string().orEmpty()
+
+ if (!response.isSuccessful) {
+ throw IOException("RevenueCat responded with ${response.code}: $responseBody")
+ }
+
+ Log.d("Superwall", "[!] Success: linked $stripeSubscriptionId to user $appUserId: $responseBody")
+ }
} catch (e: Exception) {
Log.e("Superwall", "[!] Error: unable to link $stripeSubscriptionId to user $appUserId", e)
}
@@ -120,6 +122,11 @@ class SWDelegate : SuperwallDelegate {
}
```
+
+ The example surfaces non-200 responses and network exceptions so you can add retries, user messaging,
+ or monitoring. Customize the error handling to fit your production logging and UX.
+
+
If you call `logIn` from RevenueCat's SDK, then you need to call the logic you've implemented
inside `didRedeemLink(result:)` again. For example, that means if `logIn` was invoked from
diff --git a/content/docs/expo/guides/web-checkout/using-revenuecat.mdx b/content/docs/expo/guides/web-checkout/using-revenuecat.mdx
index f5efbb3a..ca0a867b 100644
--- a/content/docs/expo/guides/web-checkout/using-revenuecat.mdx
+++ b/content/docs/expo/guides/web-checkout/using-revenuecat.mdx
@@ -48,33 +48,36 @@ export class SWDelegate extends SuperwallDelegate {
// In the background, process all subscription IDs
await Promise.all(
- stripeSubscriptionIds.map(async (stripeSubscriptionId) => {
- try {
- const response = await fetch('https://api.revenuecat.com/v1/receipts', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- 'X-Platform': 'stripe',
- 'Authorization': `Bearer ${revenueCatStripePublicAPIKey}`,
- },
- body: JSON.stringify({
- app_user_id: appUserId,
- fetch_token: stripeSubscriptionId,
- }),
- });
-
- const data = await response.json();
-
- if (response.ok) {
+ stripeSubscriptionIds.map(async (stripeSubscriptionId) => {
+ try {
+ const response = await fetch('https://api.revenuecat.com/v1/receipts', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ 'X-Platform': 'stripe',
+ 'Authorization': `Bearer ${revenueCatStripePublicAPIKey}`,
+ },
+ body: JSON.stringify({
+ app_user_id: appUserId,
+ fetch_token: stripeSubscriptionId,
+ }),
+ });
+
+ const responseText = await response.text();
+
+ if (!response.ok) {
+ throw new Error(
+ `RevenueCat responded with ${response.status}: ${responseText || 'No body'}`
+ );
+ }
+
+ const data = responseText ? JSON.parse(responseText) : {};
console.log(`[!] Success: linked ${stripeSubscriptionId} to user ${appUserId}`, data);
- } else {
- console.error(`[!] Error: unable to link ${stripeSubscriptionId} to user ${appUserId}. Response:`, data);
+ } catch (error) {
+ console.error(`[!] Error: unable to link ${stripeSubscriptionId} to user ${appUserId}`, error);
}
- } catch (error) {
- console.error(`[!] Error: unable to link ${stripeSubscriptionId} to user ${appUserId}`, error);
- }
- })
+ })
);
/// After all network calls complete, invalidate the cache
@@ -100,6 +103,11 @@ export class SWDelegate extends SuperwallDelegate {
}
```
+
+ The example explicitly checks HTTP status codes and throws on failures so you can plug in retries,
+ alerting, or user messaging. Tailor the error handling to your networking stack.
+
+
If you call `logIn` from RevenueCat's SDK, then you need to call the logic you've implemented
inside `didRedeemLink(result)` again. For example, that means if `logIn` was invoked from
diff --git a/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx b/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx
index d74d236a..1d268dd6 100644
--- a/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx
+++ b/content/docs/flutter/guides/web-checkout/using-revenuecat.mdx
@@ -50,31 +50,33 @@ class MySuperwallDelegate extends SuperwallDelegate {
// In the background, send requests to RevenueCat
for (final stripeSubscriptionId in stripeSubscriptionIds) {
- try {
- final url = Uri.parse('https://api.revenuecat.com/v1/receipts');
- final response = await http.post(
- url,
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- 'X-Platform': 'stripe',
- 'Authorization': 'Bearer $revenueCatStripePublicAPIKey',
- },
- body: jsonEncode({
- 'app_user_id': appUserId,
- 'fetch_token': stripeSubscriptionId,
- }),
- );
-
- if (response.statusCode == 200) {
+ try {
+ final url = Uri.parse('https://api.revenuecat.com/v1/receipts');
+ final response = await http.post(
+ url,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ 'X-Platform': 'stripe',
+ 'Authorization': 'Bearer $revenueCatStripePublicAPIKey',
+ },
+ body: jsonEncode({
+ 'app_user_id': appUserId,
+ 'fetch_token': stripeSubscriptionId,
+ }),
+ );
+
+ if (response.statusCode != 200) {
+ throw Exception(
+ 'RevenueCat responded with ${response.statusCode}: ${response.body}',
+ );
+ }
+
final json = jsonDecode(response.body);
print('[!] Success: linked $stripeSubscriptionId to user $appUserId: $json');
- } else {
- print('[!] Error: unable to link $stripeSubscriptionId to user $appUserId. Status: ${response.statusCode}');
+ } catch (error) {
+ print('[!] Error: unable to link $stripeSubscriptionId to user $appUserId: $error');
}
- } catch (error) {
- print('[!] Error: unable to link $stripeSubscriptionId to user $appUserId: $error');
- }
}
// After all network calls complete, invalidate the cache
@@ -100,6 +102,11 @@ class MySuperwallDelegate extends SuperwallDelegate {
}
```
+
+ The example throws when RevenueCat responds with an error so you can add retries, alerts, or custom
+ UI. Adapt the error-handling strategy to your networking and logging requirements.
+
+
Set up the delegate when configuring Superwall:
```dart
@@ -198,11 +205,13 @@ class MySuperwallDelegate extends SuperwallDelegate {
}),
);
- if (response.statusCode == 200) {
- print('[!] Successfully linked $stripeSubscriptionId to $appUserId');
- } else {
- throw Exception('Failed to link subscription: ${response.statusCode}');
+ if (response.statusCode != 200) {
+ throw Exception(
+ 'RevenueCat responded with ${response.statusCode}: ${response.body}',
+ );
}
+
+ print('[!] Successfully linked $stripeSubscriptionId to $appUserId');
}
}
```
diff --git a/content/shared/web-checkout/using-revenuecat.mdx b/content/shared/web-checkout/using-revenuecat.mdx
index f1651d45..a1dbee5c 100644
--- a/content/shared/web-checkout/using-revenuecat.mdx
+++ b/content/shared/web-checkout/using-revenuecat.mdx
@@ -42,7 +42,7 @@ final class Delegate: SuperwallDelegate {
let revenueCatStripePublicAPIKey = "strp....." // replace with your RevenueCat Stripe Public API Key
let appUserId = Purchases.shared.appUserID
- // In the background...
+ // In the background...
Task.detached {
await withTaskGroup(of: Void.self) { group in
// For each subscription id, link it to the user in RevenueCat
@@ -55,18 +55,31 @@ final class Delegate: SuperwallDelegate {
request.setValue("stripe", forHTTPHeaderField: "X-Platform")
request.setValue("Bearer \(revenueCatStripePublicAPIKey)", forHTTPHeaderField: "Authorization")
- do {
- request.httpBody = try JSONEncoder().encode([
- "app_user_id": appUserId,
- "fetch_token": stripeSubscriptionId
- ])
-
- let (data, _) = try await URLSession.shared.data(for: request)
- let json = try JSONSerialization.jsonObject(with: data, options: [])
- print("[!] Success: linked \(stripeSubscriptionId) to user \(appUserId)", json)
- } catch {
- print("[!] Error: unable to link \(stripeSubscriptionId) to user \(appUserId)", error)
- }
+ do {
+ request.httpBody = try JSONEncoder().encode([
+ "app_user_id": appUserId,
+ "fetch_token": stripeSubscriptionId
+ ])
+
+ let (data, response) = try await URLSession.shared.data(for: request)
+
+ guard let httpResponse = response as? HTTPURLResponse else {
+ print("[!] Error: Received an invalid response for \(stripeSubscriptionId)")
+ return
+ }
+
+ guard (200..<300).contains(httpResponse.statusCode) else {
+ let body = String(data: data, encoding: .utf8) ?? ""
+ print("[!] Error: RevenueCat responded with \(httpResponse.statusCode) for \(stripeSubscriptionId). Body: \(body)")
+ return
+ }
+
+ let json = try JSONSerialization.jsonObject(with: data, options: [])
+ print("[!] Success: linked \(stripeSubscriptionId) to user \(appUserId)", json)
+ } catch {
+ // Surface network errors so you can retry or notify the user.
+ print("[!] Error: unable to link \(stripeSubscriptionId) to user \(appUserId)", error)
+ }
}
}
}
@@ -93,6 +106,11 @@ final class Delegate: SuperwallDelegate {
}
```
+
+ The snippet logs HTTP failures and propagates network errors so you can build retries, show UI,
+ or report the issue. Be sure to adapt the error handling to match your monitoring and UX needs.
+
+
If you call `logIn` from RevenueCat's SDK, then you need to call the logic you've implemented
inside `didRedeemLink(result:)` again. For example, that means if `logIn` was invoked from