Save Card For Future Use
First, create a card intent
with the Card intent
endpoint. This step does not use MoneyHash's iOS SDK and is standard for all MoneyHash's
integrations, except for HPP. This endpoint requires authentication to be executed
properly. You need to provide the Account API Key as a header and send the required data in the request body.
Check the Create a Card Intent page for further explanation.
Don't forget to include
"card_token_type": "UNIVERSAL"
while creating the card intent.
Step 1: Initialize MoneyHash SDK
Before proceeding, initialize the MoneyHash SDK with your Public API Key:
import MoneyHashSDK
let moneyHashSDK = MoneyHashSDKBuilder()
.setPublicKey("<account_public_api_key>")
.build()
Step 2: Collect Card Data
Once the card form is set up, you can collect the card data. If you haven't set up the card form yet, follow the steps in the Collecting Card Information documentation.
Here's how you can collect the card data using the collect()
method:
import Foundation
class CardFormViewModel: ObservableObject {
@Published var cardForm: CardForm? // Assume this is set up in the linked documentation
func collectCardData() async throws -> VaultData? {
do {
return try await cardForm?.collect()
} catch {
print("Error collecting card data: \(error)")
throw error
}
}
}
The collect()
method asynchronously gathers the entered card information from the form, returning the collected data as a VaultData
object.
Step 3: Create a Card Token
Once the card data is collected, you can create a card token for future use by calling the createCardToken()
method:
class CardFormViewModel: ObservableObject {
@Published var cardForm: CardForm? // Assume this is set up in the linked documentation
func createCardToken(cardIntentId: String, cardData: VaultData) async {
do {
let intentStateDetails = try await cardForm?.createCardToken(
cardIntentId: cardIntentId,
cardData: cardData
)
switch intentStateDetails {
case .cardIntentSuccess:
print("Card token created successfully.")
case .urlToRender(let url):
print("Card token creation pending. Open the URL to complete the flow: \(url)")
default:
print("Card token creation failed.")
}
} catch {
print("Error creating card token: \(error)")
}
}
}
You can implement any additional business logic between collecting card data and tokenizing it.
Complete Example
Here is a complete example of how to integrate all the steps into your iOS app using Swift:
import SwiftUI
import MoneyHashSDK
class CardFormViewModel: ObservableObject {
@Published var cardForm: CardForm?
init() {
setupCardForm()
}
private func setupCardForm() {
self.cardForm = CardFormBuilder()
.setCardNumberField { [weak self] state in
print("Card Number Field State: \(state)")
}
.setCVVField { [weak self] state in
print("CVV Field State: \(state)")
}
.setCardHolderNameField { [weak self] state in
print("Card Holder Name Field State: \(state)")
}
.setExpireMonthField { [weak self] state in
print("Expire Month Field State: \(state)")
}
.setExpireYearField { [weak self] state in
print("Expire Year Field State: \(state)")
}
.setCardBrandChangeHandler { [weak self] brand in
print("Card Brand Changed: \(brand)")
}.build()
}
func saveCard(cardIntentId: String) async {
do {
guard let cardData = try await cardForm?.collect() else {
print("Failed to collect card data.")
return
}
let intentStateDetails = try await cardForm?.createCardToken(
cardIntentId: cardIntentId,
cardData: cardData
)
switch intentStateDetails {
case .cardIntentSuccess:
print("Card token created successfully.")
case .urlToRender(let url):
print("Card token creation pending. Open the URL to complete the flow: \(url)")
default:
print("Card token creation failed.")
}
} catch {
print("Error during card token creation: \(error)")
}
}
}
@available(iOS 15.0, *)
struct CardFormView: View {
@StateObject var viewModel = CardFormViewModel()
var body: some View {
VStack(spacing: 16) {
SecureTextField(cardFormCollector: viewModel.cardForm!, type: .cardHolderName) {
Text("Cardholder Name")
.foregroundColor(.gray)
}
.textFieldStyle()
SecureTextField(cardFormCollector: viewModel.cardForm!, type: .cardNumber) {
Text("Card Number")
.foregroundColor(.gray)
}
.textFieldStyle()
HStack(spacing: 8) {
SecureTextField(cardFormCollector: viewModel.cardForm!, type: .expireMonth) {
Text("MM")
.foregroundColor(.gray)
}
.textFieldStyle()
SecureTextField(cardFormCollector: viewModel.cardForm!, type: .expireYear) {
Text("YY")
.foregroundColor(.gray)
}
.textFieldStyle()
SecureTextField(cardFormCollector: viewModel.cardForm!, type: .cvv) {
Text("CVV")
.foregroundColor(.gray)
}
.textFieldStyle()
}
Button("Save Card") {
Task {
await viewModel.saveCard(cardIntentId: "<card_intent_id>")
}
}
}
.padding()
}
}
@available(iOS 15.0, *)
extension View {
func textFieldStyle() -> some View {
self
.padding()
.background(Color(UIColor.systemGray6))
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color(UIColor.separator), lineWidth: 1)
)
}
}
Updated about 1 month ago