Skip to content

Building your transaction fee functionality

Prerequisites

Before creating a transaction fee model, ensure the following:

  • To create fee models, you must have active Upvest API client credentials with the required transaction_fees:admin scopes enabled.
  • You have determined the exact structure of the fees, your desired tier thresholds and whether the fees will be absolute (fixed cash amounts) or relative (basis points of order value).

Step 1: Create your transaction fee model

Use POST /transaction_fees/models to define your fee model. Fee models are immutable once created. You can create multiple fee models.

Flat absolute fee

Applies a simple flat fee per transaction regardless of the order value.

Example: 1 EUR fee per order

POST /transaction_fees/models

{
    "label": "absolute fee amount - 1 EUR per any order",
    "currency": "EUR",
    "charge_method": "COLLECTED_BY_UPVEST",
    "value_type": "ABSOLUTE",
    "application_type": "VOLUME",
    "base_amount_scope": "ORDER",
    "tiers": [
      {
  "tier_id": "0",
  "base_amount_from": "0.00",
  "fee_amount": "1.00"
      }
    ]
  }

Tiered absolute fee

The example below uses a tiered absolute fee to reward high-volume users with lower effective rates.

Example tier structure for absolute fees:

TierThresholds (e.g., the order’s cash amount)Transaction fee
0Up to €499.99€1.00
1€500.00 – €1,999.99€2.00
2€2,000.00 – €9,999.99€5.00
3€10,000 and above€10.00

POST /transaction_fees/models

{
    "label": "absolute fee amount - tiered fee model",
    "currency": "EUR",
    "charge_method": "COLLECTED_BY_UPVEST",
    "value_type": "ABSOLUTE",
    "application_type": "VOLUME",
    "base_amount_scope": "ORDER",
    "tiers": [
      {
  "tier_id": "0",
  "base_amount_from": "0",
  "fee_amount": "1.00"
      },
      {
  "tier_id": "1",
  "base_amount_from": "500.00",
  "fee_amount": "2.00"
      },
      {
  "tier_id": "2",
  "base_amount_from": "2000.00",
  "fee_amount": "5.00"
      },
      {
  "tier_id": "3",
  "base_amount_from": "10000.00",
  "fee_amount": "10.00"
      }
    ]
}

Flat relative fee without minimum or maximum specified

Applies a simple flat fee percentage regardless of the order value.

Example: 1 % fee per order

POST /transaction_fees/models


{
    "label": "1% transaction fee",
    "currency": "EUR",
    "charge_method": "COLLECTED_BY_UPVEST",
    "value_type": "RELATIVE",
    "application_type": "VOLUME",
    "base_amount_scope": "ORDER",
    "tiers": [
      {
  "tier_id": "0",
  "base_amount_from": "0.00",
  "fee_bps": "100"
      }
    ]
  }

Flat relative fee with minimum and maximum specified

Applies a flat fee percentage with minimum and maximum fee amount.

Example: 1 % fee per order, not less than 1 EUR, not more than 100 EUR.

POST /transaction_fees/models

{
    "label": "1% transaction fee, min 1 EUR, max 100 EUR",
    "currency": "EUR",
    "charge_method": "COLLECTED_BY_UPVEST",
    "value_type": "RELATIVE",
    "application_type": "VOLUME",
    "base_amount_scope": "ORDER",
    "tiers": [
      {
  "tier_id": "0",
  "base_amount_from": "0.00",
  "fee_bps": "100",
  "min_fee_amount":"1.00",
  "max_fee_amount":"100.00"
      }
     ]
  }

Tiered relative fee models

Application to the marginal increase on top of the tier threshold

Depending on the order volume, each next EUR is charged less fee than the previous.

Example:

TierThresholds (e.g., the order’s cash amount)Fee basis point (bps)
0First €5000.00 of the order volume300
1Amount exceeding €5000.00, but less than €10000.00250
2Amount exceeding € 10.000.00200

POST /transaction_fees/models

{
    "label": "Marginal relative tiered fee model",
    "currency": "EUR",
    "charge_method": "CHARGED_BY_CLIENT",
    "value_type": "RELATIVE",
    "application_type": "MARGINAL",
    "base_amount_scope": "ORDER",
    "tiers": [
      {
  "tier_id": "0",
  "base_amount_from": "0.00",
  "fee_bps": "300"
      },
      {
  "tier_id": "1",
  "base_amount_from": "5000.00",
  "fee_bps": "250"
      },
      {
   "tier_id": "2",
   "base_amount_from": "10000.00",
   "fee_bps": "200"
        }
      ]
    }

Application to the whole order amount

Example:

TierThresholds (e.g., the total order’s cash amount)Fee basis point (bps)Fee limits
0Up to €4999.99300Min: 1
1€5000.00 – €9.999,99250-Min: 150
210.000.00 and above200Min: 250
Max: 300

POST /transaction_fees/models

{
    "label": "Tiered relative fee model with lower/upper bounds",
    "currency": "EUR",
    "charge_method": "CHARGED_BY_CLIENT",
    "value_type": "RELATIVE",
    "application_type": "VOLUME",
    "base_amount_scope": "ORDER",
    "tiers": [
      {
  "tier_id": "0",
  "base_amount_from": "0.00",
  "fee_bps": "300",
  "min_fee_amount":"1.00"
      },
      {
  "tier_id": "1",
  "base_amount_from": "5000.00",
  "fee_bps": "250",
  "min_fee_amount": "150.00"
      },
      {
   "tier_id": "2",
   "base_amount_from": "10000.00",
   "fee_bps": "200",
   "min_fee_amount": "250.00",
   "max_fee_amount": "300.00"
        }
      ]
    }

Request parameters

FieldRequiredDescription
labelRequiredA human-readable name for the fee model. The label should be unique, descriptive, and clear to aid in referencing the transaction fee model.
currencyRequiredThe currency of the fee. Alphabetic three-letter ISO 4217 currency code. This field accepts either EUR or GBP.
charge_methodRequiredThis field determines which party collects the fee. The value of this field depends on the funding arrangement you have with Upvest.

For pre-funding clients, always set charge_method equal to CHARGED_BY_UPVEST.

For post-trade settlement clients, always set charge_method equal to CHARGED_BY_CLIENT.
value_typeRequiredThe value_type field determines the type of fee to be collected. Set this equal to either:

- ABSOLUTE for fixed, flat cash fees.

- RELATIVE for basis-point-based fees.
application_typeRequiredDetermines how the fee will be applied to the transaction.

- VOLUME: the full order value is assessed against the tier thresholds. The fee in the tiers is applied to the total volume of the order.

- MARGINAL: each portion of the order value is charged at the rate of the tier it falls within. Use this to set up a marginal/progressive fee structure. Only applicable to tiered fee models.
base_amount_scopeRequiredSet this field equal to ORDER. Specifies that fee tiers are evaluated against the total order value.
tiersRequiredArray of tier objects. At least one tier must be specified. A single-tier model functions as a simple flat fee.
tiers[].tier_idRequiredA string identifier for the tier (e.g. "0", "1", "2").
tiers[].base_amount_fromRequiredThe lower boundary (inclusive) of the tier. The first tier must always start at "0".
tiers[].fee_amountConditionalRequired for ABSOLUTE models. The fixed, flat fee amount charged when the order falls within this tier.
tiers[].fee_bpsConditionalRequired for RELATIVE models. The fee rate in basis points applied to the order value for this tier.
tiers[].min_fee_amountOptionalMinimum fee amount for a RELATIVE tier. The calculated fee will not fall below this value.
tiers[].max_fee_amountOptionalMaximum fee amount for a RELATIVE tier. The calculated fee will not exceed this value.

Once you have created a fee model, the response returns an id. This is the transaction_fee_model_id for use in order requests and ex-ante cost reports.

Step 2 (when applicable): Apply a fee model in the ex-ante cost report

For ex-ante reporting, you can use the POST /reports endpoint to include your transaction fee model in the reporting.

POST /reports

{
  "type": "ORDER_EX_ANTE_COST",
  "order": {
    "user_id": "d1a4be99-8bb6-4e78-b897-8168f6823ab5",
    "account_id": "c5034305-c441-4711-adbf-93cfbc13a695",
    "order_type": "MARKET",
    "side": "BUY",
    "instrument_id": "LU0274208692",
    "instrument_id_type": "ISIN",
    "currency": "EUR",
    "quantity": "15"
  },
  "fees": [
    {
      "type": "TRANSACTION_FEE_BUY",
      "transaction_fee_model_id": "eb5ba93f-5dfe-4bf1-84da-0caacc80c000"
    },
    {
      "type": "TRANSACTION_FEE_SELL",
      "value_type": "ABSOLUTE",
      "cash_amount": "0.95",
      "currency": "EUR"
    },
    {
      "type": "ANNUAL_AUM_BASED_FEE",
      "value_type": "RELATIVE",
      "bps": "37"
    }
  ],
  "inducements": [
    {
      "value_type": "ABSOLUTE",
      "cash_amount": "0.10",
      "currency": "EUR"
    }
  ]
}

Step 3: Apply a fee model to an order

When placing an order, reference your transaction_fee_model_id in the fee_configuration array. Upvest will calculate and apply the appropriate fee based on the order value and the configured tiers.

If no fee model is assigned and an explicit fee is instead provided via fee_configuration, the explicit fee takes precedence.

POST /orders

{
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "cash_amount": "1000",
  "currency": "EUR",
  "side": "BUY",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "user_instrument_fit_acknowledgement": true,
  "limit_price": "",
  "stop_price": "",
  "fee_configuration": [
    {
      "type": "TRANSACTION_FEE_BUY",
      "transaction_fee_model_id": "eb5ba93f-5dfe-4bf1-84da-0caacc80c000"
    }
  ]
}

The fee_configuration.type must match the type of order:

  • Set TRANSACTION_FEE_BUY fee type for BUY orders
  • Set TRANSACTION_FEE_SELL fee type for SELL orders.

If there is a mismatch, the order will be rejected.

Step 4: Monitor the Cash transactions event webhook for fee details

After an order with a transaction fee is executed, fees are reflected in the CASH_TRANSACTION.EXECUTED webhook events. The fees array is populated with the fee details.
The value reflected in the delta field is dependent on your funding setup with Upvest.

  • Pre-funding clients: The delta reflects the net cash movement inclusive of both taxes and fees.
  • Post-trade settlement clients: The delta reflects the net cash movement for the order inclusive of taxes but does not include the impact of the fee.

For more information, refer to the Webhooks and transaction fee details section.

The order event webhook includes the transaction_fee_model_id but not a detailed breakdown of the transaction fee. Also, order execution events do not include details on transaction fees.