# `Worldpay.CardPayments.Features`
[🔗](https://github.com/iamkanishka/worldpay/blob/v1.0.0/lib/worldpay/access/features/card_payments_features.ex#L1)

Builder helpers for advanced Card Payments API features.

All functions return maps that can be merged into a Card Payments
`instruction` map before calling `Worldpay.CardPayments.authorize/3`
or `Worldpay.CardPayments.mit/3`.

## Usage

    instruction =
      %{
        "transactionReference" => "txn-001",
        "merchant" => Worldpay.CardPayments.Features.merchant("entity-ref"),
        "instruction" => %{
          "narrative" => %{"line1" => "My Store"},
          "value" => %{"amount" => 5000, "currency" => "USD"},
          "paymentInstrument" => %{"type" => "card/token", "href" => token_href}
        }
      }
      |> Worldpay.CardPayments.Features.with_partial_auth()
      |> Worldpay.CardPayments.Features.with_moto()
      |> Worldpay.CardPayments.Features.with_level3(line_items: [...])

    {:ok, auth} = Worldpay.CardPayments.authorize(instruction, config)

# `build_aft`

```elixir
@spec build_aft(String.t(), String.t(), keyword(), keyword()) :: %{
  required(String.t()) =&gt; term()
}
```

Full AFT funds transfer builder.

## `type` values
`"purchase"` | `"withdrawal"` | `"prepaidLoad"` | `"quasiCash"` | `"businessToBusiness"`

## `purpose` values (full enum)
`"businessToBusiness"` | `"creditCardRepayment"` | `"crypto"` | `"crowdLending"` |
`"debitCard"` | `"education"` | `"emergency"` | `"familySupport"` | `"gift"` |
`"giftCard"` | `"goodwill"` | `"loanRepayment"` | `"medicalTreatment"` | `"others"` |
`"pension"` | `"salary"` | `"taxRefund"` | `"travelAndExpense"` | `"utilities"` |
`"walletTopUp"` | `"walletWithdrawal"` | `"gamblingPayout"`

## Sender fields (keyword list)
- `:first_name`, `:middle_name`, `:last_name`
- `:date_of_birth` — YYYY-MM-DD (required for some cross-border)
- `:document_reference` — Tax ID / national ID (LatAm)
- `:address` — map

## Recipient account types
- `%{type: "card", href: token_href}`
- `%{type: "bank", account_number: "...", routing_number: "..."}`
- `%{type: "wallet", wallet_reference: "...", wallet_provider: "..."}`

# `build_payfac`

```elixir
@spec build_payfac(keyword() | nil) :: %{required(String.t()) =&gt; term()} | nil
```

Build a PayFac (Payment Facilitator) object.

# `customer_agreement`

```elixir
@spec customer_agreement(String.t(), String.t(), String.t() | nil) :: %{
  required(String.t()) =&gt; String.t()
}
```

Build a customerAgreement object for stored credential payments.

## `type` values: `"cardOnFile"` | `"subscription"` | `"installment"` | `"unscheduled"`
## `usage` values: `"first"` | `"subsequent"`

# `incremental_auth`

```elixir
@spec incremental_auth(String.t(), non_neg_integer(), String.t()) :: %{
  required(String.t()) =&gt; term()
}
```

Build an incremental authorization body (extend a pre-authorization amount).

Pass the original `payment_id` and the additional amount to authorize.

# `merchant`

```elixir
@spec merchant(
  String.t(),
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Build a merchant map with optional PayFac sub-merchant data.

## Options

- `:mcc` — merchant category code (overrides account-level MCC)
- `:payfac` — PayFac map (schemeId, independentSalesOrganizationId, subMerchant)

# `narrative`

```elixir
@spec narrative(String.t(), String.t() | nil) :: %{required(String.t()) =&gt; String.t()}
```

Build a narrative (statement descriptor).

# `with_acp_delegate`

```elixir
@spec with_acp_delegate(%{required(String.t()) =&gt; term()}, String.t()) :: %{
  required(String.t()) =&gt; term()
}
```

Add ACP (Agentic Commerce Protocol) delegate token for AI agent payments (Feb 2026).

The `delegate_token` is issued by Worldpay to a trusted AI agent.

# `with_airline_data`

```elixir
@spec with_airline_data(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add airline itinerary data for lower interchange rates.

## Options

- `:passenger_name` — name on ticket
- `:departure_date` — ISO 8601 date
- `:origin` — IATA airport code
- `:destination` — IATA airport code
- `:ticket_number` — airline ticket number
- `:restricted_ticket` — boolean
- `:legs` — list of `%{origin:, destination:, carrier_code:, flight_number:, fare_basis_code:, stopover:}`
- `:passengers` — list of `%{first_name:, last_name:, date_of_birth:}`

# `with_auto_settlement`

```elixir
@spec with_auto_settlement(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Enable auto-settlement on authorization (Payments API).

# `with_convenience_fee`

```elixir
@spec with_convenience_fee(
  %{required(String.t()) =&gt; term()},
  non_neg_integer(),
  String.t()
) :: %{
  required(String.t()) =&gt; term()
}
```

Add a convenience fee to a card payment.

Applies to all payment methods (unlike surcharge).

# `with_crypto_ramp`

```elixir
@spec with_crypto_ramp(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add crypto ramp provider identifiers.

Required for crypto purchase transactions (MCC 6051).

## Options

- `:transaction_identifier` — crypto exchange transaction ID
- `:affiliate_details` — `%{name:, id:}`

# `with_debt_repayment`

```elixir
@spec with_debt_repayment(%{required(String.t()) =&gt; term()}) :: %{
  required(String.t()) =&gt; term()
}
```

Flag a payment as a debt repayment (MCC 6012/6051 Mastercard requirement).

# `with_dynamic_mcc`

```elixir
@spec with_dynamic_mcc(%{required(String.t()) =&gt; term()}, String.t()) :: %{
  required(String.t()) =&gt; term()
}
```

Override MCC on a per-transaction basis.

# `with_exemption`

```elixir
@spec with_exemption(%{required(String.t()) =&gt; term()}, String.t()) :: %{
  required(String.t()) =&gt; term()
}
```

Request an SCA exemption inside a Payments API call.

Types: `"TRA"` | `"lowValue"` | `"trustedBeneficiary"` | `"authenticationOutage"`

# `with_external_mpi`

```elixir
@spec with_external_mpi(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add external 3DS (own MPI) authentication result to a card payment.

## Required opts

- `:eci` — Electronic Commerce Indicator
- `:authentication_value` — CAVV / UCAF
- `:transaction_id` — DS transaction ID
- `:version` — 3DS version string

# `with_korea_domestic`

```elixir
@spec with_korea_domestic(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add customerData for South Korea domestic card payments (Toss Pay).

## Options

- `:card_company_id` — Korean card company identifier
- `:installment_months` — number of installment months (0 = lump sum)

# `with_latam_installments`

```elixir
@spec with_latam_installments(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add LatAm installment data.

## Options

- `:number_of_installments` — integer (required)
- `:installment_type` — "equalInstallments" | "unequalInstallments" (default: equalInstallments)
- `:customer_document_reference` — CPF/RUT (required for some markets)
- `:document_type` — "CPF" | "RUT" | ...

# `with_level2`

```elixir
@spec with_level2(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add Level 2 purchasing card data (reduces interchange).

## Options

- `:purchase_order_number` — PO number
- `:customer_reference` — buyer-supplied reference
- `:sales_tax` — tax amount in minor units
- `:destination_postal_code` — ship-to postcode

# `with_level3`

```elixir
@spec with_level3(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add Level 3 purchasing card data with line items (lowest interchange tier).

## Options (all from Level 2, plus)

- `:line_items` — list of item maps with keys:
  - `:description`, `:quantity`, `:unit_code`, `:unit_cost`, `:tax_amount`, `:total_amount`
- `:discount_amount` — discount in minor units
- `:shipping_amount` — shipping in minor units
- `:duty_amount` — customs duty in minor units

# `with_mcc6012`

```elixir
@spec with_mcc6012(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add MCC 6012 (UK financial services) mandatory data.

Required by Visa Europe for UK financial services merchants.

## Options

- `:surname` — cardholder surname (required)
- `:account_first6` — first 6 digits of cardholder's primary account (required)
- `:account_last4` — last 4 digits (required)
- `:date_of_birth` — cardholder DOB in YYYY-MM-DD (required)
- `:postcode` — cardholder postcode (required for Visa)

# `with_moto`

```elixir
@spec with_moto(%{required(String.t()) =&gt; term()}) :: %{
  required(String.t()) =&gt; term()
}
```

Flag a payment as Mail Order / Telephone Order (MOTO).

# `with_order_reference`

```elixir
@spec with_order_reference(%{required(String.t()) =&gt; term()}, String.t()) :: %{
  required(String.t()) =&gt; term()
}
```

Add an orderReference to group payments together.

# `with_partial_auth`

```elixir
@spec with_partial_auth(%{required(String.t()) =&gt; term()}) :: %{
  required(String.t()) =&gt; term()
}
```

Enable partial authorization on a CIT.

When the issuer approves less than the requested amount,
`amounts.authorized` in the response will differ from `amounts.requested`.

Test with `instruction.value.amount` magic values in Try environment.

# `with_preferred_card_brand`

```elixir
@spec with_preferred_card_brand(%{required(String.t()) =&gt; term()}, String.t()) :: %{
  required(String.t()) =&gt; term()
}
```

Set preferred card brand for co-badged cards.

Valid values: `"visa"`, `"mastercard"`, `"cartesBancaires"`,
`"unionPay"`, `"eftpos"`, `"maestro"`, `"elo"`.

# `with_split_funding_reference`

```elixir
@spec with_split_funding_reference(%{required(String.t()) =&gt; term()}, String.t()) ::
  %{
    required(String.t()) =&gt; term()
  }
```

Add a split funding reference to route settlement to a secondary bank account.

Used for simple two-party splits at settlement time (no Marketplace required).

# `with_surcharge`

```elixir
@spec with_surcharge(%{required(String.t()) =&gt; term()}, non_neg_integer(), String.t()) ::
  %{
    required(String.t()) =&gt; term()
  }
```

Add a surcharge to a card payment.

`surcharge_amount` is in minor currency units. Credit cards only.
Cannot be combined with convenience fees.

# `with_three_ds_bypass`

```elixir
@spec with_three_ds_bypass(
  %{required(String.t()) =&gt; term()},
  keyword()
) :: %{required(String.t()) =&gt; term()}
```

Add 3DS bypass controls (Jun 2026).

## Options

- `:bypass_on` — list of conditions: `["frictionless", "lowValue"]`
- `:continue_on` — list of error conditions to ignore: `["authenticationOutage"]`

# `with_token_creation`

```elixir
@spec with_token_creation(%{required(String.t()) =&gt; term()}, String.t(), keyword()) ::
  %{
    required(String.t()) =&gt; term()
  }
```

Request token creation as part of a Payments API call.

## `type` options: `"worldpay"` | `"networkToken"`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
