> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kelviq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Accept a retention offer

> Applies the retention offer a customer accepted instead of cancelling.

Pass the cancellation reason the customer picked and the offer it maps to. `offerType` has to be the offer configured for that reason in the dashboard retention settings; any other pairing is rejected with `400`. Eligibility is checked again at this point, so an offer that was eligible when you fetched it can still be refused if, for example, the subscription was paused or scheduled to cancel in between.

What happens depends on the offer:

- `DISCOUNT` creates a single-use coupon for the configured percentage and billing cycles and attaches it to the subscription. The response includes the discounted amount and when the discount ends.
- `PAUSE` pauses the subscription for `pauseMonths`, which must be one of the durations returned by [Get retention offers](/api-reference/subscriptions/get-retention-offers). Billing and access resume on the returned date, exactly as a merchant-initiated pause would.
- `SUPPORT` records that the customer took the support offer and returns the configured support URL to send them to. Nothing changes on the subscription.

Every acceptance is recorded against the subscription and counted by the organization's offer repeat policy, so a customer cannot stack discounts or pause indefinitely by reopening the cancellation flow.

<Info>Click the base URL in the API playground and select the **Sandbox** host for test data or the **Production** host for live data. Use credentials from the same environment.</Info>


## OpenAPI

````yaml /api-reference/openapi.json post /subscriptions/{subscriptionId}/retention/accept/
openapi: 3.0.0
info:
  title: kelviq API
  version: 1.0.0
  description: >-
    API for interacting with kelviq services, derived from Python SDK
    documentation.
servers:
  - url: https://sandboxapi.kelviq.com/api/v1
    description: Sandbox — Test payments
  - url: https://api.kelviq.com/api/v1
    description: Production — Live payments
security:
  - bearerAuth: []
tags:
  - name: Products
    description: Catalog products.
  - name: Product Settings
    description: Per-product settings (currency, VPN/Tor/proxy, product URL).
  - name: Product Files
    description: Product images and downloadable assets.
  - name: Features
    description: Catalog features that can be granted as plan entitlements.
  - name: Plans
    description: Catalog plans (CRUD, publish, versions, prices).
  - name: Plan Entitlements
    description: Feature entitlements attached to a plan.
  - name: Plan Files
    description: Files attached to plans, and signed download links.
  - name: Media
    description: Generate presigned S3 upload URLs for product/plan images and files.
  - name: Partner
    description: Partner integration APIs (organization provisioning, lookup).
  - name: Charges
    description: >-
      One-time payments charged immediately against a customer's default payment
      method.
  - name: Refunds
    description: Full and partial refunds for paid orders.
  - name: Transactions
    description: >-
      Charges, refunds, disputes, and other financial movements for the
      authenticated organization.
  - name: Payment Methods
    description: Saved customer payment methods (cards, etc.).
  - name: Orders
    description: Completed and resolved orders for the authenticated organization.
  - name: Order Events
    description: Timeline events for a specific order.
  - name: Invoices
    description: Invoices generated for orders and subscription billing cycles.
  - name: Discounts
    description: >-
      Discount codes (coupons) that can be applied to products and plans at
      checkout.
  - name: Webhook Endpoints
    description: >-
      Configure the destination URLs and event subscriptions that receive
      webhook deliveries.
  - name: Webhooks
    description: Delivery logs for webhook events sent to your configured endpoints.
  - name: Checkout Sessions
    description: Merchant-side view of checkout sessions created by customers.
  - name: Checkout Session Events
    description: Timeline events for a specific checkout session.
paths:
  /subscriptions/{subscriptionId}/retention/accept/:
    post:
      tags:
        - Subscriptions
      summary: Accept a retention offer
      description: >-
        Applies the retention offer a customer accepted instead of cancelling.


        Pass the cancellation reason the customer picked and the offer it maps
        to. `offerType` has to be the offer configured for that reason in the
        dashboard retention settings; any other pairing is rejected with `400`.
        Eligibility is checked again at this point, so an offer that was
        eligible when you fetched it can still be refused if, for example, the
        subscription was paused or scheduled to cancel in between.


        What happens depends on the offer:


        - `DISCOUNT` creates a single-use coupon for the configured percentage
        and billing cycles and attaches it to the subscription. The response
        includes the discounted amount and when the discount ends.

        - `PAUSE` pauses the subscription for `pauseMonths`, which must be one
        of the durations returned by [Get retention
        offers](/api-reference/subscriptions/get-retention-offers). Billing and
        access resume on the returned date, exactly as a merchant-initiated
        pause would.

        - `SUPPORT` records that the customer took the support offer and returns
        the configured support URL to send them to. Nothing changes on the
        subscription.


        Every acceptance is recorded against the subscription and counted by the
        organization's offer repeat policy, so a customer cannot stack discounts
        or pause indefinitely by reopening the cancellation flow.
      operationId: acceptRetentionOffer
      parameters:
        - name: subscriptionId
          in: path
          required: true
          description: The unique identifier of the subscription.
          example: 78058918-9746-4280-9b9b-1bd5115eec6e
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AcceptRetentionOfferRequest'
            example:
              offerType: PAUSE
              cancellationFeedback: UNUSED
              pauseMonths: 3
      responses:
        '200':
          description: >-
            The offer was applied. The fields after `cancellationFeedback`
            depend on `offerType`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcceptRetentionOfferResponse'
              examples:
                discount:
                  summary: Discount applied
                  value:
                    message: Discount applied successfully
                    subscriptionId: 78058918-9746-4280-9b9b-1bd5115eec6e
                    offerType: DISCOUNT
                    cancellationFeedback: TOO_EXPENSIVE
                    percentageOff: 20
                    billingCycles: 3
                    appliesUntil: '2027-01-01T00:00:00Z'
                    originalAmount: '50.00'
                    discountedAmount: '40.00'
                pause:
                  summary: Subscription paused
                  value:
                    message: Subscription paused successfully
                    subscriptionId: 78058918-9746-4280-9b9b-1bd5115eec6e
                    offerType: PAUSE
                    cancellationFeedback: UNUSED
                    pauseMonths: 3
                    resumesAt: '2027-02-01T00:00:00Z'
                support:
                  summary: Support link issued
                  value:
                    message: Support link issued
                    subscriptionId: 78058918-9746-4280-9b9b-1bd5115eec6e
                    offerType: SUPPORT
                    cancellationFeedback: CUSTOMER_SERVICE
                    url: https://cal.com/acme/15min
        '400':
          description: >-
            Validation failed, the offer is not the one configured for this
            reason, the subscription is not eligible, or retention is switched
            off. Field errors are keyed by field name; everything else is
            reported in `detail`.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
              examples:
                notConfiguredForReason:
                  summary: Offer not mapped to this reason
                  value:
                    detail: That offer is not available for this reason.
                alreadyTaken:
                  summary: Repeat policy
                  value:
                    detail: This offer has already been used on this subscription.
                invalidField:
                  summary: Validation error
                  value:
                    offerType:
                      - >-
                        offer_type must be one of ['DISCOUNT', 'PAUSE',
                        'SUPPORT', 'NONE'].
components:
  schemas:
    AcceptRetentionOfferRequest:
      type: object
      required:
        - offerType
        - cancellationFeedback
      properties:
        offerType:
          type: string
          enum:
            - DISCOUNT
            - PAUSE
            - SUPPORT
          description: >-
            The offer to apply. Must be the offer configured for
            `cancellationFeedback`.
          example: PAUSE
        cancellationFeedback:
          type: string
          enum:
            - TOO_EXPENSIVE
            - MISSING_FEATURES
            - SWITCHED_SERVICE
            - UNUSED
            - CUSTOMER_SERVICE
            - LOW_QUALITY
            - TOO_COMPLEX
            - OTHER
          description: The cancellation reason the customer picked.
          example: UNUSED
        pauseMonths:
          type: integer
          nullable: true
          minimum: 1
          description: >-
            Required when `offerType` is `PAUSE`. Must be one of the `durations`
            returned by Get retention offers.
          example: 3
    AcceptRetentionOfferResponse:
      type: object
      properties:
        message:
          type: string
          example: Subscription paused successfully
        subscriptionId:
          type: string
          format: uuid
        offerType:
          type: string
          enum:
            - DISCOUNT
            - PAUSE
            - SUPPORT
        cancellationFeedback:
          type: string
          enum:
            - TOO_EXPENSIVE
            - MISSING_FEATURES
            - SWITCHED_SERVICE
            - UNUSED
            - CUSTOMER_SERVICE
            - LOW_QUALITY
            - TOO_COMPLEX
            - OTHER
        percentageOff:
          type: integer
          description: '`DISCOUNT` only.'
          example: 20
        billingCycles:
          type: integer
          description: '`DISCOUNT` only.'
          example: 3
        appliesUntil:
          type: string
          format: date-time
          nullable: true
          description: >-
            `DISCOUNT` only. When the discount stops applying, or `null` when it
            applies to a single invoice.
        originalAmount:
          type: string
          description: '`DISCOUNT` only. The amount billed per period before the discount.'
          example: '50.00'
        discountedAmount:
          type: string
          description: >-
            `DISCOUNT` only. The amount billed per period while the discount
            lasts.
          example: '40.00'
        pauseMonths:
          type: integer
          description: '`PAUSE` only.'
          example: 3
        resumesAt:
          type: string
          format: date-time
          description: '`PAUSE` only. When billing and access resume.'
        url:
          type: string
          description: '`SUPPORT` only. The support URL to send the customer to.'
          example: https://cal.com/acme/15min
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        The Server API Key obtained from the kelviq application. Pass as a
        Bearer token in the Authorization header. Example: 'Authorization:
        Bearer __YOUR_API_KEY__'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.