Contextual Enrichment Engine
How Rezolve Ai derives contextual rules from your catalog and grounds every piece of generated content in them.
The Contextual Enrichment Engine (CEE) is what separates Rezolve Ai from a prompt wrapper. Instead of generating each product description in isolation, it first reads a product set and derives contextual rules, then generates every piece of content against those rules. The result is output that stays consistent in tone, claims, and vocabulary across a whole catalog.
The eight sections
A rules generation pass produces eight sections:
| Section | What it captures |
|---|---|
| Consumer criteria | What a shopper in this category actually compares on |
| Product context | Where these products sit in the market and against each other |
| Use cases | The jobs the products get bought to do |
| Purchase occasions | When and why someone buys, including seasonality and gifting |
| Key entities | Brands, materials, standards, and terms worth naming |
| Target questions | The questions shoppers and AI assistants ask about this category |
| Differentiators | What genuinely distinguishes these products |
| Objections | The hesitations that stop a purchase, so content can answer them |
These rules are the grounding layer. Pass them into a content request and the generated copy will answer real objections and use your category's vocabulary rather than generic filler.
Three endpoints
The engine is exposed as three endpoints, and as MCP tools and SDK methods that call them.
1. Generate rules
POST /api/v1/enrichment/rules derives the eight sections from a product set. A sample of up to 5 products is answered inline. A larger one returns a job, unless you send "mode": "sync" to wait for the result.
curl -X POST https://ace.authoritas.com/api/v1/enrichment/rules \
-H "Authorization: Bearer $ACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": {
"type": "inline",
"products": [
{ "id": "sku-1", "title": "Merino base layer", "category": "Outdoor", "brand": "Fjell" },
{ "id": "sku-2", "title": "Merino hiking sock", "category": "Outdoor", "brand": "Fjell" }
]
},
"creativityLevel": 3
}'Give it a representative sample of a category rather than one product: the rules describe the category, so a broader sample produces sharper output. creativityLevel runs from 1 (conservative, sticks close to the source data) to 5 (bold).
The response's data.rules object holds the rules, keyed by product category. That object is what you pass to the content endpoint. Next to it, data.source says where the rules came from: ai, cache, or fallback. Treat fallback as a failed generation: those are generic rules, returned because the engine could not write real ones.
2. Generate grounded content
POST /api/v1/enrichment/content generates the content types you ask for, per product, grounded in rules.
curl -X POST https://ace.authoritas.com/api/v1/enrichment/content \
-H "Authorization: Bearer $ACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": { "type": "inline", "products": [{ "id": "sku-1", "title": "Merino base layer" }] },
"contentTypes": ["product-description", "meta-tags", "jsonld-schema"],
"rules": { "...": "data.rules from the /enrichment/rules response" }
}'This endpoint does not derive rules for you. Omit rules and the content is written from the product data alone. Supply them when you are enriching many batches in the same category, so every batch is grounded identically, or use the pipeline to have them derived as part of the run.
3. Run the whole thing
POST /api/v1/enrichment/pipeline does both steps in one call: derive rules, then generate content for every product against them.
curl -X POST https://ace.authoritas.com/api/v1/enrichment/pipeline \
-H "Authorization: Bearer $ACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": { "type": "inline", "products": [ /* ... */ ] },
"contentTypes": ["product-description", "meta-tags"],
"targetLanguage": "de-DE"
}'This is the right entry point for a first run and for scheduled catalog refreshes. Leave contentTypes out and the pipeline writes product-description, meta-tags, jsonld-schema, and irl-scenarios.
Where products come from
Every endpoint takes the same source:
// Inline: you supply the products.
{ "type": "inline", "products": [{ "id": "sku-1", "title": "..." }] }
// Store: Rezolve Ai reads them from a connected Shopify or WooCommerce store,
// and can write the results back.
{ "type": "store", "storeId": "...", "productIds": ["..."], "writeBack": true }A product needs only id and title. Everything else you pass through (brand, price, tags, images, attributes) becomes grounding signal, so send what you have.
Look products up first
Content is written only from the product data you send. When that data is thin and the product has a barcode, add "lookup": true to a content or pipeline request. Each product is then looked up by its gtin, isbn, asin, mpn with brand, or url, and what a published source states about that exact product is used alongside your own data.
{
"source": { "type": "inline", "products": [{ "id": "sku-1", "title": "Fineliner pen, azure", "gtin": "4006381333931" }] },
"contentTypes": ["product-description"],
"lookup": true
}Your data wins where the two disagree, and a product that cannot be matched surely is written exactly as before. true uses free sources only. Name web_search in lookup.sources to also search the web, which is charged. See Product lookup for the options and what each result reports.
Sync or async
pipeline always runs as a job and answers 202 with a job envelope.
rules and content decide from the size of the request. rules answers inline for up to 5 products. content answers inline for up to 5 products and up to 10 units (products multiplied by content types). Anything larger returns 202 with a job envelope, and so does any request with a store source. On these two endpoints you can force it either way with "mode": "async" or "mode": "sync".
For a job, poll GET /api/v1/jobs/{id} and page the output from GET /api/v1/jobs/{id}/results, or subscribe to webhooks and skip polling. Send an Idempotency-Key header so a retry resumes the original job instead of starting a second one.
Content types
| Content type | API value |
|---|---|
| Product description | product-description |
| Meta tags and SEO | meta-tags |
| Enhanced JSON-LD schema | jsonld-schema |
| IRL scenario cards | irl-scenarios |
| Internal linking recommendations | internal-links |
| Product title | product-title |
| Highlights and bullet points | highlights |
| Product Q&A | product-qa |
| Product attributes | product-attributes |
| Image alt text | image-alt |
| Google Shopping feed fields | google-shopping |
| Agentic Commerce feed fields | agentic-commerce |
| Microsoft Shopping feed fields | microsoft-shopping |
| Shopify feed fields | shopify |
| WooCommerce feed fields | woocommerce |
A value that is not in this table is skipped rather than rejected, and is listed in skippedContentTypes (on a synchronous response, or on the job's result) so you can see it was not generated or charged. image-alt needs at least one product image with a public URL.
Cost
Rules generation is free. Content is metered on the AI work done for each product and content type, so the cost of a run follows how many content types you ask for. Test keys draw on the free monthly quota instead of credits, at one unit per product per content type, so ten products with three content types uses thirty units. See Credits and usage.
From an AI assistant
The same engine is available over MCP, so an assistant in Cursor, VS Code, or Claude can drive it directly:
generate_contextual_rulesenrich_contentrun_enrichment_pipelineget_enrichment_job,list_jobs,get_job_results,cancel_job
See MCP Server for setup.
Next steps
- Generating content at scale for batching and throughput
- Webhooks to react to finished jobs
- API Reference for the full request and response schemas