Skip to main content
SQL billing rules for MSPs let you modify cost data using SQL statements to apply custom pricing adjustments, discounts, markups, and exclusions based on your customer agreements. You can write SQL queries that run against either raw AWS Cost and Usage Report (CUR) data or processed Vantage cost data.

Need Help Writing a Rule?

AI assistant conversation preview showing a billing rule being drafted

AI-Assisted Billing Rules

Describe what you need in plain language. The docs assistant will draft, validate, or troubleshoot your SQL using the reference on this page.

SQL Billing Rule Datasets

SQL billing rules comprise two different datasets:
Rules written against aws only affect how data appears in Vantage and do not modify the original CUR file.

AWS Dataset

For the aws dataset, you can query a supported subset of AWS CUR columns. Use the Available Columns list in the billing rule editor to see all queryable fields. Custom resource_tag_% columns that vary by account are not supported, though a small set of predefined resource tag columns are available.
See the AWS Data Exports Data Dictionary for column definitions.
Expand the section below for the full list of supported aws columns, organized by CUR table. Use the format aws.table/ColumnName in your SQL (e.g., aws.lineItem/UnblendedCost). Quotes around the column name are optional; the editor accepts both aws.lineItem/UnblendedCost and aws."lineItem/UnblendedCost".
bill: BillingEntity, BillingPeriodEndDate, BillingPeriodStartDate, BillType, InvoiceId, InvoicingEntity, PayerAccountId
The bill/BillingEntity field identifies whether a charge is for an AWS service or an AWS Marketplace purchase. These values are defined by AWS in the CUR Billing Details documentation.
The bill/BillType field indicates the type of bill that the line item covers. These values are defined by AWS in the CUR Billing Details documentation.
costCategory: Project, Team, Environmentdiscount: BundledDiscount, TotalDiscountidentity: LineItemId, TimeIntervallineItem: AvailabilityZone, BlendedCost, BlendedRate, CurrencyCode, LegalEntity, LineItemDescription, LineItemType, NetUnblendedRate, NormalizationFactor, NormalizedUsageAmount, Operation, ProductCode, ResourceId, TaxType, UnblendedCost, UnblendedRate, UsageAccountId, UsageAmount, UsageEndDate, UsageStartDate, UsageType
The lineItem/ProductCode field contains the AWS service code for the line item. The table below lists commonly used product codes. This is not an exhaustive list. AWS product codes can change as services are added or renamed.
This is not an exhaustive list. Verify product codes against the AWS Data Exports Data Dictionary or the product code values in your CUR data.
The lineItem/LineItemType field indicates the type of charge on each CUR row. These values are defined by AWS in the CUR Line Item Details documentation.
pricing: LeaseContractLength, OfferingClass, publicOnDemandCost, publicOnDemandRate, PurchaseOption, RateCode, RateId, term, unit
The pricing/term field indicates whether usage is On-Demand or Reserved. These values are defined by AWS in the CUR Pricing Details documentation. This field is empty for Spot Instances, Savings Plan rows, and Marketplace purchases.
The pricing/PurchaseOption field indicates the payment model for a Reserved Instance. These values are defined by AWS in the CUR Pricing Details documentation.
product: APICalls, attachmentType, availability, cacheType, capacitystatus, clockspeed, component, databaseedition, dataTransfer, dedicatedEbsThroughput, deploymentoption, description, destinationCountryISOCode, directconnectlocation, directorysize, directorytype, directorytypedescription, disableactivationconfirmationemail, durability, ebsOptimized, ecu, endpointtype, enhancedNetworkingSupported, filesystemtype, findingGroup, findingSource, freeUsageIncluded, fromLocation, fromRegionCode, fromLocationType, gpu, gpuMemory, group, groupdescription, insightsType, instance, instanceFamily, instanceSize, instanceType, instanceTypeFamily, integratingApi, integratingService, intelAvxAvailable, intelAvx2Available, intelTurboAvailable, invocation, licenseModel, location, locationType, logsDestination, maxIopsBurstPerformance, maxIopsvolume, maxThroughputvolume, memory, messageCountfee, messageType, networkPerformance, normalizationSizeFactor, operatingSystem, operation, originationIdType, osType, parameterType, physicalCores, physicalProcessor, platoClassificationType, pricingUnit, primaryplaceofuse, processorArchitecture, processorFeatures, ProductFamily, ProductName, productSchemaDescription, provisioned, provisioningType, PurchaseOption, purchaseterm, region, regioncode, replicationType, resourceAssessment, resourcePriceGroup, routeType, servicecode, servicename, singleOrDualPass, sizeFlex, sku, storage, storageclass, storagemedia, storagetype, tenancy, throughputCapacity, tier, toLocation, toLocationType, toRegionCode, transcodingResult, trialProduct, upfrontCommitment, usagetype, vcpu, videoCodec, videoFrameRate, videoQualitySetting, volumeType, workforceType
The product/ProductFamily field categorizes the type of product. The table below lists commonly seen values. This is not an exhaustive list; product family values vary by service and can change over time.
This is not an exhaustive list. Product family values vary by service and can change over time. Verify against the AWS Data Exports Data Dictionary or the values in your CUR data.
reservation: AmortizedUpfrontCostForUsage, AmortizedUpfrontFeeForBillingPeriod, AvailabilityZone, EffectiveCost, EndTime, ModificationStatus, NetAmortizedUpfrontCostForUsage, NetAmortizedUpfrontFeeForBillingPeriod, NetEffectiveCost, NetRecurringFeeForUsage, NetUnusedAmortizedUpfrontFeeForBillingPeriod, NetUnusedRecurringFee, NetUpfrontValue, NormalizedUnitsPerReservation, NumberOfReservations, RecurringFeeForUsage, ReservationARN, StartTime, SubscriptionId, TotalReservedNormalizedUnits, TotalReservedUnits, UnitsPerReservation, UnusedAmortizedUpfrontFeeForBillingPeriod, UnusedNormalizedUnitQuantity, UnusedQuantity, UnusedRecurringFee, UpfrontValueresourceTags: user:creator, user:name, user:owner, user:purposesavingsPlan: AmortizedUpfrontCommitmentForBillingPeriod, EndTime, InstanceTypeFamily, NetAmortizedUpfrontCommitmentForBillingPeriod, NetRecurringCommitmentForBillingPeriod, NetSavingsPlanEffectiveCost, OfferingType, PaymentOption, PurchaseTerm, RecurringCommitmentForBillingPeriod, Region, SavingsPlanARN, SavingsPlanEffectiveCost, SavingsPlanRate, StartTime, TotalCommitmentToDate, UsedCommitmentsplitLineItem: ActualUsage, NetSplitCost, NetUnusedCost, ParentResourceId, PublicOnDemandSplitCost, PublicOnDemandUnusedCost, SplitCost, SplitUsage, SplitUsageRatio, UnusedCost

Costs Dataset

The table below is the full data dictionary of all costs columns you can use in billing rule SQL.

Supported Cost Type Values

The cost_type column corresponds to the Charge Type filter in Cost Reports. Expand the section below for the exact raw costs.cost_type values you can use in SQL.
Each AWS discount type in the table above, such as BundledDiscount, EdpDiscount, and PrivateRateDiscount, can also have amortized and unamortized variants that use the raw costs.cost_type value with a prefix. For example, EdpDiscount can also appear as AmortizedEdpDiscount or UnamortizedEdpDiscount.
  • Amortized variants such as AmortizedEdpDiscount appear when amortization and discounts are both enabled. These represent the discount amount on fee rows, such as Marketplace or Enterprise Support charges, that has been spread across the billing period.
  • Unamortized variants such as UnamortizedEdpDiscount appear when amortization is disabled and discounts are included. These represent the discount amount on unamortized fee or commitment rows, such as Reserved Instance fees or Savings Plan recurring fees.
The AWS discount types with these variants are: EdpDiscount, BundledDiscount, SppDiscount, RiVolumeDiscount, PrivateRateDiscount, and DistributorDiscount.

Supported Provider Values

The costs.provider field uses lowercase provider codes. Use these exact values when filtering by provider in your SQL.
To find the exact values to use in your SQL (service names, categories, regions, etc.), check the filter dropdowns in Cost Reports. You can also use editable VQL to inspect stored values. These vary by workspace and provider.

Azure-Specific Field Mapping

For Azure, costs.provider_account_id and costs.resource_account_id map to different Azure identifiers depending on your workspace configuration: Some workspaces use a Vantage setting that swaps these two columns. If your Azure rule is not matching the expected rows, compare the values in your rule against a known cost line (via CSV export or API) to confirm which column holds the subscription for your workspace.

costs to aws Column Mapping

When Vantage processes AWS CUR data, it normalizes CUR columns into the costs schema. If you are choosing between writing a rule against the aws dataset (raw CUR) or the costs dataset (normalized), the table below shows how the primary CUR fields map to costs columns.
Some CUR columns like pricing/publicOnDemandCost and pricing/publicOnDemandRate are only available in the aws dataset. If your rule needs to reference on-demand pricing (e.g., for RI/SP re-rating), use the aws dataset instead of costs.

SQL Syntax Reference

This section starts with the basic structure for SQL billing rules: which SQL operations are supported, how to format column names, which operators and expressions you can use, and how Monthly Insert aggregate rules work.
See Troubleshooting for common mistakes and how to fix them.

SQL Operations

Use the following SQL operations to define billing rules:

Column Name Format

All column references must be fully qualified with the dataset name:
  • costs dataset: Use costs.column_name format (e.g., costs.amount, costs.service)
  • aws dataset: Use aws.table/ColumnName format (e.g., aws.lineItem/UnblendedCost, aws.bill/BillingEntity)

Supported Operators

The following operators and expressions are supported in WHERE clauses and SET assignments:
The following are not supported and will cause a validation error: standalone SELECT statements, INSERT INTO aws, subqueries, JOINs, CTEs (WITH), LIMIT, ORDER BY, division (/), BETWEEN, unsupported SQL functions, and unqualified column names (every column must include the dataset prefix, e.g., costs.amount). SELECT, aggregate functions, GROUP BY, HAVING, and CASE WHEN are supported only in Monthly Insert aggregate rules.
You can include leading SQL comments before the rule statement. Both -- line comments and /* */ block comments are supported.

Monthly Insert Aggregate Rules

Monthly Insert aggregate rules use INSERT INTO costs ... SELECT ... FROM costs to calculate a value from existing cost rows and insert a new monthly cost row. Use them when the rule needs the total of a set of costs, such as a management fee, surcharge, or tiered support fee. These rules run after the other billing rule stages have processed. They read from the transformed costs dataset, so prior markups, discounts, inserted charges, and exclusions can change the total that the aggregate rule sees. See Billing Rule Execution Order for the full stage model.
Monthly Insert Basic Structure
Supported aggregate expressions include SUM(), AVG(), MIN(), MAX(), and COUNT(). You can use CASE WHEN inside the SELECT to define conditional logic, and you can use GROUP BY and HAVING when the inserted rows need to be grouped. A Monthly Insert aggregate rule must include at least one aggregate function in the SELECT. A rule without one is rejected, since an INSERT ... SELECT that does not aggregate is likely not the calculation you intended.
Monthly Insert aggregate rules are available only with the costs dataset. Use INSERT INTO costs ... SELECT ... FROM costs; do not use INSERT INTO aws or a standalone SELECT.

Cost Settings

The Cost Settings dropdown appears on SQL billing rules, but it only affects Monthly Insert aggregate rules that calculate from existing costs rows. Changing these settings on row-level UPDATE, DELETE, or fixed VALUES INSERT rules does not change how those rules run. For Monthly Insert aggregate rules, Cost Settings control which source rows are available to the aggregate calculation before your SQL WHERE clause is applied: Cost Settings and your SQL filters work together. For example, if Credits are excluded in Cost Settings, credit rows are not part of SUM(costs.amount) even if the SQL does not explicitly filter them out. If amortization is disabled, one-time upfront charges, such as upfront Reserved Instance and Savings Plan fees, are included as they appear. Examples:
  • If your rule calculates SUM(costs.amount) * 0.10 and Credits are excluded, the 10% fee is calculated before credits reduce the total.
  • If Taxes are included, tax rows are part of the total unless your SQL also filters them out, such as AND costs.cost_type != 'Tax'.
  • If Amortization is disabled, a one-time upfront Reserved Instance or Savings Plan fee can be included in the month it appears. If Amortization is enabled, the fee is calculated from amortized cost rows instead.

Monthly Date Behavior

When a Monthly Insert aggregate rule omits the date column, Vantage derives the date from the source cost rows and creates one inserted row for each month of qualifying data. For a single-month period, this produces one row. If the source costs span multiple months, the rule produces one row per month. The range of months a rule can produce is bounded by the rule’s Start Date and End Date, which you set in the rule configuration rather than in the SQL. Use those fields to scope the rule to a specific period. Examples:
  • If the qualifying costs are all from January, the rule inserts one January fee row.
  • If the qualifying costs include January and February rows, the rule inserts one January fee row and one February fee row.
  • If you set the rule’s Start Date and End Date to a single month, the rule inserts a row only for that month.
Do not use a literal date value in a Monthly Insert aggregate rule, such as '2026-01-01'. Vantage derives monthly dates from the source rows so the inserted charge aligns with the month being summed.

How to Construct SQL Statements

Step-by-step guides for building UPDATE, DELETE, and INSERT statements.

UPDATE Statements

UPDATE Basic Structure
1

Start with UPDATE

Choose your dataset (costs or aws).
2

Specify what to change

Use SET to define the new value. You can update any column from the costs data dictionary or AWS column list, not just amount.
3

Add conditions

Use WHERE to specify which rows to modify.
Common patterns:
  • Apply discount: SET costs.amount = costs.amount * 0.90 (10% discount)
  • Apply markup: SET costs.amount = costs.amount * 1.15 (15% markup)
  • Set fixed amount: SET costs.amount = 100.00

DELETE Statements

DELETE Basic Structure
1

Start with DELETE FROM

Choose your dataset (costs or aws).
2

Add conditions

Use WHERE to specify which rows to remove.
Common patterns:
  • Remove by service: WHERE costs.service LIKE 'AWS Support%'
  • Remove by cost type: WHERE costs.cost_type = 'Fee'
  • Remove by amount: WHERE costs.amount < 0.01
  • Remove by multiple conditions: WHERE costs.provider = 'aws' AND costs.service = 'Amazon S3'
See Exclusions for detailed DELETE examples.

INSERT Statements

INSERT statements can only be used with the costs dataset. INSERT is not supported for the aws dataset.
INSERT Basic Structure
Use VALUES when adding a fixed charge or credit. Values must be static literals; you cannot reference columns or use expressions (e.g., costs.amount * 0.10) in the VALUES clause. Use INSERT ... SELECT for Monthly Insert aggregate rules that calculate a value from existing costs:
Monthly Insert Basic Structure
The cost_type you insert must be one of the supported cost_type values, and any provider you filter on or insert must be one of the supported provider values.
1

Start with INSERT INTO

Use the costs dataset for INSERT statements.
2

List required columns

Specify all necessary columns.
3

Add VALUES

Provide values for each column.
Common patterns:
  • Add credit: VALUES ('aws', 'Billing Credit', 'Billing Credit', 'Billing Credit', 'Credit', -100)
  • Add processing fee: VALUES ('aws', 'Processing Fee', 'Processing Fee', 'Processing Fee', 'Fee', 5)
  • Add percentage fee on total spend: SELECT SUM(costs.amount) * 0.10, ... FROM costs WHERE ...
See Insert Line Items and Monthly Insert Aggregate Rule Examples for detailed INSERT examples.

Create SQL Billing Rules

To create a new SQL billing rule:
1

Create a new custom rule

  • From the top navigation, click Settings.
  • From the left navigation, under Partner Settings, select Billing Rules.
  • Click New Billing Rule, then select Custom.
2

Configure the rule

Add the following rule details:
  • Title: Give your rule a descriptive name.
  • Start Date/End Date: Define the date range for which the rule should apply. Use these fields instead of date logic in your SQL. If you leave both blank, the rule applies to all billing periods (past and future). You can set only a Start Date (applies from that date forward) or only an End Date (applies up to that date).
  • Select whether you want to automatically apply this billing rule to all existing and new managed accounts.
3

Write the rule SQL

  • From the Available Columns list, select either the AWS/aws or Vantage/costs schema. The selected schema must match the dataset in your SQL. If you write a costs rule but leave the schema set to aws, saving will fail.
  • Under Cost Fields, view available fields and click to copy, or type any column from the costs data dictionary or AWS column list directly into the editor.
  • In the SQL editor, write your SQL statement using the selected dataset and columns. The editor supports autocomplete and syntax highlighting.
  • Click Format above the editor to auto-format your SQL with consistent indentation and line breaks.
  • Click Validate to check your query against the selected schema before saving. Validation catches syntax errors, unsupported operations, schema mismatches (e.g., using costs columns against the aws dataset), and common issues like missing spaces before SQL keywords or multiple statements in a single rule.
  • Click Submit to create the rule.

After You Save a Rule

Once you submit a rule, keep the following in mind about how it is processed and how it interacts with your other rules.
  • Reprocessing: When you save a billing rule, Vantage automatically reprocesses your cost data back to the rule’s start date. If you leave the start date empty, the rule applies to your entire history, which means more data to reprocess. Reprocessing can take several hours depending on the size of the account, and saving multiple times restarts the cycle. Finalize your SQL before saving, and test after reprocessing completes to confirm the result.
  • Rule limit: Each workspace can define up to 20 billing rules. If you need more, contact support@vantage.sh. For multiple adjustments with different conditions, create separate rules.
  • Monthly Insert rules: Aggregate INSERT ... SELECT rules run in the Monthly Insert stage, after line-item transform rules. This lets a rule calculate a fee from the final monthly cost set after prior markups, discounts, exclusions, or inserted charges have been applied.
  • Rule order: Rules are applied sequentially, so order matters when multiple rules touch the same line items. Each statement operates on the data left behind by the rules before it. For example, consider two rules that both target the same Platform Fee line item—one that sets a fixed amount and one that applies a 10% discount:
    Rule A — set a fixed amount
    Rule B — apply a 10% discount
    The final amount depends on which rule runs first:
    • A then B: the amount is set to $100, then discounted to $90.
    • B then A: the amount is discounted first, then overwritten to $100—the discount is lost.
    Reorder the rules on the Managed Account’s Billing Rules tab to control which one wins. For the full execution-stage model and how to reorder rules on a Managed Account, see Billing Rule Execution Order.

Example Rules

Many of the below examples are also documented in the FinOps as Code repository.

Discounts and Markups

Apply a 5% Discount (AWS)

Apply a 5% discount to all cost line items, excluding credits:
At this time, multiplication is supported, but not division.

Apply Service-Specific Markup

Apply a 5% markup to specific services:

Rename a Service

Rename a service label in normalized cost data:

Apply Markup by Cost Category

Apply a 10% markup to all storage costs:

Reduce Costs for a Specific AWS Account

Apply a 50% cost reduction to a specific linked account:

Set Credits to Zero

Zero out all credit line items:

Zero Out Cost and Rate for Internal Accounts

Set both the cost and rate to zero for specific internal accounts (e.g., cost optimization or internal operations accounts):

Exclusions

Exclude SPP Discounts

Remove Solution Provider Program discounts from billing:

Exclude Multiple SPP Discount Types

Remove both SPP and unamortized SPP discounts:

Exclude SPP/EDP Discount Line Items (AWS)

Remove Enterprise Discount Program and Solution Provider discount or credit line items at the CUR level:

Exclude AWS Support Products (AWS)

Remove all AWS Support product costs at the CUR level:

Exclude Support Costs

Remove AWS Business support costs from billing:

Exclude Marketplace Costs

Remove all AWS Marketplace costs from billing:

Exclude Marketplace by Billing Entity (AWS)

Remove AWS Marketplace costs at the CUR level using the billing entity field:

Exclude BundledDiscount Line Items (AWS)

Remove BundledDiscount line items from the CUR:

Remove Costs for Specific AWS Accounts

Exclude all costs from specific linked AWS accounts:
Account-based exclusions must use account IDs, not account names. The AWS CUR does not include an account name column that can be used in billing rules.

Exclude Other Provider Items

Remove Temporal Cloud Actions from billing:

Reserved Instance and Savings Plan Adjustments

Unamortize Reserved Instance and Savings Plan Costs

Convert amortized Reserved Instance and Savings Plan costs back to usage-based costs. This rule sets the line item type to Usage when the Savings Plan or reservation does not belong to the linked account (using string concatenation to compare account IDs within ARNs):

Unamortize Savings Plans for a Specific Account

Convert Savings Plan covered usage back to on-demand for a specific account by matching the account ID within the Savings Plan ARN:

Rerate Reserved Instance Costs to On-Demand Pricing

Replace discounted Reserved Instance costs with public on-demand pricing by copying values from the pricing columns. This sets both the cost and rate to their on-demand equivalents for reservations belonging to specific accounts:
When filtering by account ID within an ARN field, use LIKE '%account_id%' to match the account ID substring within the full ARN string. Do not use IN with bare account IDs — ARN fields contain full ARN strings (e.g., arn:aws:ec2:us-east-1:111111111111:reserved-instances/...), so an IN comparison against just '111111111111' will never match.

Exclude Reservation Fees for Specific Accounts

Remove Reserved Instance fees that belong to specific internal accounts without affecting other usage on those accounts. Use LIKE to match the account ID within the reservation ARN:

Monthly Insert Aggregate Rule Examples

Monthly Insert aggregate rules use INSERT INTO costs ... SELECT ... FROM costs. They calculate from existing monthly cost rows and insert new synthetic cost rows.

Add a 10% Management Fee on Qualifying AWS Spend

Insert a management fee equal to 10% of AWS spend, excluding Marketplace purchases and EDP/SPP discount line items:

Add a Tiered Support Fee

Use CASE WHEN around SUM() when the fee rate changes based on the customer’s total qualifying spend. This example charges 10% on the first $10,000, 7% on the next $70,000, and 5% above $80,000:
Validate tiered rules against expected invoice totals before applying them broadly, especially when the customer has large or multi-month billing periods.

Insert Line Items

INSERT statements can only be used with the costs dataset.

Add a Monthly Charge

Insert a flat monthly charge as a new line item:

Add a Credit

Insert a billing credit as a negative amount:

Add a Processing Fee

Insert a processing fee for services rendered:

Add a Support Fee with a Specific Date

Insert a support fee for a specific billing period. You can include the date column to specify which month the charge applies to:

Azure Examples

Azure billing rules use the costs dataset. There is no separate Azure CUR dataset. When writing Azure rules, use costs.provider = 'azure' for standard Azure or costs.provider = 'azure_csp' for Azure CSP. These are distinct provider values, and rules must target the correct one.

Apply Markup to Azure Services

Apply a 10% markup to Azure Virtual Machines:

Apply Discount Excluding Reservations (Azure)

Apply a discount to all Azure costs while excluding reservation purchases:

Apply Markup by Azure Subscription

Apply a 10% markup to costs from a specific Azure subscription. See the Azure-Specific Field Mapping section to determine whether costs.resource_account_id or costs.provider_account_id contains the subscription ID for your workspace.

Exclude Partner Earned Credit (Azure CSP)

Remove Partner Earned Credits from Azure CSP billing. Note the use of azure_csp as the provider value:

Apply Discount to NCE Licenses (Azure CSP)

Apply a 5% discount to New Commerce Experience (NCE) License purchases for Azure CSP:
Need help writing or debugging a rule? Try the AI assistant at the top of this page.

Troubleshooting

If a billing rule fails to save, the editor displays an error message. Below are common errors and how to resolve them.

Additional Troubleshooting