# IAPTIC REST API DOCUMENTATION - Base URL: https://validator.iaptic.com/ # Validator ## Validate a Receipt `POST /v1/validate` This is the endpoint called by the client to validate a receipt. It validates and registers valid receipts in the system. Optionally, it might associate the **Purchases** contained in a receipt with the **Customer**. #### Request body The `/v1/validate` request data should be a JSON object as described below in the **Request Body** section. #### Success response When validation is successful, the `/v1/validate` request data will be a JSON object as described below in the **Success 200** section. #### Error response When validation was not successful or the validated product is not owned, `/v1/validate` request returns a JSON object as described below in the **Error 4xx** section. #### Example Below those three sections, you can find an example request body and response. ### Request Body #### `id`: String Identifier of the product you want to validate. On iOS, can be set to your application identifier. #### `type`: String Type of product being validated. Possible values: - \`application\` – Validate the application download (Apple only). - \`paid subscription\` – An auto-renewing subscription. - \`non renewing subscription\` – A non renewing subscription. - \`consumable\` – A consumable product. - \`non consumable\` – A non-consumable product. #### `transaction`: Object Details about the native transaction. Can be: - An [Apple Transaction](#api-Types-Validate.TransactionApple) - A [Google Transaction](#api-Types-Validate.TransactionGoogle) - A [Windows Transaction](#api-Types-Validate.TransactionWindows) - A [Stripe Transaction](#api-Types-Validate.TransactionStripe) #### `additionalData`: Object (optional) Additional data about the purchase #### `additionalData.applicationUsername`: Object Attach the purchases to the given application user. Should be a string. See [/documentation/application-username](/documentation/application-username) for more information. #### `license`: Object (optional) Microsoft license information #### `license.storeIdKey_collections`: String (optional) Microsoft b2bKey for collections. #### `license.storeIdKey_purchases`: String (optional) Microsoft b2bKey for purchases. #### `group`: String (optional) The subscription group this product is part of #### `priceMicros`: Number (optional) Define the price of the product in micro units (i.e. `price / 1000000`) for the associated currency #### `currency`: String (optional) Currency used for this product price (cf `priceMicros`) #### `countryCode`: String (optional) The requesting users' 3 letters ISO Country Code. #### `billingPeriod`: Object (optional) Number of periods units of between payments. #### `billingPeriodUnit`: String (optional) Period unit used to define the billing interval (Day, Week, Month or Year) #### `introPriceMicros`: Number (optional) Define the price of this product in the introductory period, in micro units, for the associated currency #### `introPricePeriod`: Object (optional) Number of periods units of introductory pricing #### `introPricePeriodUnit`: String (optional) Period unit of introductory pricing (Day, Week, Month or Year) #### `trialPeriod`: Object (optional) Define the duration of the trial period, number of period units #### `trialPeriodUnit`: String (optional) Define the unit for the duration of the trial period (Day, Week, Month, Year) #### `device`: Object (optional) Metadata about the user's device #### `products`: Object[] List of products available in the store #### `products.type`: String Type of product (subscription, consumable, etc.) #### `products.id`: String Product identifier on the store (unique per platform) #### `products.offers`: Object[] List of offers available for this product #### `products.raw`: Any `products.raw` #### `products.className`: String `products.className` #### `products.title`: String `products.title` #### `products.platform`: String `products.platform` #### `products.countryCode`: String `products.countryCode` #### `products.group`: String `products.group` #### `products.description`: String `products.description` #### `offers`: Object[] (optional) List of offers available for this product #### `offers.id`: String `offers.id` #### `offers.pricingPhases`: Object[] `offers.pricingPhases` #### `offers.productId`: String `offers.productId` #### `offers.productType`: String `offers.productType` #### `offers.className`: String `offers.className` #### `offers.platform`: String `offers.platform` #### `offers.offerType`: String `offers.offerType` #### `offers.productGroup`: String `offers.productGroup` ### Success Response #### `ok`: Object Indicates a successful request #### `data`: Object[] `data` #### `data.collection`: Object[] The collection of purchases in this receipt. An array of [ValidatorPurchase](#api-Types-ValidatorPurchase) #### `data.ineligible_for_intro_price`: Object[] List of product ids for which intro price isn't available anymore #### `data.id`: String Id of the product that have been validated #### `data.latest_receipt`: Object Tell the plugin that we've used the latest receipt #### `data.transaction`: Object Native transaction detail #### `data.warning`: String A warning message about this validation. It might be present when the server had to fallback to a backup validation solution. #### `data.date`: Any Date and time the receipt validation request was processed in ISO 8601 format. YYYY-MM-DDTHH:MM:SS.MMMZ #### `ok`: Object Value `false` indicates that the request returned an error #### `status`: Number (optional) Error status #### `code`: Object (optional) An [ErrorCode](#api-Types-ErrorCode) or [ErrorNumber](#api-Types-ErrorNumber) #### `message`: String (optional) Human readable text describing the error #### `data`: Object `data` #### `data.latest_receipt`: Boolean Tells the client that we validated using the latest version of the receipt, not need to refresh it. Always `true`. ### Examples #### Request-Body ```json { "id": "com.example.app", "type": "application", "transaction": { "id": "com.example.app", "type": "ios-appstore", "appStoreReceipt": "MIIabcdefgh...xyz==" }, "additionalData": { "applicationUsername": "james_bond_007" } } ``` #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "data": { "ineligible_for_intro_price": [ "my_subscription" ], "transaction": { "platform-specific transaction data": "can be ignored" }, "collection": [ { "id": "my_subscription", "isBillingRetryPeriod": false, "isTrialPeriod": false, "isIntroPeriod": false, "renewalIntent": "Lapse", "purchaseDate": 1569766544000, "expiryDate": 1583749446000, "cancelationReason": "Customer", "lastRenewalDate": 1583749266000, "isExpired": true }, { "id": "my_subscription", "isTrialPeriod": false, "isIntroPeriod": true, "purchaseDate": 1569766544000, "expiryDate": 1569769054000, "lastRenewalDate": 1569768754000, "isExpired": true } ] } } ``` #### Error-Response ```json HTTP/1.1 200 OK { "ok": false, "route": "/v1/validate", "status": 419, "code": 6778003, "message": "Transaction has expired 2020-03-09 10:24:06 Etc/GMT", } ``` ### Error Response #### `ok`: Object Value `false` indicates that the request returned an error #### `status`: Number (optional) Error status #### `code`: Object (optional) An [ErrorCode](#api-Types-ErrorCode) or [ErrorNumber](#api-Types-ErrorNumber) #### `message`: String (optional) Human readable text describing the error #### `data`: Object `data` #### `data.latest_receipt`: Boolean Tells the client that we validated using the latest version of the receipt, not need to refresh it. Always `true`. ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` `` # Types ## class CustomerSummary Status of the customer last purchase. Mostly useful for subscriptions or single-in-app-purchases applications. ### Fields #### `applicationUsername`: String Identifier of the user in your application #### `customerInfo`: Object Information about the customers last purchase #### `customerInfo.lastPurchaseId`: String Identifier of the last purchase #### `customerInfo.lastPurchaseDate`: String Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `customerInfo.lastRenewalDate`: String Time a subscription was last renewed, in ISO 8601 date-time format. #### `customerInfo.expirationDate`: String When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `customerInfo.activeSubscriber`: Boolean True iff the user owns an active subscription purchase. #### `customerInfo.lapsedSubscriber`: Boolean True iff the user owned an active subscription purchase which is now expired. #### `customerInfo.renewalIntent`: String Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `customerInfo.isTrialPeriod`: Object True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `customerInfo.isIntroPeriod`: Object True when this is the introductory period. #### `customerInfo.discountId`: String Identifier of a discount applied to this transaction. ## class CustomerSummary Status of the customer last purchase. Mostly useful for subscriptions or single-in-app-purchases applications. ### Fields #### `applicationUsername`: String Identifier of the user in your application #### `customerInfo`: Object Information about the customers last purchase #### `customerInfo.lastPurchaseId`: String Identifier of the last purchase #### `customerInfo.lastPurchaseDate`: String Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `customerInfo.lastRenewalDate`: String Time a subscription was last renewed, in ISO 8601 date-time format. #### `customerInfo.expirationDate`: String When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `customerInfo.activeSubscriber`: Boolean True iff the user owns an active subscription purchase. #### `customerInfo.lapsedSubscriber`: Boolean True iff the user owned an active subscription purchase which is now expired. #### `customerInfo.renewalIntent`: String Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `customerInfo.isTrialPeriod`: Object True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `customerInfo.isIntroPeriod`: Object True when this is the introductory period. #### `customerInfo.discountId`: String Identifier of a discount applied to this transaction. #### `receiptIds`: Object[] (optional) @deprecated Removed in API v3 ## class EventInfo Information about a system event ### Fields #### `eventId`: String Event unique identifier #### `eventInfo`: Object Summary of the event #### `eventInfo.date`: String Event date, in ISO 8601 date-time format #### `eventInfo.type`: String An EventType #### `eventInfo.productId`: String The associated product identifier #### `eventInfo.response`: Object Overview of the system response to the event #### `eventInfo.response.status`: Number HTTP status #### `eventInfo.response.ok`: Boolean True to indicate a successful response #### `eventInfo.response.message`: String Human readable message describing the response ### Examples #### Example ```json { "eventId": "r.1654088773387.95ae286f-5703-45eb-ad10-b7d9fa846c6b.r", "eventInfo": { "date": "2022-06-01T13:06:13.387Z", "type": "receipt.validated", "productIds": [ "google:classic" ], "purchaseIds": [ "google:blahblahblah.A0-blahblahblah" ], "response": { "ok": true } } } ``` ## class EventSearchResult Single result from listing or searching events. ### Fields #### `tag`: String Value of the tag used when searching for events #### `type`: String Type of tag #### `eventId`: String Unique identifier of the event #### `context`: Object Context of the request event, a [RequestContext](#api-Types-RequestContext) #### `content`: Object Content of the request event, a [RequestContent](#api-Types-RequestContent) ## class PagingInformation Information about the subset of results in the response ### Fields #### `skip`: Number Number of rows that have been skipped #### `limit`: Number Max number of rows returned #### `total`: Number Total number of rows in the data ## class Purchase Platform-independent representation of a purchase. ### Fields ### Examples #### Example ```json { "google:classic": { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "isExpired": false, "entitledUsers": [ "prod_2bc01eedf9194" ], "notifications": [ { "date": "2021-09-05T15:48:20.889Z" "reason": "PURCHASED", }, { "date": "2021-09-19T15:48:23.051Z" "reason": "RENEWED", } ] } } ``` ## class PurchaseNotification Notification received regarding a purchase (or transaction). ### Fields #### `date`: String Notification date #### `reason`: Enum Reason for the notification. See [enum NotificationReason](#api-Types-NotificationReason). Only includes notifications related to the purchase lifecycle. ### Examples #### Example ```json { "date": "2023-01-28T07:36:04.916Z", "reason": "RENEWED" } ``` ## class RequestContent Content of an event, including purchases, transactions and products information. ### Fields #### `products`: Object[] List of products information extracted from the event #### `products[]`: String .id Product identifier #### `purchases`: Object[] List of purchases extracted from the event #### `purchases[]`: String .purchaseId Purchase identifier #### `transactions`: Object[] List of transactions extracted from the event #### `claims`: Object[] List of claims extracted from the event #### `appDownload`: Object (optional) Information about the first download of the app #### `appDownload.currentVersion`: String (optional) Version of the app the request was sent from #### `appDownload.originalVersion`: String (optional) First downloaded version #### `tags`: Object List of tags useful to find this event #### `notifications`: Object[] List of notifications present in this request ## class RequestContext Context information about an event. ### Fields #### `appName`: String Name of the application that generated the event #### `eventType`: String Type of event (e.g. "receipt.validated") #### `eventDate`: String Date of the event in ISO format #### `eventDateMs`: Number Date of the event in milliseconds #### `applicationUsername`: String (optional) Username that generated the event #### `req_id`: String (optional) Unique request identifier ## class Transaction Platform-independent representation of a transaction. ### Fields #### `transactionId`: Any Identifier #### `purchaseId`: Any Identifier for the purchase this transaction is a part of #### `productId`: Any Purchased product Format: {platform}:{productId} #### `offerId`: Any (optional) Purchased offer Format: {platform}:{productId}#{offerId} ### Examples #### Example ```json { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z" } ``` ## class Validate.TransactionApple Native Apple transaction ### Fields #### `type`: String Value `"ios-appstore"` #### `id`: String Identifier of the transaction to evaluate, or set it to your application identifier if id has been set so. #### `appStoreReceipt`: String Apple appstore receipt, base64 encoded. #### `transactionReceipt`: String (optional) Apple ios 6 transaction receipt. @deprecated Use `appStoreReceipt` ## class Validate.TransactionBraintree Native Braintree transaction #### Note about Braintree validation request Validation for Braintree will create the transaction with the parameters provided in the body. - A purchase for "consumable" will create a transaction. - The transaction will auto-settled. In effect, this validation call does more than validating a receipt, it actually creates the purchase. This is an abuse of the validation protocol, but makes the integration easier. ### Fields #### `type`: String Value `"braintree"` #### `id`: Object No need for an id #### `paymentMethodNonce`: String Payment method nonce #### `deviceData`: Any Data collected on the device ## class Validate.TransactionGoogle Native Google transaction ### Fields #### `type`: String Value `"android-playstore"` #### `id`: String Identifier of the transaction to evaluate. Corresponds to: - the `orderId` in the receipt from Google. - the `transactionId` in the receipt from Apple (or bundleID for the application receipt). #### `purchaseToken`: String Google purchase token. #### `receipt`: String Google receipt in a JSON-encoded string. #### `signature`: String Google receipt signature (used to validate the local receipt). ## class Validate.TransactionStripe Stripe transaction CURRENTLY UNSUPPORTED ### Fields #### `type`: String Value `"stripe-charge"` #### `id`: String Identifier of the Stripe charge. ## class Validate.TransactionWindows Native Microsoft Windows transaction #### Note about Microsoft validation request Validation for microsoft can respond with specific fields set: - `data.serviceTicketType` – with value “purchase” or “collections” - `data.serviceTicket` – an authentication ticket The value of this ticket is used to retrieve the storeId required in the validation request. The process is to make a first request without the `storeId`, then use the `serviceTicket` in the response to fetch it and repeat the validation request to finalize the validation process. Contact us if you need assistance with this integration. ### Fields #### `type`: String Value `"windows-store-transaction"` #### `storeId`: String The Store ID for a product in the Microsoft Store catalog. An example Store ID for a product is "9NBLGGH42CFD". #### `skuId`: String The Store ID for a product's SKU in the Microsoft Store catalog. An example Store ID for a SKU is "0010. ## class ValidatorPurchase Platform-independent representation of a purchase used in the /v1/validate endpoint. ### Fields #### `id`: String Product identifier #### `purchaseDate`: Number (optional) Date of first purchase (timestamp). #### `expiryDate`: Number (optional) Date of expiry for a subscription. #### `isExpired`: Boolean (optional) True when a subscription is expired. #### `renewalIntent`: String (optional) Renewal intent See [enum RenewalIntent](#api-Types-RenewalIntent) #### `renewalIntentChangeDate`: Number (optional) Date the renewal intent was updated by the user. #### `cancelationReason`: Enum (optional) The reason a subscription or purchase was cancelled. See href="#api-Types-CancelationReason">enum CancelationReason. #### `isBillingRetryPeriod`: Boolean (optional) True when a subscription a subscription is in the grace period after a failed attempt to collect payment #### `isTrialPeriod`: Boolean (optional) True when a subscription is in trial period #### `isIntroPeriod`: Boolean (optional) True when a subscription is in introductory pricing period #### `isAcknowledged`: Boolean (optional) True when a purchase is acknowledged #### `discountId`: String (optional) Identifier of the discount currently applied to a purchase #### `priceConsentStatus`: Enum (optional) Whether or not the user agreed or has been notified of a price change. See ["enum PriceConsentStatus"](#api-Types-PriceConsentStatus). #### `lastRenewalDate`: Number (optional) Last time a subscription was renewed. ### Examples #### Example ```json { "id": "my_subscription", "isBillingRetryPeriod": false, "isTrialPeriod": false, "isIntroPeriod": false, "renewalIntent": "Lapse", "purchaseDate": 1569766544000, "expiryDate": 1583749446000, "cancelationReason": "Customer", "lastRenewalDate": 1583749266000, "isExpired": true } ``` ## class Webhook.PurchasesUpdated Body of the "purchases.updated" application webhook ### Fields #### `password`: String Your account's Secret Key This should match your account’s Secret Key (found in your [Dashboard Settings](/settings)), to ensure that Iaptic is calling your endpoint and not someone else. #### `type`: String The string "purchases.updated" #### `notification`: Object The notification that triggered the webhook call #### `notification.reason`: String Type of trigger event. See [enum NotificationReason](#api-Types-NotificationReason). #### `notification.id`: String Unique notification identifier. It can be used to prevent handling a notification twice. Notice however that a single notification might result in different webhook calls (if more than 1 user is entitled to a given subscription for example). #### `notification.date`: String Notification date #### `notification.productId`: String Product concerned by the event (when applicable) #### `notification.purchaseId`: String Purchase concerned by the event (when applicable) #### `notification.transactionId`: String Transaction concerned by the event (when applicable) #### `applicationUsername`: String Identifier of the user in your application #### `purchases`: Object A collection of purchases indexed by product identifier See [class Purchase](#api-Types-Purchase). ### Examples #### Example ```json { "type": "purchases.updated", "notification": { "reason": "RECEIPT_VALIDATED", "productId": "apple:subscription1", "id": "1231-8982-12311234-12345544", "date": "2023-01-28T07:36:04.916Z" }, "applicationUsername": "my_username", "purchases": { "apple:cc.fovea.purchase.subscription1sx": { "productId": "apple:cc.fovea.purchase.subscription1sx", "platform": "apple", "sandbox": true, "purchaseId": "apple:1000000573800707", "purchaseDate": "2022-09-29T14:15:44.000Z", "lastRenewalDate": "2022-09-29T14:18:43.000Z", "expirationDate": "2022-09-29T14:21:43.000Z", "cancelationReason": "Customer", "renewalIntent": "Lapse", "isExpired": true }, "apple:cc.fovea.purchase.subscription2sx": { "productId": "apple:cc.fovea.purchase.subscription2sx", "platform": "apple", "sandbox": true, "purchaseId": "apple:1000000573800707", "purchaseDate": "2022-09-29T14:15:44.000Z", "lastRenewalDate": "2022-09-29T14:52:34.000Z", "expirationDate": "2022-09-29T14:57:34.000Z", "isIntroPeriod": true, "isExpired": true }, "apple:1_token": { "productId": "apple:1_token", "platform": "apple", "sandbox": true, "purchaseId": "apple:1000000581984730", "purchaseDate": "2022-10-21T18:37:48.000Z" } }, "password": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } ``` ## class Webhook.Test Body of the "test" application webhook ### Fields #### `password`: String Your account's Secret Key This should match your account’s Secret Key (found in your [Dashboard Settings](/settings)), to ensure that Iaptic is calling your endpoint and not someone else. #### `type`: String The string "test" ### Examples #### Example ```json { "type": "test", "password": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } ``` ## enum CancelationReason Reason for which a subscription or purchase has been canceled. ### Possible Values #### `Developer`: undefined `"Developer"` - Subscription canceled by the developer. #### `System`: undefined `"System"` - Subscription canceled by the system for an unspecified reason. #### `System.Replaced`: undefined `"System.Replaced"` - Subscription upgraded or downgraded to a new subscription. #### `System.ProductUnavailable`: undefined `"System.ProductUnavailable"` - Product not available for purchase at the time of renewal. #### `System.BillingError`: undefined `"System.BillingError"` - Billing error; for example customer’s payment information is no longer valid. #### `System.Deleted`: undefined `"System.Deleted"` - Transaction is gone; It has been deleted. #### `Customer`: undefined `"Customer"` - Subscription canceled by the user for an unspecified reason. #### `Customer.TechnicalIssues`: undefined `"Customer.TechnicalIssues"` - Customer canceled their transaction due to an actual or perceived issue within your app. #### `Customer.PriceIncrease`: undefined `"Customer.PriceIncrease"` - Customer did not agree to a recent price increase. See also priceConsentStatus. #### `Customer.Cost`: undefined `"Customer.Cost"` - Customer canceled for cost-related reasons. #### `Customer.FoundBetterApp`: undefined `"Customer.FoundBetterApp"` - Customer claimed to have found a better app. #### `Customer.NotUsefulEnough`: undefined `"Customer.NotUsefulEnough"` - Customer did not feel he is using this service enough. #### `Customer.OtherReason`: undefined `"Customer.OtherReason"` - Subscription canceled for another reason; for example, if the customer made the purchase accidentally. #### `Unknown`: undefined `"Unknown"` - Subscription canceled for unknown reasons. ## enum ErrorCode A request error code. ### Possible Values #### `InvalidPayload`: undefined `"InvalidPayload"` - The content of the request is invalid. #### `ConnectionFailed`: undefined `"ConnectionFailed"` - Failed to connect to an external service. #### `PurchaseExpired`: undefined `"PurchaseExpired"` - The purchase (subscription) has expired. #### `PurchaseConsumed`: undefined `"PurchaseConsumed"` - The purchase (consumable) has been consumed. #### `InternalError`: undefined `"InternalError"` - System experienced an internal problem. #### `NeedMoreData`: undefined `"NeedMoreData"` - More data is required to complete the request (typically used for validating Microsoft receipts). #### `Unknown`: undefined `"Unknown"` - Unexpected error. #### `AppNotFound`: undefined `"AppNotFound"` - Wrong app name. #### `Conflict`: undefined `"Conflict"` - The operation can't be performed because it would conflict with another one. #### `Forbidden`: undefined `"Forbidden"` - The provided credentials do not allow this request. #### `DatabaseError`: undefined `"DatabaseError"` - An error occurred at the database level. #### `ResourceNotFound`: undefined `"ResourceNotFound"` - Accessing a resource that does not exist. ## enum ErrorNumber A request error number. ### Possible Values #### `6778001`: undefined `6778001` – Invalid payload – something is wrong about the request. #### `6778002`: undefined `6778002` – Connection failed – Apple, Google or Microsoft servers are not reachable. #### `6778003`: undefined `6778003` – Subscription expired – The subscription product is expired and has not been renewed. #### `6778004`: undefined `6778004` – Purchase consumed – The consumable product has been consumed already. #### `6778005`: undefined `6778005` – Internal error – Something prevented the server from processing your request. #### `6778006`: undefined `6778006` – Need more data – Requesting more data to complete the request. #### `6778007`: undefined `6778007` – Unknown #### `7691001`: undefined `7691001` – Wrong app name. #### `7691002`: undefined `7691002` – The operation can't be performed because it would conflict with another one. #### `7691003`: undefined `7691003` – The provided credentials do not allow this request. #### `7691004`: undefined `7691004` – An error occurred at the database level. #### `7691005`: undefined `7691005` – Accessing a resource that does not exist. ## enum NotificationReason Notification that triggered a server-to-server webhook notification ### Possible Values #### `RECEIPT_VALIDATED`: undefined `"RECEIPT_VALIDATED"` - Receipt was validated by the user. #### `RECEIPT_REFRESHED`: undefined `"RECEIPT_REFRESHED"` - Receipt was refreshed. #### `WEBHOOK_REPEATED`: undefined `"REPEATED"` - Webhook is manually repeated by user (using the Dashboard or REST API) #### `ACKNOWLEDGED`: undefined `"ACKNOWLEDGED"` - Purchase was acknowledged by the server #### `PURCHASED`: undefined `"PURCHASED"` - Product was purchased. #### `REVOKED`: undefined `"REVOKED"` - Subscription has been revoked from the user before the expiration time, for example by support or by leaving family sharing #### `EXPIRED`: undefined `"EXPIRED"` - Subscription has expired. #### `RENEWED`: undefined `"RENEWED"` - An active subscription was renewed. #### `PRICE_CHANGE_CONFIRMED`: undefined `"PRICE_CHANGE_CONFIRMED"` - A subscription price change has successfully been confirmed by the user. #### `WILL_LAPSE`: undefined `"WILL_LAPSE"` - A subscription has been set to lapse at the end of the period, it won't auto-renew #### `WILL_AUTO_RENEW`: undefined `"WILL_AUTO_RENEW"` - A subscription has been set to auto-renew at the end of the period #### `EXTENDED`: undefined `"EXTENDED"` - Subscription renewal date has been extended #### `REFUNDED`: undefined `"REFUNDED"` - Purchase has been refunded #### `PAUSED`: undefined `"PAUSED"` - Subscription has been paused #### `ENTERED_GRACE_PERIOD`: undefined `"ENTERED_GRACE_PERIOD"` - Subscription entered the grace period #### `PLAN_CHANGED`: undefined `"PLAN_CHANGED"` - Subscription plan changed (Stripe only) #### `TEST`: undefined `"TEST"` - Test webhook call #### `OTHER`: undefined `"OTHER"` - Other ## enum Platform Platform a receipt, purchase, transaction or event has been generated from. ### Possible Values #### `apple`: undefined `"apple"` - A purchase made from the Apple AppStore #### `google`: undefined `"google"` - A purchase made from the Google Play Store #### `windows`: undefined `"windows"` - A purchase made from the Windows Store #### `stripe`: undefined `"stripe"` - A purchase made from Stripe ## enum PriceConsentStatus Whether or not the user agreed or has been notified of a price change. ### Possible Values #### `Agreed`: undefined `"Agreed"` - The user has agreed to the updated price. #### `Notified`: undefined `"Notified"` - The user has been notified of the updated price. ## enum RenewalIntent Whether or not the user intends to let the subscription auto-renew. ### Possible Values #### `Lapse`: undefined `"Lapse"` - The user intends to let the subscription expire without renewing. #### `Renew`: undefined `"Renew"` - The user intends to renew the subscription. # Customers Information about your customers: purchases, transactions, events. The most common use case is to fetch the customer's purchases when receiving a webhook call. See [Get Customer Purchase](#api-Customers-GetCustomerPurchases). Another common use case is to implement a full data synchronization with your server by using the [Bulk Customers](#api-Customers-GetCustomers) endpoint. ## Add Purchase to Customer `POST /v3/customers/:applicationUsername/purchases` Manually associate a customer with a purchase. Note that if you are using the "first claimer" or "last claimer" entitlement strategy, manually linked purchases will always take priority over purchases linked with a receipt validation request. Learn more about [Entitlement Strategies](/documentation/entitlement-strategies). This operation can also be done [from the Dashboard](/customers-purchases/manual-link). ### Parameters #### `applicationUsername`: String The user identifier on your system. ### Request Body #### `purchaseId`: String The purchase to associate with the customer. ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Bulk Customers Information `GET /v3/customers` Check the status of your all users purchases and subscriptions in bulk. ### Query Parameters #### `applicationUsername`: String (optional) Comma separated list of URI-encoded applicationUsernames. #### `limit`: Number (optional) Max number of rows to return in the response. Default: 100 #### `skip`: Number (optional) Number of rows to skip in the response. Default: 0 ### Success Response #### `paging`: Object Information about the subset of results in the response. See [PagingInformation](#api-Types-PagingInformation). #### `paging.skip`: Number Number of rows that have been skipped #### `paging.limit`: Number Max number of rows returned #### `paging.total`: Number Total number of rows in the data #### `rows`: Object[] Array of [CustomerSummary](#api-Types-CustomerSummary). #### `rows.applicationUsername`: String Identifier of the user in your application #### `rows.customerInfo`: Object Information about the customers last purchase #### `rows.customerInfo.lastPurchaseId`: String Identifier of the last purchase #### `rows.customerInfo.lastPurchaseDate`: String Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `rows.customerInfo.lastRenewalDate`: String Time a subscription was last renewed, in ISO 8601 date-time format. #### `rows.customerInfo.expirationDate`: String When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `rows.customerInfo.activeSubscriber`: Boolean True iff the user owns an active subscription purchase. #### `rows.customerInfo.lapsedSubscriber`: Boolean True iff the user owned an active subscription purchase which is now expired. #### `rows.customerInfo.renewalIntent`: String Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `rows.customerInfo.isTrialPeriod`: Object True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `rows.customerInfo.isIntroPeriod`: Object True when this is the introductory period. #### `rows.customerInfo.discountId`: String Identifier of a discount applied to this transaction. ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "paging": { "skip": 0, "limit": 100, "total": 1 }, "rows": [ { "applicationUsername": "my-application-username", "customerInfo": { "lastPurchaseId": "google:blahblahblah.A0-blahblahblah", "lastPurchaseDate": "2022-06-01T13:06:11.366Z", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "activeSubscriber": true, "renewalIntent": "Renew" } } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Customer Information `GET /v3/customers/:applicationUsername` ### Parameters #### `applicationUsername`: String The user identifier on your system. ### Success Response #### `applicationUsername`: String Identifier of the user in your application #### `purchases`: Object A collection of purchases indexed by product identifier See [class Purchase](#api-Types-Purchase). #### `events`: Object[] Most recent events for this user. An array of [EventInfo](#api-Types-EventInfo). #### `events.eventId`: String Event unique identifier #### `events.eventInfo`: Object Summary of the event #### `events.eventInfo.date`: String Event date, in ISO 8601 date-time format #### `events.eventInfo.type`: String An EventType #### `events.eventInfo.productId`: String The associated product identifier #### `events.eventInfo.response`: Object Overview of the system response to the event #### `events.eventInfo.response.status`: Number HTTP status #### `events.eventInfo.response.ok`: Boolean True to indicate a successful response #### `events.eventInfo.response.message`: String Human readable message describing the response #### `transactions`: Object[] List of transactions associated with the user. An array of [Transactions](#api-Types-Transaction). #### `transactions.transactionId`: Any Identifier #### `transactions.purchaseId`: Any Identifier for the purchase this transaction is a part of #### `transactions.productId`: Any Purchased product Format: {platform}:{productId} #### `transactions.offerId`: Any Purchased offer Format: {platform}:{productId}#{offerId} #### `customerInfo`: Object Information about the customers last purchase #### `customerInfo.lastPurchaseId`: String Identifier of the last purchase #### `customerInfo.lastPurchaseDate`: String Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `customerInfo.lastRenewalDate`: String Time a subscription was last renewed, in ISO 8601 date-time format. #### `customerInfo.expirationDate`: String When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `customerInfo.activeSubscriber`: Boolean True iff the user owns an active subscription purchase. #### `customerInfo.lapsedSubscriber`: Boolean True iff the user owned an active subscription purchase which is now expired. #### `customerInfo.renewalIntent`: String Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `customerInfo.isTrialPeriod`: Object True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `customerInfo.isIntroPeriod`: Object True when this is the introductory period. #### `customerInfo.discountId`: String Identifier of a discount applied to this transaction. ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "applicationUsername": "my-application-username", "purchases": { "google:classic": { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "isExpired": false } }, "events": [ { "eventId": "r.1654088776347.be347312-6f37-4e6f-9bc8-9416410a6755.r", "eventInfo": { "date": "2022-06-01T13:06:16.347Z", "type": "receipt.validated", "productIds": [ "google:classic" ], "purchaseIds": [ "google:blahblahblah.A0-blahblahblah" ], "response": { "ok": true } } }, { "eventId": "r.1654088773387.95ae286f-5703-45eb-ad10-b7d9fa846c6b.r", "eventInfo": { "date": "2022-06-01T13:06:13.387Z", "type": "receipt.validated", "productIds": [ "google:classic" ], "purchaseIds": [ "google:blahblahblah.A0-blahblahblah" ], "response": { "ok": true } } } ], "transactions": [ { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z" } ], "customerInfo": { "lastPurchaseId": "google:blahblahblah.A0-blahblahblah", "lastPurchaseDate": "2022-06-01T13:06:11.366Z", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "activeSubscriber": true, "renewalIntent": "Renew" } } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Customer Purchases `GET /v3/customers/:applicationUsername/purchases` Check the status of your users purchases and subscriptions. ### Parameters #### `applicationUsername`: String The user identifier on your system. ### Success Response #### `applicationUsername`: String Identifier of the user in your application #### `purchases`: Object A collection of purchases indexed by product identifier See [class Purchase](#api-Types-Purchase). ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "applicationUsername": "my-application-username", "purchases": { "google:classic": { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "isExpired": false } } } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Customer Subscription `GET /v3/customers/:applicationUsername/subscription` A convenience method to use over the more capable "Fetch Customer Purchases", for simplicity. ### Parameters #### `applicationUsername`: String The user identifier on your system. ### Success Response #### `applicationUsername`: String Identifier of the user in your application #### `subscription`: Object (optional) `subscription` #### `subscription.purchaseId`: String Purchase identifier #### `subscription.transactionId`: String Last transaction identifier #### `subscription.productId`: String Purchased product #### `subscription.platform`: String Platform the purchase was made from See ["enum Platform"](#api-Types-Platform). #### `subscription.sandbox`: Boolean True when the purchase was made in sandbox environment. #### `subscription.purchaseDate`: String Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `subscription.lastRenewalDate`: String Time a subscription was last renewed, in ISO 8601 date-time format. #### `subscription.expirationDate`: String When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `subscription.renewalIntent`: String Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `subscription.renewalIntentChangeDate`: String When the renewal intent was changed, in ISO 8601 date-time format. #### `subscription.cancelationReason`: String Reason for a purchase to have been cancelled. See ["enum CancelationReason"](#api-Types-CancelationReason). #### `subscription.isPending`: Boolean True when the transaction is still pending payment. #### `subscription.isAcknowledged`: Boolean True when the transaction has been acknowledged to the platform. #### `subscription.isConsumed`: Boolean True when the transaction was consumed. #### `subscription.isBillingRetryPeriod`: Boolean True when the subscription is in the grace period. #### `subscription.isTrialPeriod`: Boolean True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `subscription.isIntroPeriod`: Boolean True when this is the introductory period. #### `subscription.priceConsentStatus`: String Whether the user approved a price change. See ["enum PriceConsentStatus"](#api-Types-PriceConsentStatus). #### `subscription.discountId`: String Identifier of a discount applied to this transaction. #### `subscription.quantity`: Number Number of elements purchases (only meaningful for consumables). #### `subscription.currency`: String Currency used to make this transaction. 3 letters code. Example: EUR, USD, ... #### `subscription.isSharedPurchase`: Boolean Whether or not the user made the purchase or it was shared with him for free (like family sharing). True if the purchase wasn't made from this user's store account. #### `subscription.raw`: Any Private field, not intended for public use. #### `subscription.canRefresh`: Boolean Private field, not intended for public use. #### `subscription.isExpired`: Boolean Set to true if a subscription is expired. ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "applicationUsername": "my-application-username", "subscription": { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "isExpired": false } } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Customer Transactions `GET /v3/customers/:applicationUsername/transactions` ### Parameters #### `applicationUsername`: String The user identifier on your system. ### Success Response #### `applicationUsername`: String Identifier of the user in your application #### `transactions`: Object[] List of transactions associated with the user. An array of [Transactions](#api-Types-Transaction). #### `transactions.transactionId`: Any Identifier #### `transactions.purchaseId`: Any Identifier for the purchase this transaction is a part of #### `transactions.productId`: Any Purchased product Format: {platform}:{productId} #### `transactions.offerId`: Any Purchased offer Format: {platform}:{productId}#{offerId} ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "applicationUsername": "my-application-username", "transactions": [ { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z" } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` # Purchases A Purchase is the final state of a set of transaction related to the same product. Typically a subscription is purchased once, renewals create new transactions, but all those transactions are part of the same single "Purchase". ## Bulk Purchases `GET /v3/purchases` Get the status of all purchases in bulk. Returns a [Paginated](#api-Types-PagingInformation) array of [Purchases](#api-Types-Purchase). **Note**: when using `startdate` and `enddate`, make sure the range you specify includes less than 10,000 transactions or the result might be incomplete. ### Query Parameters #### `startdate`: Date-time (optional) Only return purchases last updated at or after the provided start date, in ISO format (included). #### `enddate`: Date-time (optional) Only return purchases last updated before the provided date, in ISO format (excluded). #### `limit`: Number (optional) Max number of rows to return in the response (ignored if startdate or enddate are specified). Default: 100 #### `skip`: Number (optional) Number of rows to skip in the response (ignored if startdate or enddate are specified). Default: 0 #### `include_notifications`: String (optional) If set to "true", the response will include a notifications array for each purchase. ### Success Response #### `paging`: Object Information about the subset of results in the response. #### `paging.skip`: Number Number of rows that have been skipped #### `paging.limit`: Number Max number of rows returned #### `paging.total`: Number Approximated total number of purchases #### `rows`: Object[] List of purchases with entitled users. An array of [Purchase](#api-Types-Purchase) including the entitledUsers. #### `rows.entitledUsers`: Object[] List of application usernames entitled to this purchase. An array of string. #### `rows.notifications`: Object[] List of notifications for this purchase. See [class PurchaseNotification](#api-Types-PurchaseNotification). Only included if the `include_notifications` query parameter is set to the string `true`. #### `rows.purchaseId`: String Purchase identifier #### `rows.transactionId`: String Last transaction identifier #### `rows.productId`: String Purchased product #### `rows.platform`: String Platform the purchase was made from See ["enum Platform"](#api-Types-Platform). #### `rows.sandbox`: Boolean True when the purchase was made in sandbox environment. #### `rows.purchaseDate`: String Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `rows.lastRenewalDate`: String Time a subscription was last renewed, in ISO 8601 date-time format. #### `rows.expirationDate`: String When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `rows.renewalIntent`: String Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `rows.renewalIntentChangeDate`: String When the renewal intent was changed, in ISO 8601 date-time format. #### `rows.cancelationReason`: String Reason for a purchase to have been cancelled. See ["enum CancelationReason"](#api-Types-CancelationReason). #### `rows.isPending`: Boolean True when the transaction is still pending payment. #### `rows.isAcknowledged`: Boolean True when the transaction has been acknowledged to the platform. #### `rows.isConsumed`: Boolean True when the transaction was consumed. #### `rows.isBillingRetryPeriod`: Boolean True when the subscription is in the grace period. #### `rows.isTrialPeriod`: Boolean True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `rows.isIntroPeriod`: Boolean True when this is the introductory period. #### `rows.priceConsentStatus`: String Whether the user approved a price change. See ["enum PriceConsentStatus"](#api-Types-PriceConsentStatus). #### `rows.discountId`: String Identifier of a discount applied to this transaction. #### `rows.quantity`: Number Number of elements purchases (only meaningful for consumables). #### `rows.currency`: String Currency used to make this transaction. 3 letters code. Example: EUR, USD, ... #### `rows.isSharedPurchase`: Boolean Whether or not the user made the purchase or it was shared with him for free (like family sharing). True if the purchase wasn't made from this user's store account. #### `rows.raw`: Any Private field, not intended for public use. #### `rows.canRefresh`: Boolean Private field, not intended for public use. #### `rows.isExpired`: Boolean Set to true if a subscription is expired. ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "paging": { "skip": 0, "limit": 100 }, "rows": [ { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "entitledUsers": [ "my-application-username" ] } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Purchase `GET /v3/purchases/:purchaseId` Retrieve data about a single purchase Returns a [Purchase](#api-Types-Purchase). ### Parameters #### `purchaseId`: String Identifier of the purchase to fetch ### Success Response #### `purchaseId`: String Purchase identifier #### `transactionId`: String Last transaction identifier #### `productId`: String Purchased product #### `platform`: Enum Platform the purchase was made from See ["enum Platform"](#api-Types-Platform). #### `sandbox`: Boolean (optional) True when the purchase was made in sandbox environment. #### `purchaseDate`: String (optional) Time the purchase was made, in ISO 8601 date-time format. For subscriptions this is equal to the date of the first transaction. Note that it might be undefined for deleted transactions (google for instance don't provide any info in that case). #### `lastRenewalDate`: String (optional) Time a subscription was last renewed, in ISO 8601 date-time format. #### `expirationDate`: String (optional) When the subscription is set to expire or auto-renew, in ISO 8601 date-time format. #### `renewalIntent`: Enum (optional) Is the subscription set to renew. See ["enum RenewalIntent"](#api-Types-RenewalIntent). #### `renewalIntentChangeDate`: String (optional) When the renewal intent was changed, in ISO 8601 date-time format. #### `cancelationReason`: Enum (optional) Reason for a purchase to have been cancelled. See ["enum CancelationReason"](#api-Types-CancelationReason). #### `isPending`: Boolean (optional) True when the transaction is still pending payment. #### `isAcknowledged`: Boolean (optional) True when the transaction has been acknowledged to the platform. #### `isConsumed`: Boolean (optional) True when the transaction was consumed. #### `isBillingRetryPeriod`: Boolean (optional) True when the subscription is in the grace period. #### `isTrialPeriod`: Boolean (optional) True when this is a transaction for the trial period. Note that a trial period is a _free_ introductory period. #### `isIntroPeriod`: Boolean (optional) True when this is the introductory period. #### `priceConsentStatus`: Enum (optional) Whether the user approved a price change. See ["enum PriceConsentStatus"](#api-Types-PriceConsentStatus). #### `discountId`: String (optional) Identifier of a discount applied to this transaction. #### `quantity`: Number (optional) Number of elements purchases (only meaningful for consumables). #### `currency`: String (optional) Currency used to make this transaction. 3 letters code. Example: EUR, USD, ... #### `isSharedPurchase`: Boolean (optional) Whether or not the user made the purchase or it was shared with him for free (like family sharing). True if the purchase wasn't made from this user's store account. #### `isExpired`: Boolean (optional) Set to true if a subscription is expired. #### `entitledUsers`: Object[] List of application usernames entitled to this purchase. An array of string. #### `notifications`: Object[] (optional) List of notifications for this purchase. See [class PurchaseNotification](#api-Types-PurchaseNotification). Only included if the `include_notifications` query parameter is set to the string `true`. #### `notifications.date`: String Notification date #### `notifications.reason`: String Reason for the notification. See [enum NotificationReason](#api-Types-NotificationReason). Only includes notifications related to the purchase lifecycle. ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z", "entitledUsers": [ "my-application-username" ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Purchase refresh token `GET /v3/purchases/:purchaseId/refresh_token` Retrieve the refresh token for a given purchase It's mostly meant for internal use, as you will most probably never need this directly. ### Parameters #### `purchaseId`: String Identifier of the purchase to fetch ### Success Response #### `purchaseId`: String `purchaseId` #### `latestRefresh`: String (optional) `latestRefresh` #### `refreshToken`: Object (optional) `refreshToken` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` # Transactions A transaction is a operation that initiates or renews a purchase. Purchases include one or many transactions. ## Bulk Transactions `GET /v3/transactions` Get the status of all transactions in bulk. Returns a [Paginated](#api-Types-PagingInformation) array of [Transactions](#api-Types-Transaction). ### Query Parameters #### `startdate`: Date-time (optional) Only return transactions that happened after the provided start date, in ISO format (included). #### `enddate`: Date-time (optional) Only return transactions that happened before the provided end date, in ISO format (excluded). #### `limit`: Number (optional) Max number of rows to return in the response. Default: 100 #### `skip`: Number (optional) Number of rows to skip in the response. Default: 0 #### `include_notifications`: String (optional) If set to "true", the response will include notifications related to the transactions. ### Success Response #### `paging`: Object Information about the subset of results in the response. See [PagingInformation](#api-Types-PagingInformation). #### `paging.skip`: Number Number of rows that have been skipped #### `paging.limit`: Number Max number of rows returned #### `paging.total`: Number Total number of rows in the data #### `rows`: Object[] List of matching transactions. An array of Transactions. #### `rows.transactionId`: Any Identifier #### `rows.purchaseId`: Any Identifier for the purchase this transaction is a part of #### `rows.productId`: Any Purchased product Format: {platform}:{productId} #### `rows.offerId`: Any Purchased offer Format: {platform}:{productId}#{offerId} ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "paging": { "limit": 2, "skip": 0, "total": 1 }, "rows": [ { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z" } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Transaction `GET /v3/transactions/:transactionId` Retrieve data about a single transaction Returns a [Transaction](#api-Types-Transaction). ### Parameters #### `transactionId`: String Identifier of the transaction to fetch ### Success Response #### `transactionId`: Any Identifier #### `purchaseId`: Any Identifier for the purchase this transaction is a part of #### `productId`: Any Purchased product Format: {platform}:{productId} #### `offerId`: Any (optional) Purchased offer Format: {platform}:{productId}#{offerId} ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "productId": "google:classic", "purchaseId": "google:blahblahblah.A0-blahblahblah", "transactionId": "google:GPA.stuff", "platform": "google", "purchaseDate": "2022-06-01T13:06:11.366Z", "expirationDate": "2023-06-01T13:06:11.366Z", "isBillingRetryPeriod": false, "isPending": false, "renewalIntent": "Renew", "isAcknowledged": false, "amountUSD": 1, "amountMicros": 1000000, "currency": "USD", "lastRenewalDate": "2022-06-01T13:06:11.366Z" } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` # Stats ## Fetch App Statistics `GET /v3/apps/:appName/stats` > **Deprecated** ### Parameters #### `appName`: String Your iaptic App Name. ### Success Response #### `monthlyQuota`: Number App's monthly quota on number of transactions #### `thisMonth`: Number Number of transactions during the current calendar month #### `lastMonth`: Number Number of transactions during last calendar month #### `reqThisMonth`: Number Number of requests made by the app during the current calendar month #### `reqLastMonth`: Number Number of requests made by the app during the last calendar month ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Fetch Statistics `GET /v3/stats` ### Success Response #### `dailyStats`: Object[] Stats per day #### `dailyStats.date`: String Day in YYYY-MM-DD format #### `dailyStats.amountUSD`: Number Total revenue for the day in USD #### `dailyStats.amountMicros`: Object Total revenue for the day by currency (key: currency code, value: amount in micros) #### `dailyStats.numRequests`: Number Number of requests made for the day #### `dailyStats.numTransactions`: Number Number of transactions for the day #### `dailyStats.numPaidTransactions`: Number Number of paid transactions for the day #### `dailyStats.monthlyRevenueUSD`: Number Total revenue since same day the previous month, in USD #### `dailyStats.monthlyTransactions`: Number Number of transactions since same day the previous month #### `dailyStats.monthlyPaidTransactions`: Number Number of paid transactions since same day the previous month #### `monthlyStats`: Object[] Stats per month #### `monthlyStats.date`: String Month in YYYY-MM format #### `monthlyStats.amountUSD`: Number Total revenue for the month in USD #### `monthlyStats.amountMicros`: Object Total revenue for the month by currency (key: currency code, value: amount in micros) #### `monthlyStats.numRequests`: Number Number of requests made during the month #### `monthlyStats.numTransactions`: Number Number of transactions during the month #### `monthlyStats.numPaidTransactions`: Number Number of paid transactions during the month ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "dailyStats": [ { "date": "2022-06-01", "amountMicros": { "USD": 1000000 }, "amountUSD": 1, "numRequests": 4, "numTransactions": 2, "numPaidTransactions": 1, "monthlyRevenueUSD": 1, "monthlyTransactions": 1 }, { "date": "2022-06-02", "amountMicros": {}, "amountUSD": 0, "numRequests": 0, "numTransactions": 0, "numPaidTransactions": 0, "monthlyRevenueUSD": 1, "monthlyTransactions": 1 } ], "monthlyStats": [ { "date": "2022-06", "amountMicros": { "USD": 1000000 }, "amountUSD": 1, "numRequests": 4, "numTransactions": 2, "numPaidTransactions": 1 } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ### Additional Examples ### Examples #### Example usage: ```curl curl \ -H "Content-type: application/json" -H "Accept: application/json" \ --user my.app.name:secret-key-abf22131 \ -X GET "https://validator.iaptic.com/v3/stats?startdate=2022-06-01&enddate=2022-06-03" ``` ## Fetch Statistics `GET /v3/stats` ### Success Response #### `dailyStats`: Object[] Stats per day #### `dailyStats.date`: String Day in YYYY-MM-DD format #### `dailyStats.amountUSD`: Number Total revenue for the day in USD #### `dailyStats.amountMicros`: Object Total revenue for the day by currency (key: currency code, value: amount in micros) #### `dailyStats.numRequests`: Number Number of requests made for the day #### `dailyStats.numTransactions`: Number Number of transactions for the day #### `dailyStats.numPaidTransactions`: Number Number of paid transactions for the day #### `dailyStats.monthlyRevenueUSD`: Number Total revenue since same day the previous month, in USD #### `dailyStats.monthlyTransactions`: Number Number of transactions since same day the previous month #### `dailyStats.monthlyPaidTransactions`: Number Number of paid transactions since same day the previous month #### `monthlyStats`: Object[] Stats per month #### `monthlyStats.date`: String Month in YYYY-MM format #### `monthlyStats.amountUSD`: Number Total revenue for the month in USD #### `monthlyStats.amountMicros`: Object Total revenue for the month by currency (key: currency code, value: amount in micros) #### `monthlyStats.numRequests`: Number Number of requests made during the month #### `monthlyStats.numTransactions`: Number Number of transactions during the month #### `monthlyStats.numPaidTransactions`: Number Number of paid transactions during the month ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "dailyStats": [ { "date": "2022-06-01", "amountMicros": { "USD": 1000000 }, "amountUSD": 1, "numRequests": 4, "numTransactions": 1, "monthlyRevenueUSD": 1, "monthlyTransactions": 1 }, { "date": "2022-06-02", "amountMicros": {}, "amountUSD": 0, "numRequests": 0, "numTransactions": 0, "monthlyRevenueUSD": 1, "monthlyTransactions": 1 } ], "monthlyStats": [ { "date": "2022-06", "amountMicros": { "USD": 1000000 }, "amountUSD": 1, "numRequests": 4, "numTransactions": 1 } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ### Additional Examples ### Examples #### Example usage: ```curl curl \ -H "Content-type: application/json" -H "Accept: application/json" \ --user my.app.name:secret-key-abf22131 \ -X GET "https://validator.iaptic.com/v3/stats?startdate=2022-06-01&enddate=2022-06-03" ``` ## Fetch Statistics `GET /v2/stats` ### Success Response #### `dailyStats`: Object[] Stats per day #### `dailyStats.date`: String Day in YYYYMMDD format #### `dailyStats.amountUSD`: Number Total revenue for the day in USD #### `dailyStats.numTransactions`: Number Number of transactions for the day #### `dailyStats.monthlyRevenueUSD`: Number Total revenue since same day the previous month, in USD #### `dailyStats.monthlyTransactions`: Number Number of transactions since same day the previous month #### `monthlyStats`: Object Stats per month #### `monthlyStats.amountUSD`: Number Total revenue for the month in USD #### `monthlyStats.numTransactions`: Number Number of transactions during the month ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` # Notifier APIs to interact with the server-to-server notifications subsystem. ## Send a Webhook Notification `POST /v3/notifier/app-webhooks` Manually call your application webhook with the result from a given request. Note that is normally used internally by the validation server, but can be useful for testing or replaying webhooks that your server failed to process. Learn more about [Application Webhooks](/documentation/webhook). ### Request Body #### `reqId`: string The request identifier, which you can find in the [Events](/events) page. ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ### Additional Examples ### Examples #### Example usage: ```curl curl \ -H "Content-type: application/json" -H "Accept: application/json" \ --user my.app.name:secret-key-abf22131 \ -X POST "https://validator.iaptic.com/v3/notifier/app-webhook" \ -d '{ "reqId": "12345678-abcdef-aaaa-ffff" }' ``` # Events ## Get Event Analysis `GET /v3/events/:id/analysis` Get detailed analysis of a specific event. Returns a detailed analysis of the event, including receipt validation details if requested. The analysis provides insights into the event's context, content, and validation status. ### Parameters #### `id`: String Event ID to analyze ### Query Parameters #### `receipts`: String (optional) Include receipt validation details in the analysis (set to any non-empty string to include) ### Success Response #### `eventId`: String The event identifier #### `context`: Object (optional) Event analyzed context, a [RequestContext](#api-Types-RequestContext) #### `content`: Any (optional) Event analyzed content, a [RequestContent](#api-Types-RequestContent) ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## List Events `GET /v3/events` Get a paginated list of events. Returns a paginated array of events. Events are sorted by date in descending order. ### Query Parameters #### `limit`: Number (optional) Max number of rows to return in the response (max: 1000) Default: 100 ### Success Response #### `ok`: Object Confirms that the retrieval was successful #### `rows`: Object[] List of results, an array of [EventSearchResult](#api-Types-EventSearchResult) ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "rows": [ { "eventId": "r.1654088776347.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.r", "tag": "", "type": "_R", "context": { "appName": "myapp", "eventType": "receipt.validated", "eventDate": "2020-04-25T11:22:58.446Z", "eventDateMs": 1587813778446, "req_id": "53419501", "includeHeavyData": false }, "content": { "purchases": [], "transactions": [], "refreshFailures": [], "products": [ { "id": "google:gold.medium", "type": "consumable", "currency": "EUR", "offers": [ { "id": "google:gold.medium", "pricingPhases": [ { "priceMicros": 1980000, "currency": "EUR" } ] } ] } ], "exchangeRates": [], "claims": [], "notifications": [], "tags": { "53415383": "_R" } } } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` ## Search Events `GET /v3/search/:tag` Search for events by tag. Returns a list of events matching the specified tag. Results are sorted by event date in descending order and limited to 100 events. ### Parameters #### `tag`: String Tag to search for ### Success Response #### `ok`: Object Confirms that the search was successful #### `rows`: Object[] List of results, an array of [EventSearchResult](#api-Types-EventSearchResult) ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "rows": [ { "type": "_X", "tag": "error", "eventId": "r.1654088776347.be347312-6f37-4e6f-9bc8-9416410a6755.r", "context": { "appName": "mygame", "applicationUsername": "user123", "eventType": "receipt.validated", "eventDate": "2022-10-15T01:16:34.035Z", "eventDateMs": 1665796594035, "req_id": "d7eb4ca5-d090-4286-a97f-2f433a6a3130", "includeHeavyData": false }, "content": { "purchases": [{ "platform": "apple", "receiptId": "apple:d69027502229063", "purchaseId": "apple:290000890514160", "productId": "apple:com.mygame.premium.noadv" }], "transactions": [{ "platform": "apple", "sandbox": false, "productId": "apple:com.mygame.premium.noadv", "purchaseId": "apple:290000890514160", "transactionId": "apple:290000890514160", "purchaseDate": "2021-07-01T23:33:43.000Z", "offerId": null, "quantity": 1, "amountMicros": null, "amountUSD": null, "currency": null }], "products": [{ "id": "apple:com.mygame.gems.large", "type": "consumable", "currency": "USD", "offers": [{ "id": "apple:com.mygame.gems.large", "pricingPhases": [{ "priceMicros": 14990000, "currency": "USD" }] }] }], "tags": { "user123": "_A", "d7eb4ca5-d090-4286-a97f-2f433a6a3130": "_R", "error": "_X", "290000890514160": "AT" }, "appDownload": { "currentVersion": "2.5.0", "originalVersion": "2.0.1" } } } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Secret Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + secretKey)}` `` # Stripe ## Change Subscription Plan `POST /v3/stripe/change-plan` Updates a subscription to a different plan/price. The endpoint requires a subscription ID and the corresponding access key that was provided when creating the checkout session. The subscription will be immediately updated to the new plan, with prorations calculated automatically. ### Request Body #### `id`: String Subscription ID (sub\_\*) #### `accessToken`: String Access key received from checkout session creation #### `offerId`: String Iaptic offer ID (e.g. "stripe:prod\_xyz#price\_xyz") ### Success Response #### `ok`: Object Whether the request was successful. #### `purchase`: Any (optional) Updated purchase. #### `newAccessToken`: String (optional) New access token for future requests. ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "purchase": { "purchaseId": "stripe:sub_xyz", "transactionId": "stripe:pi_xyz", "productId": "stripe:prod_xyz", "platform": "stripe", "purchaseDate": "2023-01-01T00:00:00Z", "lastRenewalDate": "2023-02-01T00:00:00Z", "expirationDate": "2023-03-01T00:00:00Z", "renewalIntent": "Renew", "isTrialPeriod": false, "amountMicros": 999000, "currency": "USD" } } ``` ### Error Response ### Examples #### Error-Response ```json HTTP/1.1 403 Forbidden { "status": 403, "code": 6778003, "message": "Invalid access key" } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` `` ## Create Stripe Checkout Session `POST /v3/stripe/checkout` Creates a Stripe Checkout Session for processing a payment or subscription. The endpoint returns a session ID and URL. Redirect the user to the URL to complete the payment. After successful payment, the user will be redirected to the success URL provided. An access key is generated and returned, which can be used to verify the subscription status later. #### Request body The request body should be a JSON object as described below in the Request Body section. ### Request Body #### `offerId`: String Offer ID to purchase (as returned by the `GET /stripe/prices` endpoint) #### `applicationUsername`: String User identifier in your application (optional) #### `successUrl`: String URL to redirect after successful payment #### `cancelUrl`: String URL to redirect if user cancels #### `mode`: String (optional) Payment mode: "payment" or "subscription". Defaults to "subscription" for recurring prices. #### `accessToken`: String (optional) Access token of a previous purchase, for reusing existing stripe customer. ### Success Response #### `ok`: Object Indicates successful creation of checkout session #### `sessionId`: String Unique identifier for the Stripe Checkout Session #### `url`: String Checkout URL where customer will be redirected to complete payment #### `accessToken`: String New or updated access token to fetch the status of the checkout session ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "sessionId": "cs_test_xyz", "url": "https://checkout.stripe.com/c/pay/cs_test_xyz", "accessToken": "abcdef123456.xxx.yyy" } ``` ### Error Response ### Examples #### Error-Response ```json HTTP/1.1 400 Bad Request { "status": 400, "code": 6778003, "message": "Missing required fields: priceId, applicationUsername, successUrl, cancelUrl" } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` `` ## Create Stripe Customer Portal Session `POST /v3/stripe/portal` Creates a Stripe Customer Portal session and returns the URL where the customer can manage their subscription. The endpoint requires either a checkout session ID or subscription ID, along with the corresponding access key that was provided when creating the checkout session. After the customer completes their actions in the portal, they will be redirected to the provided return URL. ### Request Body #### `id`: String Checkout session ID (cs\__) or subscription ID (sub\__) #### `accessToken`: String Access key received when creating the checkout session #### `returnUrl`: String URL to return to after managing subscription ### Success Response #### `ok`: Object `ok` #### `url`: String `url` ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "url": "https://billing.stripe.com/session/xyz" } ``` ### Error Response ### Examples #### Error-Response ```json HTTP/1.1 403 Forbidden { "status": 403, "code": 6778003, "message": "Invalid access key" } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` `` ## Get Stripe Products and Prices `GET /v3/stripe/prices` Retrieves the list of products and prices configured in Stripe. The products and prices are cached for 5 minutes to improve performance and reduce load on Stripe's API. #### Response The response contains a list of products with their associated prices (offers). Each product contains metadata and a list of offers that can be used to initiate a purchase. ### Success Response #### `ok`: Object Indicates successful response #### `products`: Object[] Array of Stripe products with their associated offers #### `products.type`: Any The type of product (e.g., 'paid subscription') #### `products.id`: String Product ID (e.g., 'stripe:prod\_xyz') #### `products.title`: String Display name of the product #### `products.description`: String Optional product description, if available #### `products.metadata`: Object Optional key-value pairs for additional product information, if available #### `products.offers`: Object[] Array of available pricing offers for this product ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "products": [ { "type": "paid subscription", "id": "prod_xyz", "title": "Premium Plan", "description": "Access to all features", "metadata": { "tier": "premium", "features": "all" }, "offers": [ { "id": "price_xyz", "platform": "stripe", "offerType": "Subscription", "pricingPhases": [ { "priceMicros": 999000, "currency": "usd", "billingPeriod": "P1M", "recurrenceMode": "INFINITE_RECURRING", "paymentMode": "PayAsYouGo" } ] } ] } ] } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` `` ## Get Stripe Purchases `GET /v3/stripe/purchases` Retrieves details about a Stripe purchase. This endpoint requires authentication using either: - The access key that was provided when creating the checkout session - The application's API key The subscription details are returned in the same format as other purchases in the system, allowing for consistent handling of subscriptions across platforms. ### Query Parameters #### `accessToken`: String Access key received from checkout session creation ### Success Response #### `ok`: Object Indicates the success of the operation. #### `purchases`: Object[] Contains the details of all valid purchases, formatted as API purchases. #### `newAccessToken`: String (optional) New access token for the customer ### Examples #### Success-Response ```json HTTP/1.1 200 OK { "ok": true, "purchases": [{ "purchaseId": "stripe:sub_xyz", "transactionId": "stripe:ch_xyz", "productId": "stripe:prod_xyz", "platform": "stripe", "purchaseDate": "2023-01-01T00:00:00Z", "lastRenewalDate": "2023-02-01T00:00:00Z", "expirationDate": "2023-03-01T00:00:00Z", "renewalIntent": "Renew", "isTrialPeriod": false, "amountMicros": 999000, "currency": "USD" }], "newAccessToken": "xxx.yyy.zzz" } ``` ### Error Response ### Examples #### Error-Response ```json HTTP/1.1 403 Forbidden { "status": 403, "code": 6778003, "message": "Invalid access key" } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` `` # Braintree ## Create a Braintree client token `POST /v3/braintree/client-token` Generate a client token to authenticate a payment request with Braintree. ### Request Body #### `applicationUsername`: String The user that makes the request. #### `customerId`: String (optional) The Braintree customerId for this user. Undefined means the user has no Braintree customerId yet. ### Success Response #### `success`: Boolean Was the request for a client token successful. #### `message`: String (optional) Error message when success is false. #### `clientToken`: String (optional) The client token, when success is true. ### Examples #### Request-Body ```json { "applicationUsername": "james_bond_007", "customerId": "xyzabcde123" } ``` #### Success-Response ```json HTTP/1.1 200 OK { "success": true, "clientToken": "XXXXXX" } ``` ### Headers #### `Authorization`: String Basic auth using **App Name** as username and **Public Key** as password. Example: `` Authorization: `Basic ${base64(appName + ':' + publicKey)}` ``