Validate Apple Store Purchase
Validates an in-app purchase or subscription completed through the Apple App Store.
Follow the notes below for a successful request:-
Trigger this endpoint after a successful purchase or restore event on the client. The server validates the transaction with Apple and associates it with the corresponding user profile, paywall, and AI Pricing model for accurate conversion tracking and attribution.
-
Identify the user by providing either
customerUserIdorprofileId. At least one is required to return the correct result.
-
transactionIdandoriginalTransactionIdmust come from StoreKit (or StoreKit 2). -
paywallId,isExperiment, andaiPricingModelIdmust match the values returned by Get Paywall. -
Use
environment: productionfor live apps andsandboxfor testing. -
The optional
sourcefield can be used to indicate whether the purchase comes from a restore flow, direct purchase, or observation.
Finding Required IDs
If you are having trouble finding transaction details, refer to the following StoreKit objects.
StoreKit-
For
transactionIdandoriginalTransactionId, use theSKPaymentTransactionobject. -
For
sourceProductId, useSKPaymentTransaction.payment.productIdentifier. -
For
originalPriceuse theSKProductobject.
-
For
transactionId,originalTransactionId, andsourceProductId, use theTransactionobject. -
For
originalPriceuse theProductobject.
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 | Apple product identifier. Example: premium_monthly |
transactionId | string | Required | StoreKit transaction ID. Example: 2000000123456789 |
originalTransactionId | string | Required | Original transaction ID. Example: 2000000123456789 |
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 | Purchase price. Example: 9.99 |
currency | string | Optional | ISO 4217 code. Example: USD |
environment | string | Optional | "production" or "sandbox" |
source | string | Optional | Purchase source: "purchase", "restore", "observation" |
Example Request
{
"profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
"productId": "premium_monthly",
"transactionId": "2000000123456789",
"originalTransactionId": "2000000123456789",
"paywallId": 42,
"isExperiment": true,
"aiPricingModelId": 32,
"environment": "production"
}
cURL Example
curl -X POST "https://app.botsi.com/api/v1/web-api/purchases/apple-store/validate" -H "Authorization: {{secret_key}}" -H "Content-Type: application/json" -d '{
"profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
"productId": "premium_monthly",
"transactionId": "2000000123456789",
"originalTransactionId": "2000000123456789",
"paywallId": 42,
"isExperiment": true,
"aiPricingModelId": 32,
"environment": "production"
}'
Response
A successful request confirms the validation and returns the updated user profile associated with the purchase.
{
"ok": true,
"data": {
"profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
"customerUserId": "user-123",
"paid": true,
"country": "US",
"platform": "ios"
}
}
Try It Out
Click "Send API Request" to see the response here.