Skip to content

Proposal to add support for explicit identification of price types such as installments and subscriptions #2689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
alex-jansen opened this issue Aug 15, 2020 · 17 comments · Fixed by #2715
Assignees

Comments

@alex-jansen
Copy link
Contributor

Context - This is a proposal from Google based on our experience consuming schema.org Offer markup and working with similar data from online merchants. If it were accepted, it would make it easier for us and others to understand flexible pricing models, for example an offer whose price consists of several separate price components.

Introduction

Many wireless devices, such a mobile phones, tablet computers, and smart watches advertised and sold on the web often have several price components, for example:

  • a one-time upfront payment ("down payment"), e.g. 215 GBP
  • monthly installment payments to pay the remaining balance for the device, e.g., 12 months at 38.65 GBP/month
  • a contract for a wireless subscription plan (for phone and data service), e.g., a minimum duration of 24 months at 15 GBP/month.

Currently, Schema.Org does not provide a structured way of identifying the different price components of an offer, the closest option is the /priceType property part of the /UnitPriceSpecification type, which is free-form Text.

We believe allowing an explicit and structured way of expressing the type of a price component would benefit the ecosystem.

Proposal

Our proposal is to add a new enumeration, for example /PriceTypeEnumeration, with values such as "Installment" and "Subscription". We would allow the new enumeration as an alternative type on property /priceType.

Example

The example offer given in the introduction could be expressed through the following schema when using the proposed /PriceTypeEnumeration:

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "sku": "GZDU23L/B",
  "image": "https://www.example.com/phone_5_32_slvr.jpg",
  "name": "Phone 5" 32GB Silver",
  "description": "New phone 5" screen in silver with 32GB + contract",
  "gtin14": "00821793049157",
  "mpn": "G-2PW4100-021-B",
  "brand": {
    "@type": "Thing",
    "name": "PhoneBrand"
  },
  "color": "Silver",
  "offers": {
    "@type": "Offer",
    "url": "http://www.example.com/GZDU23LB",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "price" : 215,
    "priceCurrency": "GBP",
    "priceSpecification": {
      "@type": "CompoundPriceSpecification",
      "priceComponent": [
        {
          "@type": "UnitPriceSpecification",
          "priceType": "https://schema.org/Installment",
          "price": 38.65,
          "billingIncrement": 1,
          "unitCode": "MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitCode": "MON"
          }
        },
        {
          "@type": "UnitPriceSpecification",
          "priceType": "https://schema.org/Subscription",
          "price": 15,
          "billingIncrement": 1,
          "unitCode": "MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "minValue": 24,
            "unitCode": "MON"
          }
        }
      ]
    }
  }
}

In this example, the /price property on /Offer is used to provide the up-front price that the consumer has to pay. The additional monthly installment and subscription payments are provided using 2 separate /priceComponent properties grouped using /CompoundPriceSpecification. See also #829 for a discussion on compound pricing.

Some considerations

  • We explored the use of /RepaymentSpecification to model installment payments. However, /RepaymentSpecification models only installment payments, which seems too narrow in scope since many other types of pricing exist as well, including the aforementioned subscription payments, but also activation fees, cleaning fees, early-termination fees, optional warranties, and damage insurance (covering other domains than wireless devices as well).
  • Instead of modeling the up-front payment under the /price property of /Offer it might seem more consistent to add it as an additional /priceComponent under /CompoundPriceSpecification. However absence of /price on /Offer might confuse existing systems consuming structured Offer data while relying on the presence of the /price property. A potential solution could be one where the total minimum lifetime price (215 + 12x38.65 + 24x15 = 1038.80 GBP) is provided in Offer.price while providing the up-front payment under CompoundPriceSpecification but that appears redundant.
@earthrefresh
Copy link

earthrefresh commented Aug 16, 2020

Unsure if this is necessary, but it may be helpful to include a way of indicating that a particular Installment or Subscription price is only valid for a certain time frame before changing into another price, e.g. '$9.95 for the first 12 months, then $15.99'.

@alex-jansen
Copy link
Contributor Author

alex-jansen commented Aug 17, 2020

@earthrefresh That is a good suggestion since that is pretty common scenario. To make this explicit we need a way to sequence /priceComponents of the same type, for example through a /sequenceNumber, or, maybe more flexible, a /billingStart property under /UnitPriceSpecification. The latter would specify when the periodic payments for a /priceComponent would start.

@danbri
Copy link
Contributor

danbri commented Aug 18, 2020

ping @mfhepp

@alex-jansen
Copy link
Contributor Author

alex-jansen commented Sep 23, 2020

After observing the usage and description of the existing /priceType property it appears to be intended for complete price specifications. We should therefore consider introducing a new /priceComponentType property with corresponding enumeration /PriceComponentTypeEnumeration to represent the types of pricing components. This would be instead of the original idea, which proposed building on the existing /priceType property to model pricing components.

The example given earlier would then change as follows:

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "sku": "GZDU23L/B",
  "image": "https://www.example.com/phone_5_32_slvr.jpg",
  "name": "Phone 5 inch 32GB Silver",
  "description": "New phone 5 inch screen in silver with 32GB + contract",
  "gtin14": "00821793049157",
  "mpn": "G-2PW4100-021-B",
  "brand": {
    "@type": "Thing",
    "name": "PhoneBrand"
  },
  "color": "Silver",
  "offers": {
    "@type": "Offer",
    "url": "http://www.example.com/GZDU23LB",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "priceCurrency": "GBP",
    "priceSpecification": {
      "@type": "CompoundPriceSpecification",
      "priceComponent": [
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Downpayment",
          "price": 215
        },
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Installment",
          "price": 38.65,
          "billingIncrement": 1,
          "unitCode": "MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitCode": "MON"
          }
        },
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 15,
          "billingIncrement": 1,
          "unitCode": "MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitCode": "MON"
          }
        },
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 19.99,
          "billingIncrement": 1,
          "billingStart": 13,
          "unitCode": "MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "minValue": 12,
            "unitCode": "MON"
          }
        }
      ]
    }
  }
}

This example has 3 other changes compared to the original example:

@alex-jansen alex-jansen linked a pull request Sep 23, 2020 that will close this issue
danbri pushed a commit that referenced this issue Oct 6, 2020
* first cut at #2689

* Revert "first cut at #2712"

This reverts commit d11143e.

* first cut at #2712 (now for real)

* Add support for structured priceType values (712)

* Fix syntax error

* move new rdfs:comment for priceType

* fix another syntax error
danbri pushed a commit that referenced this issue Oct 21, 2020
* First cut adding support for price components

* Fix syntax error

* Fix typo
@jaygray0919
Copy link

Per #2735 how to specify a period of time? The @UnitPriceSpecification works for us. But we also need to specify: subscription for 1 year, e.g. P1Y.

@jvandriel
Copy link

Would this suffice for what you're trying to accomplish @jaygray0919 ?

{
  "@type": "UnitPriceSpecification",
  "priceComponentType": "https://schema.org/Subscription",
  "price": 15,
  "billingIncrement": 1,
  "unitCode": "ANN",
  "eligibleQuantity": {
    "@type": "QuantitativeValue",
    "value": 1,
    "unitCode": "ANN"
  }
}

@danbri
Copy link
Contributor

danbri commented Oct 21, 2020

I've merged the PR but didn't yet update release notes. @alex-jansen and @mfhepp are still talking about it this week.

Summary of currently commited changes (and links to drafts): "Add support for explicit identification of pricing categories (e.g. of line items in an invoice) such as installments and subscriptions."

@danbri danbri reopened this Oct 21, 2020
@jaygray0919
Copy link

Consider @MediaObject/duration/@Duration. For @MediaObject we can apply an ISO 8601 duration value such as PT60M for 60 minutes.

Now consider @CompoundPriceSpecification/priceComponent/@UnitPriceSpecification/price on @Product/offers/@Offer
How would we specify that, after acquiring the @Product for a price, the maintenance price beginning in the 2nd year is a price?

It seems to us that we need the duration/@Duration for offers/@Offer linked to a @Service and @Product. In each case, the price for the "Thing" in the second period of specific duration might be different than the price in the first period (acquisition time with maintenance included in the price for the first period)

Am I missing a key point in the preceding dialog?

@alex-jansen
Copy link
Contributor Author

@jaygray0919 Taking the example from @jvandriel a bit further, one could have 2 UnitPriceSpecifications under 1 CompoundPriceSpecification, where the first has a discounted price of 180 for the first year and then a price of 249.99 that starts after the first year and runs for 1 or more years.

This would make use of the existing billingIncrement, unitCode, and eligibleQuantity properties together with the billingStart property, which specifies that the 2nd payment starts after the first year.

This leads to the following snippet:

...
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 180,
          "billingIncrement": 1,
          "unitCode": ANN",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "value": 1,
            "unitCode": "ANN"
          }
        },
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 249.99,
          "billingIncrement": 1,
          "billingStart": 2,
          "unitCode": "ANN",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "minValue": 1,
            "unitCode": "ANN"
          }
        }
...

For example markup in the field that does something similar, see:

@jaygray0919
Copy link

@alex-jansen But what if the billingIncrement is something different than 1 (representing 12 months)? It seems to us that duration is needed to specify a period. Otherwise we are on-board with UnitPriceSpecification, especially since it linked with Offer and not just Invoice (which does support billingPeriod/Duration but which does not have a property for a concept like "maintance").

@alex-jansen
Copy link
Contributor Author

@jaygray0919 Agree there must be a way to specify the duration of such periodic payments. Our idea was to use the /eligibleQuantity property for that purpose, so for example a monthly billing of 15 Euro for a duration of 12 months could be expressed as follows.

        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 15,
          "billingIncrement": 1,
          "unitCode": MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitCode": "MON"
          }
        }

After rereading the description of /eligibleQuantity ("The interval and unit of measurement of ordering quantities for which the offer or price specification is valid...") it could be interpreted as being intended for quantities ordered and not so much for time durations (@mfhepp for more insight).

An alternative option would be introducing another property /billingDuration of type /Number, which would lead to the following example:

        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 180,
          "billingIncrement": 1,
          "billingDuration": 12,
          "unitCode": MON",
        }

This means the total price of 180 Euro per year would be paid in increments of 1 month for a duration of 12 months.

Taking this one step further where the price increases to 249.99/year after the first 12 months for a minimum period of, say, 18 additional months:

        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 180,
          "billingIncrement": 1,
          "billingDuration": 12,
          "unitCode": MON",
        },
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 249.99,
          "billingIncrement": 1,
          "billingStart": 13,
          "unitCode": "MON",
          "billingDuration": {
            "@type": "QuantitativeValue",
            "minValue": 18,
            "unitCode": "MON"
          }
        }

The minimum 18 months period requirement means we would require /QuantitativeValue as a type for /billingDuration.

Would an additional property /billingDuration be better than using the existing /eligibleQuantity ?

@jaygray0919
Copy link

How would you feel if billingDuration linked either Number or @Duration? We're just uncomfortable with using a Number to express DateTime. Here's a real-world use case: Price for Period 1 includes Service and Support. Service is the provisioning of some level of capabilty (e.g. software). Support is answering questions. Periods 2-n are Maintenance, Service and Version. Maintenance is changes to an existing Version. Upgrade is access to a new Version. Periods may not be calendar annual, or even annual (12 months). @UnitPriceSpecification is linked to Maintenance, Service, Version and Periods. For example, AWS Service can be annual (for Price A) or monthly (for Price A/8).
IMHO we should use DateTime for types that express or imply DateTime.

@alex-jansen
Copy link
Contributor Author

I don't see a problem adding Duration as an alternative type so happy to submit a pull request for that. How would you express a minimum duration, for example a cell phone wireless contract or an apartment lease for a minimum of 12 months and then extended month-to-month?

@jaygray0919
Copy link

jaygray0919 commented Oct 30, 2020

I'll take that as a challenge and work on a response soon. Our current design has a product identifier for each period. For example, product acquisition for P1Y has a price, product specification, service component and unique @id. Then for a new period (P1Y) there is a service component, price and, of course, unique @id. The @id enables sharing of the service component specification by similar products. The service specification is not specific to @Product. A customer may purchase the @id for the first period and/or subsequent periods. We then can apply a new @UnitPriceSpecification to the aggregate acquisition (i.e. multi-period discount). But all components remain reuseable. We don't have a monthly plan, so i referenced AWS as an example. [aside] We, in fact, use AWS and pay AWS for the months we use the technical support service. When we get larger, we'll take advantage of the P1Y plan for technical support.

danbri pushed a commit that referenced this issue Nov 2, 2020
* add billingDuration per discussion in issue 2689

* fix syntax error

* fix missing comment
@alex-jansen
Copy link
Contributor Author

Added in release 11.0

@rakragh
Copy link

rakragh commented Nov 30, 2021

@jaygray0919 Agree there must be a way to specify the duration of such periodic payments. Our idea was to use the /eligibleQuantity property for that purpose, so for example a monthly billing of 15 Euro for a duration of 12 months could be expressed as follows.

        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 15,
          "billingIncrement": 1,
          "unitCode": MON",
          "eligibleQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitCode": "MON"
          }
        }

After rereading the description of /eligibleQuantity ("The interval and unit of measurement of ordering quantities for which the offer or price specification is valid...") it could be interpreted as being intended for quantities ordered and not so much for time durations (@mfhepp for more insight).

An alternative option would be introducing another property /billingDuration of type /Number, which would lead to the following example:

        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 180,
          "billingIncrement": 1,
          "billingDuration": 12,
          "unitCode": MON",
        }

This means the total price of 180 Euro per year would be paid in increments of 1 month for a duration of 12 months.

Taking this one step further where the price increases to 249.99/year after the first 12 months for a minimum period of, say, 18 additional months:

        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 180,
          "billingIncrement": 1,
          "billingDuration": 12,
          "unitCode": MON",
        },
        {
          "@type": "UnitPriceSpecification",
          "priceComponentType": "https://schema.org/Subscription",
          "price": 249.99,
          "billingIncrement": 1,
          "billingStart": 13,
          "unitCode": "MON",
          "billingDuration": {
            "@type": "QuantitativeValue",
            "minValue": 18,
            "unitCode": "MON"
          }
        }

The minimum 18 months period requirement means we would require /QuantitativeValue as a type for /billingDuration.

Would an additional property /billingDuration be better than using the existing /eligibleQuantity ?

{
  "@type": "UnitPriceSpecification",
  "priceComponentType": "https://schema.org/Subscription",
  "price": 180,
  "billingIncrement": 1,
  "billingDuration": 12,
  "unitCode": "MON"
}

Can't be correct because unitCode is 'MON'. I am sorry but that example confused me.

IMHO: 15/month leads to 180 after 12 month. Everthing else is inconsistent.

{
  "@type": "UnitPriceSpecification",
  "priceComponentType": "https://schema.org/Subscription",
  "price": 15,
  "billingIncrement": 1,
  "billingDuration": 12,
  "unitCode": "MON"
}

I agree with you if we would specify:

{
  "@type": "UnitPriceSpecification",
  "priceComponentType": "https://schema.org/Subscription",
  "price": 180,
  "billingIncrement": 1,
  "billingDuration": 1,
  "unitCode": "ANN"
}

@alex-jansen, Pls confirm or clarify that.

@Laalaa69
Copy link

Laalaa69 commented Aug 7, 2023

Ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants