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

# Create a subscription

> Ask the merchant to subscribe monthly or yearly. Requires the WRITE_CHARGES scope.

Creates a subscription and returns a `confirmationUrl`. Renewals are taken from the wallet the merchant picks. See [Payments](https://docs.salesive.com/apps/payments.md).


## OpenAPI

````yaml apps-api/specs/billing.json POST /app-billing/subscriptions
openapi: 3.1.0
info:
  title: 'Salesive Apps API: Billing'
  version: 1.0.0
  description: >-
    Charge the merchant a store is installed for, once or on a schedule. Every
    endpoint authenticates with an installed-app access token (prefix `app_`).
    Creating a charge or subscription never moves money: the store owner
    approves it in the dashboard first. Salesive keeps 5% of every payment and
    credits the rest to your payout store's wallet.
servers:
  - url: https://api.salesive.com/api/v1
    description: Production
security:
  - AppToken: []
paths:
  /app-billing/subscriptions:
    post:
      tags:
        - Subscriptions
      summary: Create a subscription
      description: >-
        Asks the merchant to subscribe. They approve once at `confirmationUrl`
        and pick the wallet to pay from. The first period is taken on approval,
        and every renewal after that is taken from that wallet automatically,
        with an email to the merchant 3 days before. A failed renewal is retried
        daily and the subscription ends after 3 failures. Subscriptions are
        wallet only. Requires `WRITE_CHARGES`. Authenticate with `Authorization:
        Bearer app_<token>`. The store is bound to the token server-side, never
        send a shop id.
      operationId: createSubscription
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - amount
                - currency
                - interval
              properties:
                name:
                  type: string
                  maxLength: 120
                  description: What the merchant sees, for example `Pro plan`.
                description:
                  type: string
                  maxLength: 500
                amount:
                  type: number
                  description: >-
                    Price in `currency`, two decimals at most. USD 1 to 1000,
                    NGN 500 to 1,500,000.
                currency:
                  type: string
                  enum:
                    - USD
                    - NGN
                returnUrl:
                  type: string
                  description: >-
                    Where the merchant goes after approving or declining. Must
                    be on your app URL's origin or one of your redirect URIs.
                idempotencyKey:
                  type: string
                  maxLength: 120
                  description: >-
                    Send the same key on a retry and you get the same charge
                    back with `200` instead of a duplicate.
                metadata:
                  type: object
                  description: Up to 20 keys and 2 KB. Returned on every read.
                interval:
                  type: string
                  enum:
                    - month
                    - year
            example:
              name: Pro plan
              amount: 10
              currency: USD
              interval: month
              returnUrl: https://myapp.example.com/billing/done
      responses:
        '200':
          description: A subscription with this `idempotencyKey` already existed.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/EnvelopeBase'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Subscription'
              example:
                status: 200
                success: true
                message: Subscription already exists
                data:
                  id: 66d1f0a3c2d4e5f6a7b8c9d1
                  reference: aps_8c21e0b4a96f47d3
                  status: pending
                  name: Pro plan
                  description: null
                  amount: 10
                  currency: USD
                  interval: month
                  platformFee: 0.5
                  netAmount: 9.5
                  currentPeriodStart: null
                  currentPeriodEnd: null
                  nextChargeAt: null
                  cancelAtPeriodEnd: false
                  cancelledAt: null
                  cancelledBy: null
                  cancelReason: null
                  cycles: 0
                  failures: 0
                  lastFailureReason: null
                  test: false
                  metadata: null
                  returnUrl: null
                  confirmationUrl: >-
                    https://app.salesive.com/apps/billing/approve/aps_8c21e0b4a96f47d3
                  expiresAt: '2026-10-27T10:30:00.000Z'
                  createdAt: '2026-10-25T10:30:00.000Z'
        '201':
          description: The subscription was created.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/EnvelopeBase'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Subscription'
              example:
                status: 201
                success: true
                message: Subscription created
                data:
                  id: 66d1f0a3c2d4e5f6a7b8c9d1
                  reference: aps_8c21e0b4a96f47d3
                  status: pending
                  name: Pro plan
                  description: null
                  amount: 10
                  currency: USD
                  interval: month
                  platformFee: 0.5
                  netAmount: 9.5
                  currentPeriodStart: null
                  currentPeriodEnd: null
                  nextChargeAt: null
                  cancelAtPeriodEnd: false
                  cancelledAt: null
                  cancelledBy: null
                  cancelReason: null
                  cycles: 0
                  failures: 0
                  lastFailureReason: null
                  test: false
                  metadata: null
                  returnUrl: null
                  confirmationUrl: >-
                    https://app.salesive.com/apps/billing/approve/aps_8c21e0b4a96f47d3
                  expiresAt: '2026-10-27T10:30:00.000Z'
                  createdAt: '2026-10-25T10:30:00.000Z'
        '400':
          description: Invalid body or amount out of range.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope'
              example:
                status: 400
                success: false
                message: amount must be between 1 and 1000 USD
                data: null
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          description: Too many requests are waiting for the merchant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope'
              example:
                status: 429
                success: false
                message: >-
                  Too many requests are waiting for the merchant. Wait for them
                  to be approved or expire.
                data: null
components:
  schemas:
    EnvelopeBase:
      type: object
      description: >-
        Standard Salesive response envelope. The operation-specific payload is
        carried in `data`.
      required:
        - status
        - success
        - message
      properties:
        status:
          type: integer
          description: HTTP status code, echoed in the body.
        success:
          type: boolean
          description: Whether the request succeeded.
        message:
          type: string
          description: Human-readable result message.
    Subscription:
      type: object
      description: >-
        A recurring charge. The merchant approves once and picks a wallet, then
        each period is taken from that wallet automatically.
      properties:
        id:
          type: string
        reference:
          type: string
          description: Starts with `aps_`.
        status:
          type: string
          enum:
            - pending
            - activating
            - active
            - past_due
            - cancelled
            - expired
            - declined
        name:
          type: string
        description:
          type:
            - string
            - 'null'
        amount:
          type: number
        currency:
          type: string
          enum:
            - USD
            - NGN
        interval:
          type: string
          enum:
            - month
            - year
        platformFee:
          type: number
        netAmount:
          type: number
        currentPeriodStart:
          type:
            - string
            - 'null'
          format: date-time
        currentPeriodEnd:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            The merchant has paid up to here. Keep their access on until this
            passes.
        nextChargeAt:
          type:
            - string
            - 'null'
          format: date-time
        cancelAtPeriodEnd:
          type: boolean
        cancelledAt:
          type:
            - string
            - 'null'
          format: date-time
        cancelledBy:
          type:
            - string
            - 'null'
          enum:
            - merchant
            - app
            - system
            - uninstall
            - null
        cancelReason:
          type:
            - string
            - 'null'
        cycles:
          type: integer
          description: Periods paid so far.
        failures:
          type: integer
          description: Failed renewal attempts in a row.
        lastFailureReason:
          type:
            - string
            - 'null'
        test:
          type: boolean
        metadata:
          type:
            - object
            - 'null'
        returnUrl:
          type:
            - string
            - 'null'
        confirmationUrl:
          type:
            - string
            - 'null'
          description: Present only while `pending`.
        expiresAt:
          type:
            - string
            - 'null'
          format: date-time
        createdAt:
          type: string
          format: date-time
    Envelope:
      allOf:
        - $ref: '#/components/schemas/EnvelopeBase'
        - type: object
          properties:
            data:
              description: Operation-specific payload (object, array, or null).
  responses:
    Unauthorized:
      description: Missing or invalid app access token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Envelope'
          example:
            status: 401
            success: false
            message: Authentication required
            data: null
    Forbidden:
      description: The app token is missing the OAuth scope required for this operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Envelope'
          example:
            status: 403
            success: false
            message: Insufficient scope
            data: null
  securitySchemes:
    AppToken:
      type: http
      scheme: bearer
      description: >-
        Installed-app access token (prefix app_), issued by the OAuth install
        flow. The store is bound to the token server-side, never send a shop id.

````

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