---
title: Multi-Attribute Pricing
slug: multi-attribute-pricing
docTags: 
createdAt: 2026-03-17T21:13:53.778Z
---

# Multi-Attribute Pricing

Multi-attribute pricing allows the pricing engine to select different Price Book Entries (PBEs) based on attribute values. Instead of resolving a single PBE per SKU + UOM combination, the engine evaluates additional fields -- such as Account type, region, or custom pricing attributes -- to find the PBE that matches the current context.

This is useful when the same product has different prices for different customer segments, partner tiers, or configuration options.

## How Multi-Attribute PBE Resolution Works

When the pricing engine resolves a Price Book Entry, it follows this order:

1. **Account field auto-resolution** -- The engine reads attribute values from the Account record linked to the Opportunity (e.g., `Account.Type`). If a PBE has a matching PricingAttribute value, that PBE is selected.
2. **Custom pricing attributes** -- If the request includes `customPricingAttributes`, those values override or supplement the Account-level values for PBE resolution.
3. **\_\_ANY\_\_ fallback** -- If a PBE is configured with the special value `__ANY__` for a pricing attribute, it acts as a universal fallback when no specific match is found.
4. **Default PBE** -- If no pricing attribute match is found and no `__ANY__` PBE exists, the engine falls back to the default PBE (one with no pricing attribute constraints).

### Resolution Priority

| Priority    | Source                               | Description                                     |
| ----------- | ------------------------------------ | ----------------------------------------------- |
| 1 (highest) | `customPricingAttributes` in request | Explicit override sent in the API call          |
| 2           | Account field auto-resolution        | Read from the Account record on the Opportunity |
| 3           | `__ANY__` PBE                        | Universal fallback PBE                          |
| 4 (lowest)  | Default PBE                          | PBE with no pricing attribute constraints       |

### AND Logic for Multiple Attributes

When a PBE has multiple pricing attribute fields, all fields must match for that PBE to be selected. This is AND logic -- every attribute must satisfy its condition.

## Example Price Book Entries

The examples below reference a product `NUE_ON_SALESFORCE` (SKU) with the following PBE configurations:

| PBE          | UOM        | PricingAttribute\_1 (Account.Type) | PricingAttribute\_2 | List Price |
| ------------ | ---------- | ---------------------------------- | ------------------- | ---------- |
| PBE-DEFAULT  | User/Month | (none)                             | (none)              | $29.90     |
| PBE-TECH     | User/Month | Technology Partner                 | (none)              | $19.90     |
| PBE-CHANNEL  | User/Month | Channel Partner                    | (none)              | $24.90     |
| PBE-ANY      | User/Month | \_\_ANY\_\_                        | (none)              | $27.50     |
| PBE-TECH-ENT | User/Month | Technology Partner                 | Enterprise          | $14.90     |

## Authentication

```javascript
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
```

## Use Case 1: Auto-Resolution from Account.Type

When the Opportunity's Account has `Type = "Technology Partner"`, the pricing engine automatically resolves to the PBE whose `PricingAttribute_1` matches `"Technology Partner"`. No extra fields are needed in the request.

```javascript
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");

const quoteData = {
  opportunityId: "006xx000001abc123",
  name: "Tech Partner Auto-Resolve Quote",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    { productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10 }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const line = result.quoteLineItems[0];
  console.log(`Resolved unit price: $${line.listUnitPrice}`);  // $19.90 (Technology Partner PBE)
  console.log(`Total: $${line.totalPrice}`);
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "Tech Partner Auto-Resolve Quote",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      { "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
    ]
  }'
```

The pricing engine reads `Account.Type` from the Opportunity's Account, finds `"Technology Partner"`, and selects PBE-TECH at $19.90/user/month.

***

## Use Case 2: Different Account.Type Values Resolving to Different PBEs

The same product SKU resolves to a different unit price depending on the Account's type. An Opportunity linked to a "Channel Partner" Account gets channel pricing.

```javascript
const quoteData = {
  opportunityId: "006xx000002def456",
  name: "Channel Partner Quote",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    { productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10 }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const line = result.quoteLineItems[0];
  console.log(`Resolved unit price: $${line.listUnitPrice}`);  // $24.90 (Channel Partner PBE)
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000002def456",
    "name": "Channel Partner Quote",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      { "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
    ]
  }'
```

The Opportunity `006xx000002def456` is linked to an Account with `Type = "Channel Partner"`, so the engine selects PBE-CHANNEL at $24.90/user/month.

***

## Use Case 3: Null Account.Type (Default PBE Fallback)

When the Account's `Type` field is null or empty, and no `__ANY__` PBE exists for that attribute, the engine falls back to the default PBE with no pricing attribute constraints.

```javascript
const quoteData = {
  opportunityId: "006xx000003ghi789",
  name: "Default Pricing Fallback",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    { productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10 }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const line = result.quoteLineItems[0];
  console.log(`Resolved unit price: $${line.listUnitPrice}`);  // $29.90 (default PBE)
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000003ghi789",
    "name": "Default Pricing Fallback",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      { "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
    ]
  }'
```

With a null `Account.Type`, no attribute-specific PBE matches. If a `__ANY__` PBE exists it would be used; otherwise the engine selects PBE-DEFAULT at $29.90/user/month.

***

## Use Case 4: Bundle Parent Auto-Resolution

Multi-attribute pricing works the same way for bundle parent products. The engine resolves the parent's PBE based on the Account's attributes, and each add-on resolves independently.

```javascript
const quoteData = {
  opportunityId: "006xx000001abc123",
  name: "Bundle with Attribute Resolution",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    {
      productSku: "ENTERPRISE_BUNDLE",
      uom: "License/Month",
      quantity: 50,
      addOns: [
        { productSku: "ADDON_SUPPORT", uom: "License/Month", quantity: 1 },
        { productSku: "ADDON_STORAGE", uom: "GB/Month", quantity: 200 }
      ]
    }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const parent = result.quoteLineItems[0];
  console.log(`Parent unit price: $${parent.listUnitPrice}`);
  parent.childrenLineItems.forEach(child => {
    console.log(`  ${child.product.sku}: $${child.listUnitPrice}`);
  });
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "Bundle with Attribute Resolution",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      {
        "productSku": "ENTERPRISE_BUNDLE",
        "uom": "License/Month",
        "quantity": 50,
        "addOns": [
          { "productSku": "ADDON_SUPPORT", "uom": "License/Month", "quantity": 1 },
          { "productSku": "ADDON_STORAGE", "uom": "GB/Month", "quantity": 200 }
        ]
      }
    ]
  }'
```

Each product in the bundle hierarchy resolves its own PBE based on the Account's attributes. The parent, ADDON\_SUPPORT, and ADDON\_STORAGE each independently match their attribute-specific PBEs.

***

## Use Case 5: Custom Pricing Attributes (Explicit Override)

Use `customPricingAttributes` to explicitly specify attribute values for PBE resolution. This overrides the auto-resolved values from the Account record.

Each entry in the array requires:

- `name` -- The API name of the pricing attribute field on the PBE (e.g., `Ruby__PricingAttribute_1__c`)
- `value` -- The value to match against

```javascript
const quoteData = {
  opportunityId: "006xx000001abc123",
  name: "Custom Attribute Override",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    {
      productSku: "NUE_ON_SALESFORCE",
      uom: "User/Month",
      quantity: 10,
      customPricingAttributes: [
        { name: "Ruby__PricingAttribute_1__c", value: "Technology Partner" }
      ]
    }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const line = result.quoteLineItems[0];
  console.log(`Resolved unit price: $${line.listUnitPrice}`);  // $19.90 (Technology Partner PBE)
  console.log(`Total: $${line.totalPrice}`);
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "Custom Attribute Override",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      {
        "productSku": "NUE_ON_SALESFORCE",
        "uom": "User/Month",
        "quantity": 10,
        "customPricingAttributes": [
          { "name": "Ruby__PricingAttribute_1__c", "value": "Technology Partner" }
        ]
      }
    ]
  }'
```

Even if the Account's `Type` is different (or null), the `customPricingAttributes` value takes precedence and forces resolution to PBE-TECH at $19.90/user/month.

***

## Use Case 6: \_\_ANY\_\_ Universal PBE Fallback

A PBE configured with `__ANY__` as its pricing attribute value matches any attribute value that does not have a dedicated PBE. This provides a catch-all price for attribute values you have not explicitly configured.

For example, if `Account.Type = "Reseller"` and there is no PBE specifically for "Reseller", the engine falls back to PBE-ANY (with `__ANY__`) at $27.50/user/month.

```javascript
const quoteData = {
  opportunityId: "006xx000004jkl012",
  name: "ANY Fallback Quote",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    { productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10 }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const line = result.quoteLineItems[0];
  console.log(`Resolved unit price: $${line.listUnitPrice}`);  // $27.50 (__ANY__ PBE)
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000004jkl012",
    "name": "ANY Fallback Quote",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      { "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
    ]
  }'
```

The Account's `Type` is "Reseller", which has no dedicated PBE. The engine matches the `__ANY__` PBE at $27.50 instead of falling through to the no-attribute default at $29.90.

***

## Use Case 7: No Matching PBE (Error Scenario)

If the pricing engine cannot find any PBE that matches the resolved attributes -- no specific match, no `__ANY__` fallback, and no default PBE -- it returns an error.

```javascript
const quoteData = {
  opportunityId: "006xx000001abc123",
  name: "No Matching PBE",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    {
      productSku: "LIMITED_PRODUCT",
      uom: "User/Month",
      quantity: 10,
      customPricingAttributes: [
        { name: "Ruby__PricingAttribute_1__c", value: "Nonexistent Tier" }
      ]
    }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  if (result.errorDetails) {
    result.errorDetails.forEach(err => {
      console.log(`Error: ${err.errorCode} -- ${err.message}`);
      // PRICEBOOK_ENTRY_MISMATCH -- No matching PBE for the given attributes
    });
  }
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "No Matching PBE",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      {
        "productSku": "LIMITED_PRODUCT",
        "uom": "User/Month",
        "quantity": 10,
        "customPricingAttributes": [
          { "name": "Ruby__PricingAttribute_1__c", "value": "Nonexistent Tier" }
        ]
      }
    ]
  }'
```

**Expected error:**

```json
{
  "status": 400,
  "error": "Failed to create quote",
  "message": "No matching Price Book Entry found for product LIMITED_PRODUCT with the given pricing attributes"
}
```

The response contains a `PRICEBOOK_ENTRY_MISMATCH` error indicating that no PBE could be resolved for the given product, UOM, and attribute combination.

***

## Use Case 8: Multi-Field Custom Attributes (AND Logic)

When a PBE requires multiple pricing attributes to match, provide all of them in the `customPricingAttributes` array. The engine uses AND logic -- all attributes must match for the PBE to be selected.

```javascript
const quoteData = {
  opportunityId: "006xx000001abc123",
  name: "Multi-Attribute AND Logic",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    {
      productSku: "NUE_ON_SALESFORCE",
      uom: "User/Month",
      quantity: 10,
      customPricingAttributes: [
        { name: "Ruby__PricingAttribute_1__c", value: "Technology Partner" },
        { name: "Ruby__PricingAttribute_2__c", value: "Enterprise" }
      ]
    }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  const line = result.quoteLineItems[0];
  console.log(`Resolved unit price: $${line.listUnitPrice}`);  // $14.90 (Tech + Enterprise PBE)
  console.log(`Total: $${line.totalPrice}`);
})
.catch(error => console.log('Error:', error));
```

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "Multi-Attribute AND Logic",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      {
        "productSku": "NUE_ON_SALESFORCE",
        "uom": "User/Month",
        "quantity": 10,
        "customPricingAttributes": [
          { "name": "Ruby__PricingAttribute_1__c", "value": "Technology Partner" },
          { "name": "Ruby__PricingAttribute_2__c", "value": "Enterprise" }
        ]
      }
    ]
  }'
```

Both attributes must match: `PricingAttribute_1 = "Technology Partner"` AND `PricingAttribute_2 = "Enterprise"`. This resolves to PBE-TECH-ENT at $14.90/user/month. If only one attribute matches, the engine does not select this PBE and falls back to the next best match.

## Key Behaviors

| Behavior                 | Description                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| **Auto-resolution**      | Pricing attributes are automatically read from the Account record on the Opportunity       |
| **Custom override**      | `customPricingAttributes` overrides auto-resolved values for the specific product          |
| **AND logic**            | Multiple pricing attributes on a PBE require all attributes to match                       |
| **\_\_ANY\_\_ fallback** | A PBE with `__ANY__` matches any attribute value without a dedicated PBE                   |
| **Default fallback**     | If no attribute-specific or `__ANY__` PBE exists, the default PBE (no constraints) is used |
| **Per-product scope**    | `customPricingAttributes` are set per product in the `products` array                      |
| **Bundle support**       | Each product in a bundle hierarchy resolves its own PBE independently                      |
| **Error on no match**    | If no PBE can be resolved, the API returns a `PRICEBOOK_ENTRY_MISMATCH` error              |

## CustomPricingAttribute Field Reference

| Field   | Type   | Required | Description                                                                                               |
| ------- | ------ | -------- | --------------------------------------------------------------------------------------------------------- |
| `name`  | string | Yes      | The API field name of the pricing attribute on the Price Book Entry (e.g., `Ruby__PricingAttribute_1__c`) |
| `value` | string | Yes      | The value to match against the PBE's pricing attribute field                                              |

## Troubleshooting

| Symptom                           | Likely Cause                                         | Resolution                                                                     |
| --------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------ |
| Unexpected price resolved         | Account.Type auto-resolution overriding expectations | Use `customPricingAttributes` to explicitly set the desired attribute value    |
| `PRICEBOOK_ENTRY_MISMATCH` error  | No PBE matches the resolved attributes               | Verify PBE configurations in the Price Book; add a `__ANY__` or default PBE    |
| Wrong PBE selected in bundle      | Add-on resolving against parent's attributes         | Each product resolves independently; check the add-on's own PBE configurations |
| `customPricingAttributes` ignored | Incorrect field `name`                               | Use the full API field name (e.g., `Ruby__PricingAttribute_1__c`), not a label |
