Product Data SDKC# - Product Data SDK

C# - Product Data SDK

Install, authenticate, and make your first product searches with the Datafiniti Product Data SDK for C#.

Get started with the C# SDK

You can use the Datafiniti Product Data SDK for C# to authenticate with the Product Data API and run common product searches, including name lookup, brand and category filtering, price-range queries, counting, and pagination.

The SDK is available on NuGet at https://www.nuget.org/packages/Datafiniti.Sdk.

Target .NET 8.0 or later. The Product SDK lives in the Datafiniti.Product namespace and shares the core client, options, and error types in Datafiniti.Core.

Installation

Install the SDK

Add the Datafiniti SDK to your project with the .NET CLI.

dotnet add package Datafiniti.Sdk

After the command finishes, the package is restored into your project. The Product SDK is included in the unified Datafiniti.Sdk package alongside the Business, People, and Property SDKs.

Authentication

Configure your API key

Authenticate by setting the DATAFINITI_API_KEY environment variable or by passing your API key directly through DatafinitiClientOptions when you create the client.

export DATAFINITI_API_KEY="YOUR_API_KEY"

If you use the environment variable approach, initialize the client with ProductClient.FromEnvironment(). The SDK reads DATAFINITI_API_KEY and throws if it is not set.

Features

Search by name

Look up product records by name using SearchByNameAsync. Use this to quickly retrieve product details without writing raw API queries.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

// Search by name — pass the product name as a single string
SearchResult results = await client.SearchByNameAsync("Nike Air Max", numRecords: 10);

Console.WriteLine("
=== NAME SEARCH TEST ===");
Console.WriteLine($"Matches: {results.NumFound}");

var records = results.Records;

if (records.Count > 0)
{
    var product = records[0];
    Console.WriteLine("
Product:");
    Console.WriteLine(product.GetProperty("name").GetString());
    Console.WriteLine(product.GetProperty("brand").GetString());
}
else
{
    Console.WriteLine("No product found.");
}

Code breakdown

SectionWhat it does
using Datafiniti.Product;Imports the ProductClient and ProductQuery types from the Datafiniti.Product namespace.
ProductClient.FromEnvironment()Creates a client instance using the DATAFINITI_API_KEY environment variable.
client.SearchByNameAsync("Nike Air Max", numRecords: 10)Queries the Product Data API for records matching the given name. Returns a Task<SearchResult>.
results.NumFoundReturns the total number of products that matched the query.
results.RecordsAn IReadOnlyList<JsonElement> of matching product records.
records[0]Accesses the first (best-match) product record from the results.
product.GetProperty("name").GetString()Reads an individual field from the record's JsonElement.

SearchByNameAsync abstracts away the raw query syntax and accepts the name as a single string, with an optional numRecords to limit results. Records are returned as System.Text.Json.JsonElement, so read fields with GetProperty(...).

Count

Get the total number of products matching a query without downloading any records. Use this to check result sizes before running larger searches or to build dashboards with aggregate counts.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

long count = await client.CountAsync("brand:"Nike" AND categories:"Shoes"");

Console.WriteLine("
=== COUNT TEST ===");
Console.WriteLine($"Products found: {count:N0}");

Code breakdown

SectionWhat it does
using Datafiniti.Product;Imports the ProductClient type from the Datafiniti.Product namespace.
ProductClient.FromEnvironment()Creates a client instance using the DATAFINITI_API_KEY environment variable.
client.CountAsync("brand:\"Nike\" AND categories:\"Shoes\"")Returns the total number of Nike shoe products without fetching full records. Returns a Task<long>.
$"Products found: {count:N0}"Formats the count with thousands separators for readability (e.g., 1,234,567).

CountAsync accepts the same query syntax as SearchAsync but only returns the total number of matching records — no data is downloaded.

Understanding the query syntax

The query string brand:"Nike" AND categories:"Shoes" uses Datafiniti's query language. Here's what you need to know:

QuestionAnswer
What is the format?See the Constructing Product Queries guide for the complete field reference, operators, and advanced examples.
How do I handle multi-word string values?Wrap them in exact quotes: brand:"Nike". In C# string literals, escape the quotes ("brand:\"Nike\"") or use a verbatim/raw string literal.
What fields can I query & what is the full list of field names?Any field in the Product Data Schemaname, brand, categories, upc, prices, and many more.

Build a query

Compose a query using the fluent ProductQuery builder. Chain field methods — such as brand, categories, UPC, or price range — and call .Build() to produce a Datafiniti query string.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

// Build a query — chain field methods, then Build()
string query = client.Query()
    .Brand("Nike")
    .Categories(new[] { "Shoes", "Running" })
    .PriceRange(minPrice: 50m, maxPrice: 200m)
    .Build();

SearchResult results = await client.SearchAsync(query, numRecords: 10);

Console.WriteLine("
=== QUERY BUILDER TEST ===");
Console.WriteLine($"Total matches: {results.NumFound:N0}");

foreach (var product in results.Records)
{
    Console.WriteLine(
        $"{product.GetProperty("brand").GetString()} — " +
        $"{product.GetProperty("name").GetString()}");
}

Code breakdown

SectionWhat it does
using Datafiniti.Product;Imports the ProductClient and ProductQuery types from the Datafiniti.Product namespace.
ProductClient.FromEnvironment()Creates a client instance using the DATAFINITI_API_KEY environment variable.
client.Query()Returns a fluent ProductQuery builder for composing a query without raw syntax.
.Brand("Nike")Filters to products of a given brand.
.Categories(new[] { "Shoes", "Running" })Filters by one or more product categories.
.PriceRange(minPrice: 50m, maxPrice: 200m)Restricts results to a price range. Both bounds are decimal?, so either can be omitted.
.Build()Produces the final Datafiniti query string from the chained fields.
client.SearchAsync(query, numRecords: 10)Executes the search and returns up to numRecords matching records.

ProductQuery is a fluent builder exposing fields relevant to the Product data type: Brand, Name, Categories, Upc, and PriceRange. Each method returns the builder so calls chain, and .Build() produces a Datafiniti query string you can pass to SearchAsync, CountAsync, or PaginateAsync. For fields the builder does not expose, use .Raw(...) or pass a raw query string directly.

Search by UPC

Look up a product directly by its UPC using the builder or a raw query string.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

string query = client.Query().Upc("085239047880").Build();

SearchResult results = await client.SearchAsync(query, numRecords: 1);

Console.WriteLine("
=== UPC SEARCH ===");
foreach (var product in results.Records)
{
    Console.WriteLine($"{product.GetProperty("brand").GetString()} — {product.GetProperty("name").GetString()}");
}

Code breakdown

SectionWhat it does
using Datafiniti.Product;Imports the ProductClient type from the Datafiniti.Product namespace.
client.Query().Upc("085239047880").Build()Builds a query matching a single product by its UPC.
client.SearchAsync(query, numRecords: 1)Executes the search and returns the matching record.

A UPC uniquely identifies a product, so a UPC search typically returns a single record. Use numRecords: 1 unless you expect variant listings.

Paginate

Iterate through large result sets page by page without loading everything into memory at once. PaginateAsync returns an IAsyncEnumerable<JsonElement>, so you consume it with await foreach.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

Console.WriteLine("
=== PAGINATION TEST ===");

int recordsSeen = 0;

// Paginate through large result sets
await foreach (var product in client.PaginateAsync(
    query: "brand:"Nike" AND prices.amountMax:*",
    pageSize: 10))
{
    recordsSeen++;
    Console.WriteLine(
        $"{product.GetProperty("brand").GetString()} — " +
        $"{product.GetProperty("name").GetString()}");

    if (recordsSeen >= 50) break; // stop after 50 total records
}

Console.WriteLine($"
Total Retrieved: {recordsSeen}");

Code breakdown

SectionWhat it does
using Datafiniti.Product;Imports the ProductClient type from the Datafiniti.Product namespace.
ProductClient.FromEnvironment()Creates a client instance using the DATAFINITI_API_KEY environment variable.
client.PaginateAsync(query, pageSize)Returns an IAsyncEnumerable<JsonElement> that yields individual product records across multiple API pages.
query: "brand:\"Nike\" AND prices.amountMax:*"The search query — all Nike products that have a maximum price (* matches any value).
pageSize: 10Fetches 10 records per API request.
if (recordsSeen >= 50) break;Stops after retrieving 50 total records, even if more are available.
await foreach (var product in ...)Iterates through each yielded record one at a time without loading the full result set into memory.

PaginateAsync handles API pagination automatically behind the scenes and streams records as an async sequence. Break out of the await foreach to cap total retrieval, or let it run to iterate through all matching results.

Views

Control which fields are returned in API responses using a premade named view. Pass the view name through the view parameter of SearchAsync (and PaginateAsync) to reduce payload size, speed up requests, and tailor results. For a full list of available product data views, see Product Data Views.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

SearchResult results = await client.SearchAsync(
    query: "brand:"Nike" AND categories:"Shoes"",
    numRecords: 5,
    view: "default");

Console.WriteLine("
=== PRODUCT VIEWS ===");
Console.WriteLine($"Total matches: {results.NumFound:N0}
");

foreach (var product in results.Records)
{
    string name  = product.TryGetProperty("name", out var n) ? n.GetString() : "N/A";
    string brand = product.TryGetProperty("brand", out var b) ? b.GetString() : "N/A";
    Console.WriteLine($"{brand} — {name}");
}

Code breakdown

SectionWhat it does
using Datafiniti.Product;Imports the ProductClient type from the Datafiniti.Product namespace.
view: "default"The named view to apply. Replace with any named view listed in the Product Data Views reference.
client.SearchAsync(query, numRecords: 5, view: "default")Executes the search with the named view applied to the response.
product.TryGetProperty("name", out var n)Safely reads a field from the record's JsonElement, returning false if it is absent.

In the C# SDK the view parameter is a named-view string (for example "default"). Named views are convenient presets that control which fields appear in the response. See the Product Data Views reference for the full list of available views.

Example: Pricing analytics for pet food

Datafiniti provides a rich collection of pricing data across product categories. This example shows how to pull data for pricing intelligence in one specific category — pet food — using the C# SDK.

Accessing pricing data

Pricing data lives in each record's prices field, a complete log of all known prices for a product along with the timestamp and source of each price. To find all pricing data in the pet food category, filter on the taxonomy, category, and the presence of prices.

using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

string query = client.Query()
    .Raw("taxonomy:"pet supplies"")
    .Categories(new[] { "food" })
    .Raw("prices:*")
    .Build();
// taxonomy:"pet supplies" AND categories:("food") AND prices:*

SearchResult results = await client.SearchAsync(query, numRecords: 10);

Console.WriteLine("
=== PET FOOD PRICING ===");
Console.WriteLine($"Total matches: {results.NumFound:N0}
");

Each returned record has a prices array. A single entry looks like this:

{
  "amountMax": 11.99,
  "amountMin": 11.99,
  "currency": "USD",
  "dateSeen": ["2021-08-31T03:44:58.977Z", "2021-07-24T02:14:58.474Z"],
  "merchant": "Chewy.com",
  "shipping": "+$4.95 shipping",
  "sourceURLs": ["https://www.google.com/shopping/product/10099448883039819830"]
}

Each price object represents a single price amount seen by Datafiniti, along with all the dates and sources for when and where that price was seen. You can read the array from each record's JsonElement:

foreach (var product in results.Records)
{
    string name = product.TryGetProperty("name", out var n) ? n.GetString() : "N/A";
    Console.WriteLine($"Product: {name}");

    if (product.TryGetProperty("prices", out var prices) && prices.ValueKind == JsonValueKind.Array)
    {
        foreach (var price in prices.EnumerateArray())
        {
            decimal amountMax = price.TryGetProperty("amountMax", out var mx) ? mx.GetDecimal() : 0m;
            string currency = price.TryGetProperty("currency", out var c) ? c.GetString() : "";
            string merchant = price.TryGetProperty("merchant", out var m) ? m.GetString() : "unknown";
            Console.WriteLine($"  {amountMax} {currency} @ {merchant}");
        }
    }
}

Finding if the current product is on sale

The mostRecentPriceIsSale field is a Boolean indicating whether a product is currently listed as on sale. Add it to the query to return only pet food that is on sale.

string query = client.Query()
    .Raw("taxonomy:"pet supplies"")
    .Categories(new[] { "food" })
    .Raw("prices:*")
    .Raw("mostRecentPriceIsSale:*")
    .Build();
// taxonomy:"pet supplies" AND categories:("food") AND prices:* AND mostRecentPriceIsSale:*

SearchResult onSale = await client.SearchAsync(query, numRecords: 10);

mostRecentPriceIsSale

All "most recent" fields are data points as of the time of the API call and are subject to change over time. If you need frequent updates, build that polling into your own logic.

Generating pricing analytics

You can pull the same prices array for every product matching your query and run a wide variety of analysis on the collection — what factors drive price for a given product, what the price distribution looks like across a market segment, and so on. Use fields like categories, taxonomy, and brand to segment the data. The following pages a full result set with PaginateAsync and computes a simple average of each product's most recent amountMax.

using System.Text.Json;
using Datafiniti.Product;

var client = ProductClient.FromEnvironment();

string query = client.Query()
    .Raw("taxonomy:"pet supplies"")
    .Categories(new[] { "food" })
    .Raw("prices:*")
    .Build();

var prices = new List<decimal>();

await foreach (var product in client.PaginateAsync(query, pageSize: 100))
{
    if (product.TryGetProperty("prices", out var priceArray) &&
        priceArray.ValueKind == JsonValueKind.Array &&
        priceArray.GetArrayLength() > 0)
    {
        var first = priceArray[0];
        if (first.TryGetProperty("amountMax", out var mx))
            prices.Add(mx.GetDecimal());
    }

    if (prices.Count >= 500) break; // cap the sample
}

Console.WriteLine("
=== PET FOOD PRICING ANALYTICS ===");
Console.WriteLine($"Products sampled: {prices.Count}");
if (prices.Count > 0)
{
    Console.WriteLine($"Average price: {prices.Average():C}");
    Console.WriteLine($"Min price:     {prices.Min():C}");
    Console.WriteLine($"Max price:     {prices.Max():C}");
}

With the knowledge of how to pull records by category, taxonomy, and brand, you can generate pricing intelligence reports for specific segments of the pet food market.

Code Examples

Here are some C# examples built upon what we have just discussed. All snippets are ready to run as long as you have your DATAFINITI_API_KEY exported.

using Datafiniti.Product;
using Datafiniti.Core;

var client = ProductClient.FromEnvironment();

string query = client.Query()
    .Brand("Nike")
    .Categories(new[] { "Shoes" })
    .PriceRange(minPrice: 50m, maxPrice: 200m)
    .Build();

try
{
    SearchResult response = await client.SearchAsync(query, numRecords: 10);

    Console.WriteLine("
=== PRODUCT SEARCH ===");
    Console.WriteLine($"Total matches: {response.NumFound:N0}
");

    foreach (var product in response.Records)
    {
        string Get(string field) =>
            product.TryGetProperty(field, out var v) ? v.ToString() : "N/A";

        Console.WriteLine($"Brand: {Get("brand")}");
        Console.WriteLine($"Name:  {Get("name")}");
        Console.WriteLine($"UPC:   {Get("upc")}
");
    }
}
catch (DatafinitiApiException e)
{
    Console.WriteLine($"
API Error {e.StatusCode}: {e.Message}");
    Console.WriteLine(e.ResponseBody);
}