---
title: "Enroll a customer in card-on-file recurring debits"
method: POST
path: "/subscription-intents"
tags: ["Subscription Intents"]
---

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

`POST /subscription-intents`

## Request

- The document declares no server URL.
- Auth: none declared. Required headers: `ApiKey`, `MerchantId`, `Environment`

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.

## Headers

- `ApiKey` string, required
- `MerchantId` string, required
- `Environment` 'live' | 'sandbox', required

## Request body

- CreateSubscriptionIntentDto
  - `customerReference` string, required: Your reference for the customer being enrolled in card-on-file.
  - `email` string, required: Customer email, to which the enrollment and recurring-debit notifications are sent.
  - `amount` number: 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.
  - `currency` string, required: Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html).
  - `frequency` 'weekly' | 'monthly': Recurring debit frequency. Required for a rbs_scheduled enrollment (the default). Not accepted for a merchant_initiated enrollment.
  - `startDate` string: ISO-8601 date of the first recurring debit. Required for a rbs_scheduled enrollment (the default). Not accepted for a merchant_initiated enrollment.
  - `billingMode` 'rbs_scheduled' | 'merchant_initiated': 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.
  - `consent` ConsentDto, required
    - `given` boolean, required: Must be true — an absent, false, or omitted consent object causes the enrollment to be rejected.
    - `timestamp` string, required: ISO-8601 timestamp of when the customer gave consent.
    - `reference` string, required: 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.
  - `onSuccessRedirectionUrl` string: The url used to redirect the user when the enrollment is successful. You must provide a fully-qualified address using https as the scheme.
  - `onFailedRedirectionUrl` string: The url used to redirect the user when the enrollment fails. You must provide a fully-qualified address using https as the scheme.

## Response `201`

- SubscriptionIntentResponseDto
  - `paymentId` string, required: Id of the underlying enrollment payment.
  - `status` 'successful' | 'failed' | 'pending' | 'action_required', required
  - `action` NextActionDto
    - `type` 'ussd' | 'otp' | 'redirection', required
    - `message` string, required
    - `data` RedirectionDataDto
      - `url` string, required: A fully qualified URL where the customer must be redirected to pursue the payment.
      - `urls` string, required: An array of fully qualified URLs where the customer must be redirected to pursue the payment.
      - `method` string, required: HTTP verb to be used to redirect the customer.
      - `headers` object
      - `data` object: 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.

## Other responses

- `400`: Bad Request
- `401`: Wrong credentials
- `403`: 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`: The authenticated merchant could not be resolved.
- `409`: 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.
- `429`: ThrottlerException: Too Many Requests
- `500`: Internal error
- `503`: Service unavailable

## Changes

- **2026-11-03** `f6d3f87df5e0`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/hub2/apis/hub2-service-api/changes/subscription-intents/post.md)

---

[API](https://skmtc.dev/hub2/apis/hub2-service-api.md) - [All operations](https://skmtc.dev/hub2/apis/hub2-service-api/llms.txt) - [OpenAPI document](https://skmtc.dev/hub2/apis/hub2-service-api/revisions/f6d3f87df5e0?raw)
