UCP Output
Standardize your procurement and agent pipelines. Native Universal Commerce Protocol (UCP) JSON output.
Design Principle: One schema, any merchant. Every response follows the same structure regardless of the source site. Write one parser, use it everywhere.
What is UCP?
The Universal Commerce Protocol (UCP) defines a strict, unified schema for commerce data. ShopGraph extracts product data across any target URL and normalizes it into UCP line_item format. One schema, regardless of the merchant's architecture. No custom mappers per supplier.
Using UCP Output
Add format=ucp to any extraction request:
{
"url": "https://www.allbirds.com/products/mens-tree-runners",
"format": "ucp"
}
UCP Line Item Output
Interface
interface UcpLineItem {
id: string; // Stable identifier (shopgraph::domain::slug)
name: string; // Product name
description: string | null; // Product description
unit_price: {
amount: number; // Price in smallest currency unit (cents)
currency: string; // ISO 4217 currency code
} | null;
quantity: number; // Always 1 for single product extraction
sku: string | null; // Product SKU
brand: string | null; // Brand name
category: string | null; // Product category
image_url: string | null; // Primary image URL
product_url: string; // Canonical product URL
availability: string | null; // in_stock, out_of_stock, pre_order
_extensions: {
shopgraph: {
extraction_method: string;
confidence_score: number;
field_confidence: Record;
};
b2b?: { // Present for B2B products
moq: number | null;
lead_time: string | null;
bulk_pricing: BulkTier[];
manufacturer_part_number: string | null;
};
};
}
Response
{
"line_item": {
"id": "shopgraph::allbirds::mens-tree-runners",
"name": "Men's Tree Runners",
"description": "Lightweight, breathable sneakers...",
"unit_price": {
"amount": 9800,
"currency": "USD"
},
"quantity": 1,
"sku": "TR-M-001",
"brand": "Allbirds",
"category": "Footwear > Sneakers",
"image_url": "https://cdn.allbirds.com/image/fetch/...",
"product_url": "https://www.allbirds.com/products/mens-tree-runners",
"availability": "in_stock",
"_extensions": {
"shopgraph": {
"extraction_method": "schema_org",
"confidence_score": 0.93,
"access_routing": {
"cdn_gate_detected": "cloudflare_turnstile",
"auth_method": "rfc_9421_signature",
"access_readiness_score": 0
},
"field_confidence": {
"name": 0.98,
"unit_price": 0.97,
"brand": 0.94,
"availability": 0.91
}
}
}
},
"_extraction_status": "complete"
}
Note: The access_routing block appears in responses when the access_readiness dimension is active. This dimension is currently at weight 0.00 and activates when Web Bot Auth adoption reaches detection threshold. All other fields are live today.
Key Differences from Standard Output
| Standard Field | UCP Field | Notes |
|---|---|---|
product.title | line_item.name | Direct mapping |
product.price | line_item.unit_price.amount | Converted to cents (integer) |
product.currency | line_item.unit_price.currency | ISO 4217 |
_shopgraph.* | _extensions.shopgraph.* | Metadata in UCP extensions |
_shopgraph.access_routing | _extensions.shopgraph.access_routing | Access routing metadata |
Field Mapping
Every field from the standard ProductData response maps to a UcpLineItem field:
| ProductData | UcpLineItem | Transformation |
|---|---|---|
title | name | Direct |
price | unit_price.amount | Multiplied by 100 (dollars to cents) |
currency | unit_price.currency | Direct |
description | description | Direct |
sku | sku | Direct |
brand | brand | Direct |
category | category | Direct |
image | image_url | Direct |
url | product_url | Direct |
availability | availability | Normalized to lowercase with underscores |
moq | _extensions.b2b.moq | Moved to B2B extension |
lead_time | _extensions.b2b.lead_time | Moved to B2B extension |
bulk_pricing | _extensions.b2b.bulk_pricing | Moved to B2B extension |
mpn | _extensions.b2b.manufacturer_part_number | Moved to B2B extension |
B2B Extensions
When B2B fields are detected (MOQ, lead time, bulk pricing, MPN), they are placed in the _extensions.b2b namespace:
{
"_extensions": {
"shopgraph": {
"extraction_method": "hybrid",
"confidence_score": 0.85
},
"b2b": {
"moq": 10,
"lead_time": "3-5 business days",
"bulk_pricing": [
{ "min_quantity": 10, "price": 135.00 },
{ "min_quantity": 50, "price": 128.50 },
{ "min_quantity": 100, "price": 122.00 }
],
"manufacturer_part_number": "4M206"
}
}
}
Extraction Status
When extraction is partial, the _extraction_status field indicates quality:
| Status | Meaning |
|---|---|
complete | All core fields extracted successfully |
partial | Some fields missing or below confidence threshold |
minimal | Only name and URL available |
failed | Extraction failed entirely |
Note: If you apply a strict_confidence_threshold to a request, fields falling below that threshold are omitted from the line_item, and the _extraction_status will downgrade to partial. For agent routing workflows, we recommend omitting the threshold and evaluating the field_confidence block directly.
Example: Catalog Ingestion
A nightly pipeline processes supplier URLs across Shopify, Uline, and McMaster-Carr. Each response comes back as a UCP line_item. The pipeline writes one parser regardless of the merchant's native data format.
const result = await fetch('https://shopgraph.dev/api/enrich', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sg_live_your_key'
},
body: JSON.stringify({
url: supplierUrl,
format: 'ucp',
strict_confidence_threshold: 0.85
})
});
const data = await result.json();
await catalog.upsert(data.line_item); // Same shape for every merchant
UCP output combined with threshold filtering. One integration path for any supplier URL.