rc-backend

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Backend Architecture with RevenueCat

使用RevenueCat构建后端架构

You do not build a receipt verification server with RevenueCat. Your backend still has a role, but that role is consuming RevenueCat state, not validating Google Play purchase tokens.
你无需基于RevenueCat构建收据验证服务器。你的后端仍有其作用,但该作用是获取RevenueCat的状态,而非验证Google Play购买令牌。

Phase 1: Discovery

阶段1:探索

RevenueCat's backend is the receipt verification server. When the Android SDK posts a purchase token, RevenueCat's backend:
  1. Calls
    purchases.subscriptionsv2.get
    or
    purchases.products.get
    against the Google Play Developer API.
  2. Validates the receipt is genuine and matches the expected product.
  3. Records the transaction in its database.
  4. Returns
    CustomerInfo
    to the SDK.
Your Android app never calls the Google Play Developer API. Your server does not call it either.
Before writing any backend code, confirm these facts about your deployment:
  • You have a RevenueCat project with an Android app configured.
  • You have a secret API key from Project Settings to API Keys (not the public Android SDK key embedded in the app).
  • You know which
    app_user_id
    your SDK uses (the same identifier your auth system uses).
  • You have decided whether the backend needs real time state (REST API) or event driven state (webhooks).
If your app only gates features inside the client, you may not need a backend component at all. RevenueCat verifies
CustomerInfo
server side before it reaches the SDK, and
EntitlementVerificationMode.INFORMATIONAL
or
.ENFORCED
adds signature verification on the client. Serve premium content from a server only when you can verify entitlement on the server.
RevenueCat的后端就是收据验证服务器。当Android SDK提交购买令牌时,RevenueCat的后端会执行以下操作:
  1. 调用Google Play Developer API的
    purchases.subscriptionsv2.get
    purchases.products.get
    接口。
  2. 验证收据的真实性,并确认其与预期产品匹配。
  3. 在数据库中记录该交易。
  4. 向SDK返回
    CustomerInfo
你的Android应用永远不会调用Google Play Developer API,你的服务器也不需要调用它。
在编写任何后端代码之前,请确认你的部署满足以下条件:
  • 你拥有一个已配置Android应用的RevenueCat项目。
  • 你从项目设置的API密钥页面获取了一个密钥API密钥(不是嵌入在应用中的公开Android SDK密钥)。
  • 你知道SDK使用的
    app_user_id
    (与你的认证系统使用的标识符相同)。
  • 你已确定后端需要实时状态(REST API)还是事件驱动状态(webhooks)。
如果你的应用仅在客户端内限制功能访问,那么你可能根本不需要后端组件。RevenueCat会在
CustomerInfo
到达SDK之前进行服务器端验证,而
EntitlementVerificationMode.INFORMATIONAL
.ENFORCED
会在客户端添加签名验证。只有当你能在服务器端验证权益时,才从服务器提供付费内容。

Phase 2: Plan

阶段2:规划

Map each backend responsibility to a RevenueCat mechanism.
Use caseMechanismNotes
React to purchase, renewal, cancellationWebhook receiverRevenueCat posts normalized events; your server updates its own DB.
Check current entitlement for a user
GET /v1/subscribers/{app_user_id}
Secret API key in
Authorization
header.
Grant promotional access (support, refunds, comps)
POST /v1/subscribers/{app_user_id}/entitlements/{entitlement_id}/promotional
Server side only.
Revoke promotional access
POST /v1/subscribers/{app_user_id}/entitlements/{entitlement_id}/revoke_promotionals
Server side only.
Set subscriber attributes from server side data
POST /v1/subscribers/{app_user_id}/attributes
Useful for CRM fields the SDK does not know.
Bulk data exportRevenueCat data exportScheduled exports to your warehouse.
What your backend still owns:
  • User authentication.
  • Your database of users and their access levels.
  • API endpoints that serve premium content.
  • The webhook receiver that processes RevenueCat events.
What your backend does not own:
  • Google Play Developer API credentials.
  • Receipt verification code.
  • linkedPurchaseToken
    chain traversal.
  • Subscription state computation across the seven subscription states.
将每个后端职责映射到对应的RevenueCat机制。
使用场景机制说明
响应购买、续订、取消操作Webhook接收器RevenueCat会提交标准化事件;你的服务器更新自身数据库。
检查用户当前的权益
GET /v1/subscribers/{app_user_id}
Authorization
头中使用密钥API密钥。
授予推广访问权限(支持、退款、赠送)
POST /v1/subscribers/{app_user_id}/entitlements/{entitlement_id}/promotional
仅支持服务器端调用。
撤销推广访问权限
POST /v1/subscribers/{app_user_id}/entitlements/{entitlement_id}/revoke_promotionals
仅支持服务器端调用。
从服务器端数据设置订阅者属性
POST /v1/subscribers/{app_user_id}/attributes
适用于SDK无法获取的CRM字段。
批量数据导出RevenueCat数据导出定期导出数据到你的数据仓库。
你的后端仍需负责:
  • 用户认证。
  • 用户及其访问级别的数据库。
  • 提供付费内容的API端点。
  • 处理RevenueCat事件的Webhook接收器。
你的后端无需负责:
  • Google Play Developer API凭据。
  • 收据验证代码。
  • linkedPurchaseToken
    链遍历。
  • 七种订阅状态下的订阅状态计算。

Phase 3: Execute

阶段3:实施

Read a subscriber

读取订阅者信息

http
GET https://api.revenuecat.com/v1/subscribers/{app_user_id}
Authorization: Bearer sk_...
X-Platform: android
The response body is the same
CustomerInfo
structure the Android SDK returns. Use it in a server side endpoint that gates premium API responses.
http
GET https://api.revenuecat.com/v1/subscribers/{app_user_id}
Authorization: Bearer sk_...
X-Platform: android
响应体与Android SDK返回的
CustomerInfo
结构相同。可在限制付费API响应的服务器端端点中使用它。

Grant a promotional entitlement

授予推广权益

http
POST https://api.revenuecat.com/v1/subscribers/{app_user_id}/entitlements/{entitlement_id}/promotional
Authorization: Bearer sk_...
Content-Type: application/json

{"duration": "monthly"}
Valid
duration
values include
daily
,
three_day
,
weekly
,
monthly
,
two_month
,
three_month
,
six_month
,
yearly
,
lifetime
. Use this for support workflows, never from the client.
http
POST https://api.revenuecat.com/v1/subscribers/{app_user_id}/entitlements/{entitlement_id}/promotional
Authorization: Bearer sk_...
Content-Type: application/json

{"duration": "monthly"}
有效的
duration
值包括
daily
three_day
weekly
monthly
two_month
three_month
six_month
yearly
lifetime
。此接口用于支持工作流,绝不能从客户端调用。

Example: Kotlin Ktor call from your server

示例:你的服务器发起Kotlin Ktor调用

kotlin
val response = client.get("https://api.revenuecat.com/v1/subscribers/$appUserId") {
    header("Authorization", "Bearer ${System.getenv("RC_SECRET_KEY")}")
    header("X-Platform", "android")
}
kotlin
val response = client.get("https://api.revenuecat.com/v1/subscribers/$appUserId") {
    header("Authorization", "Bearer ${System.getenv("RC_SECRET_KEY")}")
    header("X-Platform", "android")
}

API key rules

API密钥规则

KeyWhere it livesWhat it can do
Android public SDK keyEmbedded in the Android appPost purchases, fetch
CustomerInfo
for the current user.
Secret API keyServer environment variable onlyRead any subscriber, grant or revoke promotionals, set attributes, bulk operations.
Never ship the secret key in the Android APK, in a BuildConfig field, or in any client bundle. Rotate it if it leaks. Treat it like a database password.
密钥类型存储位置权限
Android公开SDK密钥嵌入在Android应用中提交购买请求、获取当前用户的
CustomerInfo
密钥API密钥仅存储在服务器环境变量中读取任意订阅者信息、授予或撤销推广权限、设置属性、批量操作。
绝不要将密钥打包到Android APK、BuildConfig字段或任何客户端包中。如果密钥泄露,请立即轮换。将其视为数据库密码一样对待。

Webhook receiver outline

Webhook接收器示例

kotlin
post("/revenuecat/webhook") {
    val auth = call.request.header("Authorization")
    require(auth == "Bearer ${System.getenv("RC_WEBHOOK_SECRET")}")
    val event = call.receive<RevenueCatEvent>()
    when (event.type) {
        "INITIAL_PURCHASE", "RENEWAL" -> grantAccess(event.appUserId, event.entitlements)
        "CANCELLATION", "EXPIRATION" -> scheduleRevocation(event.appUserId)
    }
    call.respond(HttpStatusCode.OK)
}
Verify the authorization header you configured in the RevenueCat dashboard. Respond 2xx fast; RevenueCat retries on non 2xx responses.
kotlin
post("/revenuecat/webhook") {
    val auth = call.request.header("Authorization")
    require(auth == "Bearer ${System.getenv("RC_WEBHOOK_SECRET")}")
    val event = call.receive<RevenueCatEvent>()
    when (event.type) {
        "INITIAL_PURCHASE", "RENEWAL" -> grantAccess(event.appUserId, event.entitlements)
        "CANCELLATION", "EXPIRATION" -> scheduleRevocation(event.appUserId)
    }
    call.respond(HttpStatusCode.OK)
}
验证你在RevenueCat仪表板中配置的授权头。快速返回2xx响应;RevenueCat会对非2xx响应进行重试。

What not to build

无需构建的内容

  • Do not build a Google Play receipt verification endpoint. RevenueCat already did.
  • Do not pass purchase tokens from the Android client to your server for manual verification. The SDK handles the round trip.
  • Do not query Google Play Developer API from your backend unless you are building a custom integration that bypasses the SDK.
  • Do not mirror the seven subscription state machine in your DB. Consume
    CustomerInfo.entitlements.active
    or webhook events instead.
  • 不要构建Google Play收据验证端点。RevenueCat已经实现了该功能。
  • 不要将购买令牌从Android客户端传递到你的服务器进行手动验证。SDK会处理这一往返流程。
  • 除非你要构建绕过SDK的自定义集成,否则不要从后端调用Google Play Developer API。
  • 不要在你的数据库中镜像七种订阅状态机。请使用
    CustomerInfo.entitlements.active
    或Webhook事件替代。

References

参考资料