ForageSDK

The ForageSDK processes Electronic Benefits Transfer (EBT) payments in your e-commerce application. It provides secure user interfaces for collecting and tokenizing an EBT cardholder’s PAN and accepting an EBT cardholder’s PIN to execute a balance check and process a payment.

Table of contents

Integration

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate ForageSDK into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'ForageSDK', '~> 0.1.1'

Swift Package Manager

The Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

We recommend using Xcode with Swift tools version 5.3 or higher. Earlier Xcode versions don’t support Swift packages with resources. To check your current Swift tools version run in your terminal:

xcrun swift -version

Follow the official Apple SPM guide instructions for more details.

Step-by-step

Add package:

Screen Shot 2022-10-31 at 09 54 23

To use Swift Package Manager, in Xcode add the https://github.com/teamforage/forage-ios-sdk dependency and choose the Dependency Rule as Branch and the branch enter main.

Screen Shot 2022-10-31 at 09 56 50

Click on Add Package button. And, on the next screen, select the package ForageSDK, and finish by clicking on Add Package.

Screen Shot 2022-10-31 at 10 00 57

Usage

Import SDK into your file

import ForageSDK

Create ForageSDK instance

To initialize a ForageSDK instance, you need to provide the merchantID and sessionToken.

ForageSDK.setup(
    ForageSDK.Config(
        merchantID: "1234567",
        sessionToken: "sandbox_eyJ0eXAiOiJKV1Qi..."
    )
)

Forage UI Elements

ForageSDK provides two UI Elements to securely communicate with the Forage API.

ForagePANTextField

A component that securely accepts the PAN number. This field validates the PAN number based on the StateIIN list

Screen Shot 2022-10-31 at 10 19 27

private let foragePanTextField: ForagePANTextField = {
    let tf = ForagePANTextField()
    tf.borderColor = .black
    tf.placeholder = "EBT Card Number"
    return tf
}()

ForagePANTextField uses a delegate ForageElementDelegate to communicate the updates to the client side.

foragePanTextField.delegate = self
public protocol ForageElementDelegate: AnyObject {
    func focusDidChange(_ state: ObservableState)
    func textFieldDidChange(_ state: ObservableState)
}

The ObservableState object has the values:

public protocol ObservableState {
    /// isFirstResponder is true if the input is focused, false otherwise.
    var isFirstResponder: Bool { get }

    /// isEmpty is true if the input is empty, false otherwise.
    var isEmpty: Bool { get }

    /// isValid is true when the input text does not fail any validation checks with the exception of target length;
    /// false if any of the validation checks other than target length fail.
    var isValid: Bool { get }

    /// isComplete is true when all validation checks pass and the input is ready to be submitted.
    var isComplete: Bool { get }
}

The ForagePINTextField exposes a function to programmatically gain focus:

func becomeFirstResponder() -> Bool

To send the PAN number, we can use ForageSDK to perform the request.

Tokenize card number

// Signature

func tokenizeEBTCard(
    foragePanTextField: ForagePANTextField,
    customerID: String,
    reusable: Bool?,
    completion: @escaping (Result<PaymentMethodModel, Error>) -> Void
)
// Usage

ForageSDK.shared.tokenizeEBTCard(
    foragePanTextField: foragePanTextField,
    // NOTE: The following line is for testing purposes only and should not be used in production.
    // Please replace this line with a real hashed customer ID value.
    customerID: UUID.init().uuidString,
    reusable: true
) { result in
    // Handle result and error here
}

ForagePINTextField

A component the securely accepts an EBT PIN for balance requests and payment capture. It only accepts 4 digit numbers.

Screen Shot 2022-10-31 at 10 21 32

private let foragePinTextField: ForagePINTextField = {
    let tf = ForagePINTextField()
    tf.borderRadius = 10
    tf.backgroundColor = .systemGray6
    tf.pinType = .balance
    return tf
}()

To identify the type of pin we are handling in the component, you can use the pinType property. We have support for these types:

public enum PinType: String {
    case snap
    case nonSnap
    case balance
}

ForagePINTextField uses a delegate ForageElementDelegate to communicate the updates to the client side.

foragePinTextField.delegate = self
public protocol ForageElementDelegate: AnyObject {
    func focusDidChange(_ state: ObservableState)
    func textFieldDidChange(_ state: ObservableState)
}

The ObservableState object has the values:

public protocol ObservableState {
    /// isFirstResponder is true if the input is focused, false otherwise.
    var isFirstResponder: Bool { get }

    /// isEmpty is true if the input is empty, false otherwise.
    var isEmpty: Bool { get }

    /// isValid is true when the input text does not fail any validation checks with the exception of target length;
    /// false if any of the validation checks other than target length fail.
    var isValid: Bool { get }

    /// isComplete is true when all validation checks pass and the input is ready to be submitted.
    var isComplete: Bool { get }
}

The ForagePINTextField exposes a function to programmatically gain focus:

func becomeFirstResponder() -> Bool

To send the PIN number, we can use the ForageSDK to perform the request.

Balance

// Signature

func checkBalance(
    foragePinTextField: ForagePINTextField,
    paymentMethodReference: String,
    completion: @escaping (Result<BalanceModel, Error>) -> Void
)
// Usage

ForageSDK.shared.checkBalance(
    foragePinTextField: foragePinTextField,
    paymentMethodReference: paymentMethodReference
) { result in
    // Handle result and error here
}

Capture payment

// Signature

func capturePayment(
    foragePinTextField: ForagePINTextField,
    paymentReference: String,
    completion: @escaping (Result<PaymentModel, Error>) -> Void
)
// Usage

ForageSDK.shared.capturePayment(
    foragePinTextField: foragePinTextField,
    paymentReference: paymentReference
) { result in
    // Handle result and error here
}

Demo Application

Demo application for using our components on iOS is here.

To get the application running,

  1. Clone this repo and open the Sample Project in the Sample folder.
  2. Ensure that you have a valid Merchant ID for the Forage API, which can be found on the dashboard (sandbox | prod).
  3. Create an authentication token with pinpad_only scope.
  4. Create a session token.
  5. Run the Sample app project and provide your Merchant ID and session token on the first screen.
  6. These credentials will be passed through to all the SDK calls inside the sample app.

Dependencies