Manual entry payments
For manual entry payments, your app provides required information about the payment and customer, including credit card details collected by a form in your app. The manual entry method encrypts sensitive cardholder data and routes the request and response to and from the Clover server. The PayResponse
object is returned. The card reader is not used, and does not need to be connected for this type of transaction.
IMPORTANT
In this payment method, the credit card information is manually entered in plain-text format. Due to this your app is not certified as Point to Point Encryption (P2PE)-compliant, even though the card data is encrypted as quickly as possible after it is entered.
For more information, see Supported payment methods.
Prerequisites
Before you integrate with the Go SDK, complete the following:
- Create a global developer account with a default test merchant account.
- Create additional test merchants, if needed.
- Create an app in the sandbox.
- Create at least one employee role user for the OAuth flow.
- Order a Clover Go reader Developer Kit (Dev Kit) and set it up.
Field descriptions
PayRequest fields
Object | Type | Description | Required/ Optional |
---|---|---|---|
keyedInCard | keyedInCard | Required for a manual card entry. See KeyedInCard for further details. | Optional |
amount | int64; boolean | Total amount payment in cents, including taxes. Format: Cents; Cannot be a negative value. Maximum amount = 999999999 | Required |
final | Boolean | Indicates how the payment is processed. Values: - True—Payment is processed as closed/settled and cannot be tip-adjusted or captured later. The capture flag also needs to be true. If a tip is not provided, then calculate the tip as zero (0).- False—Payment is processed as Auth/PreAuth and needs to be closed. See Closeout for more information. | Required |
capture | Boolean | Indicates how the payment is captured. Values: - True—Set for final sale or a payment that is ready to be captured but can be tip-adjusted later. When true, the payment is automatically and immediately captured, but it is adjustable until closeout runs; at that time it is closed or settled. - False—Set for an open sale where the payment needs to be captured later. When false, in the case of PreAuth, the payment is not automatically captured, and a subsequent call to capture is required.A captured payment is closed/settled once closeout runs. Length: Maximum 32 characters | Required |
externalPaymentId | String | Identifier (id) that the merchant keeps as a payment reference. This is useful to reference multiple payments in an order. Length: Maximum 32 characters | Optional |
externalReferenceId | String | Also referred as Invoice Number. Identifier (id) that is passed to the merchant's gateway and displayed in settlement records. Length: Maximum 12 characters | Optional |
taxAmount | int64; boolean | Tax amount in cents. Included in the total amount but can also be set to display in transaction records and receipts. Format: Cents; cannot be a negative value Length: Maximum 999999999 | Optional |
tipAmount | int64; boolean | Tip amount in cents including taxes. Format: Cents; cannot be a negative value Length: Maximum 999999999 - If the final flag is false, this value is always null/nil (not zero (0)) - If the final flag is true—that is, payment type is Sale—and tipAmount is null/nil, then it is calculated as zero (0). | Optional |
KeyedInCard
Object | Type | Description | Required/ Optional |
---|---|---|---|
cardNumberEncrypted | String | Encrypted primary account number (PAN). Encrypted through initializer on iOS; while Android takes unencrypted (as of now) and encrypts it in SDK before sending the request. | Required |
first6 | String | First 6 digits of the card number. | Required |
last4 | String | Last 4 digits of the card number. | Required |
isCardPresent | Boolean | Indicates if card is present. Values: - True—Card is present - False—Card not present (CNP) | Required |
billingAddress | String | Billing address (Billing Street and number) registered with the card provider. | Optional |
billing Zip | String | Billing postal code (ZIP) registered with the card provider. | Optional |
cardType | Enum: CardType | Card type used. A wrong cardType may not necessarily fail the transaction. Use Unknown card type if card type is not listed. | Required |
expiration | CardExpirationDate | Card expiration month (first 2 digits) and year (last 2 digits). Format: mmyy Length: 4 digits | Required |
cvv | String | Card verification value (CVV) of the card. | Required |
PayResponse fields
Object | Type | Description |
---|---|---|
payment | Payment | Payment details autopopulate on successful payment. |
Issues | Array of PaymentIssueEnum | Originally payment challenges were displayed. Now the payment proceeds if there is a payment challenge and issues are filled in for a successful payment. Note: Integrator(s) decide how they want to proceed in the case of issues. For example, if the issue is SIGNATURE_REQUIRED, the integrator may need to implement a signature capture interface and save it with transaction info. If the issue is DUPLICATE_PAYMENT or PARTIAL_PAYMENT, the integrator may make a call to void the payment. |
PaymentIssueEnum
If a payment issue occurs, the payment still processes. Merchants can request a ReversePayment
to void a payment if they have an issue such as a SignatureChallenge where signatures don't match. If a partial payment occurs, merchants can perform another transaction to collect the remaining amount.
Object | Description |
---|---|
Duplicate_Payment | Duplicate payment. |
Offline_Payment | Offline payment. Note: Offline payments are not supported with this version of Clover Go SDK. Integrators won't receive this enum. |
Partial_Payment | Card allowed only partial payment of the full amount requested. |
Signature_Required | Signature is required for the transaction. |
AVS_Mismatch | Address Verification Service (AVS) mismatch. |
CVV_Mismatch | Card verification value (CVV) mismatch. |
IMPORTANT
Review the resulting payment object amount field to verify that the full amount requested was authorized. In some scenarios, only a partial amount may be authorized, and your app needs to issue further PayRequest instances to reach the full amount or reverse the transaction.
CloverError
CloverError can be any of the following:
Error type | Description |
---|---|
CloverCardError | Transaction failed because of card error—for example, card expired. |
CloverMerchantBoardingError | Merchant status returns a declined or pending status from the server. |
CloverNetworkError | Standard HTTP errors that are captured during communications with our servers. |
CloverReaderError | Errors encountered while communicating with the Card Reader. |
CloverTransactionError | Errors encountered while processing a transaction |
CloverGenericError | Any error that doesn't fall into the error categories above. |
Android manual entry payment steps
To create a manual entry payment:
- Send a
PayRequest
. - Note the
ChargeCardReaderState
.
A successful request returns OnPaymentComplete
with the PayResponse
. An error such as a timeout returns OnPaymentError
. Instead of PaymentChallenge being displayed, the payment proceeds further and the issues enum array contains any issues received through the process.
Request details
Send a PayRequest
with KeyedInCard
details.
Response details
ChargeCardReaderState
Field | Description |
---|---|
OnPaymentComplete | Indicates a successful payment. Review the PayResponse for the successful payment details. |
OnPaymentError | Indicates an error occurred and payment is voided. |
PayRequest example
fun chargeCardReader(charge: PayRequest): Flow<ChargeCardReaderState>
For a KeyedInCard PayRequest, the card reader does not need not to be connected.
For a non-manual (without KeyedInCard) PayRequest, see Card present payments.
KeyedInCard keyedInCard = new KeyedInCard(
"123456789012345",
"123456",
"1234",
false,
CardType.UNKNOWN, //The CardType class contains the available options
"1234",
"1234",
"Clover Go St",
"12345"
);
PayRequest request = new PayRequest(
amount,
capture,
isFinal,
externalPaymentID,
externalreferenceID,
taxAmount,
tipAmount,
keyedInCard
);
goSdk.chargeCardReader(
activity,
request,
new GoSdkCallback<ChargeCardReaderState>() {
@Override
public void onNext(ChargeCardReaderState cardReaderState) {
if (chargeCardReaderState instanceof ChargeCardReaderState.OnReaderPaymentProgress) {
Log.d(TAG, "Payment in progress");
updateUI(cardReaderState);
} else if (chargeCardReaderState instanceof ChargeCardReaderState.OnPaymentComplete) {
Log.d(TAG, "Payment successful");
updateUI(cardReaderState);
} else if (chargeCardReaderState instanceof ChargeCardReaderState.OnPaymentError) {
Log.d(TAG, "Payment failed");
updateUI(cardReaderState);
} else {
//Something unexpected happened
}
}
@Override
public void onError(@NonNull Throwable e) {
//handle error scenario
}
}
);
lifecycleScope.launch {
/*
Capture State
Final/Sale - true
Tippable/Auth - true
Pre-Auth - false
*/
val keyedInCard = KeyedInCard(
cardNumberEncrypted = "123456789012345",
first6 = "123456",
last4 = "1234",
isCardPresent = false,
cardType = CardType.UNKNOWN, //The CardType class contains the available options
expiration = "1234",
cvv = "1234",
billingAddress = "Clover Go St",
billingZip = "12345"
)
val request = PayRequest(
final = final,
capture = capture,
amount = amount, //Please note that amount is not nullable, unlike taxAmount and tipAmount
taxAmount = taxAmount,
tipAmount = tipAmount,
externalPaymentId = externalID,
keyedInCard = keyedInCard
)
goSdk.chargeCardReader(
request
).collectLatest { cardReaderState ->
when (cardReaderState) {
is ChargeCardReaderState.OnPaymentComplete -> {
println("Payment successful")
updateUI(cardReaderState)
}
is ChargeCardReaderState.OnPaymentError -> {
println("Payment failed")
updateUI(cardReaderState)
}
is ChargeCardReaderState.OnReaderPaymentProgress -> {
println("Payment in progress")
updateUI(cardReaderState)
}
else -> {
//Something unexpected happened
}
}
}
}
iOS
To take a payment using a card reader:
- Create a
PayRequest
object. - Pass it to the
CloverPaymentSDK.charge(
function. - Include a
KeyedInCard
object as part of thepayRequest
, with the input about the payment and customer, including credit card details coming from a form in your app.
If the transaction succeeds, a .complete paymentEvent
is called with the associated payment and the async stream closes. If the transaction fails, an error displays and the async stream closes. During transaction processing, .progress paymentEvents
is called to provide status and instructions to the customer.
let keyedInCard = KeyedInCard(cardNumber: pan, expDate: expDate, cvv: cvv) //values manually input from your form
let payRequest = PayRequest(amount: 1000, taxAmount: 80, tipAmount: 200)
payRequest.keyedInCard = keyedInCard
do {
for try await paymentEvent in CloverPaymentSDK.shared.charge(payRequest: payRequest) {
switch paymentEvent {
case .complete(let payResponse):
print("Payment complete")
if payResponse.issues.contains(.duplicatePayment) {
print("This payment is a possible duplicate")
}
case .progress(let progressEvent):
switch event {
case .insertOrTapCard: presentAlert(title: "Insert or Tap Card", message: nil)
case .swipeInsertTapCard: presentAlert(title: "Swipe, Insert, or Tap Card", message: nil)
case .removeCard: presentAlert(title: "Remove Card", message: nil)
case .cardInserted: fallthrough
case .cardRemoved: alert?.dismiss(animated: true)
default: break
}
@unknown default: break
}
}
} catch {
print("Payment Error \(error)")
}
Updated 5 months ago