Validate Google Play Store Purchase
Validates an in-app purchase or subscription completed through the Google Play Store. This endpoint confirms the purchase token with Google and links the transaction to the user profile and paywall context.
Follow the notes below for a successful request:-
subscriptionOfferDetailsis required for subscriptions and must match the purchased offer. -
paywallId,isExperiment, andaiPricingModelIdmust match the values returned by the Get Paywall API. -
Use
environment:productionfor live apps andsandboxfor testing. -
If you previously called Get Paywall, include
isExperimentandaiPricingModelIdfrom that response to improve analytics attribution. -
At least one of
profileIdorcustomerUserIdmust be provided to identify the user.
If you are having trouble finding the token, you can refer to the official Google documentation:
A trial period is identified when at least one element within pricingPhases contains priceAmountMicros = 0.
For a trial subscription, the system expects to receive a pricingPhase with:
-
priceAmountMicros: 0(to indicate a free trial) -
The usual fields:
billingPeriod,recurrenceMode, andbillingCycleCount
This zero-priced phase allows our system to correctly identify the event as a trial rather than a paid subscription.
If this zero-priced phase is missing, the event will be interpreted as a paid subscription, which will impact your revenue statistics.
Update: One-Time Purchase (OTP) Support
This endpoint supports both subscription and one-time purchase (OTP) validations. In addition to the existing subscriptionOfferDetails field, you can send oneTimePurchaseOfferDetails for one-time purchases.
Important: You must send either oneTimePurchaseOfferDetails or subscriptionOfferDetails, but not both. The choice depends on whether you're validating a one-time purchase or a subscription.
Critical: Experiment Attribution
While paywallId, isExperiment, and aiPricingModelId are technically optional, you should always include them if the purchase originated from a paywall fetched via the Get Paywall endpoint. These fields link the purchase to the correct experiment or control group.
Without them, Botsi cannot attribute the revenue to the right variant. This means experiment results become unreliable, and the AI model will train on incomplete conversion data — degrading future pricing predictions.
Request Body
application/json
| Parameter | Type | Required | Description |
|---|---|---|---|
profileId | string | Optional | Provide profileId or customerUserId |
customerUserId | string | Recommended | Your internal user ID. Provide either profileId or customerUserId |
productId | string | Required | Google Play product ID. Example: premium_monthly |
purchaseToken | string | Required | Google Play purchase token |
paywallId | integer | Recommended | From Get Paywall response (data.id). Required for correct revenue attribution. |
isExperiment | boolean | Recommended | Must match data.isExperiment from Get Paywall. Required for experiment vs. control attribution. |
aiPricingModelId | integer | Recommended | Must match data.aiPricingModelId from Get Paywall. Ties the purchase to the AI model for training. |
placementId | string | Optional | Placement ID used to fetch the paywall |
price | number | Optional | Price. Example: 9.99 |
currency | string | Optional | Currency code. Example: USD |
subscriptionOfferDetails | object | Optional | Subscription offer details (for subscriptions) |
basePlanId | string | Optional | Base plan identifier |
offerId | string | Optional | Offer identifier |
offerToken | string | Optional | Offer token |
pricingPhases | array | Optional | Pricing phases array |
billingPeriod | string | Optional | Billing period. Example: P1M |
recurrenceMode | integer | Optional | 1=infinite, 2=finite, 3=non-recurring |
billingCycleCount | integer | Optional | Number of billing cycles |
formattedPrice | string | Optional | Formatted price. Example: $9.99 |
priceCurrencyCode | string | Optional | Currency code. Example: USD |
priceAmountMicros | string | Optional | Price in micros. Example: 9990000 |
Example Request
{
"profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
"productId": "premium_monthly",
"purchaseToken": "opaque-token-from-google-play",
"paywallId": 42,
"isExperiment": true,
"aiPricingModelId": 32,
"price": 9.99,
"currency": "USD"
}
cURL Example
curl -X POST "https://app.botsi.com/api/v1/web-api/purchases/play-store/validate" -H "Authorization: {{secret_key}}" -H "Content-Type: application/json" -d '{
"profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
"productId": "premium_monthly",
"purchaseToken": "opaque-token-from-google-play",
"paywallId": 42,
"isExperiment": true,
"aiPricingModelId": 32,
"price": 9.99,
"currency": "USD"
}'
Response
{
"ok": true,
"data": {
"profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
"customerUserId": "user-123",
"paid": true,
"country": "US",
"platform": "android"
}
}
Try It Out
Click "Send API Request" to see the response here.