---
title: Gratuity
slug: vpDT-gratuity
docTags: 
createdAt: 2025-05-20T11:26:12.311Z
---

### Tipping modes

The SDK supports three gratuity modes, configured via `GratuityConfig.mode`:

| Mode                      | Description                                                                                                 |
| ------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `GratuityMode.none`       | No tipping prompt is shown. This is the default.                                                            |
| `GratuityMode.standard`   | The SDK shows a built-in tipping menu with 10%, 15%, and 20% options. No additional configuration required. |
| `GratuityMode.configured` | The SDK builds a tipping menu from the fixed amounts or percentages you supply.                             |

In `standard` and `configured` modes, the SDK handles the full on-device flow automatically, including the initial "Add Gratuity?" yes/no prompt, the selection menu, and a built-in "Other Amount" option for free-form tip entry.

### Global configuration

Set `gratuityConfig` in `ToroConfig` to apply the same tipping behaviour to every transaction:

```swift
  let config = ToroConfig(
      gratuityConfig: GratuityConfig(mode: .standard),
      // ...
  )
```

### Per-transaction configuration

Pass a `GratuityConfig` in `TransactionMetadata` to override the global config for a specific transaction. This is the recommended approach when tipping behaviour varies per transaction — for example, when switching between amounts and percentages based on business logic.

```swift
let metadata = TransactionMetadata(
    gratuityConfig: GratuityConfig(
        mode: .configured,
        percentages: [20, 10, 5],
        header: "Select a Tip / Gratuity:"
    )
)

toro.startTransaction(
    amount: 1000,
    type: .purchase,
    currency: .gbp,
    metadata: metadata,
    // ...
)
```

### standard mode

`GratuityMode.standard` presents a built-in tipping menu with 10%, 15%, and 20% options. No amounts or percentages need to be supplied.

```swift
GratuityConfig(mode: .standard)
```

:::hint{type="warning"}
Supplying `amounts` or `percentages` in `standard` mode will cause `startTransaction()` to fail with a validation error. Use `configured` mode instead.
:::

### configured mode

`GratuityMode.configured` lets you define exactly which amounts or percentages to offer. Supply either `amounts` (in pence) or `percentages` — not both. A maximum of 3 options may be provided. The SDK automatically appends an "Other Amount" option for free-form entry.

**Fixed amounts:**

```swift
GratuityConfig(
    mode: .configured,
    amounts: [300, 200, 100], // rendered as £3.00, £2.00, £1.00
    header: "Select a Tip / Gratuity:"
)
```

**Percentage-based:**

```swift
GratuityConfig(
    mode: .configured,
    percentages: [20, 10, 5], // rendered as 20%, 10%, 5%
    header: "Select a Tip / Gratuity:"
)
```

:::hint{type="warning"}
Mixing `amounts` and `percentages` in the same config will cause `startTransaction()` to fail with a validation error.
:::

### Customising prompt text

Two text fields control what is shown on-device before and during tip selection:

- `addGratuityPrompt`: text shown on the initial yes/no screen asking the cardholder whether they want to add a tip (default: `"Add Gratuity?"`, max 30 characters)
- `header`: title shown at the top of the tip selection menu (default: `"Select Tip"`, max 30 characters)

```swift
GratuityConfig(
    mode: .configured,
    percentages: [20, 10, 5],
    addGratuityPrompt: "Add a tip?",
    header: "Select a Tip / Gratuity:"
)
```

### Responding to the customer's selection

When the customer confirms a tip, the `onGratuityConfirmed` callback is triggered:

```swift
onGratuityConfirmed: { gratuityAmount, gratuityPercentage in
    // gratuityAmount: tip in the smallest currency unit (e.g. pence)
    // gratuityPercentage: whole number percentage (e.g. 15), or 0 for a fixed-amount or free-form tip
}
```

If the customer declines the tip, `onGratuityConfirmed` is still called with `gratuityAmount = 0`.

### Custom pre-transaction flow

If you prefer to collect the tip before calling `startTransaction()` — for example in your own application UI — pass it directly via `TransactionMetadata.gratuityAmount`. In this case leave `gratuityConfig` unset (or set `mode` to `.none`) and include the tip in the total `amount`.

```swift
let metadata = TransactionMetadata(
    gratuityAmount: 100 // £1.00
)

toro.startTransaction(
    amount: 1100, // £11.00 total (£10.00 + £1.00 tip)
    type: .purchase,
    currency: .gbp,
    metadata: metadata,
    // ...
)
```

:::hint{type="warning"}
`TransactionMetadata.gratuityAmount` and a non-`none` `gratuityConfig` cannot both be set on the same transaction - `startTransaction()` will fail with a validation error.
:::

:::hint{type="warning"}
The `amount` parameter in `startTransaction()` must be the total transaction amount, including any gratuity.
:::

:::hint{type="info"}
The `onGratuityConfirmed` callback is not triggered when using the custom pre-transaction flow.
:::

