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

# Enroll a customer in card-on-file recurring debits

> Starts a card-on-file enrollment and returns the enrollment payment with the action the customer must complete. Poll its outcome with GET /subscription-intents/{id}/status.



## OpenAPI

````yaml post /subscription-intents
openapi: 3.0.0
info:
  title: Hub2 Service · Api
  description: |-
    This is the Hub2 api reference |
          Please check https://docs.hub2.io/ for the full documentation |
          Rate limits of endpoints are here : https://docs.hub2.io/en/details/limits.html.
  version: 2.185.0
  contact:
    name: Hub2
    url: https://www.hub2.io/
    email: contact@hub2.io
servers: []
security: []
tags:
  - name: Payments
    description: >-
      Best known as the PAY-IN API, it provides endpoints for merchants to
      perform Hub2 PAY-IN transactions.
  - name: Transfers
    description: >-
      Best known as the PAY-OUT API, it provides endpoints for merchants to
      perform Hub2 PAY-OUT transactions.
  - name: IRT
    description: International Remittance Transfers
  - name: Balance
    description: ''
  - name: Webhooks
    description: ''
  - name: Provisioning
    description: ''
  - name: Payment on Terminal
    description: ''
  - name: Receipt
    description: ''
  - name: Sms
    description: ''
  - name: Data
    description: ''
  - name: Compliance
    description: ''
  - name: Recipient
    description: ''
  - name: Delegation
    description: ''
  - name: Deposits
    description: ''
  - name: Payment Links
    description: ''
  - name: Subscription Links
    description: ''
  - name: Submerchants
    description: ''
  - name: Bill Payments
    description: ''
  - name: Subscriptions
    description: ''
  - name: Subscription Intents
    description: >-
      Enrolls a customer in card-on-file recurring debits and tracks how each
      enrollment ended.
  - name: Instant Payment
    description: >-
      Instant payment (PI SPI, BCEAO) resources, such as the aliases naming your
      accounts in the national directory.
paths:
  /subscription-intents:
    post:
      tags:
        - Subscription Intents
      summary: Enroll a customer in card-on-file recurring debits
      description: >-
        Starts a card-on-file enrollment and returns the enrollment payment with
        the action the customer must complete. Poll its outcome with GET
        /subscription-intents/{id}/status.
      operationId: SubscriptionIntentsController_create
      parameters:
        - name: ApiKey
          in: header
          description: >-
            Your api key. To create a key, please get into our dashboard. If you
            don't have access to it, please reach the Support team.
          required: true
          schema:
            type: string
        - name: MerchantId
          in: header
          description: >-
            Your merchant ID. This information is available in our dashboard. If
            you don't have access to it, please reach the Support team.
          required: true
          schema:
            type: string
        - name: Environment
          in: header
          description: >-
            Allow you to choose between the sandbox mode to perform some tests
            or the live mode for real world transactions.
          required: true
          schema:
            type: string
            enum:
              - live
              - sandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSubscriptionIntentDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionIntentResponseDto'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiInvalidInputErrorAlias'
        '401':
          description: Wrong credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiUnauthorizedErrorAlias'
        '403':
          description: >-
            Card-on-file is disabled, the merchant is not eligible (not
            registered in Côte d'Ivoire), the merchant is closed or suspended,
            or the merchant owns a merchant group.
        '404':
          description: The authenticated merchant could not be resolved.
        '409':
          description: >-
            Invalid request. Returned with code
            card_on_file_consent_reference_in_use when the merchant reuses a
            consent reference it already enrolled in the other mode, or when a
            sub-merchant reuses one already used by its group owner or by a
            sibling sub-merchant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiInvalidRequestErrorAlias'
        '429':
          description: 'ThrottlerException: Too Many Requests'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiTooManyRequestErrorAlias'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiInternalErrorAlias'
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiUpstreamErrorAlias'
components:
  schemas:
    CreateSubscriptionIntentDto:
      type: object
      properties:
        customerReference:
          type: string
          description: Your reference for the customer being enrolled in card-on-file.
          example: cust_01924059
          maxLength: 255
        email:
          type: string
          description: >-
            Customer email, to which the enrollment and recurring-debit
            notifications are sent.
          example: customer@example.com
        amount:
          type: number
          description: >-
            For a rbs_scheduled enrollment: the recurring debit amount, in the
            smallest currency unit (e.g. 100 cents to charge €1.00) — distinct
            from any amount charged at enrollment time. For merchant_initiated:
            not a recurring amount (ignored in live), and in sandbox it selects
            the simulated enrollment outcome like any enrollment amount would —
            omit it to simulate success.
          example: 5000
          maximum: 9999999999
        currency:
          type: string
          description: >-
            Three-letter [ISO currency
            code](https://www.iso.org/iso-4217-currency-codes.html).
          example: XOF
        frequency:
          type: string
          description: >-
            Recurring debit frequency. Required for a rbs_scheduled enrollment
            (the default). Not accepted for a merchant_initiated enrollment.
          enum:
            - weekly
            - monthly
          example: monthly
        startDate:
          type: string
          description: >-
            ISO-8601 date of the first recurring debit. Required for a
            rbs_scheduled enrollment (the default). Not accepted for a
            merchant_initiated enrollment.
          example: '2026-08-01'
        billingMode:
          type: string
          description: >-
            rbs_scheduled (default) — the customer is debited automatically on
            frequency/startDate/amount. merchant_initiated — the card is stored
            for on-demand charges via POST /subscriptions/{id}/charge; frequency
            and startDate are not accepted, and amount is not a recurring
            amount.
          enum:
            - rbs_scheduled
            - merchant_initiated
          default: rbs_scheduled
          example: rbs_scheduled
        consent:
          description: >-
            Required — per the Visa Stored Credential Framework, no card-on-file
            enrollment can start without an explicit, timestamped consent.
            Absent or invalid consent causes the enrollment to be rejected.
          allOf:
            - $ref: '#/components/schemas/ConsentDto'
        onSuccessRedirectionUrl:
          type: string
          description: >-
            The url used to redirect the user when the enrollment is successful.
            You must provide a fully-qualified address using https as the
            scheme.
          maxLength: 2084
        onFailedRedirectionUrl:
          type: string
          description: >-
            The url used to redirect the user when the enrollment fails. You
            must provide a fully-qualified address using https as the scheme.
          maxLength: 2084
      required:
        - customerReference
        - email
        - currency
        - consent
    SubscriptionIntentResponseDto:
      type: object
      properties:
        paymentId:
          type: string
          description: Id of the underlying enrollment payment.
        status:
          type: string
          enum:
            - successful
            - failed
            - pending
            - action_required
        action:
          description: >-
            Present when status is "action_required". Same shape as a regular
            payment's nextAction (see PaymentDto) — build and auto-submit a form
            from action.data.{url, method, data} to complete card enrollment on
            the hosted card page.
          allOf:
            - $ref: '#/components/schemas/NextActionDto'
      required:
        - paymentId
        - status
    ApiInvalidInputErrorAlias:
      type: object
      properties:
        status:
          type: number
          description: HTTP status.
          enum:
            - 400
          example: 400
        code:
          type: string
          description: >-
            The error code, e.g. `wrong_provider`, `provider_required`,
            `provider_not_allowed`, `invalid_url`, `invalid_sandbox_msisdn`,
            `credit_card_fees_not_supported`,
            `credit_card_provider_not_configured`,
            `credit_card_provider_unavailable`, `payment_method_not_supported`,
            `override_business_id`, `override_business_name`, `signature_error`,
            `merchant_not_found`, `forbidden_special_chars`,
            `ci.mtn.description_too_big`, `reference_required`. `Bad Request`
            for DTO validation failures and other uncoded 400s.
          example: wrong_provider
        message:
          description: >-
            What is wrong with the request. An array of messages when the
            payload fails DTO validation.
          oneOf:
            - type: string
            - type: array
              items:
                type: string
          example: >-
            Provider 'unknown_provider' does not exist for country 'CI' and
            method 'mobile_money'.
        request_id:
          type: string
          description: >-
            Identifier of the request, to quote when contacting the Support
            team.
      required:
        - status
        - code
        - message
        - request_id
    ApiUnauthorizedErrorAlias:
      type: object
      properties:
        status:
          type: number
          description: HTTP error code.
          example: 401
        error:
          description: HTTP error description.
          allOf:
            - $ref: '#/components/schemas/InternalApiUnauthorizedError'
      required:
        - status
        - error
    ApiInvalidRequestErrorAlias:
      type: object
      properties:
        httpStatus:
          type: number
          description: Http status
          enum:
            - 409
          example: 409
        type:
          type: string
          description: Error type
          example: invalid_request
        code:
          type: string
          description: Error code
          enum:
            - unsupported_action
          example: unsupported_action
        message:
          type: string
          description: Error message
          example: This action is not supported
      required:
        - httpStatus
        - type
        - code
        - message
    ApiTooManyRequestErrorAlias:
      type: object
      properties:
        status:
          type: number
          description: status
          enum:
            - 429
          example: 429
        error:
          type: string
          description: Error
          example: 'ThrottlerException: Too Many Requests'
      required:
        - status
        - error
    ApiInternalErrorAlias:
      type: object
      properties:
        type:
          type: string
          description: The type of this error.
          example: internal_error
        code:
          type: string
          description: The error code for this error.
          example:
            - internal_error
            - wrong_credentials
            - not_granted
            - live_mode_not_granted
        message:
          type: string
          description: The error message describing what happens to throw this error.
          example: An error occurred on our system. Please try again later.
      required:
        - type
        - code
        - message
    ApiUpstreamErrorAlias:
      type: object
      properties:
        status:
          type: number
          description: HTTP status.
          enum:
            - 502
            - 503
          example: 503
        code:
          type: string
          description: >-
            The error code. 503: `instant_payment_alias_rail_unavailable`,
            `merchant_group_unavailable` (the merchant group of the caller could
            not be verified, so money movement is refused). 502:
            `instant_payment_alias_not_recorded`,
            `instant_payment_alias_deletion_not_recorded`,
            `instant_payment_alias_divergence`.
          example: merchant_group_unavailable
        message:
          type: string
          description: What went wrong, and whether the call is safe to retry.
          example: >-
            Your merchant group could not be verified. Please retry in a few
            moments.
        request_id:
          type: string
          description: >-
            Identifier of the request, to quote when contacting the Support
            team.
      required:
        - status
        - code
        - message
        - request_id
    ConsentDto:
      type: object
      properties:
        given:
          type: boolean
          description: >-
            Must be true — an absent, false, or omitted consent object causes
            the enrollment to be rejected.
          example: true
        timestamp:
          type: string
          description: ISO-8601 timestamp of when the customer gave consent.
          example: '2026-07-03T10:00:00.000Z'
        reference:
          type: string
          description: >-
            Your reference identifying this consent record on your side.
            Letters, digits and hyphens only, 64 characters at most — any other
            character is refused, because the recurring-billing provider would
            reject the enrollment. Must be unique within your merchant account,
            sub-merchants of your group included; another Hub2 merchant may use
            the same value. A reference already used for another customer, or
            already enrolled for another sub-merchant of your group, makes the
            enrollment fail. One already enrolled in the other mode (sandbox or
            live), or, for a sub-merchant, one already used by its group owner
            or a sibling sub-merchant, is refused with a 409 when the
            subscription intent is created. Reusing it to retry the same
            enrollment is safe.
          example: consent-01924059
          maxLength: 64
      required:
        - given
        - timestamp
        - reference
    NextActionDto:
      type: object
      properties:
        type:
          type: string
          enum:
            - ussd
            - otp
            - redirection
        message:
          type: string
        data:
          description: ''
          allOf:
            - $ref: '#/components/schemas/RedirectionDataDto'
      required:
        - type
        - message
    InternalApiUnauthorizedError:
      type: object
      properties:
        type:
          type: string
          description: The type of this error.
          example: authorization_error
        code:
          type: string
          description: The internal error code describing what happened.
          enum:
            - bad_payment_intent_token
            - wrong_credentials
          example: wrong_credentials
        message:
          type: string
          description: Detailed error message which describe what happened.
          example: L'ID marchand et/ou la clé d'API sont incorrects.
      required:
        - type
        - code
        - message
    RedirectionDataDto:
      type: object
      properties:
        url:
          type: string
          description: >-
            A fully qualified URL where the customer must be redirected to
            pursue the payment.
        urls:
          type: string
          description: >-
            An array of fully qualified URLs where the customer must be
            redirected to pursue the payment.
        method:
          type: string
          description: HTTP verb to be used to redirect the customer.
          example: post
        headers:
          type: object
          description: ''
        data:
          type: object
          description: >-
            Data that need to be used to make the redirection. It could be
            parameters for a GET request or a body payload for a POST.
      required:
        - url
        - urls
        - method

````

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