{"id":13800704,"url":"https://github.com/Cap-go/native-purchases","last_synced_at":"2025-05-13T09:31:49.962Z","repository":{"id":187752250,"uuid":"677494519","full_name":"Cap-go/capacitor-native-purchases","owner":"Cap-go","description":"Manage IAP on capacitor with latest libs Android IOS","archived":false,"fork":false,"pushed_at":"2025-05-06T18:26:08.000Z","size":751,"stargazers_count":11,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-06T19:42:44.693Z","etag":null,"topics":["capacitor","capacitor-plugin","ionic"],"latest_commit_sha":null,"homepage":"https://capgo.app","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Cap-go.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"Cap-go","patreon":null,"open_collective":"capgo","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2023-08-11T18:04:16.000Z","updated_at":"2025-04-28T04:32:45.000Z","dependencies_parsed_at":"2023-08-12T02:56:53.432Z","dependency_job_id":"b147580b-b910-46ba-bf3e-1e6c31f75435","html_url":"https://github.com/Cap-go/capacitor-native-purchases","commit_stats":{"total_commits":100,"total_committers":3,"mean_commits":"33.333333333333336","dds":0.51,"last_synced_commit":"e09d965f54afce3d2a2667ba113e7af90116c687"},"previous_names":["cap-go/native-purchases","cap-go/capacitor-native-purchases"],"tags_count":124,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cap-go%2Fcapacitor-native-purchases","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cap-go%2Fcapacitor-native-purchases/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cap-go%2Fcapacitor-native-purchases/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cap-go%2Fcapacitor-native-purchases/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Cap-go","download_url":"https://codeload.github.com/Cap-go/capacitor-native-purchases/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253913217,"owners_count":21983277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["capacitor","capacitor-plugin","ionic"],"created_at":"2024-08-04T00:01:15.269Z","updated_at":"2025-05-13T09:31:49.953Z","avatar_url":"https://github.com/Cap-go.png","language":"Java","funding_links":["https://github.com/sponsors/Cap-go","https://opencollective.com/capgo"],"categories":["[Capgo plugins](https://capgo.app/)"],"sub_categories":[],"readme":"# native-purchases\n \u003ca href=\"https://capgo.app/\"\u003e\u003cimg src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/\u003e\u003c/a\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch2\u003e\u003ca href=\"https://capgo.app/?ref=plugin\"\u003e ➡️ Get Instant updates for your App with Capgo 🚀\u003c/a\u003e\u003c/h2\u003e\n  \u003ch2\u003e\u003ca href=\"https://capgo.app/consulting/?ref=plugin\"\u003e Fix your annoying bug now, Hire a Capacitor expert 💪\u003c/a\u003e\u003c/h2\u003e\n\u003c/div\u003e\n\n## In-app Purchases Made Easy\n\nThis plugin allows you to implement in-app purchases and subscriptions in your Capacitor app using native APIs.\n\n## Install\n\n```bash\nnpm install @capgo/native-purchases\nnpx cap sync\n```\n\n## Android\n\nAdd this to manifest\n\n```xml\n\u003cuses-permission android:name=\"com.android.vending.BILLING\" /\u003e\n```\n\n## Usage\n\nImport the plugin in your TypeScript file:\n\n```typescript\nimport { NativePurchases } from '@capgo/native-purchases';\n```\n\n### Check if billing is supported\n\nBefore attempting to make purchases, check if billing is supported on the device:\nWe only support Storekit 2 on iOS (iOS 15+) and google play on Android\n\n```typescript\nconst checkBillingSupport = async () =\u003e {\n  try {\n    const { isBillingSupported } = await NativePurchases.isBillingSupported();\n    if (isBillingSupported) {\n      console.log('Billing is supported on this device');\n    } else {\n      console.log('Billing is not supported on this device');\n    }\n  } catch (error) {\n    console.error('Error checking billing support:', error);\n  }\n};\n```\n\n### Get available products\n\nRetrieve information about available products:\n\n```typescript\nconst getAvailableProducts = async () =\u003e {\n  try {\n    const { products } = await NativePurchases.getProducts({\n      productIdentifiers: ['product_id_1', 'product_id_2'],\n      productType: PURCHASE_TYPE.INAPP // or PURCHASE_TYPE.SUBS for subscriptions\n    });\n    console.log('Available products:', products);\n  } catch (error) {\n    console.error('Error getting products:', error);\n  }\n};\n```\n\n### Purchase a product\n\nTo initiate a purchase:\n\n```typescript\nconst purchaseProduct = async (productId: string) =\u003e {\n  try {\n    const transaction = await NativePurchases.purchaseProduct({\n      productIdentifier: productId,\n      productType: PURCHASE_TYPE.INAPP // or PURCHASE_TYPE.SUBS for subscriptions\n    });\n    console.log('Purchase successful:', transaction);\n    // Handle the successful purchase (e.g., unlock content, update UI)\n  } catch (error) {\n    console.error('Purchase failed:', error);\n  }\n};\n```\n\n### Restore purchases\n\nTo restore previously purchased products:\n\n```typescript\nconst restorePurchases = async () =\u003e {\n  try {\n    const { customerInfo } = await NativePurchases.restorePurchases();\n    console.log('Restored purchases:', customerInfo);\n    // Update your app's state based on the restored purchases\n  } catch (error) {\n    console.error('Failed to restore purchases:', error);\n  }\n};\n```\n\n## Example: Implementing a simple store\n\nHere's a basic example of how you might implement a simple store in your app:\n\n```typescript\nimport { Capacitor } from '@capacitor/core';\nimport { NativePurchases, PURCHASE_TYPE, Product } from '@capgo/native-purchases';\n\nclass Store {\n  private products: Product[] = [];\n\n  async initialize() {\n    if (Capacitor.isNativePlatform()) {\n      try {\n        await this.checkBillingSupport();\n        await this.loadProducts();\n      } catch (error) {\n        console.error('Store initialization failed:', error);\n      }\n    }\n  }\n\n  private async checkBillingSupport() {\n    const { isBillingSupported } = await NativePurchases.isBillingSupported();\n    if (!isBillingSupported) {\n      throw new Error('Billing is not supported on this device');\n    }\n  }\n\n  private async loadProducts() {\n    const productIds = ['premium_subscription', 'remove_ads', 'coin_pack'];\n    const { products } = await NativePurchases.getProducts({\n      productIdentifiers: productIds,\n      productType: PURCHASE_TYPE.INAPP\n    });\n    this.products = products;\n  }\n\n  getProducts() {\n    return this.products;\n  }\n\n  async purchaseProduct(productId: string) {\n    try {\n      const transaction = await NativePurchases.purchaseProduct({\n        productIdentifier: productId,\n        productType: PURCHASE_TYPE.INAPP\n      });\n      console.log('Purchase successful:', transaction);\n      // Handle the successful purchase\n      return transaction;\n    } catch (error) {\n      console.error('Purchase failed:', error);\n      throw error;\n    }\n  }\n\n  async restorePurchases() {\n    try {\n      const { customerInfo } = await NativePurchases.restorePurchases();\n      console.log('Restored purchases:', customerInfo);\n      // Update app state based on restored purchases\n      return customerInfo;\n    } catch (error) {\n      console.error('Failed to restore purchases:', error);\n      throw error;\n    }\n  }\n}\n\n// Usage\nconst store = new Store();\nawait store.initialize();\n\n// Display products\nconst products = store.getProducts();\nconsole.log('Available products:', products);\n\n// Purchase a product\ntry {\n  await store.purchaseProduct('premium_subscription');\n  console.log('Purchase completed successfully');\n} catch (error) {\n  console.error('Purchase failed:', error);\n}\n\n// Restore purchases\ntry {\n  await store.restorePurchases();\n  console.log('Purchases restored successfully');\n} catch (error) {\n  console.error('Failed to restore purchases:', error);\n}\n```\n\nThis example provides a basic structure for initializing the store, loading products, making purchases, and restoring previous purchases. You'll need to adapt this to fit your specific app's needs, handle UI updates, and implement proper error handling and user feedback.\n\n## Backend Validation\n\nIt's crucial to validate receipts on your server to ensure the integrity of purchases. Here's an example of how to implement backend validation using a Cloudflare Worker:\n\nCloudflare Worker Setup\nCreate a new Cloudflare Worker and follow the instructions in folder (`validator`)[/validator/README.md]\n\nThen in your app, modify the purchase function to validate the receipt on the server:\n\n```typescript\nimport { Capacitor } from '@capacitor/core';\nimport { NativePurchases, PURCHASE_TYPE, Product, Transaction } from '@capgo/native-purchases';\nimport axios from 'axios'; // Make sure to install axios: npm install axios\n\nclass Store {\n  // ... (previous code remains the same)\n\n  async purchaseProduct(productId: string) {\n    try {\n      const transaction = await NativePurchases.purchaseProduct({\n        productIdentifier: productId,\n        productType: PURCHASE_TYPE.INAPP\n      });\n      console.log('Purchase successful:', transaction);\n      \n      // Immediately grant access to the purchased content\n      await this.grantAccess(productId);\n      \n      // Initiate server-side validation asynchronously\n      this.validatePurchaseOnServer(transaction).catch(console.error);\n      \n      return transaction;\n    } catch (error) {\n      console.error('Purchase failed:', error);\n      throw error;\n    }\n  }\n\n  private async grantAccess(productId: string) {\n    // Implement logic to grant immediate access to the purchased content\n    console.log(`Granting access to ${productId}`);\n    // Update local app state, unlock features, etc.\n  }\n\n  private async validatePurchaseOnServer(transaction: Transaction) {\n    const serverUrl = 'https://your-server-url.com/validate-purchase';\n    try {\n      const response = await axios.post(serverUrl, {\n        transactionId: transaction.transactionId,\n        platform: Capacitor.getPlatform(),\n        // Include any other relevant information\n      });\n\n      console.log('Server validation response:', response.data);\n      // The server will handle the actual validation with the Cloudflare Worker\n    } catch (error) {\n      console.error('Error in server-side validation:', error);\n      // Implement retry logic or notify the user if necessary\n    }\n  }\n}\n\n// Usage remains the same\nconst store = new Store();\nawait store.initialize();\n\ntry {\n  await store.purchaseProduct('premium_subscription');\n  console.log('Purchase completed successfully');\n} catch (error) {\n  console.error('Purchase failed:', error);\n}\n```\n\nNow, let's look at how the server-side (Node.js) code might handle the validation:\n\n```typescript\nimport express from 'express';\nimport axios from 'axios';\n\nconst app = express();\napp.use(express.json());\n\nconst CLOUDFLARE_WORKER_URL = 'https://your-cloudflare-worker-url.workers.dev';\n\napp.post('/validate-purchase', async (req, res) =\u003e {\n  const { transactionId, platform } = req.body;\n\n  try {\n    const endpoint = platform === 'ios' ? '/apple' : '/google';\n    const validationResponse = await axios.post(`${CLOUDFLARE_WORKER_URL}${endpoint}`, {\n      receipt: transactionId\n    });\n\n    const validationResult = validationResponse.data;\n\n    // Process the validation result\n    if (validationResult.isValid) {\n      // Update user status in the database\n      // await updateUserStatus(userId, 'paid');\n      \n      // Log the successful validation\n      console.log(`Purchase validated for transaction ${transactionId}`);\n      \n      // You might want to store the validation result for future reference\n      // await storeValidationResult(userId, transactionId, validationResult);\n    } else {\n      // Handle invalid purchase\n      console.warn(`Invalid purchase detected for transaction ${transactionId}`);\n      // You might want to flag this for further investigation\n      // await flagSuspiciousPurchase(userId, transactionId);\n    }\n\n    // Always respond with a success to the app\n    // This ensures the app doesn't block the user's access\n    res.json({ success: true });\n  } catch (error) {\n    console.error('Error validating purchase:', error);\n    // Still respond with success to the app\n    res.json({ success: true });\n    // You might want to log this error or retry the validation later\n    // await logValidationError(userId, transactionId, error);\n  }\n});\n\n// Start the server\napp.listen(3000, () =\u003e console.log('Server running on port 3000'));\n```\n\nKey points about this approach:\n\n1. The app immediately grants access after a successful purchase, ensuring a smooth user experience.\n2. The app initiates server-side validation asynchronously, not blocking the user's access.\n3. The server handles the actual validation by calling the Cloudflare Worker.\n4. The server always responds with success to the app, even if validation fails or encounters an error.\n5. The server can update the user's status in the database, log results, and handle any discrepancies without affecting the user's immediate experience.\n\nComments on best practices:\n\n```typescript\n// After successful validation:\n// await updateUserStatus(userId, 'paid');\n\n// It's crucial to not block or revoke access immediately if validation fails\n// Instead, flag suspicious transactions for review:\n// if (!validationResult.isValid) {\n//   await flagSuspiciousPurchase(userId, transactionId);\n// }\n\n// Implement a system to periodically re-check flagged purchases\n// This could be a separate process that runs daily/weekly\n\n// Consider implementing a grace period for new purchases\n// This allows for potential delays in server communication or store processing\n// const GRACE_PERIOD_DAYS = 3;\n// if (daysSincePurchase \u003c GRACE_PERIOD_DAYS) {\n//   grantAccess = true;\n// }\n\n// For subscriptions, regularly check their status with the stores\n// This ensures you catch any cancelled or expired subscriptions\n// setInterval(checkSubscriptionStatuses, 24 * 60 * 60 * 1000); // Daily check\n\n// Implement proper error handling and retry logic for network failures\n// This is especially important for the server-to-Cloudflare communication\n\n// Consider caching validation results to reduce load on your server and the stores\n// const cachedValidation = await getCachedValidation(transactionId);\n// if (cachedValidation) return cachedValidation;\n```\n\nThis approach balances immediate user gratification with proper server-side validation, adhering to Apple and Google's guidelines while still maintaining the integrity of your purchase system.\n\n## API\n\n\u003cdocgen-index\u003e\n\n* [`restorePurchases()`](#restorepurchases)\n* [`purchaseProduct(...)`](#purchaseproduct)\n* [`getProducts(...)`](#getproducts)\n* [`getProduct(...)`](#getproduct)\n* [`isBillingSupported()`](#isbillingsupported)\n* [`getPluginVersion()`](#getpluginversion)\n* [Interfaces](#interfaces)\n* [Enums](#enums)\n\n\u003c/docgen-index\u003e\n\n\u003cdocgen-api\u003e\n\u003c!--Update the source file JSDoc comments and rerun docgen to update the docs below--\u003e\n\n### restorePurchases()\n\n```typescript\nrestorePurchases() =\u003e Promise\u003cvoid\u003e\n```\n\nRestores a user's previous  and links their appUserIDs to any user's also using those .\n\n--------------------\n\n\n### purchaseProduct(...)\n\n```typescript\npurchaseProduct(options: { productIdentifier: string; planIdentifier?: string; productType?: PURCHASE_TYPE; quantity?: number; }) =\u003e Promise\u003cTransaction\u003e\n```\n\nStarted purchase process for the given product.\n\n| Param         | Type                                                                                                                                              | Description               |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |\n| **`options`** | \u003ccode\u003e{ productIdentifier: string; planIdentifier?: string; productType?: \u003ca href=\"#purchase_type\"\u003ePURCHASE_TYPE\u003c/a\u003e; quantity?: number; }\u003c/code\u003e | - The product to purchase |\n\n**Returns:** \u003ccode\u003ePromise\u0026lt;\u003ca href=\"#transaction\"\u003eTransaction\u003c/a\u003e\u0026gt;\u003c/code\u003e\n\n--------------------\n\n\n### getProducts(...)\n\n```typescript\ngetProducts(options: { productIdentifiers: string[]; productType?: PURCHASE_TYPE; }) =\u003e Promise\u003c{ products: Product[]; }\u003e\n```\n\nGets the product info associated with a list of product identifiers.\n\n| Param         | Type                                                                                                     | Description                                                    |\n| ------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |\n| **`options`** | \u003ccode\u003e{ productIdentifiers: string[]; productType?: \u003ca href=\"#purchase_type\"\u003ePURCHASE_TYPE\u003c/a\u003e; }\u003c/code\u003e | - The product identifiers you wish to retrieve information for |\n\n**Returns:** \u003ccode\u003ePromise\u0026lt;{ products: Product[]; }\u0026gt;\u003c/code\u003e\n\n--------------------\n\n\n### getProduct(...)\n\n```typescript\ngetProduct(options: { productIdentifier: string; productType?: PURCHASE_TYPE; }) =\u003e Promise\u003c{ product: Product; }\u003e\n```\n\nGets the product info for a single product identifier.\n\n| Param         | Type                                                                                                  | Description                                                   |\n| ------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |\n| **`options`** | \u003ccode\u003e{ productIdentifier: string; productType?: \u003ca href=\"#purchase_type\"\u003ePURCHASE_TYPE\u003c/a\u003e; }\u003c/code\u003e | - The product identifier you wish to retrieve information for |\n\n**Returns:** \u003ccode\u003ePromise\u0026lt;{ product: \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e; }\u0026gt;\u003c/code\u003e\n\n--------------------\n\n\n### isBillingSupported()\n\n```typescript\nisBillingSupported() =\u003e Promise\u003c{ isBillingSupported: boolean; }\u003e\n```\n\nCheck if billing is supported for the current device.\n\n**Returns:** \u003ccode\u003ePromise\u0026lt;{ isBillingSupported: boolean; }\u0026gt;\u003c/code\u003e\n\n--------------------\n\n\n### getPluginVersion()\n\n```typescript\ngetPluginVersion() =\u003e Promise\u003c{ version: string; }\u003e\n```\n\nGet the native Capacitor plugin version\n\n**Returns:** \u003ccode\u003ePromise\u0026lt;{ version: string; }\u0026gt;\u003c/code\u003e\n\n--------------------\n\n\n### Interfaces\n\n\n#### Transaction\n\n| Prop                | Type                | Description                                  |\n| ------------------- | ------------------- | -------------------------------------------- |\n| **`transactionId`** | \u003ccode\u003estring\u003c/code\u003e | RevenueCat Id associated to the transaction. |\n\n\n#### Product\n\n| Prop                              | Type                                                                    | Description                                                              |\n| --------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| **`identifier`**                  | \u003ccode\u003estring\u003c/code\u003e                                                     | \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e Id.                                       |\n| **`description`**                 | \u003ccode\u003estring\u003c/code\u003e                                                     | Description of the product.                                              |\n| **`title`**                       | \u003ccode\u003estring\u003c/code\u003e                                                     | Title of the product.                                                    |\n| **`price`**                       | \u003ccode\u003enumber\u003c/code\u003e                                                     | Price of the product in the local currency.                              |\n| **`priceString`**                 | \u003ccode\u003estring\u003c/code\u003e                                                     | Formatted price of the item, including its currency sign, such as €3.99. |\n| **`currencyCode`**                | \u003ccode\u003estring\u003c/code\u003e                                                     | Currency code for price and original price.                              |\n| **`currencySymbol`**              | \u003ccode\u003estring\u003c/code\u003e                                                     | Currency symbol for price and original price.                            |\n| **`isFamilyShareable`**           | \u003ccode\u003eboolean\u003c/code\u003e                                                    | Boolean indicating if the product is sharable with family                |\n| **`subscriptionGroupIdentifier`** | \u003ccode\u003estring\u003c/code\u003e                                                     | Group identifier for the product.                                        |\n| **`subscriptionPeriod`**          | \u003ccode\u003e\u003ca href=\"#subscriptionperiod\"\u003eSubscriptionPeriod\u003c/a\u003e\u003c/code\u003e       | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e subcription group identifier.         |\n| **`introductoryPrice`**           | \u003ccode\u003e\u003ca href=\"#skproductdiscount\"\u003eSKProductDiscount\u003c/a\u003e \\| null\u003c/code\u003e | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e introductory Price.                   |\n| **`discounts`**                   | \u003ccode\u003eSKProductDiscount[]\u003c/code\u003e                                        | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discounts list.                       |\n\n\n#### SubscriptionPeriod\n\n| Prop                | Type                | Description                             |\n| ------------------- | ------------------- | --------------------------------------- |\n| **`numberOfUnits`** | \u003ccode\u003enumber\u003c/code\u003e | The Subscription Period number of unit. |\n| **`unit`**          | \u003ccode\u003enumber\u003c/code\u003e | The Subscription Period unit.           |\n\n\n#### SKProductDiscount\n\n| Prop                     | Type                                                              | Description                                                              |\n| ------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| **`identifier`**         | \u003ccode\u003estring\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount identifier.                  |\n| **`type`**               | \u003ccode\u003enumber\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount type.                        |\n| **`price`**              | \u003ccode\u003enumber\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount price.                       |\n| **`priceString`**        | \u003ccode\u003estring\u003c/code\u003e                                               | Formatted price of the item, including its currency sign, such as €3.99. |\n| **`currencySymbol`**     | \u003ccode\u003estring\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount currency symbol.             |\n| **`currencyCode`**       | \u003ccode\u003estring\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount currency code.               |\n| **`paymentMode`**        | \u003ccode\u003enumber\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount paymentMode.                 |\n| **`numberOfPeriods`**    | \u003ccode\u003enumber\u003c/code\u003e                                               | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount number Of Periods.           |\n| **`subscriptionPeriod`** | \u003ccode\u003e\u003ca href=\"#subscriptionperiod\"\u003eSubscriptionPeriod\u003c/a\u003e\u003c/code\u003e | The \u003ca href=\"#product\"\u003eProduct\u003c/a\u003e discount subscription period.         |\n\n\n### Enums\n\n\n#### PURCHASE_TYPE\n\n| Members     | Value                | Description                        |\n| ----------- | -------------------- | ---------------------------------- |\n| **`INAPP`** | \u003ccode\u003e\"inapp\"\u003c/code\u003e | A type of SKU for in-app products. |\n| **`SUBS`**  | \u003ccode\u003e\"subs\"\u003c/code\u003e  | A type of SKU for subscriptions.   |\n\n\u003c/docgen-api\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCap-go%2Fnative-purchases","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCap-go%2Fnative-purchases","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCap-go%2Fnative-purchases/lists"}