openapi: 3.0.0
info:
  title: Subscriptions
  version: "1.0"
  description: Read the subscriptions and memberships of the signed-in contact,
    cancel a subscription, read the products a subscription can be upgraded to,
    and change the saved payment method of a subscription.
tags:
  - name: Subscriptions
paths:
  /subscriptions/subscriptions:
    get:
      operationId: listSubscriptions
      summary: List subscriptions
      description: >-
        Returns every subscription of the contact in the bearer token. A
        membership is a subscription, so memberships are in this list too.


        The list includes subscriptions that have ended. Read `status` to find
        the ones that are in use.


        The `name` of each subscription is translated. Send an `Accept-Language`
        header to choose the language.
      tags:
        - Subscriptions
      parameters:
        - $ref: "#/components/parameters/AcceptLanguage"
      responses:
        "200":
          description: The subscriptions of the contact. The array is empty when the
            contact has none.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Subscription"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /subscriptions/subscription/{subscriptionId}/cancel:
    post:
      operationId: cancelSubscription
      summary: Cancel a subscription
      description: >-
        Requests cancellation of a subscription of the contact in the bearer
        token. The request has no body.


        Only call this when `billingSchedule.isUserCancellable` is `true` and
        `canManage` is `true` for the subscription.


        After the request succeeds, [List
        subscriptions](/docs/api/subscriptions/list-subscriptions) returns the
        subscription with the status `Cancelled`. `state.activeUntil` is the
        date until which the contact keeps the benefits of the subscription.
        [Withdraw a cancellation](/docs/api/subscriptions/withdraw-cancellation)
        reverses the request.
      tags:
        - Subscriptions
      parameters:
        - $ref: "#/components/parameters/SubscriptionId"
      responses:
        "200":
          $ref: "#/components/responses/SubscriptionChanged"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/SubscriptionNotFound"
  /subscriptions/subscription/{subscriptionId}/withdrawcancel:
    post:
      operationId: withdrawCancellation
      summary: Withdraw a cancellation
      description: >-
        Reverses an earlier [Cancel a
        subscription](/docs/api/subscriptions/cancel-subscription) request, so
        that the subscription continues. The request has no body.


        After the request succeeds, [List
        subscriptions](/docs/api/subscriptions/list-subscriptions) no longer
        returns the subscription with the status `Cancelled`.
      tags:
        - Subscriptions
      parameters:
        - $ref: "#/components/parameters/SubscriptionId"
      responses:
        "200":
          $ref: "#/components/responses/SubscriptionChanged"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/SubscriptionNotFound"
  /subscriptions/subscription/{subscriptionId}/upgrade:
    get:
      operationId: getUpgradeTargets
      summary: Get upgrade targets
      description: >-
        Returns the products that one subscription of the contact can be
        upgraded to.


        To upgrade, add one of the returned products to a basket with [Add
        product to basket](/docs/api/baskets/add-product-to-basket). Send the
        `productId`, the `variantId` as `productVariantId`, the
        `subscriptionKey`, and the id of the current subscription as
        `subscriptionUpgradeId`. Then check out the basket.
      tags:
        - Subscriptions
      parameters:
        - $ref: "#/components/parameters/SubscriptionId"
      responses:
        "200":
          description: The upgrade targets of the subscription. `upgradeTargets` is empty
            when the subscription cannot be upgraded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpgradeTargets"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/SubscriptionNotFound"
        "409":
          $ref: "#/components/responses/Conflict"
  /subscriptions/subscriptions/upgrade:
    get:
      operationId: getUpgradeTargetsForContact
      summary: Get upgrade targets of the contact
      deprecated: true
      description: >-
        Returns the upgrade targets of one active subscription of the contact.
        When the contact has more than one active subscription, the API chooses
        one of them, and you cannot control which.


        Use [Get upgrade targets](/docs/api/subscriptions/get-upgrade-targets)
        instead. It takes the id of the subscription.
      tags:
        - Subscriptions
      responses:
        "200":
          description: The upgrade targets of one active subscription of the contact.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpgradeTargets"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: The contact has no active subscription.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"
        "409":
          $ref: "#/components/responses/Conflict"
  /subscriptions/subscription/{subscriptionId}/update-payment-method:
    post:
      operationId: updatePaymentMethod
      summary: Update the payment method
      description: >-
        Changes the saved payment method that renewals of one subscription are
        charged to.


        The body contains a signed payment method id. The payment provider API
        of the store returns it after the contact has authorised a new payment
        method. OneBasket checks the signature and checks that the payment
        method belongs to the contact in the bearer token. A value that fails
        either check returns `400`.


        After the request succeeds, [List
        subscriptions](/docs/api/subscriptions/list-subscriptions) returns the
        subscription with the new `paymentMethodId`.
      tags:
        - Subscriptions
      parameters:
        - $ref: "#/components/parameters/SubscriptionId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePaymentMethodRequest"
      responses:
        "200":
          $ref: "#/components/responses/SubscriptionChanged"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/SubscriptionNotFound"
  /subscriptions/subscriptions/update-payment-method:
    post:
      operationId: updatePaymentMethodBatch
      summary: Update the payment method of several subscriptions
      description: >-
        Changes the saved payment method of several subscriptions of the contact
        in one request. See [Update the payment
        method](/docs/api/subscriptions/update-payment-method) for how to obtain
        the signed payment method id.


        The response has one result for each subscription id in the request. The
        request returns `200` even when some subscriptions could not be updated,
        so check `updated` on every result.
      tags:
        - Subscriptions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePaymentMethodBatchRequest"
      responses:
        "200":
          description: One result for each subscription id in the request.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/UpdatePaymentMethodResult"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
security:
  - BearerAuth: []
    ApiKeyAuth: []
components:
  parameters:
    SubscriptionId:
      name: subscriptionId
      in: path
      required: true
      description: The id of a subscription of the contact, from [List
        subscriptions](/docs/api/subscriptions/list-subscriptions).
      schema:
        type: string
        format: uuid
    AcceptLanguage:
      name: Accept-Language
      in: header
      required: false
      description: The language of translated text in the response, for example
        `en-GB`. The store default is used when the header is missing or the
        language is not supported.
      schema:
        type: string
  responses:
    SubscriptionChanged:
      description: The subscription was changed. Do not read the response body. Call
        [List subscriptions](/docs/api/subscriptions/list-subscriptions) to read
        the new state of the subscription.
    BadRequest:
      description: The request is not valid.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/ProblemDetails"
    Unauthorized:
      description: The API key or the bearer token is missing or not valid.
    SubscriptionNotFound:
      description: The contact has no subscription with this id.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/ProblemDetails"
    Conflict:
      description: The upgrade targets cannot be calculated for the subscription in
        its current state.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/ProblemDetails"
  schemas:
    Subscription:
      type: object
      required:
        - id
        - key
        - source
        - state
        - createdAt
        - billingSchedule
        - isExternallyManaged
        - canManage
      properties:
        id:
          type: string
          format: uuid
          description: The id of the subscription.
        key:
          type: string
          description: The subscription key of the product that was bought. It is the same
            value as `subscriptionKey` in the Catalogues and Baskets APIs.
        name:
          type: string
          nullable: true
          description: The name of the subscription product, translated.
        status:
          type: string
          nullable: true
          description: The status of the subscription. `Trial` and `Active` mean the
            subscription is in use. `Overdue` means a renewal payment failed and
            will be tried again. `Cancelled` means cancellation was requested.
            The contact keeps the benefits until `state.activeUntil`. `Unknown`
            is returned when a renewal payment failed and will not be tried
            again automatically. In that case `state.type` is
            `renewal_payment_failed`.
          enum:
            - Trial
            - Active
            - Overdue
            - Paused
            - Cancelled
            - Expired
            - Suspended
            - Replaced
            - Refunded
            - Unknown
        state:
          $ref: "#/components/schemas/SubscriptionState"
        source:
          type: string
          description: A label for the system that created the subscription.
        createdAt:
          type: string
          format: date-time
        billingSchedule:
          $ref: "#/components/schemas/BillingSchedule"
        price:
          allOf:
            - $ref: "#/components/schemas/Money"
          nullable: true
          description: The price of one billing period.
        isExternallyManaged:
          type: boolean
          description: When `true`, the subscription is billed by a system outside
            OneBasket, such as a mobile app store. It cannot be cancelled,
            upgraded or given a new payment method through this API.
        paymentMethodId:
          type: string
          nullable: true
          description: The id of the saved payment method that renewals are charged to.
        assigneeContactId:
          type: string
          nullable: true
          description: The contact that receives the benefits of the subscription, when
            that is a different contact from the one who pays for it.
        canManage:
          type: boolean
          description: Whether the contact in the bearer token is allowed to cancel the
            subscription or change it. It is `false` when the contact only
            receives the benefits of a subscription that another contact pays
            for.
    SubscriptionState:
      description: Details of the current state of the subscription. The properties
        depend on `type`. `state` is `null` for a status that has no details,
        such as `Expired`.
      nullable: true
      oneOf:
        - $ref: "#/components/schemas/ActiveState"
        - $ref: "#/components/schemas/TrialState"
        - $ref: "#/components/schemas/CancelledState"
        - $ref: "#/components/schemas/OverdueState"
        - $ref: "#/components/schemas/RenewalPaymentFailedState"
      discriminator:
        propertyName: type
        mapping:
          active: "#/components/schemas/ActiveState"
          trial: "#/components/schemas/TrialState"
          cancelled: "#/components/schemas/CancelledState"
          overdue: "#/components/schemas/OverdueState"
          renewal_payment_failed: "#/components/schemas/RenewalPaymentFailedState"
    ActiveState:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - active
        nextBillingDate:
          type: string
          format: date-time
          nullable: true
          description: When the next renewal payment is taken.
    TrialState:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - trial
        trialEndDate:
          type: string
          format: date-time
          nullable: true
          description: When the trial ends and the first payment is taken.
    CancelledState:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - cancelled
        requestedAt:
          type: string
          format: date-time
          nullable: true
          description: When cancellation was requested.
        cancelledAt:
          type: string
          format: date-time
          nullable: true
          description: When the subscription was cancelled.
        activeUntil:
          type: string
          format: date-time
          nullable: true
          description: The contact keeps the benefits of the subscription until this date.
    OverdueState:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - overdue
        nextBillingDate:
          type: string
          format: date-time
          nullable: true
          description: When the failed renewal payment is tried again.
    RenewalPaymentFailedState:
      type: object
      required:
        - type
        - failedAt
      properties:
        type:
          type: string
          enum:
            - renewal_payment_failed
        failedAt:
          type: string
          format: date-time
          description: When the renewal payment failed.
    BillingSchedule:
      description: How the subscription is billed. The properties depend on `type`.
      oneOf:
        - $ref: "#/components/schemas/RecurringBillingSchedule"
        - $ref: "#/components/schemas/FixedTermBillingSchedule"
        - $ref: "#/components/schemas/ManualBillingSchedule"
      discriminator:
        propertyName: type
        mapping:
          recurring: "#/components/schemas/RecurringBillingSchedule"
          fixed-term: "#/components/schemas/FixedTermBillingSchedule"
          manual: "#/components/schemas/ManualBillingSchedule"
    RecurringBillingSchedule:
      type: object
      description: The subscription renews automatically at the end of every period.
      required:
        - type
        - isUserCancellable
        - isAdminCancellable
        - renewalDate
      properties:
        type:
          type: string
          enum:
            - recurring
        isUserCancellable:
          type: boolean
          description: Whether the contact is allowed to cancel the subscription with
            [Cancel a
            subscription](/docs/api/subscriptions/cancel-subscription).
        isAdminCancellable:
          type: boolean
          description: Whether the staff of the organisation are allowed to cancel the
            subscription.
        period:
          type: string
          nullable: true
          description: The length of one billing period, written as a number and a unit.
            For example `1M` is one month and `1Y` is one year.
          example: 1M
        renewalDate:
          type: string
          format: date-time
          description: The end of the current billing period.
    FixedTermBillingSchedule:
      type: object
      description: The subscription runs between two fixed dates, such as one season.
        It does not renew automatically. See [Get renewal
        options](/docs/api/subscriptions/get-renewal-options).
      required:
        - type
        - isUserCancellable
        - isAdminCancellable
      properties:
        type:
          type: string
          enum:
            - fixed-term
        isUserCancellable:
          type: boolean
        isAdminCancellable:
          type: boolean
        startDate:
          type: string
          format: date-time
          nullable: true
        endDate:
          type: string
          format: date-time
          nullable: true
    ManualBillingSchedule:
      type: object
      description: OneBasket does not bill the subscription on a schedule.
      required:
        - type
        - isUserCancellable
        - isAdminCancellable
      properties:
        type:
          type: string
          enum:
            - manual
        isUserCancellable:
          type: boolean
        isAdminCancellable:
          type: boolean
    Money:
      type: object
      required:
        - minorUnits
        - currencyCode
      properties:
        minorUnits:
          type: integer
          description: The amount in the smallest unit of the currency. For example `499`
            with `GBP` is £4.99.
          example: 499
        currencyCode:
          type: string
          description: The ISO 4217 currency code.
          example: GBP
    UpgradeTargets:
      type: object
      required:
        - id
        - upgradeTargets
      properties:
        id:
          type: string
          format: uuid
          description: The id of the subscription that the upgrade targets belong to. Send
            it as `subscriptionUpgradeId` when you add an upgrade target to a
            basket.
        upgradeTargets:
          type: array
          items:
            $ref: "#/components/schemas/UpgradeTarget"
    UpgradeTarget:
      type: object
      description: A product that the subscription can be upgraded to.
      required:
        - productId
        - subscriptionKey
      properties:
        productId:
          type: string
        variantId:
          type: string
          nullable: true
        subscriptionKey:
          type: string
    UpdatePaymentMethodRequest:
      type: object
      required:
        - signedPaymentMethodId
      properties:
        signedPaymentMethodId:
          type: string
          description: The signed payment method id returned by the payment provider API
            of the store.
    UpdatePaymentMethodBatchRequest:
      type: object
      required:
        - signedPaymentMethodId
        - subscriptionIds
      properties:
        signedPaymentMethodId:
          type: string
          description: The signed payment method id returned by the payment provider API
            of the store.
        subscriptionIds:
          type: array
          minItems: 1
          description: The ids of the subscriptions to update.
          items:
            type: string
            format: uuid
    UpdatePaymentMethodResult:
      type: object
      required:
        - subscriptionId
        - updated
      properties:
        subscriptionId:
          type: string
          format: uuid
        updated:
          type: boolean
          description: Whether the payment method of this subscription was changed.
    ProblemDetails:
      type: object
      description: An error in the problem details format. See [Errors](/docs/errors).
      properties:
        type:
          type: string
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
servers:
  - url: "{baseUrl}"
    description: Your Storefront API host
    variables:
      baseUrl:
        default: https://your-storefront-api-host
        description: The Storefront API base URL for your store. Your Stadion technical
          contact provides it.
