Assets
An asset is the catalog's record of a piece of media. The bytes live in Storage; the asset row says what the file is, which class of media it belongs to, and which product attribute may reference it.
| Entity | Base path |
|---|---|
asset_families | /v1/products/asset_families |
assets | /v1/products/assets |
Asset families
A family is a class of media with one shared shape — packshots, datasheets, installation videos.
{
"code": "packshots",
"labels": { "en": "Packshots", "de": "Packshots" },
"naming_convention": {
"source": "sku",
"pattern": "{sku}_{index}",
"allowed_extensions": ["jpg", "png", "webp"]
}
}
naming_convention is how a file of this family is named, so a bulk import can bind a file to a product without a mapping table: source is the product value the name is built from, pattern how it is assembled, allowed_extensions what may be uploaded.
Like a reference entity, an asset family carries its own attributes — declare them with entity_type: "asset" and entity_ref: "<family code>".
Assets
{
"asset_family_id": "…",
"code": "ACME-4711-BLK_1",
"source": "storage",
"storage_asset_id": "ast_01hxyz…",
"attribute_values": { "common": { "alt_text": "Cordless drill, front" } }
}
{
"asset_family_id": "…",
"code": "ACME-4711-BLK_video",
"source": "external",
"external_url": "https://cdn.example.com/acme/4711/assembly.mp4"
}
| Field | Meaning |
|---|---|
code | Stable identifier within its family — the value a product's media attribute stores. |
asset_family_id | Which family. A create with none falls back to the tenant's default_asset_family setting. |
source | Where the bytes live: storage (this platform's object store) or external (somebody else's host). |
storage_asset_id | The stable ast_… id of the storage object. Required when source is storage. |
external_url | Absolute URL. Required when source is external. |
delivery_path | The path the CDN serves the asset under. |
attribute_values | The asset's own modelled values, same four buckets as a product. |
The database enforces the pair, so neither half of a source/identifier combination can be stored on its own.
Two rules worth internalising
Never join on delivery_path. It is the convenient value for rendering and it changes when the file is moved. storage_asset_id survives a rename or a folder move, which is exactly why it and not the path is the identifier.
External URLs are gated, and only here. source: "external" is accepted only when the tenant has allow_external_media on and the host is on its external_media_allowed_hosts list. POST /v1/products/assets is the only place an external URL can enter the catalog, so it is the only place those checks exist.
Getting the bytes there
Uploading a file is a Storage operation, not a catalog one. Upload first, take the returned ast_… id, then create the asset row that points at it. See Storage for the upload paths and Import and export for the bulk version.
Where a product references it
A media or media-collection attribute stores the asset code:
{ "common": { "images": ["ACME-4711-BLK_1", "ACME-4711-BLK_2"] } }
Which attribute carries the main image is a family setting — families.image_attribute, read by grid thumbnails and pickers. See Data model.
Where to go next
- Storage — where the bytes actually live.
- Data model — declaring the media attribute.
- Import and export — binding files to products in bulk.