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

# Create a payment recovery link

> Creates a link the buyer opens, without logging in, to replace the payment method of an
**overdue** subscription and pay what is overdue. Send it to the buyer yourself, by any
channel. It is the same page COPE's payment-failed email and payment reminders link to.

**`url` carries a secret and is shown once.** COPE stores only a digest of it, so it cannot
show the link again. Treat it like a password: send it to the buyer, and do not log or store
it. It stops working after `expires_at` (7 days), and as soon as the subscription is no longer
overdue — paid, cancelled or ended. Creating a link does not invalidate earlier ones,
including the ones COPE emailed.

**`Idempotency-Key` is required.** A repeat with the same key answers `201` with
`Idempotent-Replayed: true` and a **new** `url` for the same link: the secret from the earlier
answer stops working, so a response lost in transit never leaves a working link behind. The
expiry does not move. Only the latest answer under a key works, so do not send concurrent
requests with the same key: both answer `201`, and the first `url` is already dead. A key
binds to one subscription; the same key sent for another subscription creates a separate link
there. A repeat after the link expired is refused with `idempotency_key_spent` (409); use a
new key.

A subscription with nothing to recover is refused with `payment_recovery_not_available`
(422), and `errors[0].code` says why — `not_overdue`, for example. Treat that set of reasons
as open. At most 10 links are created for one subscription in 24 hours, counting the ones COPE
emails; the next is refused with `too_many_payment_recovery_links` (429).

Requires the `subscriptions` permission at `write`. An API key holds a permission at the lower of its own level (`read` for a read-only key) and its holder's role; a key without it is refused with 403.



## OpenAPI

````yaml /api-reference/commerce-v1.openapi.json post /v1/commerce/subscriptions/{id}/payment-recovery-links
openapi: 3.0.3
info:
  description: >-
    Public REST API for COPE vendor integrations. Authenticate with a COPE API
    key and call the endpoints described below.
  title: COPE Public API
  version: v1
servers:
  - description: Production
    url: https://api.cope.com
security:
  - cope_sk: []
paths:
  /v1/commerce/subscriptions/{id}/payment-recovery-links:
    post:
      tags:
        - Subscriptions
      summary: Create a payment recovery link
      description: >-
        Creates a link the buyer opens, without logging in, to replace the
        payment method of an

        **overdue** subscription and pay what is overdue. Send it to the buyer
        yourself, by any

        channel. It is the same page COPE's payment-failed email and payment
        reminders link to.


        **`url` carries a secret and is shown once.** COPE stores only a digest
        of it, so it cannot

        show the link again. Treat it like a password: send it to the buyer, and
        do not log or store

        it. It stops working after `expires_at` (7 days), and as soon as the
        subscription is no longer

        overdue — paid, cancelled or ended. Creating a link does not invalidate
        earlier ones,

        including the ones COPE emailed.


        **`Idempotency-Key` is required.** A repeat with the same key answers
        `201` with

        `Idempotent-Replayed: true` and a **new** `url` for the same link: the
        secret from the earlier

        answer stops working, so a response lost in transit never leaves a
        working link behind. The

        expiry does not move. Only the latest answer under a key works, so do
        not send concurrent

        requests with the same key: both answer `201`, and the first `url` is
        already dead. A key

        binds to one subscription; the same key sent for another subscription
        creates a separate link

        there. A repeat after the link expired is refused with
        `idempotency_key_spent` (409); use a

        new key.


        A subscription with nothing to recover is refused with
        `payment_recovery_not_available`

        (422), and `errors[0].code` says why — `not_overdue`, for example. Treat
        that set of reasons

        as open. At most 10 links are created for one subscription in 24 hours,
        counting the ones COPE

        emails; the next is refused with `too_many_payment_recovery_links`
        (429).


        Requires the `subscriptions` permission at `write`. An API key holds a
        permission at the lower of its own level (`read` for a read-only key)
        and its holder's role; a key without it is refused with 403.
      operationId: commerce.subscriptions.payment_recovery_links.create
      parameters:
        - description: id public identifier.
          example: ps_A1b2C3d4E5f6
          in: path
          name: id
          required: true
          schema:
            example: ps_A1b2C3d4E5f6
            pattern: ^ps_[A-Za-z0-9]{8,32}$
            type: string
        - description: >-
            Required. At most 255 characters of valid UTF-8 with no NUL byte.
            The link is bound to this key. A repeat under the same key answers
            201 with `Idempotent-Replayed: true` and a new `url` for the same
            link: the secret in any earlier answer stops working, so a response
            lost in transit leaves no working link behind, and `expires_at` does
            not move. Only the latest answer under a key works, so do not send
            concurrent requests with the same key. A key binds to one
            subscription. A repeat after the link expired is refused with 409
            `idempotency_key_spent`; send a new key.
          in: header
          name: Idempotency-Key
          required: true
          schema:
            maxLength: 255
            type: string
      requestBody:
        content:
          application/json:
            schema:
              additionalProperties: false
              properties: {}
              type: object
      responses:
        '201':
          content:
            application/json:
              schema:
                additionalProperties: false
                properties:
                  data:
                    additionalProperties: false
                    properties:
                      expires_at:
                        description: When the link stops working.
                        format: date-time
                        type: string
                      object:
                        enum:
                          - payment_recovery_link
                        type: string
                      subscription_id:
                        example: ps_A1b2C3d4E5f6
                        pattern: ^ps_[A-Za-z0-9]{8,32}$
                        type: string
                      url:
                        description: >-
                          The page the buyer opens to replace the payment method
                          and pay what is overdue. It carries a secret: send it
                          to the buyer and do not store or log it. COPE keeps no
                          copy and cannot show it again.
                        format: uri
                        type: string
                    required:
                      - object
                      - url
                      - expires_at
                      - subscription_id
                    type: object
                required:
                  - data
                type: object
          description: Successful response
        '400':
          content:
            application/problem+json:
              examples:
                invalid_request:
                  summary: Invalid request
                  value:
                    code: invalid_request
                    detail: null
                    errors:
                      - code: unsupported
                        detail: funnel_id is not supported by this public endpoint
                        param: funnel_id
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 400
                    title: Invalid Request
                    type: https://docs.cope.com/errors/invalid_request
                unparsable_request:
                  summary: Unparsable request
                  value:
                    code: invalid_request
                    detail: >-
                      The request could not be parsed. Check the query string
                      and the request body.
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 400
                    title: Invalid Request
                    type: https://docs.cope.com/errors/invalid_request
                recovery_link_idempotency_key_required:
                  summary: No Idempotency-Key header
                  value:
                    code: idempotency_key_required
                    detail: >-
                      an Idempotency-Key header is required to create a payment
                      recovery link
                    errors:
                      - code: idempotency_key_required
                        detail: >-
                          an Idempotency-Key header is required to create a
                          payment recovery link
                        param: idempotency_key
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 400
                    title: Idempotency Key Required
                    type: https://docs.cope.com/errors/idempotency_key_required
                subscription_invalid_idempotency_key:
                  summary: Malformed Idempotency-Key header
                  value:
                    code: invalid_idempotency_key
                    detail: >-
                      Idempotency-Key header must be at most 255 characters of
                      valid UTF-8 without a NUL byte
                    errors:
                      - code: invalid_idempotency_key
                        detail: >-
                          Idempotency-Key header must be at most 255 characters
                          of valid UTF-8 without a NUL byte
                        param: idempotency_key
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 400
                    title: Invalid Idempotency Key
                    type: https://docs.cope.com/errors/invalid_idempotency_key
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: Invalid request, or the Idempotency-Key is missing or unusable
        '401':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: Missing or invalid bearer token
        '403':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: Bearer token is not authorized for this route
        '404':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: Resource not found
        '409':
          content:
            application/problem+json:
              examples:
                recovery_link_idempotency_key_spent:
                  summary: The link this key created has expired
                  value:
                    code: idempotency_key_spent
                    detail: >-
                      the payment recovery link created under this
                      Idempotency-Key has expired; use a new key
                    errors:
                      - code: idempotency_key_spent
                        detail: >-
                          the payment recovery link created under this
                          Idempotency-Key has expired; use a new key
                        param: idempotency_key
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 409
                    title: Idempotency Key Spent
                    type: https://docs.cope.com/errors/idempotency_key_spent
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: >-
            The link this Idempotency-Key created has expired. Send a new key
            for a new link.
        '422':
          content:
            application/problem+json:
              examples:
                recovery_link_validation_failed:
                  summary: The body carries a member
                  value:
                    code: validation_failed
                    detail: null
                    errors:
                      - code: unsupported
                        detail: >-
                          expires_in_days is not supported by this public
                          endpoint
                        param: expires_in_days
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 422
                    title: Validation Failed
                    type: https://docs.cope.com/errors/validation_failed
                payment_recovery_not_available:
                  summary: The subscription has nothing to recover
                  value:
                    code: payment_recovery_not_available
                    detail: the subscription has no overdue payment to recover
                    errors:
                      - code: not_overdue
                        detail: the subscription has no overdue payment to recover
                        param: subscription_id
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 422
                    title: Payment Recovery Not Available
                    type: >-
                      https://docs.cope.com/errors/payment_recovery_not_available
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: >-
            The body carries a member, or the subscription has nothing to
            recover. `errors[0].code` names the reason; treat the set of reasons
            as open.
        '429':
          content:
            application/problem+json:
              examples:
                too_many_payment_recovery_links:
                  summary: >-
                    Ten links were created for this subscription in the last 24
                    hours
                  value:
                    code: too_many_payment_recovery_links
                    detail: >-
                      at most 10 payment recovery links are created for one
                      subscription in 24 hours
                    errors:
                      - code: rate_limited
                        detail: >-
                          at most 10 payment recovery links are created for one
                          subscription in 24 hours
                        param: subscription_id
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 429
                    title: Too Many Payment Recovery Links
                    type: >-
                      https://docs.cope.com/errors/too_many_payment_recovery_links
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: >-
            10 links were already created for this subscription in the last 24
            hours, counting the ones COPE emails. Earlier links still work.
        '503':
          content:
            application/problem+json:
              examples:
                user_not_ready:
                  summary: The key's user is not available yet
                  value:
                    code: user_not_ready
                    detail: Retry after 2 seconds
                    errors:
                      - code: user_not_ready
                        detail: Retry after 2 seconds
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 503
                    title: User Not Ready
                    type: https://docs.cope.com/errors/user_not_ready
                tenant_not_ready:
                  summary: The key's business is not available yet
                  value:
                    code: tenant_not_ready
                    detail: Retry after 2 seconds
                    errors:
                      - code: tenant_not_ready
                        detail: Retry after 2 seconds
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 503
                    title: Tenant Not Ready
                    type: https://docs.cope.com/errors/tenant_not_ready
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: >-
            The API key is valid but its user or business is not available to
            this API yet (`user_not_ready`, `tenant_not_ready`). Retry after the
            `Retry-After` seconds.
        '504':
          content:
            application/problem+json:
              examples:
                gateway_timeout:
                  summary: The request did not complete in time
                  value:
                    code: gateway_timeout
                    detail: The request did not complete in time
                    errors:
                      - code: gateway_timeout
                        detail: The request did not complete in time
                    request_id: 0b6e3f2a-8c4d-4f1e-9a7b-5d2c8e1f4a90
                    status: 504
                    title: Gateway Timeout
                    type: https://docs.cope.com/errors/gateway_timeout
              schema:
                $ref: '#/components/schemas/PublicProblemDetail'
          description: >-
            The request did not complete in time, so a link may have been
            created. Repeat it under the same Idempotency-Key: the answer is the
            same link under a new secret, and any secret it was given before
            stops working.
      security:
        - cope_sk: []
components:
  schemas:
    PublicProblemDetail:
      additionalProperties: false
      properties:
        code:
          type: string
        detail:
          nullable: true
          type: string
        errors:
          items:
            additionalProperties: false
            properties:
              code:
                type: string
              detail:
                type: string
              param:
                type: string
            required:
              - code
              - detail
            type: object
          type: array
        request_id:
          description: >-
            Correlates this response with COPE's logs; the response also carries
            it as `X-Request-Id`. It is the `X-Request-Id` you sent when that is
            1-128 letters, digits, `_`, `@` or `-`, and otherwise one COPE
            generated. Quote it when you contact support.
          type: string
        status:
          type: integer
        title:
          type: string
        type:
          type: string
      required:
        - type
        - title
        - status
        - code
        - request_id
      type: object
  securitySchemes:
    cope_sk:
      description: >-
        Bearer credential for the public API: a live COPE API key (`ck_live_*`;
        keys issued earlier as `cope_sk_live_*` keep working). Dashboard sign-in
        tokens are not accepted.
      scheme: bearer
      type: http

````

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