Skip to main content

Mobile SDK

CocoaPods

caution

All card programs using APTO's SDKs or Mobile API are required to implement Signed Payloads. This is a mandatory update that must be completed to avoid program suspension. Please follow the Signed Payloads guide for more information, or contact programsupport@aptopayments.com with any questions.

Welcome to the Apto iOS Mobile SDK. This SDK provides access to Apto's mobile API, and is designed to be used for mobile apps. When using this SDK, there is no need for a separate API integration. All of the API endpoints are exposed as simple-to-use SDK methods and encapsulate the data returned by the underlying API.

Note: This SDK can be used in conjunction with our UI SDK. However, if you would like to control your UI/UX, we recommend using the standalone Mobile SDK and implementing your own UI/UX.

With this SDK, you can:

Note: The Apto Mobile API has a request rate limit of 1 request per 30 seconds for the verification and login endpoints.

This document provides an overview of how to:

Note: To enable your cardholders to view PCI Data, you will also need to use our PCI SDK.

You can access the iOS Mobile SDK on GitHub.

To contribute to the SDK development, see Contributions & Development

Requirements

  • iOS 12.0 (minimum version)
  • Swift 5 (minimum version)
  • CocoaPods. No minimum version is required, but version 1.8.3 or higher is recommended.

Get the Mobile API key

A Mobile API Key is required to run the SDK. To retrieve your Mobile API Key see Get the Mobile API Key for the SDKs.

Install the SDK

We suggest using CocoaPods to install the SDK.

  1. In your project's Podfile:

    • At the top of the document, ensure the platform specified is set to iOS 12 and frameworks are enabled:

      platform :ios, '12.0'

      ...

      use_frameworks!
    • Add the Apto iOS SDK pod dependency:

          pod 'AptoSDK'
      ```
  2. Open your Terminal app, and navigate to your project's folder containing the Podfile using cd and install the SDK by running the pod install command

    cd PATH_TO_PROJECT_FOLDER
    pod install
  3. Use the .xcworkspace file to open and run your project.

Note: This Xcode workspace is required for your project to find the CocoaPods libraries.

Initialize the SDK

Follow the steps below to initialize the SDK:

  1. Import AptoSDK into your source code file:
import AptoSDK
  1. Invoke the initializeWithApiKey SDK method and pass in the MOBILE_API_KEY from the Apto Developer Portal. This fully initializes the SDK for your application.
AptoPlatform.defaultManager().initializeWithApiKey("MOBILE_API_KEY")

Note: By default, the SDK is initialized for the production environment.

To use the SDK in sandbox mode, append the environment parameter during initialization and set the environment to .sandbox:

AptoPlatform.defaultManager().initializeWithApiKey("MOBILE_API_KEY", environment: .sandbox)

Signed Payloads

Once you have finished setting up your server, as outlined in the Signed Payloads guide, you will need to create an AptoPlatformWebTokenProvider that fetches the JWT token from that server.

class MyWebTokenProvider : AptoPlatformWebTokenProvider {

public func getToken(_ payload: [String: Any], callback: @escaping (Result<String, NSError>) -> ()) {

var req = URLRequest(url: "http://localhost/sign")
req.method = .post
req.headers = ["Content-Type": "application/json", "Accept": "application/json"];

do {
req.httpBody = try JSONSerialization.data(withJSONObject: payload)
} catch {
print("HTTP Request Failed \(error)")
// let SDK know an error happened
callback(.failure(WebTokenError()))
}

let task = URLSession.shared.dataTask(with: req) { data, response, error in
do {
if let data = data {
let result: JWTToken = try JSONDecoder().decode(JWTToken.self, from: data)
// send the JWT back to the SDK
callback(.success(result.token))
} else if let error = error {
print("HTTP Request returned bad data \(error)")
// let SDK know an error happened
callback(.failure(WebTokenError()))
}
} catch {
print("HTTP Request Failed \(error)")
// let SDK know an error happened
callback(.failure(WebTokenError()))
}
}

task.resume()

}
}

You will then need to set the WebTokenProvider at the same time you initialize the SDK. This class will be called anytime a signed payload is needed.

AptoPlatform.defaultManager().webTokenProvider = MyWebTokenProvider()

Verify a User Credential to Obtain a User Token

The SDK enables users to sign up or sign in to the Apto Mobile API.

A user's credentials must be verified prior to authenticating a user. A successful verification will return a user token, which is used during the authentication process. Depending on your project's configuration, the user's credentials can be:

  • Primary credential: The user's phone number or email address. Green Program is the default program, that uses a phone number as the primary credential. Only Blue or Orange Programs can use an email address as the primary credential, and this must be configured by Apto Payments. Please contact us if you would like to use a different primary credential.

    Note: The system associated with the primary credential must be capable of receiving a secret One-Time Passcode (OTP) code that is used to verify the user's primary credential. For example, the phone number must be able to receive an SMS message, and the email address must be able to receive an email sent by Apto Payments.

  • Secondary credential: The default is the user's date of birth.

There are three main methods for the User Verification Process:

User Verification Process

  1. Start verification for the user's primary credential. See Start a New Verification for more information.

  2. Complete verification for the user's primary credential. See Complete a Verification for more information.

  3. Determine if the user is a new or existing user. Once the user's primary credential is verified, the API response will contain data indicating if the credential belongs to an existing user or a new user.

    If the credentials belong to an existing user:

    1. Verify the user's secondary credential. See Complete a Verification for more information.
    2. Use the SDK's login method to obtain a user session token. The login method consumes the two previous verifications, and the SDK automatically stores and manages the user token. See Log in with an Existing User for more information.

    If the credentials don't belong to an existing user:

    • Create a new user with the verified credentials and obtain a user token. The SDK automatically stores and manages the user token.
info

When testing your program in Sandbox, you'll only be able to create users with U.S. phone numbers. If you're a customer of one of our Blue or Orange Programs and would like to use non-U.S. phone numbers to test cardholder operations, contact us at support@aptopayments.com

Start a New Verification

Depending on your project's configuration for your users, use one of the following SDK methods to start a new verification. Green Program can only use the phone verification.

Phone Verification

The phone number used for a phone verification must be capable of receiving an SMS.

To initialize a user verification with a phone number:

  1. Initialize a PhoneNumber object, passing in the user's country code and phone number as strings:

    Note:

    • The country code for the United States is 1.
    • The PHONE_NUMBER value should only contain numerical values.
let phoneNumber = PhoneNumber("COUNTRY_CODE", "PHONE_NUMBER")
  1. Pass the phoneNumber object into the startPhoneVerification method to start the phone verification:
AptoPlatform.defaultManager().startPhoneVerification(phoneNumber) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let verification):
// The verification started and the user received an SMS with a single use code (OTP).
}
}
  • When the method succeeds, a verification object is included in the callback:
  • When the method fails, error handling can be performed using the error response. Errors can include an incorrect OTP code submission or connection problems to the API.

Email Verification

Email verification is only available for Blue or Orange Programs. To set the primary credential to use the user's email address, please contact us.

To initialize a user verification with an email address, use the startEmailVerification method and pass in the user's email as a string:

  1. Create an Email object with the user's email address:
let email = Email(email: "user@gmail.com", verified: nil, notSpecified: nil)
  1. Pass the email object into the startEmailVerification method to start the email verification:
AptoPlatform.defaultManager().startEmailVerification(email) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let verification):
// The verification started and the user received an email with a single use code.
}
}
  • When the method succeeds, a verification object is included in the callback:
  • When the method fails, error handling can be performed using the error response. Errors can include an incorrect OTP code submission or connection problems to the API.

Complete a Verification

To complete a verification, the user will need to enter their SMS / email code or date of birth, depending on the type of verification.

Note: If this is the completion of a secondary verification, ensure you use the primary verification's secondaryCredential value as the verification object for this method.

  1. Set the secret property on the verification object:

    Note: For verifying phone numbers and email addresses when testing in the sandbox environment, you must use 000000 as the OTP code.

    • If verifying a phone number, replace OTP_CODE_OR_BIRTHDATE with the OTP code received via SMS from the Start a New Verification process. Note: Use only numerical values.
    • If verifying an email address, replace OTP_CODE_OR_BIRTHDATE with the OTP code received via email from the Start a New Verification process. Note: Use only numerical values.
    • If verifying a date of birth, replace OTP_CODE_OR_BIRTHDATE with the user's date of birth, using the format YYYY-MM-DD. For example, 1999-01-01.
verification.secret = "OTP_CODE_OR_BIRTHDATE"
  1. Complete the verification by passing the verification object into the completeVerification method.
AptoPlatform.defaultManager().completeVerification(verification) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let verification):
if verification.status == .passed {
// The verification succeeded. If it belongs to an existing user, it will contain a non null `secondaryCredential`.
}
else {
// The verification failed: the secret is invalid.
}
}
}
  • When the method succeeds, a Verification object is included in the callback:
    • If the verification's status property is set to VerificationStatus.PASSED, the verification is successful.
      • For primary verifications, if the verification belongs to an existing user, the response will contain a non-null secondaryCredential value. Use the secondaryCredential value to complete verification for the user's secondary credential.
      • For secondary verifications, the user is now fully verified and log in can proceed.
    • Otherwise, the verification failed due to an invalid secret value. If this is primary verification, you can add error handling and restart the primary verification for the user to re-enter their OTP code.
  • When the method fails, error handling can be included within the error response.

Restart a Verification

If you previously initialized a phone or email verification, you can restart a verification by passing in the primary verification object into the restartVerification method:

AptoPlatform.defaultManager().restartVerification(verification) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let verification):
// The verification restarted and the user received a new secret via email or phone.
}
}
  • When the method succeeds, a verification object is included in the callback:
    • The user will receive a single-use code (OTP) via SMS or email (depending on the type of verification). Use that code and the returned verification object to complete verification for the user's primary credential.
    • (Optional) Add verification handling within the success callback.
  • When the method fails, error handling can be included within the error response.

Authenticate a User

A user session token is required for authentication. A session token is generated once you successfully sign up a new user or log a user into the SDK. The session token is valid until:

  • The user is logged out of the SDK.

  • A timeout occurs (i.e., the user doesn't interact with the app for one year in production mode or one month in sandbox mode).

    Note: The session length may be configured to a custom duration. Contact us if you'd like to customize the session length.

For the Green Program the session token is created by the SDK after verifying the user.

Blue or Orange Programs, have access to our Core API which enables you to leverage an existing session token for a user. Use the setUserToken method and replace USER_TOKEN with your existing user token. This enables the user to bypass the requirement to enter an OTP code they receive via SMS or email.

Note: Ensure your user token is passed in as a string.

AptoPlatform.defaultManager().setUserToken("USER_TOKEN")

Note: This is optional. If a session token is not provided, the SDK will obtain one by verifying the user.

Manage Users

The SDK enables you to:

Create a New User

A user's primary credential must be verified prior to creating a new user. Once the primary credential verification is complete, if a user already exists, a new user can not be created. See the User Verification Process for more information.

Once a user's primary credential is verified and a new user can be created, use the createUser method to create a new user.

  1. Create a primary credential object and set its verification object.

    This example, creates a PhoneNumber object for project configurations that use a phone number as the primary credential.

// Prepare a DataPointList containing the verified user's primary credential.
let primaryCredential = PhoneNumber(countryCode, phoneNumber)
primaryCredential.verification = verification // The verification obtained before.
  1. Create a DataPointList object and add the following information:

    • Verified primary credential object
    • Phone Number Note: The PhoneNumber object requires a numerical country code and numerical phone number passed in as strings.
    • Email
    • First and last name
    • Address
    • Date Of Birth
    • (Optional) Any additional DataPoint.Type enum data.
let userData = DataPointList()
userData.add(primaryCredential)

let phoneNumber = PhoneNumber("1", "1234567890")
let phone = PhoneDataPoint()
userData.add(phone)

let email = EmailDataPoint("user@gmail.com")
userData.add(email)

let name = NameDataPoint(firstName = "Jane", lastname = "Smith")
userData.add(name)

let address = AddressDataPoint(streetOne = "123 Main Street", locality = "San Francisco", region = "CA", postalCode = "94103", country = "US")
userData.add(address)

let birthdate = BirthDataPoint(LocalDate.of(year = 1963, month = 1, dayOfMonth: 31 ))
userData.add(birthdate)
  1. Pass the userData object into the createUser method to create a new user.
AptoPlatform.defaultManager().createUser(userData: userData) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let user):
// The user created. It contains the user id and the user session token.
}
}
  • When the method succeeds, a User object is returned containing the user ID and user session token.
  • When the method fails, error handling can be included within the error response.

Note: The createUser method can accept the following optional parameters:

  • custodianUid - Use this parameter to send Apto the user's ID for inclusion in future webhook notifications. This simplifies the process of matching the user with the notification event.
  • metadata - Use this parameter to send Apto metadata about the new user (maximum 256 characters).
let custodianUid = "your_platform_user_id"

AptoPlatform.defaultManager().createUser(userData: userPII, custodianUid: custodianUid, metadata: "My data") { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let user):
// The user created. It contains the user id and the user session token.
}
}

Log in with an Existing User

Once the primary and secondary credentials are verified, log the user in with the loginUserWith method and obtain a user token for the existing user.

Note: Ensure you pass in the successful verifications for your primary primaryVerification and secondary secondaryVerification verifications.

AptoPlatform.defaultManager().loginUserWith(verifications: [primaryVerification, secondaryVerification]) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let user):
// The user logged in. The user variable contains the user id and the user session token.
}
}
  • When the method succeeds, the user object contains the user ID and user session token.
  • When the method fails, error handling can be included within the error response.

Update a User's Info

You can update the user's information using the updateUserInfo method:

  1. Create a DataPointList object:
let userPII = DataPointList()
  1. Create DataPoint objects for the data you want to update and add it to userPII.
let address = Address(address:"123 Main Street", apUnit: nil, country: Country.defaultCountry, city: "San Francisco", region: "CA", zip: "12345")

userPII.add(address)

val name = PersonalName(firstName: "John", lastName: "Doe")

userPII.add(name)

The available list of DataPoint objects are:

DataPointDescription
AddressAddress information for the update.
PersonalNameUser's first and last name for the update.
PhoneNumberPhone's country code and number for the update.
EmailEmail address for the update.
BirthDateUser's date of birth for the update.
IdDocumentUser's ID verification document for the update.
  1. Pass the userData into the updateUserInfo method:
// Add to userPII the datapoints that you want to update
AptoPlatform.defaultManager().updateUserInfo(userPII) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let user):
// Update successful
}
}
  • When the method succeeds, the update is successful and a User object is returned containing the updated user information.
  • When the method fails, error handling can be included within the error response.

Close a User Session

When a session is closed, it will log the user out of all sessions on all devices.

To close the current user's session, use the logout SDK method:

AptoPlatform.defaultManager().logout()

Note: If the user closes the app without invoking the logout method (i.e., the user switches to another app, manually closes the app, etc.), the user's session will still be active.

Manage Card Programs

The SDK enables you to manage card programs. This section explains how to use the SDK to:

Note: Card Programs used to be called Card Products, so you may see the SDK methods reflect the term products. These method names may change in the future to match the correct term programs.

Get Available Card Programs

To retrieve a list of all the available card programs, use the fetchCardProducts method:

AptoPlatform.defaultManager().fetchCardProducts() { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let cardProductSummary):
// cardProductSummary is a CardProductSummary object
}
}
  • When the method succeeds, a list of CardProductSummary objects are returned, containing details for each card program.
  • When the method fails, error handling can be included within the error response.

Get Card Program Details

To retrieve a specific card program, pass a card program ID into the fetchCardProduct method:

forceRefresh is a boolean value indicating if transactions should be retrieved from the Apto Mobile API or the local cached transaction list. If set to true, transactions are retrieved from the Apto Mobile API.

AptoPlatform.defaultManager().fetchCardProduct(cardProductId: cardProductId, forceRefresh: false) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let cardProduct):
// cardProduct is a CardProduct object
}
}
  • When the method succeeds, a CardProduct object is returned containing details for the card program.
  • When the method fails, error handling can be included within the error response.

Manage Cards

The SDK enables you to manage cards. This feature is only available for Blue or Orange Programs.

Note: Green Program only support one card per user.

This section explains how to use the SDK to:

Get the List of Cards for the User

To retrieve a list of cards for the current user, pass the following into the fetchCards method:

  • pagination: A PaginationQuery object that represents the details of a pagination. Optional.
PropertyTypeDescription
limitIntThis value specifies the upper limit of the number of payment sources returned per call. The maximum value for this parameter is 50.
startingAfterStringIf this value is set, only payment source ID's larger than this value are returned.
endingBeforeStringIf this value is set, only payment source ID's less than this value are returned.

Note: The startingAfter and endingBefore parameters are mutually exclusive. Only one of these parameters may be present per call. If both parameters are set, an error will be thrown.

AptoPlatform.defaultManager().fetchCards(pagination: pagination) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let paginatedCards):
// paginatedCards contain an array of PaginatedCard objects
let nonClosedCards = paginatedCards.list.filter { $0.state != .cancelled }
.....
}
}
  • When the method succeeds, a ListWithPagination<Card> object is returned. The object contains the list of Card objects and the details of the pagination: page, rows, hasMore, totalCount. The Card objects can be accessed directly on the paginatedCards object, by accessing the listproperty.
  • When the method fails, error handling can be included within the error response.

Retrieve a Card by ID

To retrieve a specific card program, pass a card ID into the fetchCard method:

  • cardId - A string representing the ID of the card you want to retrieve.
  • forceRefresh - A boolean value which forces data to be returned from an API call rather than the local cache.
  • retrieveBalances - A boolean value indicating if the card balance should be returned in the response.
AptoPlatform.defaultManager().fetchCard(cardId, forceRefresh: false, retrieveBalances: false) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let card):
// card is a Card object
}
}
  • When the method succeeds, a Card object is returned containing details for the card.
  • When the method fails, error handling can be included within the error response.

Change a Card PIN

If your app enables users to change their card PIN, we recommend asking the user to confirm their current PIN prior to entering and confirming a new PIN.

To set or change the card PIN, use the changeCardPin method and pass in the following:

  • accountID - The cardProductId of the Card object you want to change.
  • pin - A four-digit PIN passed in as a string.
AptoPlatform.defaultManager().changeCardPIN(accountId, pin: "1234") { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let card):
// Operation successful
}
}

Note: The returned Card object will not contain the PIN property.

  • When the method succeeds, a card object is returned containing information about the updated card.
  • When the method fails, error handling can be included within the error response.

Lock / Unlock a Card

You can enable users to lock and unlock their cards.

Transactions using a locked card will be rejected by the merchant's POS, and therefore we recommend to lock cards only if a user makes an explicit request to lock their card.

Lock a Card

To lock a card, pass the card's accountID into the lockCard method:

AptoPlatform.defaultManager().lockCard(accountId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let card):
// Operation successful
}
}
  • When the method succeeds:
    • A Card object is returned containing information about the locked card, and the card's state property will be listed as .inactive.
    • The registered user will receive an email confirmation that the card has been deactivated.
  • When the method fails, error handling can be included within the error response.

Unlock a Card

To unlock a card, pass the card's accountID into the unlockCard method:

AptoPlatform.defaultManager().unlockCard(accountId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let card):
// Operation successful
}
}
  • When the method succeeds, a Card object is returned containing information about the unlocked card, and the card's state property will be listed as .active. Note: Unlike the lock method, the registered user will NOT receive an email confirmation that the card has been activated.
  • When the method fails, error handling can be included within the error response.

Issue a New Card

Once a user is created, you can issue a card for the user.

The steps to issue a card are:

  1. Get Card Programs
  2. Apply for a Card
  3. Get the Next Application Step
  4. Issue the Card

Get Card Programs

Each card must be issued under a card program.

To retrieve a list of all the available card programs, use the fetchCardProducts method:

AptoPlatform.defaultManager().fetchCardProducts() { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let cardProductSummary):
// cardProductSummary is a CardProductSummary object
}
}

Note: Card Programs used to be called Card Products, so you may see the SDK methods reflect the term products. These method names may change in the future to match the correct term programs.

  • When the method succeeds, a list of CardProductSummary objects are returned, containing details for each card program. Save the card program's ID you want to use to apply for a new card.
  • When the method fails, error handling can be included within the error response.

Apply for a Card

Use the card program's ID from the previous step to apply for a card.

To apply for a card:

  1. Create a CardProduct object passing in the cardProductId:
let cardProduct = CardProduct(cardProductId)
  1. Pass cardProduct into the applyToCard SDK method:
AptoPlatform.defaultManager().applyToCard(cardProduct) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let cardApplication):
// In this step we have successfully applied for a card.
// Check the cardApplication.nextAction property to identify the next step of the application
}
}
  • When the method succeeds, a CardApplication object is returned, containing details for the card application. Save the cardApplication object for the remaining steps of the application.
  • When the method fails, error handling can be included within the error response.

Get the Next Application Step

Once you have a card application initiated, check for the next application step in the nextAction property.

Note: Prior to checking for the next application step, ensure you update the card application status using the fetchCardApplicationStatus() method. For example:

AptoPlatform.defaultManager().fetchCardApplicationStatus(cardApplication.id) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let updatedCardApplication):
// Check for the next step.
if (updatedCardApplication.nextAction is WorkflowActionType.SHOW_DISCLAIMER) {
// Show the disclaimer
}
}
}

The cardApplication.nextAction is a WorkflowActionType value. The available WorkflowActionType values are:

ValueDescription
COLLECT_USER_DATAIf any required user information is missing, the next action value will be COLLECT_USER_DATA.
SELECT_BALANCE_STOREFor Blue or Orange Programs, if using an OAuth application process and all required user information was submitted during user creation, this is the default step. See Set the Balance Store using OAuth (Blue or Orange only) to process this step.
SHOW_DISCLAIMERFor all programs, if all required user information was submitted during user creation, this is the default step prior to issuing a card. See Accept the Disclaimer to process this step.
ISSUE_CARDIndicates the application is complete and a card can be issued for the user. See Issue the Card to issue a card for the user.
UNSUPPORTED_ACTION_TYPEThis indicates the next step is not currently supported.
Set the Balance Store using OAuth (Blue or Orange Programs only)

To set the balance store using OAuth:

  1. Get the allowed balance type from the nextAction's actionConfiguration.allowedBalanceTypes.first() property.
let allowedBalanceType = cardApplication.nextAction.actionConfiguration.allowedBalanceTypes.first()
  1. Pass the allowed balance type into the startOauthAuthentication method:
AptoPlatform.defaultManager().startOauthAuthentication(allowedBalanceType) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let oauthAttempt):
let url = oauthAttempt.url
// Start the oauth attempt in a separate screen
}
}
  • When the method succeeds, an OAuth attempt object will be returned. Save its url property for the next OAuth process.
  • When the method fails, error handling can be included within the error response.
  1. Load the OAuth-attempt URL in a web view.

Note: Your OAuth server must call the Apto OAuth callback endpoint /v1/oauth/callback adhering to OAuth2 standards, including passing in the token and secret, or the error message (if any).

  1. Once the user completes the OAuth process, the user will be redirected to the apto-sdk://oauth-finish URL. Use this to check for the OAuth status.
AptoPlatform.defaultManager().verifyOauthAttemptStatus(oauthAttempt) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let oauthAttempt):
// Verify that the state is PASSED
if (oauthAttempt.state == "PASSED") {
// The OAuth attempt is successful
} else {
// The OAuth attempt failed
}
}
}
}

The available values for the OAuth state are PASSED or FAILED:

  • If the OAuth state is PASSED, proceed to the next step to set the balance store using the returned OAuth token ID.
  • If the OAuth state is FAILED, the user must restart the OAuth process to retrieve an OAuth token ID.
  1. Once the OAuth completes successfully, pass the card application ID and OAuth token ID into the setBalanceStore method:
AptoPlatform.defaultManager().setBalanceStore(cardApplication.id, oauthAttempt.tokenId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let selectBalanceStoreResult):
// selectBalanceStoreResult.result should be VALID
}
}
  • When the method succeeds, a select balance store result object is returned. Ensure the result property is VALID before proceeding to the next step.
  • When the method fails, error handling can be included within the error response.
  1. Check the application status by passing the card application ID into the fetchCardApplicationStatus method:
AptoPlatform.defaultManager().fetchCardApplicationStatus(cardApplication.id) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let updatedCardApplication):
// Check the next step. After the balance store the result should be SHOW_DISCLAIMER
if (updatedCardApplication.nextAction is WorkflowActionType.SHOW_DISCLAIMER) {
// Show the disclaimer
}
}
}
  • When the method succeeds, check the application's nextAction property. The value should be SHOW_DISCLAIMER to indicate the next step in the application is to display the disclaimer. See Accept the Disclaimer to process this step.
  • When the method fails, error handling can be included within the error response.
Accept the Disclaimer

The user must accept the disclaimer to complete their card application. To process the user's disclaimer acceptance:

  1. Display the disclaimer to the user and ask for their acceptance.

  2. Once the user confirms they accept the disclaimer, pass the application's workflowObjectId and nextAction properties into the acceptDisclaimer method to mark the disclaimer as accepted:

AptoPlatform.defaultManager().acceptDisclaimer(cardApplication.workflowObjectId, cardApplication.nextAction) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let success):
// disclaimer has been accepted
}
}
  • When the method succeeds, the disclaimer has been successfully processed.
  • When the method fails, error handling can be included within the error response.
  1. Check the application status by passing the card application ID into the fetchCardApplicationStatus method:
AptoPlatform.defaultManager().fetchCardApplicationStatus(cardApplication.id) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let updatedCardApplication):
// Check the next step. After the disclaimer the result should be ISSUE_CARD
if (updatedCardApplication.nextAction is WorkflowActionType.ISSUE_CARD) {
// Issue the card
}
}
}
  • When the method succeeds, check the application's nextAction property. The value should be ISSUE_CARD to indicate the application is approved so you may issue a card to the user.
  • When the method fails, error handling can be included within the error response.

Issue the Card

To issue a card to the user, pass in the card's approved application ID into the issueCard method.

Note: This method also accepts as the following optional parameters:

  • cardMetadata - String that will be stored with the card data.
  • design - An IssueCardDesign containing information about the design (Blue or Orange Programs only).
AptoPlatform.defaultManager().issueCard(cardApplication.id) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let card):
// card has been issued
}
}
  • When the method succeeds, the card has been issued.
  • When the method fails, error handling can be included within the error response.

Order a Physical Card

Registered cardholders can order a physical card matching the same PAN as their virtual card. Once ordered, the card will be sent by postal mail to their registered address.

A cardholder should:

  • Have an existing virtual card. A physical card can only be ordered if the user already has an existing virtual card.
  • Be aware of potential costs when ordering a new physical card.
  • Have enough funds to purchase a card (if there is a cost) prior to proceeding with the order request.

Ensure you validate this information prior to issuing a physical card request.

Get Program Configuration for Physical Card

Depending on your program configuration, there may be a cost associated with ordering a physical card.

Depending on the program, the card configuration may have the "digital with optional physical" configuration. This configuration enables the cardholder to issue a digital card during the onboarding process. Afterwards, the user can choose to order a physical card.

To check if the physical card requires a fee, use the getOrderPhysicalCardConfig method to retrieve the configuration details:

AptoPlatform.defaultManager().getOrderPhysicalCardConfig(cardId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let cardConfig):
// Operation successful
}
}
  • When the method succeeds, an PhysicalCardConfig object is returned containing information about the card configuration for the physical card ordering process.
    • issuanceFee refers to the amount the user will have to pay for the physical card.
    • userAddress is the address where the physical card will be shipped.
  • When the method fails, error handling can be included within the error response.

Submit a Physical Card Order

To order a physical card, pass the card accountID into the orderPhysicalCard method:

AptoPlatform.defaultManager().orderPhysicalCard(cardId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let card):
// Operation successful
}
}
  • When the method succeeds, a card object is returned containing information about the status of the order in the orderedStatus property, which can be one of the following values: notApplicable, available, ordered, received.
  • When the method fails, error handling can be included within the error response.

Activate a Physical Card

Physical cards need to be activated using the provided activation code sent to the cardholder.

For the Green Program, physical cards are shipped to user in a card carrier envelope. This carrier contains:

  • The physical card
  • The card’s Activation Code
  • The issuing statement and the name of your program.

For more information about physical cards, see the Apto Developer Guides.

To activate a physical card, use the activatePhysicalCard method and pass in the card's account ID accountID and the user's Activation Code PHYSICAL_CARD_ACTIVATION_CODE as a string:

AptoPlatform.defaultManager().activatePhysicalCard(cardId: accountID, code: PHYSICAL_CARD_ACTIVATION_CODE) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let result):
// Result contains information about the activation process and, if it failed, the reason why it failed.
}
}
  • When the method succeeds, a result object is returned containing information about the activation process.
  • When the method fails, an error object will contain the reason for the failure. Error handling can be included within the error response. Reasons for failure may include: internet connection issues, inoperable API, bad code, etc.

View Card Transactions and Spending

The SDK provides methods to:

View Card Transactions

To retrieve a list of transactions, pass the following into the fetchCardTransactions method:

  • accountId - The card's accountId property
  • filters - A TransactionListFilters object, that filters the transactions by page, row, date, mcc, type, etc. For more information about the parameters for this object, see the Mobile API
  • forceRefresh - Boolean value indicating if transactions should be retrieved from the Apto Mobile API or the local cached transaction list. If set to true, transactions are retrieved from the Apto Mobile API.
AptoPlatform.defaultManager().fetchCardTransactions(accountId, filters: filters, forceRefresh: false) { [weak self] result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let transactions):
// Operation successful
}
}
  • When the method succeeds, a transactions object is returned containing a list of Transaction objects.
  • When the method fails, error handling can be included within the error response.

View Monthly Spending Stats

The SDK enables you to view the monthly spending for cards, classified by category.

To retrieve information about the monthly spending for a card, use the cardMonthlySpending method with the following parameters:

  • Card's accountId property
  • Date object specifying (at minimum) the
    • Spending month
    • Spending year

Note: The results will include the spending for the month specified in the Date object. For example, a result with a date of January 15, 2021 will include the results for the entire month of January 2021.

AptoPlatform.defaultManager().cardMonthlySpending(card.accountId, date: Date()) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let monthlySpending):
// monthlySpending contains the stats of the given month; spendings classified by transaction category and difference with the previous month.
}
}
  • When the method succeeds, a monthlySpending object is returned containing the stats for the provided month. The spending is classified by transaction category, and difference from the previous month.
  • When the method fails, error handling can be included within the error response.

Manage Card Payment Sources / Load Funds

Funds loaded onto a user's card are automatically deducted from the payment source. The balance is maintained on the user's card, managed by Apto Payments. You can load money onto a user's card using a valid debit card.

Sandbox Cards for Testing

We've provided a list of cards that can be used to test adding card funds within the sandbox environment:

Card TypeCard Number
Visa4111111111111111
Visa400000076000002
Mastercard5200828282828210
Mastercard2223000048400011

For all test cards:

  • Any expiration date set to a future date may be used.
  • Any CVV value may be used.
  • Any 5-digit postal code value may be used.

Get Payment Sources

A list of payment sources can be retrieved using the getPaymentSources method. The method accepts three optional parameters:

ParameterTypeDescription
limitIntThis value specifies the upper limit of the number of payment sources returned per call. The maximum value for this parameter is 50.
startingAfterStringIf this value is set, only payment source ID's larger than this value are returned.
endingBeforeStringIf this value is set, only payment source ID's less than this value are returned.

Note: The startingAfter and endingBefore parameters are mutually exclusive. Only one of these parameters may be present per call. If both parameters are set, an error will be thrown.

let limit = 10
let startingAfter = "id_123"
let endingBefore = "id_456"

let pagination = PaginationQuery.init(limit: limit, startingAfter: startingAfter, endingBefore: endingBefore)

AptoPlatform.defaultManager().getPaymentSources(request: pagination) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let paymentSources):
// paymentSources is a list of PaymentSource objects.
}
}
  • When the method succeeds, a paymentSources object is returned containing a list of PaymentSource objects.
  • When the method fails, error handling can be included within the error response.

Add a Payment Source

To add a payment source:

  1. Create a PaymentSourceRequest object:

    Note: Currently only cards are accepted.

val paymentSource = PaymentSourceCardRequest(
pan: "4111111111111111",
cvv: "123",
expirationDate = "12/22",
zipCode = "12345"
)
  1. Pass paymentSource into the addPaymentSource method:

    Note: Added payment sources are automatically marked as preferred and will be set as the new default payment source.

AptoPlatform.defaultManager().(with: paymentSource) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let paymentSource):
// paymentSource is a PaymentSource object.
}
}
  • When the method succeeds, the added PaymentSource object is returned without the PII (Personal Identifiable Information).
  • When the method fails, error handling can be included within the error response.

Delete a Payment Source

To delete a payment source, pass the payment source ID into the deletePaymentSource method:

Note: A preferred payment source can not be deleted.

AptoPlatform.defaultManager().deletePaymentSource(paymentSourceId: paymentSourceId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success:
// No result
}
}
  • When the method succeeds, no response will be returned.
  • When the method fails, error handling can be included within the error response.

Add Funds to a Card

To add funds to a card, pass the following parameters into the pushFunds method:

ParameterTypeDescription
balanceIdStringID of the card's funding source you want to fund. See Get a Card's Default Funding Source to retrieve the balance ID property.
paymentSourceIdStringID of the Payment Source that will be used to add funds.
amountMoneyAmount and currency that will be added to the balance. Note: The amount parameter of this object must use the Double format.
val paymentSourceId = "payment_source_XXXXXXXXX"
val balanceId = "bal_XXXXXXXXX"
val amount = Amount(100.00, "USD")

let pushFundsRequest = PushFundsRequest(paymentSourceId: paymentSourceId, balanceId: balanceId, amount: amount)

AptoPlatform.defaultManager().pushFunds(with: pushFundsRequest) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let paymentResult):
// paymentResult is a PaymentResult object.
}
}
  • When the method succeeds, a Payment object is returned with the completed payment information.
  • When the method fails, error handling can be included within the error response.

Manage Card Funding Sources for On-demand Debits (Blue or Orange Programs only)

Funding sources may be used for on-demand debiting. When a user spends using their card, the amount can be debited from a specified funding source, rather than using the funds loaded onto their card. A card can have more than one funding source.

Note: Only Blue or Orange Programs may use this feature to connect a funding source to a card. Green Program may only load funds onto a card.

The Mobile SDK enables you to:

Get a Card's Default Funding Source

To retrieve a card's default funding source, pass the following parameters into the fetchCardFundingSource method.

  • accountID - The card's account ID
  • forceRefresh - Boolean value indicating if transactions should be retrieved from the Apto Mobile API or the local cached transaction list. If set to true, transactions are retrieved from the Apto Mobile API.

Note: If no default funding source is specified, the first available funding source will be used as the default funding source.

AptoPlatform.defaultManager().fetchCardFundingSource(cardId: accountId, forceRefresh: false) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let fundingSource):
// fundingSource is a FundingSource object.
}
}
  • When the method succeeds, a FundingSource object is returned containing information about the funding source.
  • When the method fails, error handling can be included within the error response.

List a Card's Available Funding Sources

Apto cards may have multiple funding sources. To retrieve a list of available funding sources for a card, use the fetchCardFundingSources method. Ensure you pass in the following:

  • accountId: The accountId of the Card object for the funding source retrieval.
  • page: Page number of the results to retrieve.
  • rows: Number of rows to return in the result.
  • forceRefresh - A boolean value indicating if transactions should be retrieved from the Apto Mobile API or the local cached transaction list. If set to true, transactions are retrieved from the Apto Mobile API.
AptoPlatform.defaultManager().fetchCardFundingSources(accountId, page: 0, rows: 10, forceRefresh: false) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let fundingSources):
// fundingSources contain a list of FundingSource objects.
}
}
  • When the method succeeds, a fundingSources object is returned containing a list of FundingSource objects.
  • When the method fails, error handling can be included within the error response.

Connect a Funding Source to a Card

Blue or Orange Programs can issue cards connected to a funding source not controlled by Apto Payments. Therefore, only Blue or Orange Programs can manage funding sources.

For example, when using the Coinbase card program, users connect their Coinbase wallet and select whether the card is Bitcoin or Ethereum using these funding source management methods.

To connect a funding source to a card, pass the card accountID and funding source id into the setCardFundingSource method:

AptoPlatform.defaultManager().setCardFundingSource(fundingSourceId, cardId: accountId) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let fundingSource):
// Operation successful
}
}
  • When the method succeeds, a fundingSource object is returned containing information for the funding source.
  • When the method fails, error handling can be included within the error response.

Set Notification Preferences

Push notifications for users are available for several events (transactions, card status changes, etc.). The SDK can enable the users to decide how they receive some of these notifications.

Notifications

This section demonstrates how to:

Get Notification Preferences

To retrieve the current user's notification preferences, use the fetchNotificationPreferences method.

AptoPlatform.defaultManager().fetchNotificationPreferences() { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let notificationPreferences):
// notificationPreferences contains all the information regarding the current user preferences.
}
}
  • When the method succeeds, a NotificationPreferences object is returned containing the information for current user's notification preferences. Its preferences property contains a list of NotificationGroup objects, containing details for each notification.
  • When the method fails, error handling can be included within the error response.

Update Notification Preferences

To update the current user's notification preferences:

  1. Create a NotificationPreferences object.
let existingNotificationGroup = notificationPreferences.preferences.first
let notificationGroup = NotificationGroup(groupId: existingNotificationGroup!.groupId, category: existingNotificationGroup!.category, state: NotificationGroup.State.disabled, channel: existingNotificationGroup!.channel)
let preferences = NotificationPreferences(preferences: [notificationGroup])
  1. Pass the preferences object into the updateNotificationPreferences method.
// Set the user preferences in `preferences`
AptoPlatform.defaultManager().updateNotificationPreferences(preferences) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let updatedNotificationPreferences):
// Operation successful
}
}
  • When the method succeeds, an updatedNotificationPreferences object is returned containing the information for current user's notification preferences.
  • When the method fails, error handling can be included within the error response.

In-App Provisioning

In-app provisioning lets a user provision their card to their Apple Wallet allowing an easier adoption of your card program. To do In-App provisioning the card data needs to be tokenized and secured with special keys to be safe to send it over the internet.

For more details, refer to In-App Provisioning.

P2P Payments

P2P payments are transactions between users of the same card program with many use cases like splitting a dinner bill between friends. The process to send money to another users is divided in two:

Find the recipient

To retrieve a recipient, pass the following parameters into the p2pFindRecipient method:

  • (Optional) phone - This is the recipient phone number.
  • (Optional) email - This is the email address.

Note: Include only the primary credential of your card program.

AptoPlatform.defaultManager().p2pFindRecipient(phone: phone, email: email) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let transferRecipientResult):
// transferRecipientResult is a TransferRecipientResult object.
}
}
  • When the method succeeds, a TransferRecipientResult object is returned containing information about the recipient.
  • When the method fails, error handling can be included within the error response.

Make the transfer

To complete the transfer you must:

1- Create an amount object

let amount = Amount(100.00, "USD")

2- Create a P2PTransferRequest object

let transferRequest = P2PTransferRequest(sourceId: sourceId, recipientId: cardholderId, amount: amount)

Note: The cardholderId should be obtained from Find the recipient

3- Pass the transferRequest object into the p2pMakeTransfer method make the transfer:

AptoPlatform.defaultManager().p2pMakeTransfer(transferRequest) { result in
switch result {
case .failure(let error):
// Do something with the error
case .success(let trasnferResponse):
// P2P transfer successful
}
}
  • When the method succeeds, an P2PTransferResult object is returned.
  • When the method fails, error handling can be included within the error response.

Contributing & Development

We look forward to receiving your feedback, including new feature requests, bug fixes and documentation improvements.

If you would like to help:

  1. Refer to the issues section of the repository first, to ensure your feature or bug doesn't already exist (the request may be ongoing, or a newly-finished task).
  2. If your request is not in the issues section, please feel free to create one. We'll get back to you as soon as possible.

If you want to help improve the SDK by adding a new feature or bug fix, we'd be happy to receive pull requests