openapi: 3.1.0
info:
  title: External Purchases API (BETA)
  version: '0.1'
x-revenuecat-hidden: true
servers:
  - url: https://api.revenuecat.com/
x-tagGroups:
  - name: General
    tags:
      - Introduction
      - Example Subscription Lifecycle
      - Backfill Logic
      - Beta Limitations
  - name: Endpoint Reference
    tags:
      - External Purchases
tags:
  - name: Introduction
    x-traitTag: true
    description: >
      <div class="theme-admonition theme-admonition-info alert alert--warning">
        <div class="heading">Private Beta</div>
        <div>This is a documentation of the External Purchases API, which is currently in private beta.</div>
      </div>

      What is the External Purchases API? When to use it?


      ## Context


      The External Purchases API enables you to track subscription status and
      revenue data from Payment Service Providers that RevenueCat doesn't
      support natively. Such examples of Payment Service Providers, referenced
      as _External Sources_, are Paddle, PayPal, Braintree, Adyen, Recurly, etc.


      You can post subscription status and payment events to the External
      Purchases API to use RevenueCat as a single source of truth for providing
      access to your application across mobile and web and to consolidate
      revenue data and key subscription metrics. Customer history, Webhooks and
      Integration events are supported as well, but they have
      [limitations](#tag/Beta-Limitations) during the Beta period.


      The API expects data to be posted in a format defined in the [API
      reference](#tag/External-Purchases), meaning that you would need to
      convert or transform data from the _External Source_ before posting it to
      the External Purchases API endpoint. RevenueCat accepts data posted to
      this endpoint as is, and relies on your timely requests to provide
      entitlement access.


      If you have a mobile first business with a web presence that follows a
      similar monetization model and subscription lifecycle implementation
      typical to the app stores, then this API is the right choice for you to
      consolidate your stack.


      ## Adding an External Source


      You can add an External Source under _Project > Apps > +New_. All you need
      to provide is the App name. The External API Keys and RevenueCat App ID
      required to call the API are automatically generated after hitting _Save
      Changes_.


      ![](/docs/images/external-purchases-api/adding-external-app.png)


      ![](/docs/images/external-purchases-api/external-app-settings.png)



      ## Authentication


      Authentication for the External Purchases API is achieved by setting the
      `Authorization` header with a valid API secret external key. You'll find
      two main types of API keys in your RevenueCat dashboard: _public
      app-specific_ , _secret_ and _secret app-specific_.


      ```Text Authorization Header

      Authorization: Bearer YOUR_REVENUECAT_APP_SPECIFIC_SECRET_API_KEY

      ```


      The API keys are automatically generated for each External Source whenever
      you add a new _External Source_ on the _Add New App_ screen in the
      Dashboard.


      You can retrieve these API keys both on the _Apps settings_ page and
      _Project settings > API Keys_ page.


      ![](/docs/images/external-purchases-api/external-secret-api-keys.png)


      ## Permissions


      You can call the External Purchases API only with the corresponding
      _app-specific Secret API key_.

      The _app-specific Secret API Key_ should be kept out of any publicly
      accessible areas such as GitHub or client side code.

      Additionally, an _app-specific Public API Key_ is generated so public
      endpoints like
      [Offerings](/docs/api-v1#tag/offerings/operation/get-offerings) can be
      accessed.


      # Base URL


      The base URL for the External Purchases API is
      `https://api.revenuecat.com/`.


      # Endpoints


      The API has one endpoint, `POST/receipts/external`.


      `POST/receipts/external` is used for requests with a single purchase
      and/or payment, and processes them right away. Calling [Get
      Customer](/docs/api-v1#tag/customers/operation/subscribers) right after
      will return the updated entitlements.


      For more details check the [API
      reference](#operation/track-external-purchases).


      ## Payload


      The body of the `POST` requests should be encoded in JSON and have the
      'Content-Type' header set to 'application/json'.


      ```Text Content-Type Header

      Content-Type: application/json

      ```


      ```json Sample body

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-04-01T00:00:00",
          "current_period_starts_at": "2023-04-01T00:00:00",
          "current_period_ends_at": "2023-05-01T00:00:00",
          "gives_access": true,
          "status": "active",
          "environment": "production",
          "auto_renewal_status": "will_renew"
        },
        "payment": {
          "object": "external_subscription_payment",
          "source_subscription_identifier": "paddle_sub_id1234",
          "payment_identifier": "payment_id1234",
          "processed_at": "2023-04-01T00:00:00",
          "amount_in_local_currency": {
            "gross": 9.99,
            "currency": "USD"
          }
        }
      }

      ```
  - name: Example Subscription Lifecycle
    x-traitTag: true
    description: >
      This example of a subscription lifecycle demonstrates the series of API
      request to make to the External Purchases API and the resulting events
      generated (for Customer History, Webhooks and Integration Events).


      This flow covers a Trial Flow with Successful Conversion, an ordinary
      Subscription Renewal, a Billing Issue Flow that gets resolved in Grace
      Period, and eventually a Cancellation Flow.


      ## Sample API requests


      ### Trial purchase

      ```json Trial purchase

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-03-01T00:00:00",
          "current_period_starts_at": "2023-03-01T00:00:00",
          "current_period_ends_at": "2023-04-01T00:00:00",
          "gives_access": true,
          "status": "trialing",
          "environment": "production"
        },
        "payment": null
      }

      ```

      ### Trial conversion

      ```json Trial conversion

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-04-01T00:00:00",
          "current_period_starts_at": "2023-04-01T00:00:00",
          "current_period_ends_at": "2023-05-01T00:00:00",
          "gives_access": true,
          "status": "active",
          "environment": "production",
          "auto_renewal_status": "will_renew"
        },
        "payment": {
          "object": "external_subscription_payment",
          "source_subscription_identifier": "paddle_sub_id1234",
          "payment_identifier": "payment_id1234",
          "processed_at": "2023-04-01T00:00:00",
          "amount_in_local_currency": {
            "gross": 9.99,
            "currency": "USD"
          }
        }
      }

      ```

      ### Renewal

      ```json Renewal

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-05-01T00:00:00",
          "current_period_starts_at": "2023-05-01T00:00:00",
          "current_period_ends_at": "2023-06-01T00:00:00",
          "gives_access": true,
          "status": "active",
          "environment": "production",
          "auto_renewal_status": "will_renew"
        },
        "payment": {
          "object": "external_subscription_payment",
          "source_subscription_identifier": "paddle_sub_id1234",
          "payment_identifier": "payment_id2345",
          "processed_at": "2023-05-01T00:00:00",
          "amount_in_local_currency": {
            "gross": 9.99,
            "currency": "USD"
          }
        }
      }

      ```

      ### Billing issue

      ```json Billing issue

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-06-01T00:00:00",
          "current_period_starts_at": "2023-06-01T00:00:00",
          "current_period_ends_at": "2023-06-14T00:00:00",
          "gives_access": true,
          "status": "in_grace_period",
          "environment": "production",
          "auto_renewal_status": "will_not_renew"
        },
        "payment": null
      }

      ```

      ### Billing succeeds

      ```json Billing succeeds

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-06-12T00:00:00",
          "current_period_starts_at": "2023-06-01T00:00:00",
          "current_period_ends_at": "2023-07-01T00:00:00",
          "gives_access": true,
          "status": "active",
          "environment": "production",
          "auto_renewal_status": "will_renew"
        },
        "payment": {
          "object": "external_subscription_payment",
          "source_subscription_identifier": "paddle_sub_id3456",
          "payment_identifier": "payment_id1234",
          "processed_at": "2023-06-12T00:00:00",
          "amount_in_local_currency": {
            "gross": 9.99,
            "currency": "USD"
          }
        }
      }

      ```

      ### Cancellation

      ```json Cancellation

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-06-18T00:00:00",
          "current_period_starts_at": "2023-06-01T00:00:00",
          "current_period_ends_at": "2023-07-01T00:00:00",
          "gives_access": true,
          "status": "active",
          "environment": "production",
          "auto_renewal_status": "will_not_renew"
        },
        "payment": null
      }

      ```

      ### Expiration

      ```json Expiration

      {
        "purchase": {
          "object": "external_subscription",
          "customer_id": "app_user_id12341234",
          "source_subscription_identifier": "paddle_sub_id1234",
          "source_product_identifier": "paddle_product_id1234",
          "updated_at": "2023-07-01T00:00:00",
          "current_period_starts_at": "2023-06-01T00:00:00",
          "current_period_ends_at": "2023-07-01T00:00:00",
          "gives_access": false,
          "status": "expired",
          "environment": "production",
          "auto_renewal_status": "will_not_renew"
        },
        "payment": null
      }

      ```


      > Note: Make sure to include the `current_period_starts_at` for the
      transaction you are trying to expire. Otherwise your target transaction
      might not be found by the system.


      ## Webhook events flow


      ![](/docs/images/external-purchases-api/b310775-Screenshot_2023-08-03_at_16.36.49.png)


      ![](/docs/images/external-purchases-api/0ac4f83-Screenshot_2023-08-03_at_16.16.32.png)
  - name: Backfill Logic
    x-traitTag: true
    description: >
      ## Backfill new transaction in the subscription


      If subscription statuses arrive out of order (eg. RevenueCat receives a
      previous subscription period before a subsequent subscription period),
      RevenueCat needs to make a decision about how the history of the
      subscription looked like. This section describes various scenarios that
      can occur.


      ### Context


      We know that the new transaction ends before the latest old one.


      ### Overall Scenario


      The transaction can fit everywhere between or overlap the existing
      transactions.  The new transaction can be in any of the following
      positions.


      ![](/docs/images/external-purchases-api/36e8e3a-Screenshot_2023-08-08_at_11.33.29.png)



      We need to find the previous and next overlapping transactions if any.


      #### Scenario 1


      Both previous and next overlapping old transactions exist. As a result, we
      shrink the previous old transaction to end right before the new one.
      Similarly, we shrink the new transaction to end right before the next old
      one.


      ![](/docs/images/external-purchases-api/ab6705e-Screenshot_2023-08-08_at_11.38.02.png)



      #### Scenario 2


      Only the previous overlapping old transaction exist. As a result, we
      shrink the prev transaction to end right before the new one. The new
      transaction is not changed.


      ![](/docs/images/external-purchases-api/acee024-Screenshot_2023-08-08_at_11.39.12.png)



      #### Scenario 3


      Only the next overlapping old transaction exist. As a result, we shrink
      the new transaction to end right before the next old one.


      ![](/docs/images/external-purchases-api/670069c-Screenshot_2023-08-08_at_11.40.13.png)



      #### Scenario 4


      There’s no old transaction overlapping with the new one. As a result, we
      just store the new transaction as is.


      ![](/docs/images/external-purchases-api/9e1c7f6-Screenshot_2023-08-08_at_12.56.05.png)



      #### Scenario 5


      The new transaction overlaps completely a old one (prev). As a result, we
      send ERROR, the new transaction is skipped.


      ![](/docs/images/external-purchases-api/f3b21e7-Screenshot_2023-08-08_at_12.56.52.png)



      ### Move back the latest_expiring_transaction start date if needed


      ### Context


      We know that the new transaction ends after the latest old one.


      #### Scenario 1


      Old transaction starts before and ends during new one. As a result, we
      shrink the old transaction to end right before the new one


      ![](/docs/images/external-purchases-api/0839207-Screenshot_2023-08-08_at_13.00.01.png)



      #### Scenario 2


      Old transaction starts and ends during new one. As a result, we send
      ERROR, the new transaction is skipped.


      ![](/docs/images/external-purchases-api/88623c8-Screenshot_2023-08-08_at_13.01.06.png)



      #### Scenario 3


      Old transaction starts and ends before the  new one. As a result, the new
      transaction is saved, the old one is not modified.


      ![](/docs/images/external-purchases-api/7d07cf7-Screenshot_2023-08-08_at_13.02.19.png)
  - name: Beta Limitations
    x-traitTag: true
    description: >
      The following limitations apply during Beta period:


      1. For `purchase` JSON with `external_subscription` object:
          1. Currently you cannot change the `customer_id` field, meaning that we don't support [Transferring purchases seen on multiple App User IDs](/getting-started/restoring-purchases#transferring-purchases-seen-on-multiple-app-user-ids)
          2. We don't generate a new event in a scenario, when `current_period_ends_at` was in the future, and it's changed to a different future date.
          3. We support the following options for the `auto_renew_status` field:  `will_renew`, `will_not_renew`, `unknown` value. We omit the `will_change_product` for now, meaning that we don't support Upgrades, Downgrade, Crossgrades and resulting event (`PRODUCT_CHANGE` event).
          4. Family shared subscriptions are not supported (but you can still create shared subscriptions as regular subscriptions).
      2. In a scenario when payments are posted after a subscription or purchase
      was created we don't generate Events (since the revenue information was
      already sent with the `INITIAL_PURCHASE` / `RENEWAL` event)

      3. Receipt validation:
          1. Currently, we do not validate receipts or data posted to RevenueCat via the External purchases API. Customers must ensure that data posted to the endpoint is already validated, and they need to ensure that the External API Key is not getting exposed to the public.
      4. Refunds:
          1. In the scenario when the third party payment service provider retains commissions in case of a refund, Revenuecat does not track negative revenues. Meaning, that in such cases, you will see data discrepancies with the equivalent of the commission retained by the payment service provider.
      5. Entitlement identifier:
          1. We support only new entitlement identifiers ([not the legacy version](/docs/integrations/webhooks/event-types-and-fields#subscription-lifecycle-events-fields)).
      6. [Backfills](#tag/Backfill-Logic) that modify `current_period_ends_at`
      date, do not alter existing Events, which means that the Customer history
      won't reflect accurately the most up to date `expiration_at_ms`.

      7. If a different `source_subscription_identifier` gets provided, doesn’t
      matter if it’s the same product, we can end up with concurrent
      transactions

      8. `EXPIRATION` Events are not fired automatically. The developer needs to
      explicitly send a request to the External Purchases API endpoint when
      `status` changed to `expired`.
  - name: External Purchases
    description: Operations to track external subscriptions and purchases.
paths:
  /v1/receipts/external:
    post:
      tags:
        - External Purchases
      summary: Tracks the status of external purchases
      operationId: track-external-purchases
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalPurchaseRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalPurchaseResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestError'
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConflictError'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExceededQuotaError'
      security:
        - api_key: []
components:
  schemas:
    AmountInLocalCurrency:
      properties:
        currency:
          type: string
          title: Currency
          description: ISO 4217 currency code
        gross:
          anyOf:
            - type: number
            - type: string
          title: Gross
          description: >-
            The gross amount of the payment. Positive for payments, negative for
            refunds.
        tax:
          anyOf:
            - type: number
            - type: string
          title: Tax
          description: >-
            The amount of tax taken out of the gross payment. Positive for
            payments, negative for refunds. Defaults to 0.
        commission:
          anyOf:
            - type: number
            - type: string
          title: Commission
          description: >-
            The amount of fees and commissions taken out of the gross payment.
            Positive for payments, negative for refunds. Defaults to 0.
      additionalProperties: false
      type: object
      required:
        - currency
        - gross
      title: AmountInLocalCurrency
    AmountInUSD:
      properties:
        gross:
          anyOf:
            - type: number
            - type: string
          title: Gross
          description: >-
            The gross amount of the payment. Positive for payments, negative for
            refunds.
        tax:
          anyOf:
            - type: number
            - type: string
          title: Tax
          description: >-
            The amount of tax taken out of the gross payment. Positive for
            payments, negative for refunds. Defaults to 0.
        commission:
          anyOf:
            - type: number
            - type: string
          title: Commission
          description: >-
            The amount of fees and commissions taken out of the gross payment.
            Positive for payments, negative for refunds. Defaults to 0.
      additionalProperties: false
      type: object
      required:
        - gross
      title: AmountInUSD
    BadRequestError:
      properties:
        code:
          type: integer
          title: Code
        message:
          type: string
          title: Message
      type: object
      required:
        - code
        - message
      title: BadRequestError
      examples:
        - code: 7000
          message: Invalid Platform.
        - code: 7226
          message: Some parameters are incorrect.
    ConflictError:
      properties:
        code:
          type: integer
          title: Code
        message:
          type: string
          title: Message
      type: object
      required:
        - code
        - message
      title: ConflictError
      examples:
        - code: 7752
          message: Different transactions cannot overlap.
    ExceededQuotaError:
      properties:
        code:
          type: integer
          title: Code
        message:
          type: string
          title: Message
      type: object
      required:
        - code
        - message
      title: ExceededQuotaError
      description: |2-

            The client exceeded the quota for their API KEY.
            
      examples:
        - code: 7000
          message: Invalid Platform.
        - code: 7226
          message: Some parameters are incorrect.
    ExternalPurchase:
      properties:
        object:
          const: external_purchase
          title: Object
          description: The type of the object
        customer_id:
          type: string
          title: Customer Id
          description: >-
            The `app_user_id` of the customer that this subscription should be
            associated with.
        source_purchase_identifier:
          type: string
          title: Source Purchase Identifier
          description: The purchase identifier in the external source
        source_product_identifier:
          type: string
          title: Source Product Identifier
          description: The product identifier in the external source
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: >-
            The date and time as of which this status was up-to-date, in ms
            since epoch. This is used to ensure status updates arriving out of
            order are not overwriting a more recent status.
        status:
          anyOf:
            - type: string
              enum:
                - owned
                - refunded
          title: Status
          description: >-
            The status of the external subscription. If not present or `null`,
            will default to `unknown`.
          default: owned
        environment:
          anyOf:
            - type: string
              enum:
                - sandbox
                - production
          title: Environment
          description: >-
            The environment in which this subscription was created. If not
            present or `null`, will default to `production`.
          default: production
        metadata:
          type: object
          title: Metadata
          description: >-
            Metadata about the purchase. Content must be key-value pairs with
            string, number, boolean, or null values.
      additionalProperties: false
      type: object
      required:
        - object
        - customer_id
        - source_purchase_identifier
        - source_product_identifier
        - updated_at
      title: ExternalPurchase
    ExternalPurchasePayment:
      properties:
        object:
          const: external_purchase_payment
          title: Object
          description: The type of the object
        source_purchase_identifier:
          type: string
          title: Source Purchase Identifier
          description: The purchase identifier in the external source
        payment_identifier:
          type: string
          title: Payment Identifier
          description: >-
            A unique identifier to identify this payment. This is used to ensure
            that payments aren't tracked multiple times in case they get posted
            multiple times. You do not have to deduplicate payments. Refunds
            should have distinct identifiers from their original payment. If the
            source doesn't have a unique identifier for a payment, it is
            probably possible to create one from a subscription identifier plus
            subscription period identifier, or subscription identifier plus
            timestamp of the payment.
        processed_at:
          anyOf:
            - type: string
              format: date-time
          title: Processed At
          description: The date and time the payment was processed.
        country:
          anyOf:
            - type: string
          title: Country
          description: The billing country, in ISO3166.1 format.
        amount_in_local_currency:
          allOf:
            - $ref: '#/components/schemas/AmountInLocalCurrency'
          description: >-
            Amount of the payment or refund in the currency it was charged in.
            Will be converted to USD by RevenueCat unless the field
            `amount_in_usd` is present.
        amount_in_usd:
          anyOf:
            - $ref: '#/components/schemas/AmountInUSD'
          description: >-
            Amount of the payment or refund in USD, if available from the
            transaction source.
        active_offer_type:
          anyOf:
            - type: string
              enum:
                - introductory_offer
                - offer_code
                - win_back_offer
                - promotional_offer
                - unspecified_offer
          title: Active Offer Type
          description: The type of offer that was active when the payment was processed.
        active_offer:
          type: string
          title: Active Offer Identifier
          description: >-
            The identifier of the offer that was active when the payment was
            processed.
      additionalProperties: false
      type: object
      required:
        - object
        - source_purchase_identifier
        - payment_identifier
        - amount_in_local_currency
      title: ExternalPurchasePayment
    ExternalPurchaseRequest:
      properties:
        purchase:
          anyOf:
            - $ref: '#/components/schemas/ExternalPurchase'
            - $ref: '#/components/schemas/ExternalSubscription'
          title: Purchase
          description: The current status of one external purchase to track
        payment:
          anyOf:
            - $ref: '#/components/schemas/ExternalSubscriptionPayment'
            - $ref: '#/components/schemas/ExternalPurchasePayment'
          title: Payment
          description: The current status of one external payment to track
      additionalProperties: false
      type: object
      title: ExternalPurchaseRequest
    ExternalPurchaseResponse:
      properties:
        purchase:
          anyOf:
            - type: string
          title: Purchase
          description: The id of the created purchase/subscription. If any was created.
        payment:
          anyOf:
            - type: string
          title: Payment
          description: The id of the created payment. If any was created.
      type: object
      title: ExternalPurchaseResponse
    ExternalSubscription:
      properties:
        object:
          const: external_subscription
          title: Object
          description: The type of the object
        customer_id:
          type: string
          title: Customer Id
          description: >-
            The `app_user_id` of the customer that this subscription should be
            associated with.
        source_subscription_identifier:
          type: string
          title: Source Subscription Identifier
          description: >-
            Identifier of the subscription in the source system. This will be
            used to match subscription status updates. Renewals of the same
            subscription should have the same `source_subscription_identifier`.
        source_product_identifier:
          type: string
          title: Source Product Identifier
          description: The product identifier in the external source
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: >-
            The date and time as of which this status was up-to-date, in ms
            since epoch. This is used to ensure status updates arriving out of
            order are not overwriting a more recent status.
        current_period_starts_at:
          anyOf:
            - type: string
              format: date-time
          title: Current Period Starts At
          description: >-
            The date and time at which the current period has begun, in ms since
            epoch. If this field is `null` or not present, it is assumed to be
            equal to `status_as_of`, unless this is an update to a previously
            posted subscription period with the same end date.
        current_period_ends_at:
          type: string
          format: date-time
          title: Current Period Ends At
          description: >-
            The date and time at which the current period ends, in ms since
            epoch. If no update is received when the current period ends, the
            subscription is assumed to have expired.
        gives_access:
          type: boolean
          title: Gives Access
          description: >-
            Whether or not the customer should currently have access to any
            entitlements granted by this subscription.
        status:
          anyOf:
            - type: string
              enum:
                - trialing
                - active
                - expired
                - in_grace_period
                - in_billing_retry
                - paused
                - unknown
          title: Status
          description: >-
            The status of the external subscription. If not present or `null`,
            will default to `unknown`.
          default: unknown
        environment:
          anyOf:
            - type: string
              enum:
                - sandbox
                - production
          title: Environment
          description: >-
            The environment in which this subscription was created. If not
            present or `null`, will default to `production`.
          default: production
        auto_renewal_status:
          anyOf:
            - type: string
              enum:
                - will_renew
                - will_not_renew
                - will_change_product
                - will_pause
                - requires_price_increase_consent
                - has_already_renewed
                - unknown
          title: Auto Renewal Status
          description: >-
            Whether or not the subscription is currently set to auto-renew at
            the end of the current subscription period. If not present or
            `null`, will default to `unknown`.
          default: unknown
        metadata:
          type: object
          title: Metadata
          description: >-
            Metadata about the subscription. Content must be key-value pairs
            with string, number, boolean, or null values.
      additionalProperties: false
      type: object
      required:
        - object
        - customer_id
        - source_subscription_identifier
        - source_product_identifier
        - updated_at
        - current_period_ends_at
        - gives_access
      title: ExternalSubscription
    ExternalSubscriptionPayment:
      properties:
        object:
          const: external_subscription_payment
          title: Object
          description: The type of the object
        source_subscription_identifier:
          type: string
          title: Source Subscription Identifier
          description: >-
            Identifier of the subscription in the source system. This will be
            used to match the payment to the subscription.
        payment_identifier:
          type: string
          title: Payment Identifier
          description: >-
            A unique identifier to identify this payment. This is used to ensure
            that payments aren't tracked multiple times in case they get posted
            multiple times. You do not have to deduplicate payments. Refunds
            should have distinct identifiers from their original payment. If the
            source doesn't have a unique identifier for a payment, it is
            probably possible to create one from a subscription identifier plus
            subscription period identifier, or subscription identifier plus
            timestamp of the payment.
        processed_at:
          anyOf:
            - type: string
              format: date-time
          title: Processed At
          description: The date and time the payment was processed.
        country:
          anyOf:
            - type: string
          title: Country
          description: The billing country, in ISO3166.1 format.
        amount_in_local_currency:
          allOf:
            - $ref: '#/components/schemas/AmountInLocalCurrency'
          description: >-
            Amount of the payment or refund in the currency it was charged in.
            Will be converted to USD by RevenueCat unless the field
            `amount_in_usd` is present.
        amount_in_usd:
          anyOf:
            - $ref: '#/components/schemas/AmountInUSD'
          description: >-
            Amount of the payment or refund in USD, if available from the
            transaction source.
        active_offer_type:
          anyOf:
            - type: string
              enum:
                - free_trial
                - introductory_offer
                - offer_code
                - win_back_offer
                - promotional_offer
                - unspecified_offer
          title: Active Offer Type
          description: The type of offer that was active when the payment was processed.
        active_offer:
          type: string
          title: Active Offer Identifier
          description: >-
            The identifier of the offer that was active when the payment was
            processed.
      additionalProperties: false
      type: object
      required:
        - object
        - source_subscription_identifier
        - payment_identifier
      title: ExternalSubscriptionPayment
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    api_key:
      type: http
      description: The External Purchases API Key
      scheme: bearer
