> This page is for Developer.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.bigcommerce.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.bigcommerce.com/_mcp/server.

# Get Product Variant

GET https://api.bigcommerce.com/stores/{store_hash}/v3/catalog/products/{product_id}/variants/{variant_id}

Returns a single product variant. Optional parameters can be passed in.

Reference: https://docs.bigcommerce.com/developer/api-reference/rest/admin/catalog/product-variants/get-product-variant

## Authentication

- `X-Auth-Token` header (required) — ### OAuth scopes | UI Name | Permission | Parameter | |:--------|:-----------|:----------| | Products | modify | `store_v2_products` | | Products | read-only | `store_v2_products_read_only` | ### Authentication header | Header | Argument | Description | |:-------|:---------|:------------| | `X-Auth-Token` | `access_token` | For more about API accounts that generate `access_token`s, see our [Guide to API Accounts](/developer/docs/overview/api-fundamentals/api-accounts#api-accounts). | ### Further reading For example requests and more information about authenticating BigCommerce APIs, see [Authentication and Example Requests](/developer/docs/overview/api-fundamentals/api-accounts#x-auth-token-header-example-requests). For more about BigCommerce OAuth scopes, see our [Guide to API Accounts](/developer/docs/overview/api-fundamentals/api-accounts#oauth-scopes). For a list of API status codes, see [API Status Codes](/developer/api-reference/rest/overview#rest-http-status-codes).

## Request

### Path parameters

- `product_id` (integer, required) — The ID of the `Product` to which the resource belongs. Product variant metafield endpoints that have the `product_id` in the request path are successful as long as the parameter is not empty. The `product_id` segment is there only for path consistency.
- `variant_id` (integer, required) — ID of the variant on a product, or on an associated Price List Record.
- `store_hash` (string, required) — Permanent ID of the BigCommerce store.

### Query parameters

- `include_fields` (list of string, optional) — Fields to include, in a comma-separated list. The ID and the specified fields will be returned.
- `exclude_fields` (list of string, optional) — Fields to exclude, in a comma-separated list. The specified fields will be excluded from a response. The ID cannot be excluded.

### Headers

- `Accept` (string, required, default: application/json) — The [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) of the response body.

## Response

### 200

OK

- `data` (productVariant_Full, optional)
- `meta` (metaEmpty_Full, optional) — Response metadata.

## Errors

### 404 Not Found Error

The resource was not found.

- `status` (integer, optional) — 404 HTTP status code.
- `title` (string, optional) — The error title describing the particular error.
- `type` (string, optional)
- `instance` (string, optional)

## Types

### productVariant_Full

- `bin_picking_number` (string, optional, nullable) — Identifies where in a warehouse the variant is located.
- `calculated_price` (double, optional) — The price of the variant as seen on the storefront. This price takes into account `sale_price` and any price adjustment rules that are applicable to this variant.
- `calculated_weight` (double, optional)
- `cost_price` (double, optional, nullable) — The cost price of the variant. It is not affected by Price List prices. This value displays as null in the control panel when `cost_price` equals zero.
- `depth` (double, optional, nullable) — Depth of the variant, which can be used when calculating shipping costs. If this value is `null`, the productʼs default depth (set in the Product resourceʼs `depth` field) will be used as the base depth.
- `fixed_cost_shipping_price` (double, optional, nullable) — A fixed shipping cost for the variant. If defined, this value will be used during checkout instead of normal shipping-cost calculation.
- `gtin` (string, optional, nullable)
- `height` (double, optional, nullable) — Height of the variant, which can be used when calculating shipping costs. If this value is `null`, the productʼs default height (set in the Product resourceʼs `height` field) will be used as the base height.
- `id` (integer, optional)
- `image_url` (string, optional) — Publicly available image url
- `inventory_level` (integer, optional, nullable) — Inventory level for the variant, which is used when the product’s inventory_tracking is set to `variant`. The Catalog API returns the inventory for only the default location. The inventory for a variant cannot exceed 2,147,483,647 in the catalog. The sum of the variant inventories, or the total inventory for a product, cannot exceed 2,147,483,647. If you exceed the limit, the store sets the variant inventory to the limit if no other variant inventories are set. If other variant inventories are set, the store does not save the variant inventory rather than setting the variant inventory to the remaining limit. The Catalog API handles limits in a different way than the Inventory API. For more information, see [Limit handling](/developer/docs/admin/catalog-and-inventory/inventory-adjustments#limit-handling-in-inventory-versus-catalog-api).
- `inventory_warning_level` (integer, optional, nullable) — When the variant hits this inventory level, it is considered low stock.
- `is_free_shipping` (boolean, optional) — Flag used to indicate whether the variant has free shipping. If `true`, the shipping cost for the variant will be zero.
- `mpn` (string, optional, nullable) — The Manufacturer Part Number (MPN) for the variant.
- `option_values` (list of productVariantOptionValue_Full, optional) — Array of option and option values IDs that make up this variant. Will be empty if the variant is the productʼs base variant.
- `price` (double, optional, nullable) — This variant’s base price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is `null`, the product’s default price (set in the Product resource’s `price` field) will be used as the base price.
- `product_id` (integer, optional)
- `purchasing_disabled` (boolean, optional) — If `true`, this variant will not be purchasable on the storefront.
- `purchasing_disabled_message` (string, optional) — If `purchasing_disabled` is `true`, this message should show on the storefront when the variant is selected.
- `retail_price` (double, optional, nullable) — This variant’s retail price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product’s retail price (set in the Product resource’s `price` field) will be used as the retail price.
- `sale_price` (double, optional, nullable) — This variant’s sale price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product’s sale price (set in the Product resource’s `price` field) will be used as the sale price.
- `sku` (string, optional)
- `sku_id` (integer, optional, nullable) — Read-only reference to v2 APIʼs SKU ID. Null if it is a base variant.
- `upc` (string, optional, nullable) — The UPC code used in feeds for shopping comparison sites and external channel integrations.
- `weight` (double, optional, nullable) — This variant’s base weight on the storefront. If this value is null, the product’s default weight (set in the Product resource’s weight field) will be used as the base weight.
- `width` (double, optional, nullable) — Width of the variant, which can be used when calculating shipping costs. If this value is `null`, the productʼs default width (set in the Product resourceʼs `width` field) will be used as the base width.

### metaEmpty_Full

Response metadata.

### productVariantOptionValue_Full

- `id` (integer, optional) — `option_value` ID.
- `label` (string, optional) — The label of the option value.
- `option_display_name` (string, optional) — The name of the option.
- `option_id` (integer, optional) — `option` ID.

## Examples

**Response**

```json
{
  "data": {
    "bin_picking_number": "",
    "calculated_price": 25,
    "calculated_weight": 1,
    "cost_price": 25,
    "depth": 5,
    "fixed_cost_shipping_price": 10,
    "gtin": "",
    "height": 5,
    "id": 384,
    "image_url": "",
    "inventory_level": 0,
    "inventory_warning_level": 0,
    "is_free_shipping": false,
    "mpn": "",
    "option_values": [
      {
        "id": 176,
        "label": "Black",
        "option_display_name": "Color",
        "option_id": 220
      }
    ],
    "price": 25,
    "product_id": 192,
    "purchasing_disabled": false,
    "purchasing_disabled_message": "",
    "retail_price": 25,
    "sale_price": 20,
    "sku": "SMIT-2",
    "sku_id": 350,
    "upc": "",
    "weight": 2,
    "width": 5,
    "map_price": {}
  },
  "meta": {}
}
```

**SDK Code**

```python Response
import requests

url = "https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1"

headers = {
    "Accept": "application/json",
    "X-Auth-Token": "<apiKey>"
}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript Response
const url = 'https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1';
const options = {
  method: 'GET',
  headers: {Accept: 'application/json', 'X-Auth-Token': '<apiKey>'}
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Response
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Accept", "application/json")
	req.Header.Add("X-Auth-Token", "<apiKey>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Response
require 'uri'
require 'net/http'

url = URI("https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Accept"] = 'application/json'
request["X-Auth-Token"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

```java Response
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1")
  .header("Accept", "application/json")
  .header("X-Auth-Token", "<apiKey>")
  .asString();
```

```php Response
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1', [
  'headers' => [
    'Accept' => 'application/json',
    'X-Auth-Token' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp Response
using RestSharp;

var client = new RestClient("https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1");
var request = new RestRequest(Method.GET);
request.AddHeader("Accept", "application/json");
request.AddHeader("X-Auth-Token", "<apiKey>");
IRestResponse response = client.Execute(request);
```

```swift Response
import Foundation

let headers = [
  "Accept": "application/json",
  "X-Auth-Token": "<apiKey>"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.bigcommerce.com/stores/store_hash/v3/catalog/products/1/variants/1")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```