Overview
Introduction to the Emfas REST API
The Emfas API allows you to programmatically manage your product catalog. Use it to sync products from external systems, build custom integrations, or automate your product data workflows.
Base URL
All API requests are made to:
https://api.emfas.ai/v1Request Format
The API accepts JSON request bodies for POST, PATCH, and PUT requests. Set the Content-Type header accordingly:
Content-Type: application/jsonResponse Format
All responses return JSON. A successful response typically contains the requested data:
{
"result": [
{
"identifier": "PROD-001",
"name": "Example Product",
"attributes": {}
}
]
}HTTP Methods
| Method | Usage |
|---|---|
GET | Retrieve resources |
POST | Create new resources |
PATCH | Update existing resources |
DELETE | Remove resources |
Getting Started
To start using the API:
- Enable API access — Contact the Emfas team if API access isn't available for your organization
- Generate an API key — Go to Settings in your Emfas workspace to create an API key
- Make your first request — Try listing your products to verify everything works
curl "https://api.emfas.ai/v1/products" \
-H "Authorization: Bearer YOUR_API_KEY"Core Concepts
If you're new to Emfas, these concepts from our documentation are helpful for understanding the API:
- Products — The main entities in your catalog
- Variants — Product variations (size, color, etc.)
- SKUs — Stock-keeping units, the sellable items
- Attributes — Custom fields that hold your product data
- Categories — Hierarchical organization of products
Product Hierarchy
Emfas uses a flexible product hierarchy with up to three levels:
- Product → Variant → SKU
Not all levels are required — some organizations use all three, some use only product + variant, and some use only products.
Fetching Related Resources
To avoid N+1 requests when you need products together with their variants or SKUs, use the include parameter:
| Request | What you get |
|---|---|
GET /products?include=variants | Each product embeds its variants |
GET /products?include=variants,skus | Each product embeds its variants, each variant embeds its SKUs |
GET /variants?include=skus | Each variant embeds its SKUs |
curl "https://api.emfas.ai/v1/products?include=variants,skus" \
-H "Authorization: Bearer YOUR_API_KEY"Attribute scope: Embedded children carry only their own attributes. The parent's attributes already sit at the top level of the parent object and are not repeated. This differs from the top-level /variants endpoint, where the parent product's attributes are merged into the variant's attributes map.
include=skus alone on /products returns a 400 error — SKUs nest under variants, so use include=variants,skus to reach them.
Sideloading Referenced Metaobjects
Metaobject-typed attributes return only the referenced metaobject's identifier (for example "nike"), so resolving their field values would otherwise mean one extra request per metaobject. Add metaobjects to include to have every referenced metaobject resolved in the same response, under a top-level included array. It is available on /products, /variants, and /skus, for both single and list requests, and combines freely with the other include values.
| Request | What you get |
|---|---|
GET /products/PROD-001?include=metaobjects | The product, plus every metaobject it references under included |
GET /products?include=metaobjects | A page of products, plus all metaobjects they reference (deduplicated across the page) under included |
GET /products?include=variants,skus,metaobjects | Products with embedded variants and SKUs, plus metaobjects referenced anywhere in the returned hierarchy |
curl "https://api.emfas.ai/v1/products/PROD-001?include=metaobjects" \
-H "Authorization: Bearer YOUR_API_KEY"Each entry in included is addressable by the definition + identifier pair — metaobject identifiers are only unique within their definition. Match an attribute to its entry using the metaobjectDefinition and data (the identifier) the attribute already carries:
{
"result": {
"identifier": "PROD-001",
"attributes": {
"product.brand": [
{ "value": "nike", "data": "nike", "type": "metaobject", "metaobjectDefinition": "brand" }
]
}
},
"included": [
{
"type": "metaobject",
"definition": "brand",
"identifier": "nike",
"name": "Nike",
"attributes": {
"brand.tagline": [
{ "locale": "en", "value": "Just Do It", "data": "Just Do It", "type": "text" },
{ "locale": "sv", "value": "Bara gör det", "data": "Bara gör det", "type": "text" }
]
}
}
]
}The included array is present only when include=metaobjects is requested; it is [] when nothing is referenced. Each metaobject's attributes carry all locales, just like the dedicated metaobject endpoints. Resolution is one level deep — if a sideloaded metaobject's own attributes reference further metaobjects, those remain identifiers.
Hierarchy-Aware Change Tracking
Every response carries two timestamps:
updatedAt— the last time anything affecting this entity's response changed, including parents and descendants. This is what the?updated_afterquery parameter and the_updated_atsystem filter match against.selfUpdatedAt— the last time this entity itself was changed, ignoring parents and descendants.
?updated_after filters by the hierarchy timestamp on every endpoint, so each level catches relevant changes across the full subtree:
| Endpoint | Catches changes on |
|---|---|
/products?updated_after=X | Product, its variants, its SKUs |
/variants?updated_after=X | Variant, its parent product, its SKUs |
/skus?updated_after=X | SKU, its parent variant, its parent product |
To distinguish "this entity itself changed" from "something in the subtree changed" without webhooks, compare updatedAt against selfUpdatedAt: when they differ, the change came from elsewhere in the hierarchy. See Incremental Sync for more details.
Attributes in Responses
The API only returns attributes that have values. If an attribute has not been set, it will not appear in the response.
To see all available attributes in your workspace, use GET /v1/attributes. Attributes will appear in product, variant, and SKU responses once values have been set.
Filtering Lists
List endpoints accept a search query parameter for filtering results by attribute values. The same JSON shape works across /products, /variants, and /skus. See Filtering for the full reference.
Need Help?
For questions about the API or your integration, contact us at integrations@emfas.ai.