Enhanced Data (Level 2 and Level 3)
Overview
Every card payment carries a basic set of data: the amount, the date, and the merchant's name and category. Commercial cards can also carry richer data about what the payment was for. This is enhanced data. It adds two levels to the basic data: Level 2 and Level 3.
| Level | What it adds | Examples |
|---|---|---|
| 1 | The basic data that every card payment carries. | Amount, date, merchant name, merchant category code |
| 2 | Order-level tax and reference data. | Sales tax, a customer reference or purchase order number |
| 3 | Line-item detail for each item or service on the invoice. | Product code, description, quantity, unit cost, discount |
Level 3 includes the Level 2 data, so send both. Business buyers use this data to match each payment to an invoice or purchase order. In return, the card networks can charge your merchants a lower interchange rate on eligible commercial cards.
Visa rewards Level 3 data. Level 2 data alone earns a better rate only for commercial cards at fuel merchants. Visa's Level 3 rate applies only to commercial or small-business credit cards. Mastercard rewards Level 2 and Level 3 data. Its Level 3 rate applies only to large-market commercial credit cards, which include fleet credit cards, not to small business cards or commercial debit and prepaid cards.
Consumer cards do not qualify, so the data matters most to merchants that sell to businesses and governments.
Networks set the rates and the rules, and they change them, so this page does not list rates. Sending enhanced data does not guarantee a lower rate. Use real values. The networks check the data.
Blank or generic values, such as a one-letter description or the merchant's name used as the item description, can stop a payment from qualifying. Visa also assigns each merchant a verification status.
A payment from a merchant that Visa has not verified can settle at the standard commercial rate, and Visa may adjust it later.
Mastercard also requires an eligible merchant category and prompt clearing. Highnote claims Mastercard's Level 2 rate only for card-not-present payments. Highnote does not claim Mastercard's Level 3 rate at fuel locations. Some payments, merchants and late captures do not qualify.
You send enhanced data in the optional enhancedData input on authorizePaymentTransaction, chargePaymentTransaction and capturePaymentTransaction. All three take the same shape. Requests that omit enhancedData behave as before. Enhanced data supports Visa and Mastercard cards.
AcquiringEnhancedDataInput takes one member for the network of the card you charge: visa or mastercard. You must set exactly one member. If you set none or both, the API returns a top-level GraphQL validation error. If the member does not match the network of the card, the request fails with the ENHANCED_DATA_INVALID error code.
Highnote enables enhanced data one organization at a time. If your organization is not enabled, a request that includes enhancedData fails with the ENHANCED_DATA_NOT_ENABLED error code. Contact Highnote support to request enablement.
What reaches each network
| Data | Visa | Mastercard |
|---|---|---|
| Header fields | Highnote sends the Level 2 fields to Visa. When the payment qualifies for Level 3, it also sends the Level 3 summary fields, except taxSignage. The value added tax (VAT) registration numbers and taxSignage are stored with the payment and not sent to Visa. | Highnote sends customerCode and totalTax on commercial cards. taxExempt is stored with the payment and not sent. |
| Line items | Highnote sends them to Visa when the payment qualifies for Level 3. Otherwise the payment clears as Level 2. | Highnote sends them to Mastercard when the payment qualifies for Mastercard's Level 3 rate. Otherwise Highnote does not send them. See Mastercard line items. |
In the Test environment, Highnote stores enhanced data and does not send it to the network.
Send enhanced data
Both examples authorize the same purchase: 3 office chairs at $100.00 each plus $24.75 sales tax, so amount is 32475. Omit a field to leave it unset. Send 0 to state an explicit zero.
Visa
The Visa example sends a header and one line item.
authorizePaymentTransaction with Visa enhanced data
Query
mutation AuthorizePaymentTransaction(
$input: AuthorizePaymentTransactionInput!
) {
authorizePaymentTransaction(input: $input) {
__typename
... on UserError {
errors {
errorPath
code
description
}
}
... on CardAuthorizationStepSummary {
createdAt
transaction {
__typename
id
createdAt
accountingDirection
authorizedAmount {
value
currencyCode
}
authorizedRemainingAmount {
value
currencyCode
}
settledAmount {
value
currencyCode
}
disbursedAmount {
value
currencyCode
}
canceledAmount {
value
currencyCode
}
refundedAmount {
value
currencyCode
}
responseCode {
authorizationCode
processorResponseCode
addressCode
postalCode
securityCode
}
}
}
}
}
Variables
{ "input": { "credential": { "paymentCard": { "cardNumber": "4000000000000002", "expiryYear": "31", "expiryMonth": "12", "securityCode": "111", "cardHolder": { "billingAddress": { "streetAddress": "1234 Visa Street", "countryCodeAlpha3": "USA", "extendedAddress": "extended-address", "locality": "Visa", "region": "California", "postalCode": "12345" } } } }, "merchantAcceptorId": "<MERCHANT_ACCEPTOR_ID>", "amount": { "value": 32475, "currencyCode": "USD" }, "idempotencyKey": "UUID_v4", "paymentInitiator": "CUSTOMER_INITIATED_VIA_WEB", "enhancedData": { "visa": { "header": { "customerReferenceNumber": "CC-4471", "purchaseIdentifier": "ORD-500", "purchaseIdentifierFormat": "ORDER", "localTax": { "value": 2475, "currencyCode": "USD" }, "summaryCommodityCode": "5111", "taxTreatment": "NLL", "orderDate": "2026-10-18" }, "lineItems": [ { "descriptor": "Office Chair", "productCode": "CHR123", "quantity": 3, "unitOfMeasure": "EA", "unitCost": { "value": 10000, "currencyCode": "USD" }, "taxAmount": { "value": 2475, "currencyCode": "USD" }, "taxRate": 825, "lineItemTotal": { "value": 30000, "currencyCode": "USD" }, "lineItemDetailIndicator": "NORMAL" } ] } } } }
Result
{
"data": {
"authorizePaymentTransaction": {
"__typename": "CardAuthorizationStepSummary",
"createdAt": "2026-10-18T17:26:20.474Z",
"transaction": {
"__typename": "PaymentDebitTransactionSummary",
"id": "<PAYMENT_DEBIT_TRANSACTION_SUMMARY_ID>",
"createdAt": "2026-10-18T17:26:20.474Z",
"accountingDirection": "DEBIT",
"authorizedAmount": {
"value": 32475,
"currencyCode": "USD"
},
"authorizedRemainingAmount": {
"value": 32475,
"currencyCode": "USD"
},
"settledAmount": null,
"disbursedAmount": null,
"canceledAmount": null,
"refundedAmount": null,
"responseCode": {
"authorizationCode": "Q5Z539",
"processorResponseCode": "APPROVED",
"addressCode": "NOT_VERIFIED",
"postalCode": "NOT_VERIFIED",
"securityCode": "NOT_VERIFIED"
}
}
}
},
"extensions": {
"requestId": "<REQUEST_ID>",
"rateLimit": {
"cost": 18,
"limit": 60060,
"remaining": 60041
}
}
}
Mastercard
The Mastercard example sends a header and one line item. Highnote takes the merchant's business type and tax identification number from the merchant's onboarding details, so you do not send them.
authorizePaymentTransaction with Mastercard enhanced data
Query
mutation AuthorizePaymentTransaction(
$input: AuthorizePaymentTransactionInput!
) {
authorizePaymentTransaction(input: $input) {
__typename
... on UserError {
errors {
errorPath
code
description
}
}
... on CardAuthorizationStepSummary {
createdAt
transaction {
__typename
id
createdAt
accountingDirection
authorizedAmount {
value
currencyCode
}
authorizedRemainingAmount {
value
currencyCode
}
settledAmount {
value
currencyCode
}
disbursedAmount {
value
currencyCode
}
canceledAmount {
value
currencyCode
}
refundedAmount {
value
currencyCode
}
responseCode {
authorizationCode
processorResponseCode
addressCode
postalCode
securityCode
}
}
}
}
}
Variables
{ "input": { "credential": { "paymentCard": { "cardNumber": "5555555555554444", "expiryYear": "31", "expiryMonth": "12", "securityCode": "222", "cardHolder": { "billingAddress": { "streetAddress": "2134 Mastercard St", "countryCodeAlpha3": "USA", "locality": "Mastercard", "region": "California", "postalCode": "21345" } } } }, "merchantAcceptorId": "<MERCHANT_ACCEPTOR_ID>", "amount": { "value": 32475, "currencyCode": "USD" }, "idempotencyKey": "UUID_v4", "paymentInitiator": "CUSTOMER_INITIATED_VIA_WEB", "enhancedData": { "mastercard": { "header": { "customerCode": "PO-7781", "totalTax": { "value": 2475, "currencyCode": "USD" } }, "lineItems": [ { "descriptor": "Office Chair", "productCode": "CHR123", "quantity": 3, "unitOfMeasure": "EA", "unitCost": { "value": 10000, "currencyCode": "USD" }, "lineItemTotal": { "value": 30000, "currencyCode": "USD" }, "debitCreditIndicator": "DEBIT" } ] } } } }
Result
{
"data": {
"authorizePaymentTransaction": {
"__typename": "CardAuthorizationStepSummary",
"createdAt": "2026-10-18T17:31:02.118Z",
"transaction": {
"__typename": "PaymentDebitTransactionSummary",
"id": "<PAYMENT_DEBIT_TRANSACTION_SUMMARY_ID>",
"createdAt": "2026-10-18T17:31:02.118Z",
"accountingDirection": "DEBIT",
"authorizedAmount": {
"value": 32475,
"currencyCode": "USD"
},
"authorizedRemainingAmount": {
"value": 32475,
"currencyCode": "USD"
},
"settledAmount": null,
"disbursedAmount": null,
"canceledAmount": null,
"refundedAmount": null,
"responseCode": {
"authorizationCode": "M7K204",
"processorResponseCode": "APPROVED",
"addressCode": "NOT_VERIFIED",
"postalCode": "NOT_VERIFIED",
"securityCode": "NOT_VERIFIED"
}
}
}
},
"extensions": {
"requestId": "<REQUEST_ID>",
"rateLimit": {
"cost": 18,
"limit": 60060,
"remaining": 60041
}
}
}
Visa header fields
Send one header per request. The visa.header input is AcquiringVisaEnhancedDataHeaderInput.
| Field | Type | Level | Max length | Description |
|---|---|---|---|---|
customerReferenceNumber | String | 2 | 17 | The reference your customer uses for this purchase, such as a cost center or purchase order number. |
purchaseIdentifier | String | 2 | 25 | An order number or invoice number that identifies this purchase. |
purchaseIdentifierFormat | VisaPurchaseIdFormat | 2 | Whether purchaseIdentifier is an order number or an invoice number. Required when you send purchaseIdentifier. | |
localTax | AmountInput | 2 | The local sales tax charged on the purchase. Send the exact tax charged, or 0 for a tax-exempt purchase. If you omit it, clearing tells Visa the purchase was not subject to tax. | |
nationalTax | AmountInput | 2 | The national tax on the purchase. | |
otherTax | AmountInput | 2 | Any other tax on the purchase. | |
summaryCommodityCode | String | 2 | 4 | A code that classifies the goods or services purchased, as a whole. |
merchantTaxRegistrationNumber | String | 20 | The merchant's value added tax (VAT) registration number. Not needed for US Level 2. | |
customerTaxRegistrationNumber | String | 13 | Your customer's VAT registration number. Not needed for US Level 2. | |
discount | AmountInput | 3 | The discount applied at invoice level. Excludes discounts applied to individual line items. | |
discountSignage | VisaAmountSignage | 3 | Whether discount is a charge or a refund on the invoice. | |
discountTreatment | VisaDiscountTreatment | 3 | How tax was calculated in relation to the invoice-level discount. | |
duty | AmountInput | 3 | The duty charged on the purchase. | |
dutySignage | VisaAmountSignage | 3 | Whether duty is a charge or a refund on the invoice. | |
taxTreatment | VisaTaxTreatment | 3 | How tax is calculated on the invoice. | |
taxSignage | VisaAmountSignage | 3 | Whether the invoice's tax amount is a charge or a refund. Stored with the payment and not sent to Visa. | |
vatInvoiceReferenceNumber | String | 3 | 15 | The VAT invoice reference number. |
orderDate | Date | 3 | The date the order was placed. |
Shipping amounts and the ship-from postal code are not part of this input.
Visa line items
Send up to 998 lineItems, one per item or service purchased, in invoice order. Each line item is AcquiringVisaEnhancedDataLineItemInput.
| Field | Type | Max length | Description |
|---|---|---|---|
commodityCode | String | 12 | A code that classifies the item, from the commodity coding scheme your buyer uses, such as the United Nations Standard Products and Services Code (UNSPSC). |
descriptor | String | 26 | A free-text description of the item or service. |
productCode | String | 12 | Your code for the item, typically a stock keeping unit (SKU). |
quantity | UnsignedInt | The number of units, scaled by quantityDecimalPlaces. A quantity of 1500 with 2 decimal places is 15.00 units. | |
quantityDecimalPlaces | UnsignedInt | The number of decimal places in quantity. Omit for a whole number of units. At most 4. | |
unitOfMeasure | String | 12 | The unit of measure for quantity, such as EA or HR. |
unitCost | AmountInput | The cost of one unit. | |
unitCostDecimalPlaces | UnsignedInt | The number of decimal places in unitCost.value. A value of 12345 with 4 decimal places is 1.2345. Omit when unitCost uses the currency's minor units. Requires unitCost. At most 4. | |
taxAmount | AmountInput | The sales tax on this line item. | |
taxRate | UnsignedInt | The sales tax rate on this line item, in basis points. A taxRate of 825 is 825 basis points. | |
discountPerItem | AmountInput | The discount applied to this line item. | |
lineItemDiscountTreatment | VisaDiscountTreatment | How tax was calculated in relation to this line item's discount. | |
lineItemTotal | AmountInput | The total for this line item: quantity multiplied by unitCost, less discountPerItem. | |
lineItemDetailIndicator | VisaLineItemDetailIndicator | The type of line item. |
For Level 3, the payment amount must equal the sum of the lineItemTotal values, minus header.discount, plus header.localTax. There is no shipping field, so the line items must account for any shipping charge. otherTax is not part of this sum. The API does not check the sum, but clearing does. If the amounts do not add up, Highnote sends no Level 3 data to Visa and the payment clears as Level 2. Make sure your amounts reconcile before you send them.
localTax must also equal the sum of the line item taxAmount values. If it does not, the payment clears as Level 2.
nationalTax and duty must be omitted or 0. A payment with either above 0 clears as Level 2.
Level 3 also requires, among other checks, a US merchant, a US commercial or small-business credit card, and a single clearing in USD with no installments.
The API does not report whether a payment cleared with Level 2 or Level 3.
Visa enum values
| Enum | Value |
|---|---|
VisaPurchaseIdFormat | ORDER, INVOICE |
VisaTaxTreatment | NLL: net prices, tax at line item level. NIL: net prices, tax at invoice level. GLL: gross prices, tax at line item level. GIL: gross prices, tax at invoice level. NON: no tax on the invoice. |
VisaDiscountTreatment | NO_DISCOUNT: no discount applies. POST_DISCOUNT: tax was calculated on the post-discount total. PRE_DISCOUNT: tax was calculated on the pre-discount total. |
VisaAmountSignage | NULL: no signage applies. DEBIT: a charge on the invoice. CREDIT: a refund on the invoice. |
VisaLineItemDetailIndicator | NORMAL, CREDIT, PAYMENT |
See VisaTaxTreatment, VisaDiscountTreatment, VisaAmountSignage, VisaPurchaseIdFormat and VisaLineItemDetailIndicator in the API reference.
Mastercard header fields
Send one header per request. The mastercard.header input is AcquiringMastercardEnhancedDataHeaderInput. Send at least one of customerCode, totalTax, or taxExempt set to true. A header with none of them fails with the ENHANCED_DATA_INVALID error code.
| Field | Type | Max length | Description |
|---|---|---|---|
customerCode | String | 25 | The code your customer uses for this purchase, such as a cost center or purchase order number. |
totalTax | AmountInput | The total sales tax or value added tax (VAT) on the purchase, in the currency of the payment. Send 0 when no tax was charged. | |
taxExempt | Boolean | Whether the purchase is exempt from tax. A tax-exempt purchase cannot carry a totalTax other than 0. A request that does fails with ENHANCED_DATA_INVALID. |
Highnote does not claim Mastercard's Level 2 rate for a purchase whose total tax is zero or that is tax exempt. Highnote still accepts the request. Send the tax you charged.
Mastercard line items
Send up to 998 lineItems, one per item or service purchased, in invoice order. Each line item is AcquiringMastercardEnhancedDataLineItemInput.
| Field | Type | Max length | Description |
|---|---|---|---|
commodityCode | String | 15 | A code that classifies the item. |
descriptor | String | 35 | A free-text description of the item or service. Cannot be all zeros. |
productCode | String | 15 | Your code for the item, typically a SKU. Cannot be all zeros. |
quantity | UnsignedInt | The number of units, scaled by quantityDecimalPlaces. Must be greater than 0, and at most 12 digits. | |
quantityDecimalPlaces | UnsignedInt | The number of decimal places in quantity. Omit for a whole number of units. At most 4. | |
unitOfMeasure | String | 12 | The unit of measure for quantity, such as EA or HR. Cannot be all zeros. |
unitCost | AmountInput | The cost of one unit. Not negative. At most 12 digits at its decimal places. | |
unitCostDecimalPlaces | UnsignedInt | The number of decimal places in unitCost.value. Omit when unitCost uses the currency's minor units. Requires unitCost. At most 4. | |
discountAmount | AmountInput | The discount for the whole line item, not for one unit. Not negative. At most 12 digits in the currency's minor units. | |
lineItemTotal | AmountInput | The total for this line item before any discount: quantity multiplied by unitCost. Send 0 for a line item with no charge. At most 12 digits in the currency's minor units. | |
debitCreditIndicator | AcquiringMastercardDebitCreditIndicator | Whether this line item is a debit or a credit to the cardholder: DEBIT or CREDIT. Required. |
The two networks total a line item differently. For Visa, lineItemTotal is quantity multiplied by unitCost, less discountPerItem. For Mastercard, lineItemTotal is the amount before any discount, and you send the discount in discountAmount.
Highnote sends your line items to Mastercard, and the payment can earn the Level 3 rate, only when all of these hold:
- The payment is on a large-market commercial credit card, which includes a fleet credit card.
- The payment is not at a fuel location.
- The merchant category code is not 7361.
- You send at least one line item, and no more than 998.
- Every line item has
productCode,descriptor,quantity,unitOfMeasure,lineItemTotalanddebitCreditIndicator. - The payment also meets the Level 2 conditions, so send the header with the line items.
When a payment does not meet these conditions, Highnote does not send the line items. The payment keeps its Level 2 treatment if it qualifies. The API does not report whether a payment cleared with line items.
Capture
A capture can carry its own enhancedData. Highnote combines the capture's data with the authorization's data. The rules differ by network.
Visa
For Visa Level 2, clearing combines the capture's data with the authorization's data.
| Field group | Rule |
|---|---|
| Any field you send on the capture | Replaces the authorization's value for that field. |
customerReferenceNumber, purchaseIdentifier, purchaseIdentifierFormat and summaryCommodityCode | Come from the authorization when the capture omits them, on every capture. |
localTax, nationalTax and otherTax | Come from the authorization only for a single capture of the full authorized amount, and only when the authorization was approved for the full amount requested. Every other capture carries only the tax it sends, because the authorization's tax describes the original amount. |
On a Visa capture, lineItems describe the amount you capture.
Mastercard
| Field group | Rule |
|---|---|
lineItems | Line items you send on the capture replace the authorization's line items as a set. If you send none, the authorization's line items apply only to a single capture of the full authorized amount, and only when the authorization was approved for the full amount requested and no incremental authorization was approved. Any other capture without its own line items carries none, so it cannot earn the Level 3 rate. |
totalTax | Comes from the authorization only for a single capture of the full authorized amount, and only when the authorization was approved for the full amount requested and no incremental authorization was approved. Every other capture carries only the tax it sends, because the authorization's tax describes the original amount. |
| Any field you send on the capture | Replaces the authorization's value for that field. |
customerCode and taxExempt | Come from the authorization when the capture omits them, on every capture. If the authorization sent taxExempt as true and the capture sends a totalTax other than 0, also send taxExempt as false on the capture. Otherwise the payment stays tax exempt and Highnote does not claim Mastercard's Level 2 rate. |
Errors
Enhanced data errors return in UserError.errors[]. Each error names the input field in errorPath.
| Code | Cause |
|---|---|
ENHANCED_DATA_NOT_ENABLED | Enhanced data is not enabled for your organization. Contact Highnote support to request enablement. |
ENHANCED_DATA_INVALID | Highnote cannot accept the enhanced data. You sent the visa member for a card that is not a Visa card, or the mastercard member for a card that is not a Mastercard card. For Visa: visa has neither a header field nor a line item, or purchaseIdentifier has no purchaseIdentifierFormat. For Mastercard: mastercard has no header, the header has none of customerCode, totalTax or taxExempt set to true, taxExempt is true and totalTax is not 0, customerCode starts with a space, totalTax is negative or longer than 12 digits counting the minor units, a line item has no debitCreditIndicator, a line item descriptor, productCode or unitOfMeasure is all zeros, a line item quantity is 0, a line item unitCost, discountAmount or lineItemTotal is negative, or a line item quantity, unitCost, discountAmount or lineItemTotal is longer than 12 digits. For either network: a text field is blank, holds a character other than printable ASCII, or holds a card number, or an amount uses a currency other than the payment's. Correct or remove the field that the error path names. |
ENHANCED_DATA_FIELD_TOO_LONG | A text field is longer than its maximum length. Shorten the field that the error path names. |
INVALID_INPUT | You sent more than 998 line items for either network. A quantity or a Visa taxRate is greater than 9007199254740991. quantityDecimalPlaces or unitCostDecimalPlaces is greater than 4. unitCostDecimalPlaces has no unitCost. |
WALLET_PAYMENT_METHOD_NOT_SUPPORTED | The request sets a field that a wallet payment method cannot carry, such as enhancedData. The error path names the field. Highnote creates no payment. |
WALLET_CAPTURE_FIELD_NOT_SUPPORTED | You sent enhancedData on a capture of a wallet payment. The error path is paymentTransactionId. |