emfasemfas

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/v1

Request Format

The API accepts JSON request bodies for POST, PATCH, and PUT requests. Set the Content-Type header accordingly:

Content-Type: application/json

Response Format

All responses return JSON. A successful response typically contains the requested data:

{
  "result": [
    {
      "identifier": "PROD-001",
      "name": "Example Product",
      "attributes": {}
    }
  ]
}

HTTP Methods

MethodUsage
GETRetrieve resources
POSTCreate new resources
PATCHUpdate existing resources
DELETERemove resources

Getting Started

To start using the API:

  1. Enable API access — Contact the Emfas team if API access isn't available for your organization
  2. Generate an API key — Go to Settings in your Emfas workspace to create an API key
  3. 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:

  • ProductVariantSKU

Not all levels are required — some organizations use all three, some use only product + variant, and some use only products.

To avoid N+1 requests when you need products together with their variants or SKUs, use the include parameter:

RequestWhat you get
GET /products?include=variantsEach product embeds its variants
GET /products?include=variants,skusEach product embeds its variants, each variant embeds its SKUs
GET /variants?include=skusEach 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.

RequestWhat you get
GET /products/PROD-001?include=metaobjectsThe product, plus every metaobject it references under included
GET /products?include=metaobjectsA page of products, plus all metaobjects they reference (deduplicated across the page) under included
GET /products?include=variants,skus,metaobjectsProducts 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_after query parameter and the _updated_at system 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:

EndpointCatches changes on
/products?updated_after=XProduct, its variants, its SKUs
/variants?updated_after=XVariant, its parent product, its SKUs
/skus?updated_after=XSKU, 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.