Making payments

Once the PgClient is initialized, you can start making payments.

AgentCASH SDK supports following types of transactions: purchases, refunds, authorizations and captures.

They are all executed by creating an instance of TransactionRequest and providing it as argument to one of the methods of PgClient: Charge, Refunds, Authorize and Capture.

Executing a purchase

Assuming that pgClient is a properly initialized instance of PgClient class, here’s how to execute a purchase:

// creating a new transaction request. Only the amount is mandatory
var payment = new TransactionRequest { Amount = amount };
// execute the payment request
await pgClient.Charge(payment);

Amount is the only required TransactionRequest property for purchases. Later, we will see other properties, but they are not required for purchases. The currency will be deduced from the merchant account settings.

Authorization payment with signature

In the case when the card requires signature authorization, pgClient will raise a SignatureRequested event.

In this case, the application should display the signature capture dialog, where customer will paint the signature with his finger. It should look similar to this one:

Signature collection screen

In the case when customer declines to authorize the transaction and presses “Cancel”, the application has to cancel the current request by invoking CancelSignature() method on the argument of SignatureRequested event:

void OnSignatureRequested(object sender, SignatureRequestedEventArgs e)
{
    // assuming that ShowCollectSignatureUI returns some Result object which
    // has SignatureValid and SignatureData properties
    var result = ShowCollectSignatureUI();
    if (!result.SignatureValid)
    {
      e.CancelSignature();
    }
    ....
}

In the more common case, when customer successfully signs on the screen and presses Authorize, application should ask the merchant to match the signature on the back of the card to the signature on the screen. It should be done by displaying an appropriate confirmation dialog similar to this one:

Signature verification screen

In the case when signatures don’t match, application should cancel the transaction by calling SignatureRequestedEventArgs.CancelSignature.

In the case when signatures match, application should finish the transaction by calling SetSignature method on SignatureRequestedEventArgs instance:

void OnSignatureRequested(object sender, SignatureRequestedEventArgs e)
{
    var result = ShowCollectSignatureUI();
    if (!result.SignatureValid)
    {
      e.CancelSignature();
    }
    else
    {
      // assuming that result.SignatureData is a byte array containing an image
      // (JPG, PNG) representing the signature
      e.SetSignature(result.SignatureData);
    }
}

Signature will be stored on AgentCASH servers and will be shown on digital and printed receipts and used in case of chargeback - i.e. as a proof of authorization if customer later decides to dispute the transaction through his issuing bank. The stored signature image can be later accessed via TransactionInfo.ReceiptUrl property of TransactionFinished event:

void OnTransactionFinished(object sender, TransactionFinishedEventArgs e)
{
  Log("Transaction finished: {0}", e.Succeeded ? "Success" : "Failure");
  Log("Status: {0}", e.TransactionInfo.Status);
  Log("Transaction ID: {0}", e.TransactionInfo.TransactionId);
  Log("Receipt URL: {0}", e.TransactionInfo.ReceiptUrl);
}

Refund

In some occasions, successful payments can be refunded later on customer request.

In this case, TransactionRequest.OriginalTransactionId must be set to the ID of the transaction being refunded.

The ID of the original transaction is available via TransactionFinished event arguments (see example above).

Another way to get the ID is to retrieve transaction info by calling PgClient.FindTransactions to look up transactions by authorization code or card PAN. Please note that searching for previous transactions, as well as performing refunds, requires that you provide username and password or access token in Configuration data.

var request = new TransactionRequest {
                OriginalTransactionId = originalTrxId,
                PreferredVerificationMethod = VerificationMethod.CardPresent,
                Amount = amount
            };

await pgClient.Refund(request);

Depending on whether the issuer supports partial refunds, specified amount can be less the original amount.

Additionally, PreferredVerificationMethod can be specified, depending on whether refund requires cardholder to be present or not.

Authorization & Capture

AgentCASH supports two-step payments, also known as “auth and capture”. This process allows you to authorize a charge and wait to settle it later.

Authorization

This is done in the same way as purchase, but instead of Charge, the Authorize method is called instead:

var payment = new TransactionRequest { Amount = amount };
await pgClient.Authorize(payment);

Capture

When you’re ready to actually accept the payment, you’ll just need to make a second API call to capture the charge. The ID of the original authorization must be specified.

You don’t have to capture the total amount that was authorized: if you want to charge less than the initial amount, you can pass in the Amount parameter and we’ll refund the rest back to the customer. Note that a charge must be captured within several days (depending on the acquirer) or it will be cancelled.

var request = new TransactionRequest
            {
                OriginalTransactionId = originalAuthorizationId,
                PreferredVerificationMethod = VerificationMethod.CardNotPresent,
                Amount = capturedAmount
            };

await pgClient.Capture(request);

Account verification

In order to check the status of the card account, PgClient.Verify method should be used with TransactionRequest.Amount set to 0:

var request = new TransactionRequest { Amount = 0 };
await pgClient.Verify(request);

This transaction type is not supported by all acquirers. Failing request should not be treated as if the card account is invalid - it means that it was not possible to check the account status.

Canceling a transaction

Once the transaction is started, it can be cancelled by calling PgClient.Cancel method. Please note that cancellation is not possible during later stages of the transaction.

Configuring the payment

As noted earlier, each payment is specified by an instance of TransactionRequest class, which provides following properties:

  • Amount : decimal - Sets/gets the amount to be charged from the credit card holder
  • Currency : string - ISO 4217 code of currency of the amount (e.g. “EUR”). If ommitted, the default currency for the merchant will be used
  • InstallmentCount : int - Gets/sets installment count. Default is 1.
  • OriginalTransactionId : string - Id of the transaction which this request refers to. E.g. when doing a refund or a capture, must be set to the id of the transaction which is being refunded/captured. Also used for top-up preauthorizations
  • ExternalId : string - Gets/sets the external identifier, used by 3rd party apps to identify the transactions in their own system. It will just be stored with transaction
  • CallbackUrl : string - Gets/sets the callback URL. If this is set, payment gateway will call the servers URL after payment transaction ends
  • PreferredVerificationMethod : VerificationMethod - Gets/set preferred method for capture and refund transactions:
    • CardPresent - Processing requires card to be presented to the card reader
    • CardNotPresent - Processing can be done without presenting card to the reader
  • Id : string - Returns the id of the transaction.
  • RefundReason : string - Gets/sets the reason for refund. It is not used for other types of transactions.
  • CardEntryMode : CardEntryMode - Gets/sets how card details are to be entered:
    • Standard - Card will be inserted, swiped or tapped
    • ManualEntry - Card data will be entered manually by the customer
    • MOTO - Card data will be entered manually by the merchant, without card being present
  • Metadata : IDictionary<string, object> - can be used to store custom data with payment
  • RegisterId : string - specifies the register assigned to the payment. If omitted, default register is used (first register of first non-online outlet)

Sending notifications

As we saw earlier, when the payment is executed, among other payment information returned to caller is also receipt URL.

It is possible to send the receipt as email or SMS notification. To do this, execute following methods:

  • SendReceiptByMail - sends notification to specified email address
  • SendReceiptBySMS - sends SMS notification with receipt URL to specified phone number

Examples:

  // get transaction through lookup or in the transaction result
  TransactionInfo trx = ...

  // both methods have overloads which take TransactionInfo object or transaction ID
  await pgClient.SendReceiptByMail(trx, "test@email.com");

  // you can also use phone number form with 00 prefix, e.g. 004494..
  await pgClient.SendReceiptBySMS(trx.TransactionId, "+4494...");

In case of failure, PgException will be thrown. As this are asynchronous methods, in order to catch the exception, you have to await the method call.

Error handling

All errors which may occur during the transaction processing will be reported via Error event:

...
// in initialization part, client app subscribes to Error event:
pgClient.Error += OnError;
...

The error handler can access more details about error through Code and Description fields of TransactionErrorEventArgs object:

void OnError(object sender, TransactionErrorEventArgs e)
{
    Log("Transaction failed due to an error: {0} - {1}", e.Code, e.Description);
}

TransactionErrorEventArgs class provides following properties:

  • Scope : ErrorScope - describes the source of the error.
    • CommunicationError: Error in communication with card reader, payment gateway or AC server.
    • TransactionError: Error received by gateway as outcome of transaction.
  • Code : ErrorCode - describes error reason.
    • CardReaderFailedToConnect: connecting to card reader failed.
    • CardReaderDisconnected: card reader disconnected during transaction.
    • PaymentGatewayError: communication with payment gateway failed.
    • TransactionCancelled: transaction was cancelled during processing.
    • SignatureError: transaction finished, signature verification failed.
    • TransactionVoid: transaction finished but was voided.
    • TransactionDeclined: transaction finished, but was declined.
    • TransactionDeclinedKeepCard: transaction finished, but was declined and card should be kept by merchant.
    • InvalidCard: transactions not allowed for the card or card not.
    • GenericError: any other error, see Description for more details.
  • Description : string - informational text describing the error.

Adding custom data to payments

Custom information can be added to payment and stored on the server. This is done by specifying the values in TransactionRequest.Metadata dictionary:

var request = new TransactionRequest {
                OriginalTransactionId = originalTrxId,
                PreferredVerificationMethod = VerificationMethod.CardPresent,
                Amount = amount
            };

request.Metadata["reference"] = "142av331";
request.Metadata["duration"] = 30;

await pgClient.Charge(request);

Metadata is also returned as a part of TransactionInfo, and can be used for payment lookup.

Specifying a register

Except for small merchants, typical merchant will have multiple registers in store, or even multiple outlets.

In that case, payment information should contain ID of the corresponding register.

Register can be listed using PgClient.GetOutletsAsync() method. It will return list of all outlets, each containg information about available registers.

var outlets = await pgClient.GetOutletsAsync();

Outlet object provides following properties:

  • Id : string - outlet identifier
  • Name : string - outlet name
  • IsOnline : bool - whether it is webshop or brick&mortar store
  • IsClosed : bool - whether it is open
  • WorkingHours : string - working time
  • Address : Address - outlet address (contains address, city, zipcode...)
  • Registers : IList<Register> - list of registers (containing id and name)

This can now be used to configure payment:

// find first register of London outlet
var registerId = outlets.First(o => o.Address.City == "London").Registers.First();
var request = new TransactionRequest
{
    Amount = 10,
    RegisterId = registerId
};
await pgClient.Charge(request);

If register info is omitted, default register is used (first register of first non-online outlet).