Sale

This transaction obtains real-time authorization for an EMV, magnetic stripe, contactless or manual card entry transaction and enters the transaction in the Unsettled batch. This transaction also logs purchases by cash.

Commerce SDK handles all the necessary prompting and flow regardless if the card is EMV, magnetic stripe, contactless or manual entry.

error_outline
important

For a credit card transaction, a connected valid terminal is mandatory.

These are the processing options that you can integrate with a card Sale transaction:

Code Samples

CWS

Request

method
string | required
startPaymentTransaction
 
requestId
string | required
Transaction Request ID
 
targetType
string | required
paymentGatewayConverge
 
parameters
JSONObject | required
All relevant parameters for Sale transactions.
 
paymentGatewayId
string | required
Payment Gateway ID
Unique identifier of the payment gateway as returned in the openPaymentGateway transaction response.
transactionType
string | required
Transaction Type
Valid value: SALE
baseTransactionAmount
JSONObject | required
Transaction Amount
"baseTransactionAmount" : { "currencyCode" : "USD", "value" : 1900 },
Note: Value for monetary amounts is always in minor units.
tenderType
string | required
Tender Type
Valid value: CARD or CASH
taxAmounts
array | optional
Tax
Default: 0
isTaxInclusive
boolean | optional
Is Tax Included in Transaction Amount
Valid values:
  • true
  • false (Default)
discountAmounts
array | optional
Discount Amount
Deducted from baseTransactionAmount.
key: "currencyCode" ("USD") key: "value" ("2000" - in minor units)

Response

requestId
string
Transaction request ID specified in request.
 
statusDetails
string
Status of the request.
 
data
JSONObject
Object holding various responses.
 
paymentGatewayCommand
JSONObject
Payment Gateway Command
 
completed
boolean
Transaction Status
 
eventQueue
array
Event Queue
List of events that occurred and its corresponding timestamps.
chanId
boolean
Transaction ID
Identifier used to query the status of the transaction until completion.

Example

Request

Kick off a back end transaction.

{
  "method" : "startPaymentTransaction",
  "requestId" : "32878540",
  "targetType" : "paymentGatewayConverge",
  "version" : "1.0",
  "parameters" : {
    "paymentGatewayId" : "11b0032b-eb0d-4d9a-8664-eb430684cb92",
    "transactionType" : "SALE",
    "baseTransactionAmount" : {
      "value" : 2000,
      "currencyCode" : "USD"
    },
    "tenderType" : "CARD",
    "cardType" : null,
    "isTaxInclusive" : false,
    "taxAmounts" : [{
      "value" : 0,
      "currencyCode" : "USD"
    }],
    "discountAmounts" : null
  }
}

Later to query the status of the transaction.

{
  "method" : "getPaymentTransactionStatus",
  "requestId" : "32878541",
  "targetType" : "paymentGatewayConverge",
  "version" : "1.0",
  "parameters" : {
    "paymentGatewayId" : "11b0032b-eb0d-4d9a-8664-eb430684cb92",
    "chanId" : "239c9b47-c6c3-462b-8701-b83586bdf3e6"
  }
}
Response
Incomplete
{
  "requestId" : "32878540",
  "statusDetails" : "REQUEST_ACCEPTED",
  "data" : {
    "paymentGatewayCommand" : {
      "completed" : false,
      "eventQueue" : [ {
        "timeStamp" : "1457115273607",
        "statusDetails" : "STARTING"
      } ],
      "chanId" : "239c9b47-c6c3-462b-8701-b83586bdf3e6"
    }
  }
EMV Successful
{
  "requestId" : "1947227770",
  "statusDetails" : "REQUEST_ACCEPTED",
  "data" : {
    "paymentGatewayCommand" : {
      "completed" : true,
      "eventQueue" : [ ],
      "chanId" : "7c332149-ba08-497d-9c7f-ab57792dac1f",
      "paymentTransactionData" : {
        "result" : "APPROVED",
        "authCode" : "******",
        "iccAid" : "A0000000031010",
        "iccAppName" : "Visa Credit",
        "iccMode" : "ICC_MODE",
        "iccTvr" : "80C0008000",
        "iccTsi" : "6800",
        "resultMessage" : "APPROVAL",
        "iccCvmr" : "SIGNATURE",
        "date" : "Fri Mar 04 13:21:39 MST 2016",
        "cardEntryType" : "EMV_CONTACT",
        "cardScheme" : "VISA",
        "amount" : {
          "currencyCode" : "USD",
          "value" : 8700
        },
        "id" : "040316A15-F48AB876-9635-4933-B773-136888A3D972",
        "transactionType" : "SALE",
        "approved" : "yes",
        "errors" : [ ],
        "tax" : {
          "currencyCode" : "USD",
          "value" : 200
        },
        "maskedPan" : "******",
        "gratuityAmount" : {
          "currencyCode" : "USD",
          "value" : 300
        },
        "signatureBitmap" : {
          "data" : "` +J  !_ P____ X _'___ _& _'  ( _' _/ _'  ( _/ _/  ( _7 _/  ( _7 _/ _7 _7  ( _/ _/ _/ _/ _'  ( _& _%___ _'_______________________W____ X__W_ P____ Y_ P_ X  !_ X  \"  !  )  !  )  )  )  )  )  1  )  1  *  )  (  1  )  1  )  )  (  )  )  (  )  !p`#+Q  !  0  !  0  0  )  8  8  0  8  )  0 _/  0  0 _'  ( _&  (___ _& _'______ _&___ _'___ _&___ _'___ _'___ _& _'___ _/___ _' _/ _& _'p`'&__ X _&p`+)?_ P____ X___________W_ X________^_________ _'___ _'___ _/ _' _/  ( _/  0  8  (  (  1  (  )  0  )  )  )  )  )  !  )  !  !_ Y  !  !_ Y  !_ Y_ Y_ Y_ Y_ X_ Y_ Xp`-*( _'_ X_______ X _'_ X _'_ X _'_ X _'___ _'______ _'__^ _' _' _' _/ _' _/ _/  0 _/  0  (  0  (  0  1  0  1  (  1  )  1  )  )  )  !  )  !_ Z  !_ Y_ Y_ Q_ Z_ Q_ P_ Q_ Q_ Q_ H_ Q_ P_ Q_ P_ P__W_ X_ P___p",
          "format" : "SIG_BIN_2"
        },
        "tenderType" : "CARD",
        "balanceDue" : {
          "currencyCode" : "UNKNOWN",
          "value" : 0
        }
      }
    }
  }
}
Card Swipe Successful
{
  "requestId" : "32878570",
  "statusDetails" : "REQUEST_ACCEPTED",
  "data" : {
    "paymentGatewayCommand" : {
      "completed" : true,
      "eventQueue" : [ ],
      "chanId" : "239c9b47-c6c3-462b-8701-b83586bdf3e6",
      "paymentTransactionData" : {
        "result" : "APPROVED",
        "authCode" : "******",
        "date" : "Fri Mar 04 13:14:54 MST 2016",
        "cardEntryType" : "SWIPE",
        "resultMessage" : "APPROVED",
        "cardScheme" : "VISA",
        "amount" : {
          "currencyCode" : "USD",
          "value" : 2500
        },
        "id" : "040316A15-6C692699-7640-454A-9FAE-7B2FBFADCB53",
        "transactionType" : "SALE",
        "approved" : "yes",
        "errors" : [ ],
        "tax" : {
          "currencyCode" : "USD",
          "value" : 200
        },
        "maskedPan" : "******",
        "gratuityAmount" : {
          "currencyCode" : "USD",
          "value" : 300
        },
        "signatureBitmap" : {
          "data" : "` *G_ P_ X     !_ X  )  (  )  (  )  0  0  0  8  0 _/  ( _'  ( _'  ( _& _& _&___ _&_____^_____^ _'__V _&__V _'__^__W _'_____^ _'____ X _& _'  ( _'  0  0  0  8  8  )  8  (  1  0  0  )  0  0  0p`'*)_ X _'_ P _'_ X _'____ X _&_ X _& _'  ( _' _/ _'  ( _/  ( _/ _'  0 _/  0 _'  ( _/  ( _'  ( _'  ( _&___ _'___ _'_ X___ _'____ P _'__W_ X____ H_ X___p`&*0  \"  (  !  (  !  (  )  )  (  )  )  (  )  0  )  (  1  0  )  8  )  8  (p`)&Y      p`-)C_ X _'_ X____ X _'_ X _'______ _'___ _&___ _& _' _/ _' _/  ( _'  ( _/  8  8  0  )  (  1  )  )  !  (  )  )  #  )  \"  \"_ Y  !_ Y  !_ Y_ Y_ Y_ Xp`0)J _'_ X _'_ X _&_ X _'___ _'_ X _&___ _& _& _& _/  ( _'  ( _/  0  8  (  0  )  0  )  (  2  (  *  (  *  )  !  *  !  !  \"  !_ Y  !_ Z_ Y_ Y_ X_ Q_ Y_ P_ Y_ P_ X_ Q_ P____ X_ Pp",
          "format" : "SIG_BIN_2"
        },
        "tenderType" : "CARD",
        "balanceDue" : {
          "currencyCode" : "UNKNOWN",
          "value" : 0
        }
      }
    }
  }
}
Failed
{
  "requestId" : "670817917",
  "statusDetails" : "REQUEST_ACCEPTED",
  "data" : {
    "paymentGatewayCommand" : {
      "completed" : true,
      "eventQueue" : [ {
        "timeStamp" : "1447437024243",
        "statusDetails" : "CARD_READER_TRANSACTION_COMPLETED"
      } ],
      "chanId" : "481c043e-78ad-410b-bb48-44ee2526be2a",
      "paymentTransactionData" : {
        "id" : "131115CAD-A66E04AD-E559-4A7D-AF29-17E2BA8D4A77",
        "result" : "DECLINED",
        "authCode" : "******",
        "transactionType" : "SALE",
        "approved" : "no",
        "errors" : [ ],
        "maskedPan" : "******",
        "tenderType" : "CREDIT_CARD",
        "date" : "Fri Nov 13 12:50:19 MST 2015",
        "cardScheme" : "VISA"
      }
    }
  }
}

Java

To submit a Sale transaction, complete the following steps:

  1. Initialize Commerce SDK and receive an ECLAccountInterface instance named account.

  2. Create a money object by specifying a currency code and an amount.

    ECLMoney amount = new ECLMoney(ECLCurrencyCode.USD, 300L);
  3. Create a transaction reference.

    ECLCurrencyTransactionInterface transaction = account.getTransactionProcessor().createSaleTransactionWithSubtotal(amount);
  4. Create a tender instance.

    Card Tender

    ECLCardTenderInterface tender = account.getTransactionProcessor().createCardTender();

    Cash Tender

    ECLCashTenderInterface tender = account.getTransactionProcessor().createCashTender();
  5. Create a transaction processing listener. The transaction processing listener enables your application to receive callbacks during transaction processing.

    // Create an Instance of ECLTransactionProcessingListener (handle all callbacks and any requests for information during transaction processing)
    ECLTransactionProcessingListener transactionListener = new ECLTransactionProcessingListener()
    {
        /**
        * Transaction Completed ...  How did it turn out?
        */
        @Override
        public void transactionDidComplete(ECLTransactionInterface transaction, ECLTenderInterface tender, final ECLTransactionOutcome outcome)
        {
            if (outcome == null)
            {
                // Warning - No outcome was present
                logger.warning("transaction completed... with null outcome");
            }
            else if (outcome.isApproved())
            {
                // Transaction was APPROVED!!!  Use the "outcome" instance for transaction details (approval code, etc.)
            }
            else
            {
                // Transaction was DECLINED!!!  Use the "outcome" instance for transaction details (approval code, etc.)
            }
    
            // Can check error field to see if an error occurred during the processing.
            // Can check signatureError field to see why signature failed to be sent
            if (outcome.isSignatureSent())
            {
                // Signature collected and sent for transaction.
            }
    
            // If the transaction happened to utilize an EMV chip card, check for any errors.
            if (outcome instanceof ECLEmvCardTransactionOutcome)
            {
                ECLEmvCardTransactionOutcome emvOutcome = (ECLEmvCardTransactionOutcome)outcome;
                // reversal error is if the transaction was approved by Converge server and card declined it but Commerce were unable to tell Converge server to reverse.
                showErrors("reversal error", Arrays.asList(emvOutcome.getReversalError()));
                // update error is if after transaction completed the card told us to update the EMV properties associated with the transaction but commerce failed to do that.
                showErrors("update error", Arrays.asList(emvOutcome.getUpdateTransactionError()));
            }
        }
    
        @Override
        public void transactionDidCancel(ECLTransactionInterface transaction, ECLTenderInterface tender)
        {
            // Transaction was cancelled.  Time to move on...
        }
    
        @Override
        public void transactionDidFail(ECLTransactionInterface transaction, ECLTenderInterface tender, List<ECCError> errors)
        {
            // Uh oh, transaction failed.  Display the errors (list).
        }
    
        @Override
        public void shouldProvideInformation(final ECLTransactionInterface transaction, final ECLTenderInterface tender, final ECLTransactionRequirementsInterface transactionRequires, final ECLTenderRequirementsInterface tenderRequires)
        {
            // Hold on, we need more information to process the transaction!
            // During transaction processing, this callback may be executed one or more times for the purpose
            // of collecting more information to continue processing the transaction.
    
            boolean continueTransaction = false;
            if (tenderRequires.isDigitalSignatureRequired())
            {
                // Transaction Requires a [Digital] Signature!
                // The example below simply provides a basic image block to satisfy the signature image requirement.
                // If using a smartphone, for example, capture the signature on-screen and then pass the signature image to Commerce SDK.
                // Should the signature be cancelled at this point (i.e. "cardTender.cancelSignature();"), Commerce SDK will include a blank signature line on the printed receipt.
                Thread thread = new Thread()
                {
                    @Override
                    public void run()
                    {
                        GetSignatureDialog getSignatureDialog = new GetSignatureDialog();
                        getSignatureDialog.setLocationRelativeTo(parentFrame);
                        getSignatureDialog.setVisible(true);
                        ECLCardTenderInterface cardTender = (ECLCardTenderInterface) tender;
                        if (getSignatureDialog.isClickedOK())      /* Did the user click OK? */
                        {
                            ECLDimension minSize = tenderRequires.getMinimumDigitalSignatureSize();
                            deckard.graphics.desktop.DesktopBitmap sig = new deckard.graphics.desktop.DesktopBitmap();
                            sig.initialize(minSize.getWidth(), minSize.getHeight(), Bitmap.Config.BLACK_AND_WHITE);
                            sig.fillWithColor(0, 0, minSize.getWidth(), minSize.getHeight(), Color.BLACK);
                            cardTender.setDigitalSignature(new ECLSignatureData(sig));
                        }
                        else
                        {
                            cardTender.cancelSignature();
                        }
                        account.getTransactionProcessor().continueProcessingTransaction(transaction, tender, transactionListener);
                    }
                };
                thread.start();
                return;
            }
            if (tenderRequires.getRequiresVoiceReferral() != ECLVoiceReferralRequirement.NOT_REQUIRED)
            {
                // Voice Referral Required!
                // Some transactions may require calling the issuer to obtain an approval code.
                // Should this be required, pass the approval code to Commerce SDK once the code has been provided.
                ((ECLCardTenderInterface) tender).setVoiceReferralHandledAndApproved("321");
                continueTransaction = true;
            }
            if (tenderRequires.getRequiresSignatureVerification() != ECLSignatureVerificationRequirement.NOT_REQUIRED)
            {
                // Signature Verification Required!
                // In some cases, processing may ask to verify the cardholder's signature.  Once verified, the transaction processing may continue.
                ((ECLCardTenderInterface) tender).setSignatureVerificationHandledAndVerified();
                continueTransaction = true;
            }
    
            if (tenderRequires.requiresSpecifyingCardPresence())
            {
                // Is the Card Physically Present at the Time of Processing?
                // When manually entering a card number, it may be necessary to indicate if the card is physically present and in-hand.
                // If the card is not present, the state should be set to "NO".
                Thread thread = new Thread()
                {
                    @Override
                    public void run()
                    {
                        CardPresentDialog dialog = new CardPresentDialog();
                        dialog.setLocationRelativeTo(parentFrame);
                        dialog.setVisible(true);
                        if (dialog.isClickedOK())
                        {
                            if (dialog.isCardPresent())
                            {
                                ((ECLCardTenderInterface) tender).setCardPresent(ECLTriState.YES);
                            }
                            else
                            {
                                ((ECLCardTenderInterface) tender).setCardPresent(ECLTriState.NO);
                            }
                            account.getTransactionProcessor().continueProcessingTransaction(transaction, tender, transactionListener);
                        }
                        else
                        {
                            account.getTransactionProcessor().cancelTransaction(transaction, tender, transactionListener);
                        }
                    }
                };
                thread.start();
                return;
            }
            if (transactionRequires.isGratuityRequired() && transaction instanceof ECLCurrencyTransactionInterface)
            {
                // Transaction Supports Gratuity...  Was a value already determined/provided?  If so, set the amount here.
                ((ECLCurrencyTransactionInterface)transaction).setGratuity(null);
                logger.info("   Gratuity");
                continueTransaction = true;
            }
    
            if (continueTransaction)
            {
                // Has the required information been provided?  If so, continue transaction processing.
                logger.warning("shouldProvideInformation continue");
                account.getTransactionProcessor().continueProcessingTransaction(transaction, tender, transactionListener);
            }
            else
            {
                logger.warning("shouldProvideInformation unhandled - canceling transaction");
                account.getTransactionProcessor().cancelTransaction(transaction, tender, transactionListener);
            }
        }
    
        @Override
        public void shouldSetCardReaderToUse(ECLTransactionInterface transaction, ECLTenderInterface tender, List<String> cardReadersReadyForUse)
        {
            // Lucky day, more than one card reader is available!
            // Should this scenario arise, provide a mechanism to select the appropriate card reader.
            logger.warning("unhandled shouldSetCardReaderToUse(List) so canceling transaction");
        }
    
        public void transactionProgress(final ECLTransactionProgress progress, final ECLTransactionInterface transaction, final ECLTenderInterface tender)
        {
            // Always good to know what is happening while the transaction is processing!
            // Use this callback to provide status information (i.e. "progress" messages)
            logger.info(String.format("ECLTransactionProcessingListener transactionProgress %s", progress.name()));
        }
    };
    
  6. Start the transaction.

    account.getTransactionProcessor().processTransaction(transaction, tender, transactionListener);

Objective-C

To submit a Sale transaction, complete the following steps:

  1. Initialize Commerce SDK and receive an ECLAccountInterface instance named account.

  2. Create a money object by specifying a currency code and an amount.

    ECLMoney *amount = [[ECLMoney alloc] initWithMinorUnits:300 withCurrencyCode:ECLCurrencyCode_USD];
  3. Create a transaction protocol.

    id<ECLCurrencyTransactionProtocol> transaction = [account.transactionProcessor createSaleTransactionWithSubtotal:amount];
  4. Create a tender instance.

    Card Tender

    id<ECLCardTenderProtocol> tender = [account.transactionProcessor createCardTender];

    Cash Tender

    id<ECLCashTenderProtocol> tender = [account.transactionProcessor createCashTender];
    // Need to set the amount of cash handed to us from the customer
    // Here we will set it to the same amount as it costs
    tender.amountTendered = amount;
  5. Create a transaction processing delegate. The transaction processing delegate enables your application to receive callbacks during transaction processing.

    // in your header file
    #import <Commerce-Converge/ECLTransactionProcessingDelegate.h>
    @interface TransactionProcessingDelegate : NSObject<ECLTransactionProcessingDelegate>
    
    // In your .m file
    #import "TransactionProcessingDelegate.h"
    #import <Commerce-Converge/ECLAccountProtocol.h>
    #import <Commerce-Converge/ECLTransactionProcessorProtocol.h>
    #import <Commerce-Converge/ECLCurrencyTransactionProtocol.h>
    #import <Commerce-Converge/ECLTransactionRequirementsProtocol.h>
    #import <Commerce-Converge/ECLCardTenderProtocol.h>
    #import <Commerce-Converge/ECLEmvCardTransactionOutcome.h>
    #import <CommerceDataTypes/CommerceDataTypes.h>
    #import <Commerce-Converge/ECLTenderRequirementsProtocol.h>
    #import <Commerce-Converge/ECLTransactionProgress.h>
    #import <Commerce-Converge/ECLDebugDescriptions.h>
    @implementation TransactionProcessingDelegate
        + (void)transactionDidComplete:(id<ECLTransactionProtocol>)transaction using:(id<ECLTenderProtocol>)tender outcome:(ECLTransactionOutcome *)outcome {
    
        if (outcome == nil) {
            NSLog(@"nil outcome");
            return;
        } 
    
        if (outcome.error != nil) {
            NSLog(@"transactionDidComplete with error: %@", outcome.error.debugDescription);
        }
    
        // can also check signatureError to see if we failed to send signature
    
        if (outcome.isApproved == YES) {
            // Transaction was APPROVED!!!  Use the "outcome" instance for transaction details (approval code, etc.)
        } else {
            // Transaction was DECLINED!!!  Use the "outcome" instance for transaction details (approval code, etc.)
        }
        if ([outcome isKindOfClass:[ECLCardTransactionOutcome class]]) {
            // Outcome is for a Card Transaction so cast to ECLCardTransactionOutcome to get more info 
            if ([outcome isKindOfClass:[ECLEmvCardTransactionOutcome class]]) {
                // Outcome is for a EMV Card Transaction so cast to ECLEmvCardTransactionOutcome to get more info 
                // including checking if we failed to reverse a transaction from reverseError property
                // or we failed to update a transaction on the server from updateError property
            }
        }
    }
        + (void)transactionDidCancel:(id<ECLTransactionProtocol>)transactionParam using:(id<ECLTenderProtocol>)tenderParam {
        // Transaction was canceled
    }
        + (void)transactionDidFail:(id<ECLTransactionProtocol>)transactionParam using:(id<ECLTenderProtocol>)tenderParam errors:(NSArray *)arrayOfNSErrors {
        // Transaction failed. Check the array of NSErrors to see why.
        // Use nsError.debugDescription to log more information
    }
    
        + (void)shouldProvideInformation:(id<ECLTransactionProtocol>)transactionParam tender:(id<ECLTenderProtocol>)tenderParam transactionRequires:(id<ECLTransactionRequirementsProtocol>)transactionRequires tenderRequires:(id<ECLTenderRequirementsProtocol>)tenderRequires {
        // We need more information to process the transaction!        
        // During transaction processing, this callback may be executed one or more times for the purpose
        // of collecting more information to continue processing the transaction.    
        // SEE SAMPLE APP FOR OTHER REQUIREMENTS YOU SHOULD PROVIDE WHEN THIS METHOD IS CALLED. Listed here is only sample of those.
    
        BOOL continueTransaction = NO;
    
        if (transactionRequires.requiresGratuity) {
            // Transaction requires gratuity to be set but if we don't want to set any we can set it to nil.
            // Lets make sure it is a ECLCurrencyTransactionProtocol
            if ([transactionParam conformsToProtocol:@protocol(ECLCurrencyTransactionProtocol)]) {
                id<ECLCurrencyTransactionProtocol> currencyTransaction = (id<ECLCurrencyTransactionProtocol>)transactionParam;
                [currencyTransaction setGratuity:nil];
                continueTransaction = YES;
            }
        }
    
        if (tenderRequires.requiresVoiceReferral != ECLVoiceReferral_NotRequired) {
            // Voice Referral Required!                
            // Some transactions may require calling the issuer to obtain an approval code.
            // Should this be required, pass the approval code to Commerce SDK once the code has been provided.        
            // Lets make sure it is a ECLCardTenderProtocol
            if ([tenderParam conformsToProtocol:@protocol(ECLCardTenderProtocol)]) {
                id<ECLCardTenderProtocol> cardTenderProtocol = (id<ECLCardTenderProtocol>)tenderParam;
                [cardTenderProtocol setVoiceReferralHandledAndApproved:@"321"]; // we should show UI to get Authorization Code 
                                                                                // and call continueTransaction after we get it but here we just set it
                continueTransaction = YES;
            }
        }
    
        if (tenderRequires.requiresSignatureVerification != ECLSignatureVerification_NotRequired) {
            // Signature Verification Required!                
            // In some cases, processing may ask to verify the cardholder's signature.  Once verified, the transaction processing may continue.
            // Lets make sure it is a ECLCardTenderProtocol
            if ([tenderParam conformsToProtocol:@protocol(ECLCardTenderProtocol)]) {
                id<ECLCardTenderProtocol> cardTenderProtocol = (id<ECLCardTenderProtocol>)tenderParam;
                [cardTenderProtocol setSignatureVerificationHandledAndVerified]; // we should show UI to ask for verification
                                                                                // and call continueTransaction after we get it but here we just set it
                continueTransaction = YES;
            }
        }
    
        if (tenderRequires.requiresDigitalSignature){
            // We should launch signature capture UI and setDigitalSignature on ECLCardTenderProtocol and call continueTransaction
            // See sample app how to capture signature. Search for the line below
            // [myViewController performSegueWithIdentifier:@"signatureScreenSegue" sender:self];
            // return;
    
            // but for now lets cancel the signature and that will print a line on the receipt for customer to sign
            // Lets make sure it is a ECLCardTenderProtocol
            if ([tenderParam conformsToProtocol:@protocol(ECLCardTenderProtocol)]) {
                id<ECLCardTenderProtocol> cardTenderProtocol = (id<ECLCardTenderProtocol>)tenderParam;
                [cardTenderProtocol cancelSignature];
                continueTransaction = YES;
            }
        }
    
        if (continueTransaction) {
            // NOTE: You should always do a dispatch_async when calling from a delegate method back into Commerce to process a transaction or before showing UI
            dispatch_async(dispatch_get_main_queue(), ^() {
                // continue the transaction because we updated required information
                [yourInstanceOfECLAccountProtocol.transactionProcessor continueProcessingTransaction:transactionParam using:tenderParam delegate:self];
            });
        } else {
            // we failed to provide the information. Should cancel transaction. Check log for what was required
        }
    }
    
        + (void)shouldSetCardReaderToUse:(id<ECLTransactionProtocol>)transactionParam tender:(id<ECLTenderProtocol>)tenderParam cardReaders:(NSArray *)cardReadersReadyForUse {
        // Commerce detected more than one card reader so you need to let the user choose which one from the list of NSStrings in cardReadersReadyForUse
        // Should this scenario arise, provide a mechanism to select the appropriate card reader.
    
        // NOTE: You should always do a dispatch_async when calling from a delegate method back into Commerce to process a transaction or before showing UI
        dispatch_async(dispatch_get_main_queue(), ^() {
            // Show your UI here
            // Then call yourInstanceOfECLAccountProtocol.cardReaders setDeviceToUse to set the card reader chosen
            // Then call yourInstanceOfECLAccountProtocol.transactionProcessor continueProcessingTransaction
        });
        return;
    }
        + (void)transactionProgress:(ECLTransactionProgress)progress transaction:(id<ECLTransactionProtocol>)transactionParam using:(id<ECLTenderProtocol>)tenderParam {
        // Always good to know what is happening while the transaction is processing!        
        // Use this callback to provide status information (i.e. "progress" messages)
        NSLog(@"transactionProgress %@", [ECLDebugDescriptions descriptionOfTransactionProgress:progress]);
    }
  6. Start the transaction.

    TransactionProcessingDelegate *delegate = [[TransactionProcessingDelegate alloc] init];
    [account.transactionProcessor processTransaction:transaction using:tender delegate:delegate];

C#

A sale transaction with a card tender for $3.25.

Request

PaymentArgs bea = new PaymentArgs();
Money m = new Money(Money.CurrencyCodefromString("USD"), 325);
bea.baseTransactionAmount = m;
bea.tenderType = TenderType.CARD;            
/* If you were using a CASH tender you will also need to set 'bea.tenderedAmount' to the amount of cash you took from the customer */
bea.transactionType = TransactionType.SALE;
bea.paymentGatewayId = m_PaymentGatewayId; 

m_CWS.StartPaymentTransaction(bea, MyNotifyCWSEvent, MyPaymentComplete);            

Response

public void MyPaymentComplete(PaymentTransactionResults ber)
{
    PaymentTransactionData betd = ber.PaymentTransactionData;

    if (null != betd)
    {
        if (null != betd.errors)
        {
            for (int i = 0; i < betd.errors.Length; i++)
            {
                Log(String.Format("Error[{0}] =  {1}", i, betd.errors[i]));
            }
        }

        if ((null != betd.approved) && (betd.approved.Equals("yes")))
        {
            /* transaction was approved */
        }
    }
    String[] req = ber.getRequiredInformation();
    if (null != req)
    {
        Log("---- Information Required ----");
        for (int i = 0; i < req.Length; i++)
        {
            Log(String.Format("Required[{0}] = {1}", i, req[i]));
        }
    }
}