> For the complete documentation index, see [llms.txt](https://docs.verifone.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.verifone.com/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/payment_functions/semi-integrated-payments/performing-a-sale.md).

# Performing a Sale

As noted earlier, every transaction is wrapped within a session, so all transactions described from here forward assume that a session has been established with a valid [CommerceListener](https://docs.verifone.com/psdk-api-latest/android-java/index/commercelistener2). Multiple payments can occur within a single session, as in the use cases for multi-tender or split-tender, but a session should be ended before a new cart/order is started. See [Getting Started ](/psdk-latest/readme.md)to start a session, and [PSDK State Transitions](/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/pos_guide.md#psdk-state-transitions) for information on when different commands can be performed.

### Setup and Start a Payment <a href="#setup-and-start-a-payment" id="setup-and-start-a-payment"></a>

Before initiating a sale transaction, a [Payment](https://docs.verifone.com/psdk-api-latest/android-java/index/payment) object must be created. Creating the payment object automatically creates a [AmountTotals](https://docs.verifone.com/psdk-api-latest/android-java/index/amounttotals) object which must be assigned to the payment object via [getRequestedAmounts](https://docs.verifone.com/psdk-api-latest/android-java/index/payment#getrequestedamounts). The following amounts may be assigned to the AmountTotals object: Subtotal, Tax, Gratuity, Total, Cashback, Fees, and Donation. Please note that these fields are all optional and if not required, should be either omitted or set to null. Other common attributes which may optionally be set in the payment object are [setRequestedPaymentType](https://docs.verifone.com/psdk-api-latest/android-java/index/payment#setrequestedamounts-amounttotals) and [setTransactionType](https://docs.verifone.com/psdk-api-latest/android-java/index/payment#settransactiontype-transactiontype).

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
// A session must be open to perform a payment

Payment payment = Payment.create();
// Creating a Payment also creates an empty AmountTotals object in the requested amounts.
AmountTotals requestedAmounts = payment.getRequestedAmounts();
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
requestedAmounts.setSubtotal(
ConversionUtility.parseAmount(8.00));
requestedAmounts.setTax(ConversionUtility.parseAmount(1.00));
requestedAmounts.setGratuity(ConversionUtility.parseAmount(1.00));
requestedAmounts.setTotal(ConversionUtility.parseAmount(10.00));
transactionManager.startPayment(payment);
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // A session must be open to perform a payment
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
 val payment = Payment.create().apply {
    RequestedAmounts.apply {
        Subtotal = Decimal(8.00)
        Tax = Decimal(1.00)
        Gratuity = Decimal(1.00)
        Total = Decimal(10.00)
    }
}
// Creating a Payment also creates an empty AmountTotals object in the requested amounts.
transactionManager.startPayment(payment)
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// A session must be open to perform a payment

var payment = VFIPayment.create()
// Creating a Payment also creates an empty AmountTotals object in the requested amounts.
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
var requestedAmounts = payment?.getRequestedAmounts()
requestedAmounts?.setSubtotal(VFIDecimal.init(valueDecimal: Decimal.init(8.00)))
requestedAmounts?.setTax(VFIDecimal.init(valueDecimal: Decimal.init(1.00)))
requestedAmounts?.setGratuity(VFIDecimal.init(valueDecimal: Decimal.init(1.00)))
requestedAmounts?.setTotal(VFIDecimal.init(valueDecimal: Decimal.init(10.00)))
sdk.getTransactionManager()?.start(payment)
// Listener receives the PaymentCompletedEvent.
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> // A session must be open to perform a payment
</strong>
// Please note that all amount fields are optional and
// should be omitted or set to null if not used.
var amount_totals = new AmountTotals();
PaymentSDK.Decimal subtotal = new PaymentSDK.Decimal(8.00);
PaymentSDK.Decimal gratuity = new PaymentSDK.Decimal(1.00);
PaymentSDK.Decimal tax = new PaymentSDK.Decimal(1.00);
PaymentSDK.Decimal total = new PaymentSDK.Decimal(10.00);
amount_totals.SetWithAmounts(subtotal, tax, gratuity, total);
var payment = new Payment
{
    RequestedAmounts = amount_totals
};
payment_sdk_.TransactionManager.StartPayment(payment);
// Listener receives the PaymentCompletedEvent.
</code></pre>

{% endtab %}

{% tab title="Linenos" %}
{% code lineNumbers="true" %}

```cpp
// A session must be open to perform a payment

   auto payment = verifone_sdk::Payment::create();
   // Creating a Payment also creates an empty AmountTotals object in the requested amounts.
   // Please note that all amount fields are optional and
   // should be omitted or set to null if not used.
   payment->getRequestedAmounts()->setSubTotals(8.00)
                                 ->setTax(1.00)
                                 ->setGratuity(1.00)
                                 ->setTotal(10.00);
   psdk->getTransactionManager()->startPayment(payment);
   // Listener receives the PaymentCompletedEvent.


.. code-tab:: c# .NET
   :linenos:

   // A session must be open to perform a payment
   // Please note that all amount fields are optional and
   // should be omitted or set to null if not used.

   var amount_totals = AmountTotals.Create(false);
   VerifoneSdk.Decimal subtotal = new VerifoneSdk.Decimal(8);
   VerifoneSdk.Decimal gratuity = new VerifoneSdk.Decimal(1);
   VerifoneSdk.Decimal tax = new VerifoneSdk.Decimal(1);
   VerifoneSdk.Decimal total = new VerifoneSdk.Decimal(10);
   amount_totals.SetWithAmounts(subtotal, tax, gratuity, total, null, null, null);
   var payment = Payment.Create();
   payment.RequestedAmounts = amount_totals;
   payment_sdk_.TransactionManager.StartPayment(payment);
   // Listener receives the PaymentCompletedEvent.
 

 


```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**See also**

* [AmountTotals](https://docs.verifone.com/psdk-api-latest/android-java/index/amounttotals)
* [Payment](https://docs.verifone.com/psdk-api-latest/android-java/index/payment)
  {% endhint %}

### Multi-Currency <a href="#multi-currency" id="multi-currency"></a>

A payment transaction can be performed with different currencies each time. A specific currency (eg. USD, EUR) may be specified for the transaction by configuring the currency in the transaction object [Transaction.setCurrency().](https://docs.verifone.com/psdk-api-latest/android-java/index/transaction#setcurrency-string) If no currency is set, then it defaults to the local currency. The currency which is set in the transaction object can be overridden by setting it in the payment object Payment.[setCurrency](https://docs.verifone.com/psdk-api-latest/android-java/index/payment#setcurrency-string)().

### Handling Precision of Monetary Values <a href="#handling-precision-of-monetary-values" id="handling-precision-of-monetary-values"></a>

PSDK uses the Decimal class for monetary values. The values are represented by value and scale: please see [DecimalBase](https://docs.verifone.com/psdk-api-latest/android-java/index/decimalbase)(). A Decimal object consists of a 64 bit integer value and a 32 bit integer scale. The scale represents the number of digits to the right of the decimal point. For example, 10.99 is represented as a value of 1099 and a scale of 2.

### Handle Payment Completed Event <a href="#handle-payment-completed-event" id="handle-payment-completed-event"></a>

Once the payment has been initiated, the payment application handles everything, including consumer UI, card reader interaction, and host authorization. We just need to wait for the [TransactionEvent.TRANSACTION\_PAYMENT\_COMPLETED](https://docs.verifone.com/psdk-api-latest/android-java/index/transactionevent) event and check the authorization result. The following code snippet is assumed to be within the [CommerceListener.handlePaymentCompletedEvent()](https://docs.verifone.com/psdk-api-latest/android-java/index/commercelistener2#handlepaymentcompletedevent-paymentcompletedevent) method of the [CommerceListener2](https://docs.verifone.com/psdk-api-latest/android-java/index/commercelistener2) instance passed into the session. See the [AuthorizationResult](https://docs.verifone.com/psdk-api-latest/android-java/index/authorizationresult) enumeration for more details on the result types.

{% tabs fullWidth="false" %}
{% tab title="Java" %}
{% code lineNumbers="true" fullWidth="true" %}

```java
@Override // Overridden from the CommerceListenerAdapter
public void handlePaymentCompletedEvent(PaymentCompletedEvent event) {
    if (TransactionEvent.TRANSACTION_PAYMENT_COMPLETED.equals(event.getType())) {
        if (event.getStatus() == StatusCode.SUCCESS) {
            Payment payment = event.getPayment();
            AuthorizationResult authorizationResult = payment.getAuthResult();
            // Confirm the authorization result is AUTHORIZED instead
            // of DECLINED or some other result.
        }
        // Else handle failure by examining the status code and message.
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
 // Overridden from the CommerceListenerAdapter
override fun handlePaymentCompletedEvent(event: PaymentCompletedEvent) {
    if (TransactionEvent.TRANSACTION_PAYMENT_COMPLETED.equals(event.getType())) {
        if (event.getStatus() == StatusCode.SUCCESS) {
            val payment = event.getPayment()
            val authorizationResult = payment.getAuthResult()
            // Confirm the authorization result is AUTHORIZED instead
            // of DECLINED or some other result.
        }
        // Else handle failure by examining the status code and message.
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
// Overridden from the VFICommerceListenerAdapter
override func handle(_ event: VFIPaymentCompletedEvent?) {
    if (event?.getType() == VFITransactionEventTRANSACTIONPAYMENTCOMPLETED) {
        if (event?.getStatus() == VFIStatusCodeSuccess) {
            let payment = event?.getPayment()
            let authorizationResult = payment?.getAuthResult()
            // Confirm the authorization result is AUTHORIZED instead
            // of DECLINED or some other result.
        }
        // Else handle failure by examining the status code and message.
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp" data-line-numbers data-full-width="true"><code class="lang-csharp"><strong> private void HandlePaymentCompletedEvent(PaymentCompletedEvent event)
</strong>{
    if (event.Type.Value == TransactionEvent.TRANSACTION_PAYMENT_COMPLETED)
    {
        if (event.Status == StatusCode.SUCCESS)
        {
            Payment payment = event.Payment;
            AuthorizationResult authorization_result = payment.AuthResult;
            // Confirm the authorization result is AUTHORIZED instead
            // of DECLINED or some other result.
        }
        // Else handle failure by examining the status code and message.
    }
}
</code></pre>

{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// Overridden from the CommerceListenerAdapter
void handlePaymentCompletedEvent(
    const std::shared_ptr<verifone_sdk::PaymentCompletedEvent>& event) override {
    if (event->getType() == TransactionEvent::TRANSACTION_PAYMENT_COMPLETED) {
      if (event->getStatus() == StatusCode::SUCCESS) {
          auto payment = event->getPayment();
          auto auth_result = payment->getAuthResult();
          // Confirm the authorization result is AUTHORIZED instead
          // of DECLINED or some other result.
      }
      // Else handle failure by examining the status code and message.
    }
}
```

{% endcode %}
{% endtab %}

{% tab title=".NET" %}
{% code lineNumbers="true" %}

```aspnet
private void HandlePaymentCompletedEvent(PaymentCompletedEvent sdk_event)
{
    if (sdk_event.Type == TransactionEvent.TRANSACTION_PAYMENT_COMPLETED)
    {
        if (sdk_event.Status == 0)
        {
            var payment = sdk_event.Payment;
            AuthorizationResult authorization_result = payment.AuthResult.Value;
            // Confirm the authorization result is AUTHORIZED instead
            // of DECLINED or some other result.
        }
        // Else handle failure by examining the status code and message.
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**See also**

* [PaymentCompletedEvent](https://docs.verifone.com/psdk-api-latest/android-java/index/paymentcompletedevent)
* [Payment](https://docs.verifone.com/psdk-api-latest/android-java/index/payment)
* [AuthorizationResult](https://docs.verifone.com/psdk-api-latest/android-java/index/authorizationresult)
* [TransactionManager.startSession2()](https://docs.verifone.com/psdk-api-latest/android-java/index/transactionmanager#startsession2-transaction)
* [CommerceListener2](https://docs.verifone.com/psdk-api-latest/android-java/index/commercelistener2)
  {% endhint %}

### Print Receipt <a href="#print-receipt" id="print-receipt"></a>

The [Receipt](https://docs.verifone.com/psdk-api-latest/android-java/index/receipt) can be retrieved from [PaymentCompletedEvent.getReceipts()](https://docs.verifone.com/psdk-api-latest/android-java/index/paymentcompletedevent#getreceipt), returning a map of receipts, keyed by either [ReceiptType.CUSTOMER ](https://docs.verifone.com/psdk-api-latest/android-java/index/payment_sdk_receipttype)or [ReceiptType.MERCHANT](https://docs.verifone.com/psdk-api-latest/android-java/index/payment_sdk_receipttype). The selected receipt can then be modified at specific points using [Receipt.insertTextAtSection(html, section)](https://docs.verifone.com/psdk-api-latest/android-java/index/receipt#inserttextatsection-string-receiptsection), inserting additional HTML into the desired section. Finally, use [Receipt.getAsHtml()](https://docs.verifone.com/psdk-api-latest/android-java/index/receipt#getashtml) to get a printable HTML string to send to the printer, or use to email/text to the customer. See [Printing](/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/peripherals_guide.md#id3) for more information on the printing APIs.

***

{% columns %}
{% column width="25%" %}

<figure><img src="/files/9ezXRridnCaI1awLr3X9" alt="" width="150"><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="25%" %}

{% endcolumn %}

{% column width="16.66666666666666%" %}
**Version:**\
**Date:**
{% endcolumn %}

{% column width="33.333333333333336%" %} <code class="expression">space.vars.psdk\_version</code>\ <code class="expression">space.vars.psdk\_date</code>
{% endcolumn %}
{% endcolumns %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.verifone.com/psdk-latest/psdk-user-guide-and-training/psdk-user-guide/payment_functions/semi-integrated-payments/performing-a-sale.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
