# API Overview
Even if you don't plan to use the Flux API to calculate discounts but doing that using the `IDiscountCalculator` directly you will want to deploy the API in order to use the Flux UI which requires the API to work.
## Authentication
By default Flux doesn't require authentication to talk to the API. That can work if your Flux application isn't public to the internet and you don't care about keeping track of who changed what in Flux.
In most cases you will want to add authentication to the API. You do that by implementing authentication in ASP.NET outside of Flux and then tell Flux to disallow anonymous API access like this:
```cs
builder.Services
.AddFlux()
.AddApi(options => options.AllowAnonymousAccess = false)
.Build()
;
```
You're free to use multiple authentication schemes as you probably want different authentication for your API clients and the Flux UI. The Flux UI doesn't have a login form on it's own so your authentication should redirect to a login page or you can use basic auth.
---
# Changelog
Flux is released often as NuGet packages, sometimes several versions a day. This page groups
the notable changes by month. The current version is **0.0.67**.
## October 2026 (next release)
**Changed**
- All API endpoints have an operation id, a summary and a description in the OpenAPI document.
**Fixed**
- Registering purchases is at `POST /api/purchases`. It was at `POST /` by mistake.
:::warning[Breaking change]
If you register purchases through the API, change the URL from `/` to `/api/purchases`.
The request and response are unchanged.
:::
## May 2026 (0.0.59 – 0.0.67)
**Added**
- Multi-tenancy. `TenantId` is an `int`.
- Dashboard in the admin UI, with KPIs, a filter bar, a scoreboard, contribution margin, a campaign
calendar and a comparison panel. Money is formatted per currency.
- MCP server, including a tool that describes the enums in the API.
- Product brands.
- Import batches.
- Change history for discounts.
- Discounts can be limited to a country.
- Autocomplete for some system tags.
- The admin UI can be extended, and all its components are exported.
**Changed**
- The whole product catalog no longer needs to fit in memory.
- The customer key can be updated on customer discounts.
- The condition builder in the admin UI is easier to use.
- Prices are shown in more places in the admin UI.
- Nexus jobs are disabled by default in the demo project.
**Fixed**
- Duplicate prices and price lists are prevented.
- Pagination URLs.
- The active menu item in the admin UI navigation.
## April 2026 (0.0.28 – 0.0.58)
**Added**
- SQL Server and PostgreSQL support (`Flux.SqlServer`, `Flux.Postgres`).
- Database-backed Flux events, and RabbitMQ support (`Flux.RabbitMQ`).
- API client project, and `ICatalogImporter` for importing the catalog through the API.
- `ISubscriptionReader`. Subscriptions support discount codes and optional webhook authentication.
- Uploads of discount codes and customer discounts.
- Price list admin UI, an "Included products" tab on discounts, and product images in the admin UI.
- Tag autocomplete, and country-specific tag definitions.
- A condition can target several entity types.
- `LineItemTarget.UseDiscountCondition`.
- System setting to distribute order discounts over the order lines.
- Purchase tracking for system tags.
- Audit trail properties.
- Static factory methods, for .NET Framework compatibility.
- The documentation site.
**Changed**
- `Discount.IsActive` is replaced by `Discount.Status`.
- All price candidates are included in the response.
- `DiscountedPrice` is not set when it equals `Price`.
- Caches no longer do a full refresh on every entity change.
- A subscription can have only one customer, delivery and sales channel.
- Faster imports and a faster "Included products" calculation.
**Fixed**
- Buy X get Y discounts could only be applied once.
- Subscriptions didn't react correctly when prices or price lists changed.
- `Customer.Key` as an empty string.
## October 2025 (0.0.27)
**Added**
- Creating and updating subscriptions.
## September 2025 (0.0.25 – 0.0.26)
**Added**
- Discount description.
**Fixed**
- Discount preview.
## August 2025 (0.0.13 – 0.0.24)
**Added**
- Admin UI for fee types, customer discounts, custom field definitions, system settings, prices and
price tiers, and gift targets.
- Custom fields and tags can be edited on discounts, products and product categories.
- `GiftTarget.MaxValue`.
- Searchable discount codes.
**Changed**
- Inactive discounts are hidden by default.
**Fixed**
- X for Y discount logic.
- Generating subscription events.
## July 2025 (0.0.1 – 0.0.12)
First published versions on the Commerce Mind NuGet feed.
**Added**
- Admin UI for discounts, discount codes, products, product categories and tag definitions.
- Demo project.
- Lazy tag values, through a URL callback on the tag definition.
---
# Buy X get Y discounts
Use a **Buy X get Y** discount when the customer must buy a certain number of eligible items before some of them are discounted.
Good examples are:
- Buy 3, pay for 2.
- Buy 2 shirts, get 50% off the cheapest one.
- Buy a camera, get 25% off one accessory.
- Buy 10 items, get 5 discounted.
## Create a Buy X get Y discount
1. Create or open a discount.
2. In **Discount target**, choose **Buy X get Y**.
3. Add a **Line item condition** for the items that count toward the offer.
4. Optionally add a **Discounted line item condition** if different items should receive the discount.
5. Enter **Buy quantity**.
6. Enter **Get discount on quantity**.
7. Choose **Line item selection**.
8. Optionally enter **Max usages per cart**.
9. Choose the reward type and value.
10. Save the discount.
## Buy quantity
**Buy quantity** is how many eligible items the customer must have before the discount can be used.
For a "3 for 2" offer, set **Buy quantity** to `3`.
## Get discount on quantity
**Get discount on quantity** is how many items receive the discount each time the offer is used.
For a "3 for 2" offer, set **Get discount on quantity** to `1`.
## Line item selection
**Line item selection** decides which matching item receives the discount when there are several choices.
- **Cheapest** discounts the least expensive eligible item.
- **Most expensive** discounts the most expensive eligible item.
For most "3 for 2" offers, choose **Cheapest**.
## Max usages per cart
Use **Max usages per cart** to limit how many times the offer can repeat in one cart.
Example:
- Buy quantity: `3`
- Get discount on quantity: `1`
- Max usages per cart: empty
If the customer buys 6 eligible items, the discount can be used twice.
If **Max usages per cart** is `1`, the same customer only gets one discounted item, even with 6 eligible items.
## Line item condition
The **Line item condition** decides which items count toward the offer.
For a normal "3 for 2 on socks" offer, the line item condition should match socks. The same socks both trigger the discount and receive the discount.
## Discounted line item condition
Use **Discounted line item condition** when the items that receive the discount are different from the items that trigger it.
Example:
- Line item condition: product is a camera.
- Discounted line item condition: product is an accessory.
- Buy quantity: `1`
- Get discount on quantity: `1`
- Reward: 25% off.
In that example, buying a camera gives a discount on one accessory. The accessory does not count as the item the customer had to buy.
If you leave **Discounted line item condition** empty, Flux discounts items from the same group that triggered the offer.
## Common setup examples
For **3 for 2 on the cheapest item**:
- Line item condition: matching campaign products.
- Buy quantity: `3`
- Get discount on quantity: `1`
- Line item selection: **Cheapest**
- Reward: 100% off.
For **buy 4, get 2 at 50% off**:
- Line item condition: matching campaign products.
- Buy quantity: `4`
- Get discount on quantity: `2`
- Line item selection: **Cheapest**
- Reward: 50% off.
For **buy one main product, get one accessory discounted**:
- Line item condition: main product.
- Discounted line item condition: accessory.
- Buy quantity: `1`
- Get discount on quantity: `1`
- Reward: the accessory discount.
---
# Create a discount
A discount in Flux is primarily made up of two parts:
- **Condition** decides when the discount can be used.
- **Discount target** decides what the customer gets, which can contain additional conditions.
For example, "10% off jackets when the cart is over 100 EUR" has a condition of "cart is over 100 EUR" and a target of "10% off jacket line items".
## Create the discount
1. Go to **Discounts**.
2. Select **Create discount**.
3. Enter a clear **Name**.
4. Add a short **Description** so other people understand why the discount exists.
5. Optionally enter a **Key** if another system needs a fixed identifier for this discount.
6. Set **Sort order** if this discount should be applied before or after other discounts.
7. Choose whether the discount **Requires** anything.
8. Set **Period & schedule** if the discount should only be active during certain dates, times, weekdays, or repeating periods.
9. Add a **Condition** if the discount should only apply to certain carts.
10. Choose a **Discount target**.
11. Configure categories and combination rules.
12. Choose whether to activate the discount immediately.
13. Select **Create**.
## Requirements
The **Requires** field controls whether the discount is available automatically or only through a specific application.
- **(nothing)** means Flux can apply the discount automatically when the conditions match.
- **Discount code** means the customer must use a valid code.
- **Customer discount** means the discount must be connected to a specific customer, and such a discount will then automatically get applied for that customer.
Use a requirement when you do not want every cart that matches the conditions to receive the discount automatically.
## Conditions
A condition limits when the discount is available. Common examples are:
- Cart total is above a certain amount.
- Customer belongs to a certain group.
- Cart contains products with specific tags.
- Delivery country is one of the selected countries.
If you leave the condition empty, the discount can still be limited by the target. For example, a line item target can still say that only products with a certain tag are discounted.
If you're creating a discount with "20% off on brand X" you're probably tempted to add a "Brand is X" condition on the discount itself, but in most cases what you want is a discount without a main condition with a line item target that discounts any line item with brand X.
## Discount targets
The target decides what Flux should discount or give to the customer.
- **Line item** discounts products or order lines.
- **Buy X get Y** discounts a certain number of items after the customer buys enough items that meet the conditions.
- **Total price** discounts the cart total.
- **Fee** discounts a fee, such as shipping.
- **Gift** gives one or more gift products.
- **None** creates a discount record without Flux calculating a reward. This is mostly useful for external discounts such as Google Automated Discounts that you still want to track in Flux.
Use the separate target pages in this section when you need help choosing or configuring a target.
## Reward types
Most discount targets that reduce a price let you choose one of these reward types:
- **Percentage off** takes a percentage away, such as 10% off.
- **Amount off** takes a fixed amount away, such as 50 SEK off.
- **Fixed price** changes the target to a specific price.
- **Price list** uses prices from a selected price list.
If you use amount off or fixed price, enter values for every currency where the discount should work. If a currency is missing, shoppers using that currency will not receive that discount.
## Categories and combinations
Categories help Flux decide which discounts can be used together.
- **Categories** describe what kind of discount this is and you're free to create any category that makes sense to you.
- **Not combinable with categories** blocks this discount from getting combined with discounts from selected categories.
- **Only combinable with categories** allows this discount to combine only with discounts from selected categories.
You can use either **Not combinable with categories** or **Only combinable with categories**, not both at the same time.
Enable **Undiscounted line items can be combined** when other discounts should still be allowed on products that this discount did not actually discount. Eg a "20% on brand X" will only target some line items, and you might want to let other discounts target other line items.
## External discounts
Use **Is external discount** when another system decides the discounted price, but you still want Flux to track the discount and control how it combines with other discounts.
A common example is Google Automated Discounts where GAD will set the discounted price, but you might want a Flux discount for the GAD in order to control possible combinations and to get purchase tracking.
## Activate carefully
Create important discounts as inactive first. Then open the discount, review the condition and target, use the preview if available, and activate it when everything looks correct.
---
# Fee discounts
Use a **Fee** discount when the reward should reduce a fee, such as shipping, handling, service fees, or other charges your store sends to Flux.
Good examples are:
- Free shipping.
- 50% off express delivery.
- 49 SEK off a service fee.
## Create a fee discount
1. Create or open a discount.
2. Add a main **Condition** if the discount should only be available for certain carts.
3. In **Discount target**, choose **Fee**.
4. Choose the **Fee type**.
5. Choose the reward type.
6. Enter the discount value.
7. Save the discount.
## Fee type
The **Fee type** tells Flux which fee should be discounted.
For example, your store might have fee types for:
- Standard shipping.
- Express shipping.
- Invoice fee.
- Handling fee.
Choose the fee type that matches the charge you want to reduce. Flux allows you to create your own fees and doesn't restrict you in which or how many types of fees you have.
## Common examples
For **free standard shipping**:
- Condition: cart total is at least the free shipping threshold.
- Target: fee.
- Fee type: standard shipping.
- Reward: 100% off.
For **half price express shipping**:
- Condition: optional, such as customer is a member.
- Target: fee.
- Fee type: express shipping.
- Reward: 50% off.
For **fixed amount off a fee**:
- Target: fee.
- Fee type: the fee you want to reduce.
- Reward: amount off.
## Reward types
Fee discounts support:
- **Percentage off**, such as 100% off shipping.
- **Amount off**, such as 49 SEK off a delivery fee.
- **Fixed price**, such as setting shipping to 29 SEK.
- **Price list**, if fee prices are controlled through a selected price list.
If you use amount off or fixed price, enter all currencies where the discount should work.
## Things to check
Make sure the fee exists in the cart that Flux receives. A fee discount can only reduce fees that are present.
Also make sure you choose the right fee type. If the customer selects express shipping but the discount targets standard shipping, the express shipping fee will not be discounted.
---
# Gifts
Use a **Gift** discount when the customer should receive one or more products instead of a price reduction.
Good examples are:
- Get a free tote bag when buying for 500 SEK.
- Choose one free sample with your order.
- Get all selected gift products with a campaign purchase.
## Create a gift discount
1. Create or open a discount.
2. Add a main **Condition** if the gift should only be available for certain carts.
3. In **Discount target**, choose **Gift**.
4. Choose **Selection type**.
5. Add the gift products.
6. Optionally set **Max total gift value**.
7. Optionally set **Buy for amount to get gift**.
8. Optionally set **Max gifts per cart/order**.
9. Save the discount.
## Selection type
The selection type decides how the gift products are handled.
- **Get all products** means the customer can receive all selected gift products.
- **Pick one product** means the customer can choose one product from the selected gift products.
Use **Pick one product** when you want to offer a choice, such as "choose one free sample".
Use **Get all products** when the campaign includes a fixed gift bundle.
## Products
Add the product keys for the products that can be given as gifts.
These are the products the customer may receive when the discount is applied. Make sure the product keys match the products in your store.
## Max total gift value
**Max total gift value** is available when the selection type is **Get all products**.
Use it when the customer can choose multiple gifts, but the total value of the chosen gifts must stay under a limit.
Example:
- Gift products: several sample products.
- Max total gift value: 200 SEK.
The customer can choose gifts until the total gift value reaches 200 SEK.
## Buy for amount to get gift
Use **Buy for amount to get gift** when the customer should earn gifts based on the cart total.
Example:
- Buy for amount to get gift: 100 SEK.
- Max gifts per cart/order: empty.
- Cart total: 350 SEK.
The customer can receive 3 gifts, because the cart reached the 100 SEK threshold three times.
## Max gifts per cart/order
Use **Max gifts per cart/order** to prevent a customer from receiving too many gifts in one order.
Example:
- Buy for amount to get gift: 100 SEK.
- Max gifts per cart/order: 1.
- Cart total: 350 SEK.
The customer receives only 1 gift, even though the cart total would otherwise allow 3.
## When to use another target
Use **Line item** if the product should be discounted instead of given as a gift.
Use **Buy X get Y** if the customer must buy a certain number of products before another product is discounted.
---
# Line item discounts
Use a **Line item** discount when you want to discount specific products or order lines.
Good examples are:
- 20% off all shoes.
- 100 SEK off selected jackets.
- Member price on products in a campaign.
- A fixed price for items with a certain product tag.
## Create a line item discount
1. Create or open a discount.
2. In **Discount target**, choose **Line item**.
3. Add a **Line item condition** to decide which items can be discounted.
4. Choose whether to also apply the main discount condition to the line items. Your main discount condition might select carts where any line item with a certain tag exists. If you only want to discount such line items you either have to set the same condition again in the target, or simply include the main condition on the line item selection. Use the preview to see the effect.
5. Choose the reward type.
6. Enter the discount value.
7. Save the discount.
## Line item condition
The **Line item condition** decides which lines that get the discount reward.
Use it to target things like:
- Products with a certain tag.
- Products from a certain brand.
- Products in a certain category.
- One or more specific products.
Only line items that match this condition can receive the line item discount.
## Main condition and line item condition
A discount can have both a main **Condition** and a **Line item condition**.
The main condition usually describes the cart or customer. The line item condition describes the products that can be discounted.
Example:
- Main condition: customer is a member.
- Line item condition: product has the tag `summer-sale`.
- Target: 15% off.
In that example, members get 15% off summer sale products.
## Also apply the main discount condition
The line item target includes a setting called **Also apply the main discount condition to limit which line items are eligible for the discount**.
Leave this enabled when the main condition should also help decide which line items are eligible.
Turn it off only when the main condition should decide whether the discount is available, but should not restrict the discounted line items.
## Reward types
Line item discounts support:
- **Percentage off**, such as 20% off each matching item.
- **Amount off**, such as 50 SEK off each matching item.
- **Fixed price**, such as setting each matching item to 199 SEK.
- **Price list**, such as using a campaign price list.
If you use amount off or fixed price, enter all currencies where the discount should work.
## When to use another target
Use **Buy X get Y** instead if the discount depends on buying a certain number of items, such as "3 for 2".
Use **Total price** instead if the reward should be taken from the order total rather than from specific products.
Use **Gift** instead if the customer should receive a product for free rather than a price reduction.
---
# No discount target
Use **None** when the discount should exist in Flux, but Flux should not calculate a product, fee, gift, or total price reward from the discount itself.
This is useful when the discounted price is calculated somewhere else but you still want Flux to track the usage and control which other discounts it can be combined with.
## When to use None
Choose **None** when:
- The discount is external and another system calculates the reward.
- You want to track an external discount in Flux.
- You want Flux to control combination rules for a discount from another system.
## External discount example
An external system may decide that a customer should receive a special product price. Flux does not calculate that price, but you still want Flux to:
- Know that the discount exists.
- Decide whether it can combine with other discounts.
- Track discount usage.
- Show statistics later.
In that case, create the discount, set the target to **None**, and enable **Is external discount**.
## Discount code or customer discount example
Sometimes the main discount record is used as a container for discount codes or customer discounts.
If the reward is not set directly on the discount itself, **None** can be used on the main discount. The actual application can then be managed through the relevant discount code or customer discount setup.
## What None does not do
None does not reduce product prices, fees, or cart totals by itself. It also does not add gifts by itself.
If Flux should calculate the customer reward, choose one of the other targets:
- **Line item** for product or order line discounts.
- **Buy X get Y** for quantity-based item discounts.
- **Total price** for order total discounts.
- **Fee** for fee discounts.
- **Gift** for gift products.
## Good practice
Use a clear name and description for discounts with no target. People reviewing the discount later should be able to tell which external system or business process creates the actual customer reward.
---
# Total price discounts
Use a **Total price** discount when the reward should be taken from the cart total instead of from specific products.
Good examples are:
- 10% off the whole order.
- 200 SEK off when buying for at least 1,000 SEK.
- A campaign discount that should appear as an order-level discount.
## Create a total price discount
1. Create or open a discount.
2. Add a main **Condition** if the customer must meet rules before getting the discount.
3. In **Discount target**, choose **Total price**.
4. Choose the reward type.
5. Enter the discount value.
6. Save the discount.
## Use conditions for thresholds
Total price discounts often need a cart total threshold.
Example:
- Condition: cart total is at least 1,000 SEK.
- Target: total price.
- Reward: 200 SEK off.
The customer receives 200 SEK off the cart total when the cart reaches the required amount.
## Reward types
Total price discounts support:
- **Percentage off**, such as 10% off the whole order.
- **Amount off**, such as 200 SEK off the whole order.
- **Fixed price**, which sets the total price to a specific amount.
- **Price list**, when the discount should be based on prices from a selected price list.
For most order-level campaigns, **Percentage off** or **Amount off** is the clearest choice.
## When total price is a good choice
Choose total price when:
- The customer should receive one discount on the order total.
- The discount is based on the cart amount.
- You do not need to show exactly which products were discounted.
- The offer is easy to explain as "off your order".
## When to use another target
Use **Line item** if the discount should belong to specific products.
Use **Buy X get Y** for quantity-based offers like "3 for 2".
Use **Fee** if the discount should reduce shipping or another fee.
Use **Gift** if the customer should receive a product instead of a price reduction.
---
# Introduction
Flux from Commerce Mind is a discount/promotion engine that can be used with any e-commerce platform. Flux handles discounts and optionally prices in a more flexible way than any e-commerce platform out there. If the discounts in your e-commerce platform is holding you back but switching platform isn't an option then Flux is for you. Or if you're looking to re-platform but the platform you're looking at doesn't meet your discount needs.
:::tip Is Flux a SaaS product?
No, you can host your own Flux instance and **have full control**. You can either use the API from any tech stack or use the .NET packages and run Flux inside your .NET application.
:::
## Why Flux?
Flux is built to support complex discount requirements like customer specific discounts that your customer service can offer customers when something goes wrong. It even supports calculating discounts from a historic snapshot so you can recalculate discounts when an order is updated after purchase.
- **Flexible** – it doesn't force you to sync your catalog into Flux
- **Tag based** – tag based conditions means that your discounts can target just about anything
- **Scalable** – Flux can scale horizontally without a central bottleneck like a database
- **Discount hints** – Flux returns hints like when there's a 3 for 2 discount but the cart doesn't yet have 3 items
## Quick taste
You can access the demo environment here: [https://flux-web-app-a0dpctebf6cteraf.westeurope-01.azurewebsites.net/flux](https://flux-web-app-a0dpctebf6cteraf.westeurope-01.azurewebsites.net/flux). The demo environment shuts down when nobody is using it, so the first request might take some time.
```cs
public class MyCartService(IDiscountCalculator discountCalculator, ICalculationInputFactory calculationInputFactory)
{
public async Task CalculateCartDiscounts()
{
var calculationInput = await calculationInputFactory.Create(new Cart
{
// Country, currency, line items, customer data, delivery data
});
var result = await discountCalculator.Calculate(calculationInput, calculateCartRequest.DateTimeUtc);
}
}
```
Read the [Getting Started guide](./technical-guide/getting-started) to install the NuGet packages and get up and running!
---
# Architecture
Flux is built to be horizontally scalable and not make any database calls as part of a customer request since we don't want the database to become a bottleneck during peak loads.
This is achieved by heavily caching all data needed to calculate discounts for customer requests. All caching implementations in Flux uses memory by default. Which is a great default, but if you have more specific requirements you can implement your own cache services to use eg Redis as a central cache.
When changes occur change events are broadcasted using `IFluxEventBroker` which has three implementations, one for single server use, one that uses the database as event store, and one using RabbitMQ. You can add your own implementation using a message broker of choice if you want to.
When the change event is picked up by the different caches they will refresh themselves in the background. This is important as some cache invalidation implementations will drop the cache when a change occur and rely on the next call to detect an empty cache and fetch it from the database. Flux will instead keep using the stale cache until the background refresh is finished to avoid adding any direct dependency on the database for customer traffic.
# Tags
Tags are a central concept of Flux and it's used on most of the core entities. Tags go hand in hand with Conditions which are set on discounts, pricelists, etc to match entities.
Tags are much like any attribute-value implementation, but they are named tags rather than attributes because Flux is not meant to store the full data for eg products. If you decide to store products in Flux the product tags you create should only be the ones you need for discount targeting. Another reason for them being tags instead of attributes is that they are supposed to be shaped for matching. Oftentimes you want your product attributes to be the raw data. Eg availability might be calculated from a number of product attributes and in that case you want a single tag for availability in Flux rather than discount creators having to build complex conditions to target the correct attributes.
# Catalog sync is optional
When we designed Flux we didn't want to create another hard dependency of syncing the entire catalog to another system. If the sync fails or is delayed in some way we didn't want that to affect the correctness of discounts. So when you ask Flux to calculate discounts from a cart you don't only send in identifiers (eg product key) but you send all of the product tags as part of the calculation call.
Which means that it doesn't matter if the catalog sync has a delay or is down at the moment, Flux is basing it's condition calculations on the tags passed in rather than the tags from the catalog sync.
With that said it is possible to omit tags in calculation calls and let Flux fetch them from the product data stored in Flux. But then you need to have high confidence in the catalog sync.
The catalog sync into Flux is entirely optional optional, but it makes it a lot easier to build and test discounts in the Flux UI if there's products in the system.
# Subscriptions
Flux realizes that it's not alone and not the one system that all other systems revolve around. Sending notifications to other systems for current and future discount prices is a core concept of Flux as it enables you to show discounted prices everywhere and not just in your cart. [Subscriptions](./subscriptions) lets you set up Flux to ping your other systems when current and future discount prices change.
---
# Database
At the time of writing Flux supports Sqlite, SQL Server and PostgreSQL. But it's trivial for us to support any other database that is supported by [Entity Framework](https://learn.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli) so if you need MySQL or something else, please let us know.
## Install NuGet package
We recommend that you always include the Sqlite package because it makes local development easy. After you've picked eg Sqlite and SQL Server you modify your `Program.cs` like this:
```cs
var fluxBuilder = builder.Services
.AddFlux()
.AddProcessing()
.AddApi()
.AddUI()
;
if (builder.Environment.IsDevelopment())
{
fluxBuilder.AddSqlite();
}
else
{
fluxBuilder.AddSqlServer(options =>
{
// By default Flux will look for a connection string by calling IConfiguration.GetConnectionString("sqlserver")
// (or "postgres") but you can implement your own loader like this if you need.
options.ConnectionStringLoader = serviceProvider => "Data Source=localhost;Initial Catalog=flux;Integrated Security=true";
});
}
fluxBuilder.Build();
```
## Running migrations
Flux uses Entity Framework and will include database migrations in some versions. It's left up to you to run migrations during deploy or during application startup, but you need to ensure that you're not running the same migrations on different servers at the same time.
Flux includes a `IMigrationRunner` that you can use which will take a distributed database lock and run migrations inside it. Which means that it's safe to run during application startup like this:
```cs
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddFlux()
// Other .Add() calls
.Build();
await app.Services.GetRequiredService().RunMigrations(CancellationToken.None);
```
:::tip Backward compatibility
Minor and patch releases of Flux will always be backward compatible which means that you can do zero-downtime deployment. But major versions of Flux might contain migrations that aren't backward compatible and requires downtime until migrations have run. Major versions have dedicated upgrade documentation that states if the upgrade deploy has any migrations that require downtime.
:::
---
# Getting Started
The first thing you need to do is to create a .NET application where you will install Flux into. Or, install it into an existing application.
You install it by adding the Commerce Mind GitHub NuGet package repository to your NuGet config, including an access token that you get from Commerce Mind.
You use your Github username as username and the Personal Access Token as password. Read more about the Github NuGet feed here:
https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-nuget-registry
Once you've added the NuGet repository you install the following packages:
```
commercemind.flux.core
commercemind.flux.api
commercemind.flux.processing
commercemind.flux.ui
commercemind.flux.sqlite
```
The package `commercemind.flux.sqlite` is great to get started quickly and for local development but not something you use in production. So you should also install the package for the database you want to run in production.
You don't have to install all packages in the same application. If you want you can have a separate application for the admin UI and the API as well as a separate application for the background processing in `commercemind.flux.processing`.
## Prerequisites
You will need:
- .NET 9 or higher
- A SQL database supported by Entity Framework: https://learn.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli
You can deploy Flux anywhere you can deploy .NET. It can run on Linux, Windows, etc and doesn't have any special requirements.
## Using the NuGet packages
In your `Program.cs` the minimal setup you need is this:
```cs
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddFlux()
.AddProcessing()
.AddApi()
.AddUI()
.AddDatabaseEventBroker() // Needed if you have more than one server
.AddSqlite()
.Build()
;
await app.Services.GetRequiredService().RunMigrations(CancellationToken.None);
app.UseNexusAdminUI();
app.UseFlux();
app.MapControllers();
app.Run();
```
If you're wondering what `app.UseNexusAdminUI()` it's that Flux uses [Nexus](https://nexus.commercemind.se) for background processing so you probably want to include the UI to keep track of the built-in jobs and queues in Flux.
After including this you should be able to start the application and access the admin UI at the url `/flux`.
## Next steps
- Picking and install a database → [Database](./database)
- Read the high-level [Architecture](./architecture) overview
- Explore the [API overview](../api/overview) for programmatic runs
---
# Subscriptions
A subscription is an entity you create that tells Flux to keep an eye on a defined set of product prices and to push a notification to an external system whenever those prices change. Instead of having you poll the API on a schedule, you register a subscription once and let Flux deliver the changes as they happen.
Each subscription describes three things:
1. **What to watch.** A "cart", the country and currency, and optional customer, delivery and sales channel context that Flux should use when it calculates prices.
2. **Where to send updates.** A destination - either an HTTP webhook or a RabbitMQ exchange.
3. **How to batch updates.** A maximum number of products per outbound notification (`maxProductsPerEvent`).
## Why subscriptions exist
Prices in Flux are not static values stored on a product. They are the result of a calculation that takes into account base prices, price lists, discounts, the customer making the request, the country and currency they're shopping in, the delivery method, and the sales channel. That calculation can change for many reasons that do not involve anyone touching the product itself: a discount starts or ends, a price list is updated, a campaign is scheduled, a delivery rule is changed.
For systems that need to keep a copy of the price (search engine, caches, etc), polling for these changes is not very efficient. With subscriptions you tell Flux which contexts you care about, and Flux tells you when something inside those contexts has produced a different result than the last time it was calculated.
You will typically want multiple subscriptions to deal with different kinds of prices. Eg one subscription for the public list prices, one subscription for member-only prices, etc.
When a subscription receives a notification you will get product prices that are active right now, but also any future prices that Flux currently knows about. Which is any future discount, price or price list that will become active in the future.
You will also receive a new notification if a future discount is rescheduled even if it doesn't affect the current price of the products.
## Creating a subscription
You can create a subscription through the [API](/api/reference/flux-api) or through the Flux UI. In most cases it's simpler through the UI since you'll need to create a condition for which products you want in the subscription.
## Destinations
A destination tells Flux *how* and *where* to deliver notifications. There are two kinds at the time of writing, but if you need a new destination type then please let us know.
### Webhook destination
A webhook destination POSTs JSON over HTTPS to a URL you control. Flux supports authentication in the webhook either through basic authentication or with a custom header.
### RabbitMQ destination
A RabbitMQ destination publishes the same JSON payload to a RabbitMQ exchange.
## Notification payload
Whichever destination you choose, the payload Flux sends is the same JSON document:
```json
{
"subscriptionKey": "storefront-se",
"results": [
{
"productId": "…",
"countryCode": "SE",
"currencyCode": "SEK",
"productPriceCents": 19900,
"discountedProductPriceCents": 14900,
"discountedCartPriceCents": 14900,
"startsAtUtc": "2026-04-25T00:00:00Z",
"endsAtUtc": "2026-05-02T00:00:00Z"
}
]
}
```
The top-level `subscriptionKey` is the key you supplied at creation time, which lets the receiver decide what to do with the message without having to look anything up. `results` is a list of up to `maxProductsPerEvent` `ProductPriceCalculation` objects, each describing a product whose calculated price changed since the last run, together with the validity window of the new price. If a single recalculation produces more changes than fit in one batch, Flux emits multiple notifications.
:::tip Tips
- Choose `key` carefully — it's how the receiving end identifies the subscription, and it is part of every payload.
- Start with a small `maxProductsPerEvent` (say, 50–100). You can raise it later if your consumer can handle larger batches without timing out.
- Keep webhook handlers fast and idempotent. Flux retries on failure, so a slow handler that occasionally times out will see the same message more than once.
:::