Card present payments
You need to set up the Clover Go reader to accept payments. Then, you can use the PayRequest method to accept customer payment when they insert a card or tap the card on the device.
Set up the Clover Go reader to accept payments.
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 |
---|---|---|---|
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 case of PreAuth, the payment is not automatically captured and 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 to 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 | KeyedInCard | See Manual entry payments for more information. Value for card reader payments = null/nil. | Required only for a manual card entry. |
PayResponse fields
Object | Type | Description |
---|---|---|
payment | Payment | Payment details auto-populate on successful payment. |
issues | Array of PaymentIssueEnum | Array of the enum of the concerns related to the payment. The integrator may want to void this payment in some scenarios. 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 information. - If the issue is PARTIAL_PAYMENT, the integrator may send a request to void the payment or keep the payment and make another PayRequest to complete the transaction for the rest of the payment.For integrators who work with other Clover systems or the older version of the Go SDK, this is similar to Payment Challenges that occur. On other systems, when a Payment Challenge occurs, the payment is put on hold until the user continues or cancels the payment or a timeout occurs. The process is simpler in the latest SDK. The payment process proceeds when there is a PaymentChallenge . The issues field populates with the corresponding enum. The integrator can call a void if they want to cancel the payment. For example, if a signature is required, you can match the signature with the receipt and call a void if it doesn't match. |
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 | Payment is detected as a duplicate payment. |
Offline_Payment | Payment is detected as offline payment. Note: Offline payments are not supported with this version of Clover Go software development kit (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) detects an address mismatch. |
CVV_Mismatch | Card verification value (CVV) detects a CVV mismatch. |
IMPORTANT
Review the resulting payment object's 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 card present payment steps
To create a card present payment:
- Connect the card reader and ensure it has more than 2% of battery power.
- Use
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.
The integrator needs to call ReversePayment
to cancel the transaction.
If the request fails—for example, if there is a timeout, a CloverError returns. See CloverError for further details.
Response details
ChargeCardReaderState
Field | Description |
---|---|
OnPaymentComplete | Indicates a successful payment. Review the PayResponse for the successful payment details. |
OnPaymentError | Indicates an error occurred. The payment is voided. See CloverError for error descriptions. |
OnReaderPaymentProgress | Captures the progress state in between. See PaymentProgressEvent for in-between progress events. |
PaymentProgressEvent
Field | Description |
---|---|
Card_Inserted | Card reader detected that the card is inserted. |
Card_Removed | Card is removed after the dip. |
Card_Swiped | Card reader detected that the card is swiped (in case the device supports it). |
Card_Tapped | Card reader detected that the card is tapped. |
Contactless_Failed_Try_Again | For some reason, the contactless failed. Retry or try other methods like dip. |
EMV_Card_Swiped | Card reader detected that Europay, Mastercard, and Visa (EMV) card is swiped, if the device supports EMV. |
EMV_Dip_Failed_Try_Again | Card dip failed. Try again or try another method, such as contactless. |
Insert_Or_Tap_Card | Card reader is ready to take the payment. |
Multiple_Contactless_Cards_Detected | Multiple cards are tried in an attempt to make a payment. |
Remove_Card | If the card is dipped, the card data is read, and it needs to be removed to proceed. |
Request_In_Flight | Transaction is started and the state is put in flight. If another transaction is tried while this is in progress, the other transactions fail. Clear the state onPaymentComplete/onPaymentError. |
Swipe_Failed | Swipe failed in instances where swipe is supported. |
PayRequest example
fun chargeCardReader(charge: PayRequest): Flow<ChargeCardReaderState>
For a non-KeyedInCard PayRequest—such as no KeyedInCard details—ensure the card reader is connected and has more than 2% battery power.
PayRequest request = new PayRequest(
amount,
capture,
isFinal,
externalPaymentID,
externalreferenceID,
taxAmount,
tipAmount,
null //since this is a card present payment, keyed in card is null
);
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 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
)
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 card present payment steps
To accept payment using a card reader:
- Create a
PayRequest
object. - Pass it to the
CloverPaymentSDK.shared.charge()
function.- Successful transaction returns a .complete paymentEvent with the associated payment, and the async stream closes.
- Failed transaction throws an error, and the async stream closes. During transaction processing, .progress paymentEvents is called to provide status and instructions to provide to the customer.
let payRequest = PayRequest(amount: 1000, taxAmount: 80, tipAmount: 200)
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 6 days ago