One link per offering
The page shows the offering's web plans, the trial and a Save badge for the cheapest monthly price.
Feature
A RevenueDot purchase link is a hosted checkout page for one offering, which you put in emails, ads, QR codes or your website. Buyers pay on Stripe Checkout. A redemption link then opens your app and passes the purchase to the SDK's redeemWebPurchase, which moves it to the app user so the entitlement is active.
Free up to $10,000 a month in tracked revenue. Works with the RevenueCat SDK you already ship.
The page shows the offering's web plans, the trial and a Save badge for the cheapest monthly price.
?app_user_id= buys for a signed-in user, ?email= pre-fills the email and ?code= pre-fills a discount code.
Links can expire, be turned off and carry an automatic web discount.
The SDK parses the redemption link and RevenueDot answers success, invalidToken, purchaseBelongsToOtherUser or expired.
An expired or turned-off link answers 410 with a page that says the link has expired. The key needs project_configuration:offerings:read_write.
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/purchase_links" \
-H "Authorization: Bearer $SECRET_KEY" -H "Content-Type: application/json" \
-d '{"name":"Spring sale","offering_id":"ofrngm2u3h89blc","slug":"spring-sale"}' | Parameter | What it does |
|---|---|
| ?app_user_id=user_123 | Buys for this app user id. The purchase goes straight to that customer, so no redemption link is needed. |
| ?email=ana@example.com | Pre-fills the email. Stripe Checkout shows it and the receipt goes there. |
| ?code=SPRING20 | Pre-fills a discount code and checks it at once. |
Put your app's real user id in app_user_id, the same one you pass to Purchases.logIn.
A buyer who paid without an app user id gets a deep link such as scanner://redeem_web_purchase?redemption_token=rdrt_... and an https link at /pay/r/<token> for emails and QR codes. Register your URL scheme in the app, then pass the link to the SDK. The link works for 24 hours by default, and only the token's hash is stored.
import RevenueCat
import SwiftUI
struct ContentView: View {
var body: some View {
HomeView()
.onOpenURL { url in
// Only redemption links parse; other deep links return nil.
guard let redemption = url.asWebPurchaseRedemption else { return }
Task {
switch await Purchases.shared.redeemWebPurchase(redemption) {
case let .success(customerInfo):
print("Active:", customerInfo.entitlements.active.keys)
case .invalidToken, .purchaseBelongsToOtherUser, .expired, .error:
print("Show a message and offer help.")
}
}
}
}
} Redeeming merges the anonymous web buyer into the app user, the same way logIn merges an anonymous customer, and RevenueDot sends one PURCHASE_REDEEMED webhook.
| SDK result | Server answer | What happened |
|---|---|---|
| success | 200, customer info | The purchase is on the app's user. A retry by the same customer also succeeds. |
| invalidToken | 400, code 7849 | The token is unknown, malformed or from another project. |
| purchaseBelongsToOtherUser | 400, code 7852 | Another customer already redeemed it. |
| expired | 400, code 7853 | The link is too old. RevenueDot emails a new link, at most once an hour per purchase. |
| error | 401, 5xx or no network | Show an error and let the buyer try again. |
FAQ
Create a purchase link for an offering in the RevenueDot dashboard and share its URL, such as https://api.revenuedot.app/pay/scanner/spring-sale. The page shows the offering's web plans and sends buyers to Stripe Checkout. Add ?app_user_id= to buy for a signed-in user.
Register a URL scheme, parse the incoming link with asWebPurchaseRedemption on iOS or Android, and call redeemWebPurchase. The purchase moves to the app's user and the entitlement becomes active at once. The result is success, invalidToken, purchaseBelongsToOtherUser, expired or error.
Redeeming an expired link makes RevenueDot email a fresh link and answer expired with the buyer's email in an obfuscated form. The old link keeps answering expired, so the app can always tell the buyer to check their email. A buyer who gave no email needs support.
Yes. Set expires_at when you create or update the link, or turn the link off. An expired or turned-off link answers 410 with a page that says the link has expired, and starting a checkout from it also answers 410.
No. If the link carries the app user id, for example from an email or an in-app button, the purchase goes straight to that customer. Redemption is for anonymous web buyers.
Get started
Start free on RevenueDot Cloud, free up to $10,000 a month in tracked revenue, or move an existing RevenueCat app with one line of code.
Already have an account? Sign in · Prefer your own servers? Self-host free