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

# iOS Custom Card Component (Non-PCI)

> Integrate the Cashfree Subscription Custom Card Component into your iOS application to accept subscription payments without handling raw card data.

The Cashfree Subscription Custom Card Component lets you embed a secure, SDK-managed card input field directly into your iOS application UI. The `CFSubsCardComponent` captures and processes the card number entirely within the SDK. Your application never receives the raw card number.

This integration is suitable for non-PCI merchants. A non-PCI merchant is not certified to store, process, or transmit raw cardholder data and relies on the SDK to handle card data securely on their behalf.

The component provides auto-formatted card number input (groups of four digits), real-time card network detection with icon display, Luhn validation on every keystroke, and automatic BIN lookup after eight digits. Metadata is delivered through `CFSubsCardListener`. You receive only digit count, Luhn result, and BIN info, not the raw card number.

<Note>
  This page covers the custom card component integration only. For the full iOS Subscription Element integration, including UPI and eNach (net banking), see [iOS Integration](/payments/subscription/custom-checkout/mobile/ios-subscription-element).
</Note>

<Note>
  For merchants with raw card access (PCI-DSS certified), use `.setCardNumber()` on `CFCardSubs.CFCardSubsBuilder()` directly instead of `CFSubsCardComponent`. That path follows the standard subscription card flow.
</Note>

## Prerequisites

Complete the following tasks before you start the integration:

* Create a [Cashfree Merchant Account](https://merchant.cashfree.com/merchants/signup).
* Log in to the [Merchant Dashboard](https://merchant.cashfree.com/auth/login) and generate an **App ID** and **Secret Key**. Learn how to [generate API keys](/api-reference/authentication#generate-api-keys).
* Use Cashfree iOS SDK version **2.4.0** or above.
* Set your application's minimum deployment target to **iOS 13.0** or higher.

The integration consists of three steps:

<CardGroup cols={3}>
  <Card title="Step 1" icon="money-bill-wave" href="/payments/subscription/custom-checkout/custom-card/ios-custom-card#step-1-create-a-subscription-server-side">
    Create a subscription
  </Card>

  <Card title="Step 2" icon="desktop" href="/payments/subscription/custom-checkout/custom-card/ios-custom-card#step-2-open-the-payment-page-client-side">
    Open the payment page
  </Card>

  <Card title="Step 3" icon="circle-check" href="/payments/subscription/custom-checkout/custom-card/ios-custom-card#step-3-confirm-the-payment-server-side">
    Confirm the payment
  </Card>
</CardGroup>

## Step 1: Create a subscription <Badge color="green">Server-side</Badge>

Create a subscription from your backend server before you process any payment.

<Note>This API requires your secret key. Create subscriptions through your server only. Do not call this API directly from your mobile application.</Note>

After the subscription is created, your backend receives a `subscription_id` and a `subscription_session_id`. Pass both values to your iOS client to proceed with the payment.

<AccordionGroup>
  <Accordion title="API request for creating a subscription">
    The following example shows how to create a subscription using the Create Subscription API:

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl --request POST \
        --url https://sandbox.cashfree.com/pg/subscriptions \
        --header 'Content-Type: application/json' \
        --header 'x-api-version: 2025-01-01' \
        --header 'x-client-id: <your-client-id>' \
        --header 'x-client-secret: <your-client-secret>' \
        --data '{
          "subscription_id": "Demo_Subscription",
          "customer_details": {
            "customer_name": "john",
            "customer_email": "john@dummy.com",
            "customer_phone": "9908730221",
            "customer_bank_account_number": "59108290701802",
            "customer_bank_ifsc": "HDFC0002614",
            "customer_bank_code": "HDFC",
            "customer_bank_account_type": "SAVINGS"
          },
          "plan_details": {
            "plan_name": "plan12345",
            "plan_type": "PERIODIC",
            "plan_amount": 10,
            "plan_max_amount": 100,
            "plan_max_cycles": 100,
            "plan_intervals": 2,
            "plan_currency": "INR",
            "plan_interval_type": "WEEK",
            "plan_note": "Bi-weekly INR 10 plan"
          },
          "authorization_details": {
            "authorization_amount": 100,
            "authorization_amount_refund": true,
            "payment_methods": [
              "card"
            ]
          },
          "subscription_meta": {
            "return_url": "https://example.com/subscription/return",
            "notification_channel": [
              "EMAIL",
              "SMS"
            ],
            "session_id_expiry": "2025-06-01T23:00:08+05:30"
          },
          "subscription_expiry_time": "2100-01-01T23:00:08+05:30",
          "subscription_first_charge_time": "2025-06-01T23:00:08+05:30",
          "subscription_tags": {
            "psp_note": "Monthly subscription payment"
          }
        }'
      ```

      ```javascript Node theme={"dark"}
      // Creating a subscription using the Cashfree Node SDK
      // https://github.com/cashfree/cashfree-pg-sdk-nodejs
      ```

      ```java Java theme={"dark"}
      // Creating a subscription using the Cashfree Java SDK
      // https://github.com/cashfree/cashfree-pg-sdk-java
      ```

      ```go Golang theme={"dark"}
      // Creating a subscription using the Cashfree Go SDK
      // https://github.com/cashfree/cashfree-pg
      ```

      ```csharp .NET theme={"dark"}
      // Creating a subscription using the Cashfree .NET SDK
      // https://github.com/cashfree/cashfree-pg-sdk-dotnet
      ```

      ```python Python theme={"dark"}
      // Creating a subscription using the Cashfree Python SDK
      // https://github.com/cashfree/cashfree-pg-sdk-python
      ```

      ```php PHP theme={"dark"}
      // Creating a subscription using the Cashfree PHP SDK
      // https://github.com/cashfree/cashfree-pg-sdk-php
      ```
    </CodeGroup>

    A successful response returns the `subscription_id` and `subscription_session_id`. Use these values to build the `CFSubscriptionSession` object in [Step 2](#step-2-open-the-payment-page-client-side). The API returns the following response on success:

    ```json theme={"dark"}
    {
      "subscription_id": "Demo_Subscription",
      "subscription_session_id": "subs_token_tc9JCN4MzUIJ",
      "subscription_status": "INITIALIZED",
      "cf_subscription_id": "4"
    }
    ```

    For the full list of request parameters and response fields, see the [Create Subscription API](/api-reference/payments/latest/subscription/mandate/create).
  </Accordion>
</AccordionGroup>

## Step 2: Open the payment page <Badge color="orange">Client-side</Badge>

After you create the subscription, set up the card component and open the payment page so the customer can provide their card details.

### 1. Set up the SDK

The Cashfree iOS SDK is available via CocoaPods. The integration requires version **2.4.0** or above and iOS **13.0** or higher.

Add the following to your `Podfile`:

```ruby theme={"dark"}
platform :ios, '13.0'

target 'YourAppTarget' do
  use_frameworks!
  pod 'CashfreePG', '2.4.0'
end
```

Run `pod install` to install the dependency.

### 2. Complete the payment

To complete the payment, follow these steps:

1. Add the `CFSubsCardComponent` to your view.
2. Initialise the card component after the session is ready.
3. Create a `CFSubscriptionSession` object.
4. Conform to `CFSubsCardListener` to receive card metadata.
5. Set up the payment callback.
6. Build the payment object and initiate the payment.

#### Add the card component to your view

`CFSubsCardComponent` is a `UIView` that you can add in Interface Builder or programmatically. In Interface Builder, set the custom class of a `UIView` to `CFSubsCardComponent` and connect it as an outlet:

```swift theme={"dark"}
@IBOutlet weak var cfCardComponent: CFSubsCardComponent!
```

Apply standard `UIView` styling as needed:

```swift theme={"dark"}
cfCardComponent.layer.borderColor = UIColor.systemGray4.cgColor
cfCardComponent.layer.borderWidth = 1.0
cfCardComponent.layer.cornerRadius = 8.0
```

The component manages only the card number field. Collect cardholder name, expiry month, expiry year, and CVV in separate input fields in your checkout UI.

#### Initialise the card component

Call `initializeCardComponent` only after you have a valid `CFSubscriptionSession`. The component uses the session to authenticate BIN lookup requests.

| Parameter        | Type                    | Required | Description                                                               |
| ---------------- | ----------------------- | -------- | ------------------------------------------------------------------------- |
| `session`        | `CFSubscriptionSession` | Yes      | Session from your backend.                                                |
| `card_listener`  | `CFSubsCardListener`    | Yes      | Receives metadata on every keystroke.                                     |
| `hint_text`      | `String`                | Yes      | Placeholder text. Pass `""` for the default `XXXX XXXX XXXX XXXX` format. |
| `font`           | `UIFont?`               | No       | Custom font. Pass `nil` for the system default.                           |
| `textColor`      | `UIColor?`              | No       | Text colour. Pass `nil` for the system default.                           |
| `enable_pasting` | `Bool`                  | Yes      | Whether the user can paste from the clipboard.                            |

The following example initialises the component with custom font and text colour:

```swift theme={"dark"}
cfCardComponent.initializeCardComponent(
    session: subsSession,
    card_listener: self,
    hint_text: "",
    font: UIFont.systemFont(ofSize: 16),
    textColor: UIColor.label,
    enable_pasting: false
)
```

#### Create a session

The `CFSubscriptionSession` object holds the session context for the payment. It accepts the `subscription_session_id` and `subscription_id` obtained from [Step 1](#step-1-create-a-subscription-server-side), and the Cashfree environment (`.SANDBOX` or `.PRODUCTION`).

Set the environment to `.SANDBOX` for testing or `.PRODUCTION` for live payments. The following example shows how to create the session object:

```swift theme={"dark"}
do {
    let subsSession = try CFSubscriptionSession.CFSubscriptionSessionBuilder()
        .setSubscriptionId("your_subscription_id")
        .setSubscriptionSessionId("your_subscription_session_id")
        .setEnvironment(.SANDBOX) // or .PRODUCTION
        .build()
} catch {
    print(error.localizedDescription)
}
```

#### Set up the CFSubsCardListener callback

Conform your view controller to `CFSubsCardListener` and implement `cardMetaData(card_listener_response:)`. This callback fires on every keystroke and again after the BIN lookup completes.

```swift theme={"dark"}
class CheckoutViewController: UIViewController, CFSubsCardListener {

    func cardMetaData(card_listener_response: CFSubsCardListenerResponse) {
        let charCount = card_listener_response.numberOfCharacters ?? 0
        let meta = card_listener_response.meta_data ?? [:]

        let isLuhnValid = meta["luhn_check"] as? Bool ?? false
        let binInfo = meta["card_bin_info"] as? [String: Any]

        // Enable Pay button when the card number is complete and valid
        payButton.isEnabled = (charCount == 16 && isLuhnValid)

        if let scheme = binInfo?["card_scheme"] as? String {
            print("Card scheme: \(scheme)")
        }
    }
}
```

The callback delivers a `CFSubsCardListenerResponse` with the following top-level fields:

| Field                | Type             | Description                                                       |
| -------------------- | ---------------- | ----------------------------------------------------------------- |
| `numberOfCharacters` | `Int?`           | Number of digits entered in the card component (spaces excluded). |
| `message`            | `String?`        | Informational message about the response.                         |
| `type`               | `String?`        | Always `"card_info"`.                                             |
| `meta_data`          | `[String: Any]?` | Contains card validation and BIN data (see below).                |

The `meta_data` dictionary contains the following keys:

| Key             | Type            | Description                                                                                                              |
| --------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `card_length`   | `Int`           | Same as `numberOfCharacters`; total digits entered.                                                                      |
| `luhn_check`    | `Bool`          | `true` if the entered card number passes the Luhn algorithm; `false` otherwise.                                          |
| `card_bin_info` | `[String: Any]` | Populated once 8 digits are entered. Contains BIN lookup data from the server. `nil` if fewer than 8 digits are entered. |

<Warning>
  The `card_bin_info` object is only present in the callback after the customer has entered at least 8 digits. Always check that the key exists in `meta_data` before accessing it.
</Warning>

After 8 digits are entered, the component calls the Cashfree BIN API automatically. The response is delivered in `meta_data["card_bin_info"]` on the next `cardMetaData` callback. No additional setup is required. Authentication uses the `x-sub-session-id` from the session provided at initialisation.

The `card_bin_info` dictionary returned from the BIN lookup API contains the following fields:

| Field       | Description                   |
| ----------- | ----------------------------- |
| `Card_bin`  | Bank Identification Number.   |
| `logo`      | Card network logo reference.  |
| `sub_type`  | Card sub-type classification. |
| `type`      | Card type classification.     |
| `schema`    | Card network schema.          |
| `brand`     | Card brand classification.    |
| `bank name` | Issuing bank name.            |

The component auto-detects the following card networks and displays the corresponding icon: Visa, Mastercard, American Express (Amex), RuPay, Diners Club, Discover, and JCB.

The following example illustrates how callback data evolves as the customer enters their card number:

```json theme={"dark"}
// After the 1st digit
{"card_length": 1, "luhn_check": false}

// After the 8th digit — card_bin_info becomes available
{
  "card_length": 8,
  "luhn_check": false,
  "card_bin_info": {
    "card_scheme": "visa",
    "type": "filtered",
    "sub_type": "filtered",
    "brand": "filtered",
    "bank name": "axis bank"
  }
}

// After all 16 digits, luhn_check passes
{
  "card_length": 16,
  "luhn_check": true,
  "card_bin_info": {
    "card_scheme": "visa",
    "type": "filtered",
    "sub_type": "filtered",
    "brand": "filtered",
    "bank name": "axis bank"
  }
}
```

#### Set up the payment callback

The SDK exposes the `CFResponseDelegate` protocol to receive callbacks when the subscription payment journey ends. This protocol consists of two methods:

```swift theme={"dark"}
func onError(_ error: CFErrorResponse, order_id: String)
func verifyPayment(order_id: String)
```

<Tip>Register the callback on `CFPaymentGatewayService` before you call `doSubsPayment`. Set `paymentService.setCallback(self)` in your view controller before initiating payment.</Tip>

The following example shows how to implement the callback:

```swift theme={"dark"}
extension CheckoutViewController: CFResponseDelegate {

    func onError(_ error: CFErrorResponse, order_id: String) {
        print("Error: \(error.message ?? "")")
        // Show error to user
    }

    func verifyPayment(order_id: String) {
        print("Flow complete. Verify order: \(order_id)")
        // Verify subscription status from your backend before proceeding.
    }
}
```

<Warning>
  Backend verification is mandatory. The SDK signals that the payment UI flow ended, not that payment succeeded. Always verify payment status from your backend before presenting success.
</Warning>

#### Build the payment object and initiate payment

When the customer fills in their card details and taps the pay button, build the `CFCardSubs` and `CFCardSubsPayment` objects and call `doSubsPayment()` on `CFPaymentGatewayService`.

<Warning>
  You must call `.setCardComponent(cfCardComponent)` on the `CFCardSubs` builder. Because the SDK manages the card number internally via `CFSubsCardComponent`, your application does not have access to the raw card number. `.setCardComponent()` and `.setCardNumber()` are mutually exclusive. Never call both. Omitting `.setCardComponent()` or calling `.setCardNumber()` alongside it causes the payment to fail.
</Warning>

The `CFCardSubs.CFCardSubsBuilder()` supports the following methods:

| Method                                                | Required                | Description                                       |
| ----------------------------------------------------- | ----------------------- | ------------------------------------------------- |
| `.setChannel(_ channel: String)`                      | Yes (default: `"link"`) | Payment flow type.                                |
| `.setCardComponent(_ component: CFSubsCardComponent)` | Yes                     | Component reference; replaces `.setCardNumber()`. |
| `.setCardHolderName(_ name: String)`                  | No                      | Cardholder name.                                  |
| `.setCardExpiryMonth(_ month: String)`                | Yes                     | Expiry month in `"MM"` format.                    |
| `.setCardExpiryYear(_ year: String)`                  | Yes                     | Expiry year in `"YY"` format.                     |
| `.setCVV(_ cvv: String)`                              | Yes                     | Card CVV.                                         |

```swift theme={"dark"}
@IBAction func payButtonTapped(_ sender: Any) {
    do {
        let card = try CFCardSubs.CFCardSubsBuilder()
            .setChannel("link")
            .setCardComponent(cfCardComponent)
            .setCardExpiryMonth(expiryMonthField.text ?? "")
            .setCardExpiryYear(expiryYearField.text ?? "")
            .setCardHolderName(cardHolderNameField.text ?? "")
            .setCVV(cvvField.text ?? "")
            .build()

        let payment = try CFCardSubsPayment.CFCardPaymentSubsBuilder()
            .setCard(card)
            .setSession(subsSession)
            .build()

        let paymentService = CFPaymentGatewayService.getInstance()
        paymentService.setCallback(self)
        try paymentService.doSubsPayment(payment, viewController: self)

    } catch {
        print(error.localizedDescription)
    }
}
```

<Note>
  There is no public API to read the card number out of `CFSubsCardComponent`. The SDK uses it securely when `doSubsPayment` is called.
</Note>

#### Sample code

The following example shows a complete custom card component payment flow, including session creation, card component initialisation, metadata handling, and payment initiation.

<AccordionGroup>
  <Accordion title="Custom card component payment sample">
    The following example demonstrates a complete non-PCI card payment integration using `CFSubsCardComponent`:

    ```swift theme={"dark"}
    class CheckoutViewController: UIViewController, CFSubsCardListener, CFResponseDelegate {

        @IBOutlet weak var cfCardComponent: CFSubsCardComponent!
        @IBOutlet weak var payButton: UIButton!

        private var subsSession: CFSubscriptionSession!

        override func viewDidLoad() {
            super.viewDidLoad()

            cfCardComponent.layer.borderColor = UIColor.systemGray4.cgColor
            cfCardComponent.layer.borderWidth = 1.0
            cfCardComponent.layer.cornerRadius = 8.0

            do {
                subsSession = try CFSubscriptionSession.CFSubscriptionSessionBuilder()
                    .setSubscriptionId("your_subscription_id")
                    .setSubscriptionSessionId("your_subscription_session_id")
                    .setEnvironment(.SANDBOX) // or .PRODUCTION
                    .build()

                cfCardComponent.initializeCardComponent(
                    session: subsSession,
                    card_listener: self,
                    hint_text: "",
                    font: UIFont.systemFont(ofSize: 16),
                    textColor: UIColor.label,
                    enable_pasting: false
                )

                let paymentService = CFPaymentGatewayService.getInstance()
                paymentService.setCallback(self)

            } catch {
                print(error.localizedDescription)
            }
        }

        func cardMetaData(card_listener_response: CFSubsCardListenerResponse) {
            let charCount = card_listener_response.numberOfCharacters ?? 0
            let meta = card_listener_response.meta_data ?? [:]
            let isLuhnValid = meta["luhn_check"] as? Bool ?? false
            payButton.isEnabled = (charCount == 16 && isLuhnValid)
        }

        @IBAction func payButtonTapped(_ sender: Any) {
            do {
                let card = try CFCardSubs.CFCardSubsBuilder()
                    .setChannel("link")
                    .setCardComponent(cfCardComponent)
                    .setCardExpiryMonth(expiryMonthField.text ?? "")
                    .setCardExpiryYear(expiryYearField.text ?? "")
                    .setCardHolderName(cardHolderNameField.text ?? "")
                    .setCVV(cvvField.text ?? "")
                    .build()

                let payment = try CFCardSubsPayment.CFCardPaymentSubsBuilder()
                    .setCard(card)
                    .setSession(subsSession)
                    .build()

                let paymentService = CFPaymentGatewayService.getInstance()
                try paymentService.doSubsPayment(payment, viewController: self)

            } catch {
                print(error.localizedDescription)
            }
        }

        func onError(_ error: CFErrorResponse, order_id: String) {
            print("Error: \(error.message ?? "")")
        }

        func verifyPayment(order_id: String) {
            print("Flow complete. Verify order: \(order_id)")
        }
    }
    ```
  </Accordion>
</AccordionGroup>

For a working end-to-end implementation, refer to the sample integration on GitHub.

<AccordionGroup>
  <Accordion title="iOS subscription custom card component sample">
    [iOS SDK on GitHub](https://github.com/cashfree/core-ios-sdk)
  </Accordion>
</AccordionGroup>

## Step 3: Confirm the payment <Badge color="green">Server-side</Badge>

After the SDK delivers a callback via `verifyPayment`, confirm the payment status from your backend before taking any action. The SDK callback signals only that the payment flow has ended. It does not guarantee a successful payment.

Use the [Fetch Details of All Payments of a Subscription API](/api-reference/payments/latest/subscription/payment/fetch-payments-for-mandate) to retrieve the current payment status.

<AccordionGroup>
  <Accordion title="API request for fetching subscription payments">
    The following request fetches all payments for a subscription:

    ```bash theme={"dark"}
    curl --request GET \
      --url https://api.cashfree.com/pg/subscriptions/{subscription_id}/payments \
      --header 'x-api-version: 2025-01-01' \
      --header 'x-client-id: <your-client-id>' \
      --header 'x-client-secret: <your-client-secret>'
    ```

    A successful response returns an array of payment objects. Check the `payment_status` field to determine the outcome. The API returns the following response on success:

    ```json theme={"dark"}
    [
      {
        "cf_payment_id": "123456",
        "cf_subscription_id": "7891011",
        "payment_id": "your-payment-id",
        "payment_amount": 1,
        "payment_status": "SUCCESS",
        "payment_type": "AUTH",
        "payment_initiated_date": "2025-06-01T22:14:58+0530",
        "subscription_id": "your-subscription-id",
        "retry_attempts": 0,
        "failure_details": {
          "failure_reason": ""
        }
      }
    ]
    ```
  </Accordion>
</AccordionGroup>

<Note>Always verify the subscription status from your backend before delivering goods or services to the customer. Proceed only when `payment_status` is `SUCCESS`.</Note>

## Error codes

If a required field or object is missing when you initiate payment, the SDK returns an error through the `catch` block or `onError` callback. The following table lists common SDK-level validation errors and when they occur.

<Accordion title="Show error codes">
  The SDK validation errors are grouped by category as follows:

  ### Session errors

  These errors occur when the `CFSubscriptionSession` object or its required fields are not provided.

  | Error code                            | Message                                                    | Description                                                                                                |
  | ------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
  | `SUBSCRIPTION_SESSION_OBJECT_MISSING` | The "CFSubscriptionSession" is missing in the request.     | The `CFSubscriptionSession` object was not passed to the payment builder.                                  |
  | `SUBSCRIPTION_SESSION_ID_MISSING`     | The "subscription\_session\_id" is missing in the request. | The `subscription_session_id` was not set on the `CFSubscriptionSession` builder.                          |
  | `SUBSCRIPTION_ID_MISSING`             | The "subscription\_id" is missing in the request.          | The `subscription_id` was not set on the `CFSubscriptionSession` builder.                                  |
  | `ENVIRONMENT_MISSING`                 | The "environment" is missing in the request.               | The Cashfree environment (`.SANDBOX` or `.PRODUCTION`) was not set on the `CFSubscriptionSession` builder. |

  ### Payment method object errors

  These errors occur when a payment method object is absent or one of its required fields is not set.

  | Error code                         | Message                                            | Description                                                                |
  | ---------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------- |
  | `SUBSCRIPTION_CARD_OBJECT_MISSING` | The "CFCardSubs" object is missing in the request. | The `CFCardSubs` object was not passed to the `CFCardSubsPayment` builder. |

  ### Callback errors

  These errors occur when the payment callback is not registered before initiating payment.

  | Error code         | Message                        | Description                                                                                                                            |
  | ------------------ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
  | `CALLBACK_MISSING` | The "callback" cannot be null. | `setCallback` was not called on `CFPaymentGatewayService` before `doSubsPayment()`. Register the callback before you initiate payment. |
</Accordion>

## Other options

The following optional configurations let you customise the payment screen behaviour.

<AccordionGroup>
  <Accordion title="(Optional) Enable full-screen payment">
    To present the payment flow in full screen, call `setFullScreen(true)` on the payment object before you call `doSubsPayment()`:

    ```swift theme={"dark"}
    payment.setFullScreen(true)
    ```
  </Accordion>
</AccordionGroup>

<div class="hidden" data-table-of-contents="bottom">
  <p class="mt-4 font-medium flex items-center gap-2 related-docs-heading">
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="w-4 h-4">
      <path d="M3 4h7a2 2 0 0 1 2 2v13a2 2 0 0 0-2-2H3z" />

      <path d="M21 4h-7a2 2 0 0 0-2 2v13a2 2 0 0 1 2-2h7z" />
    </svg>

    <span>Related topics</span>
  </p>

  <ul>
    <li><a href="/docs/payments/subscription/custom-checkout/mobile/ios-subscription-element">iOS Integration (Full Element SDK)</a></li>
    <li><a href="/docs/payments/subscription/create">Create a Subscription</a></li>
    <li><a href="/docs/api-reference/payments/latest/subscription/payment/fetch-payments-for-mandate">Fetch Details of All Payments of a Subscription API</a></li>
    <li><a href="/docs/payments/subscription/payment-modes">Supported Payment Methods</a></li>
    <li><a href="https://github.com/cashfree/core-ios-sdk" target="_blank">iOS SDK on GitHub</a></li>
  </ul>
</div>
