Catalog AI
Sign In

Brand Enrichment API

AI-powered enrichment that generates rich brand profiles — descriptions, taglines, founding year, SEO fields, custom attributes, and more — using live web research or your linked product catalogue.

Overview

The Brand Enrichment API enriches brand records with structured attributes you define under Settings → Enrichment → Brand Attributes. Each job uses your active attributes (or a specific Attribute Set) and either researches brands via live web search or grounds enrichment in your linked product catalogue.

Jobs run asynchronously, processing up to 2,000 brands per job with 5 brands processed concurrently.

Endpoints Overview

Method Endpoint Description
POST /brand-enrichment-jobs/create Create a batch enrichment job
POST /brand-enrichment-jobs/get List enrichment jobs
POST /brand-enrichment-jobs/{job_id}/items/get Get a job's enriched results
POST /brand-enrichment-jobs/{job_id}/stop Stop a running job
GET /brand-enrichment-jobs/{job_id}/download Download job results as CSV

All endpoints are prefixed with /api/{organization}.


Create a Batch Enrichment Job

Start a job to enrich multiple brands in parallel. The job runs asynchronously — brands are processed concurrently (up to 5 at a time) in the background.

Endpoint: POST /api/{organization}/brand-enrichment-jobs/create

Request Body

Field Type Required Default Description
rows object[] Yes — Array of brand records. Each row must include a name, brand, brand_name, or brandName key. 1–2,000 rows.
inputColumns string[] Yes — List of column names present in rows
fileName string No — Display name shown in the jobs list (max 255 characters, recommended to end with .csv)
modelType string No budget-v1 AI model to use: budget-v1 or pro-v1
attributeSetId string No — ID of a specific Attribute Set; omit to use all active attributes
useWebsearch boolean No true Allow the AI to search the web for brands that have no linked products. Set to false if you only want product-grounded enrichment
includeExistingAttributes boolean No true Pass the latest completed attribute values for each brand to the model. Set false to regenerate without keeping old specs.

Model Types

Value Description
budget-v1 Cost-effective, fast. Recommended for bulk runs.
pro-v1 Higher quality. Best for flagship brands.

Limits

Limit Value
Max rows per job 2,000
Max CSV size 8 MB
Concurrency 5 brands at a time

Note: Only one enrichment job can run at a time per organisation. If a job is already pending or processing, the request returns an error asking you to wait.

Brand Name Column Detection

The brand name is detected from the row using the first non-blank match from these keys, in order:

name → brand → brand_name → brandName

Enrichment Modes

Each brand is processed in one of two modes chosen automatically at runtime:

Mode Triggered when Behaviour
products Brand has ≥ 1 linked product in your catalogue AI uses up to 10 sampled products as grounding; no web search
websearch Brand has no linked products and useWebsearch is true AI performs live web searches and fetches brand pages

If a brand has no linked products and useWebsearch is false, that item fails with the error: "No products are linked to this brand. Link products via Enrich Brand on a product, or enable "Use Websearch" before enriching."

Example Request

curl -X POST https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/create \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [
      { "name": "Nike",   "country": "US" },
      { "name": "Adidas", "country": "DE" }
    ],
    "inputColumns": ["name", "country"],
    "fileName": "brands.csv",
    "modelType": "budget-v1",
    "useWebsearch": true
  }'

Response

{
  "success": true,
  "data": {
    "success": true,
    "message": "Brand enrichment job created successfully",
    "jobId": "bej_abc123"
  }
}

List Enrichment Jobs

Retrieve a paginated list of brand enrichment jobs for the organisation.

Endpoint: POST /api/{organization}/brand-enrichment-jobs/get

Request Body

Field Type Required Default Description
page number No 1 Page number (min 1)
limit number No 20 Items per page (max 100)

Example Request

curl -X POST https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/get \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"page": 1, "limit": 20}'

Response

{
  "success": true,
  "data": {
    "success": true,
    "jobs": [
      {
        "id": "bej_abc123",
        "status": "completed",
        "modelType": "budget-v1",
        "fileName": "brands.csv",
        "useWebsearch": true,
        "attributeSetId": null,
        "inputColumns": ["name", "country"],
        "totalBrands": 200,
        "processedCount": 200,
        "successCount": 198,
        "failedCount": 2,
        "errorSummary": null,
        "startedAt": "2026-05-18T08:00:00Z",
        "completedAt": "2026-05-18T08:06:42Z",
        "createdAt": "2026-05-18T07:59:55Z",
        "createdBy": {
          "name": "Aditya",
          "email": "aditya@example.com"
        }
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 5,
      "totalPages": 1
    }
  }
}

Job Status Values

Status Description
pending Job is queued and will start shortly
processing Brands are being enriched right now
completed All brands finished successfully
completed_with_errors Job finished but some brands failed
failed Job failed before processing
stopped Job was manually stopped

Get Job Items

Retrieve detailed enriched results for a specific job, paginated by row.

Endpoint: POST /api/{organization}/brand-enrichment-jobs/{job_id}/items/get

Path Parameters

Parameter Type Required Description
job_id string Yes Job ID

Request Body

Field Type Required Default Description
page number No 1 Page number (min 1)
limit number No 50 Items per page (max 100)

Example Request

curl -X POST https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/bej_abc123/items/get \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"page": 1, "limit": 50}'

Response

{
  "success": true,
  "data": {
    "success": true,
    "job": {
      "id": "bej_abc123",
      "modelType": "budget-v1",
      "fileName": "brands.csv",
      "inputColumns": ["name", "country"],
      "totalBrands": 200,
      "processedCount": 200,
      "successCount": 198,
      "failedCount": 2,
      "status": "completed",
      "errorSummary": null
    },
    "items": [
      {
        "id": "item_001",
        "jobId": "bej_abc123",
        "rowIndex": 0,
        "brandName": "Nike",
        "inputData": {
          "name": "Nike",
          "country": "US"
        },
        "enrichedAttributes": {
          "brand_description": {
            "attributeId": "attr_001",
            "attributeName": "Brand Description",
            "attributeType": "text",
            "value": "Nike is a global leader in athletic footwear, apparel, and equipment..."
          },
          "tagline": {
            "attributeId": "attr_002",
            "attributeName": "Tagline",
            "attributeType": "text",
            "value": "Just Do It"
          },
          "founded_year": {
            "attributeId": "attr_003",
            "attributeName": "Founded Year",
            "attributeType": "number",
            "value": 1964
          },
          "page_title": {
            "attributeId": "attr_004",
            "attributeName": "Page Title",
            "attributeType": "text",
            "value": "Nike — Athletic Footwear, Apparel & Equipment"
          }
        },
        "referenceData": {
          "mode": "websearch",
          "urls": [
            "https://www.nike.com/",
            "https://en.wikipedia.org/wiki/Nike,_Inc."
          ]
        },
        "status": "completed",
        "cost": 0.0042,
        "startedAt": "2026-05-18T08:00:05Z",
        "completedAt": "2026-05-18T08:00:18Z"
      },
      {
        "id": "item_002",
        "jobId": "bej_abc123",
        "rowIndex": 1,
        "brandName": "UnknownBrand",
        "inputData": {
          "name": "UnknownBrand",
          "country": "US"
        },
        "referenceData": null,
        "status": "failed",
        "errorMessage": "No products are linked to this brand. Link products via Enrich Brand on a product, or enable \"Use Websearch\" before enriching."
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 50,
      "total": 200,
      "totalPages": 4
    }
  }
}

enrichedAttributes Object

Each key in enrichedAttributes is the attribute slug (e.g. brand_description, page_title). The value object has the following fields:

Field Type Description
attributeId string Internal attribute ID
attributeName string Human-readable attribute name
attributeType string One of text, html, number, boolean, select, multiselect
value string | number | boolean | string[] | null The enriched value

referenceData Object

Field Type Description
mode string "products" or "websearch"
productIds string[] (products mode only) IDs of the sampled products used as context
urls string[] (websearch mode only) URLs fetched during web research

Item Status Values

Status Description
pending Waiting to be processed
processing Currently being enriched
completed Successfully enriched
failed Failed (see errorMessage)

Stop a Job

Stop a pending or processing job. Brands already enriched keep their results. All remaining pending and processing items are immediately marked as failed with the message "Job was stopped by user".

Endpoint: POST /api/{organization}/brand-enrichment-jobs/{job_id}/stop

Path Parameters

Parameter Type Required Description
job_id string Yes ID of the job to stop

Example Request

curl -X POST https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/bej_abc123/stop \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Response

{
  "success": true,
  "message": "Brand enrichment job stopped successfully",
  "data": {
    "jobId": "bej_abc123",
    "status": "stopped"
  }
}

Error Responses

If the job does not exist:

{
  "success": false,
  "message": "Job not found"
}

If the job is already completed, failed, or stopped:

{
  "success": false,
  "message": "Job cannot be stopped because it is not in progress"
}

Notes

  • Only jobs with status pending or processing can be stopped
  • All pending and processing items are immediately marked failed with error "Job was stopped by user"

Download Job Results as CSV

Download all enriched rows as a CSV file. The file preserves your original input columns and appends enrichment status and one column per configured attribute.

Endpoint: GET /api/{organization}/brand-enrichment-jobs/{job_id}/download

Path Parameters

Parameter Type Required Description
job_id string Yes Job ID

Example Request

curl -X GET https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/bej_abc123/download \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -o enriched-brands.csv

Response

A text/csv file with Content-Disposition: attachment. The filename format is:

{original_filename_without_extension}_enriched_{YYYY-MM-DD}.csv

Falls back to brands_{first8charsOfJobId}_enriched_{YYYY-MM-DD}.csv when no file name is set.

The header row is structured as:

<your input columns>, Enrichment Status, Enrichment Error, <one column per enriched attribute>

Attribute column notes:

  • html type attributes are written as raw HTML; any other attribute whose value contains HTML tags is automatically stripped to plain text
  • multiselect values are joined with ;
  • boolean values are written as Yes / No
  • All other types are written as plain strings
  • null values are written as empty strings

Workflow Example

1. Prepare Brand Rows

const brands = [
  { name: 'Nike', country: 'US' },
  { name: 'Adidas', country: 'DE' },
  { name: 'Sony', country: 'JP' }
]

2. Create the Job

const createRes = await fetch(
  'https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/create',
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      rows: brands,
      inputColumns: ['name', 'country'],
      modelType: 'budget-v1',
      useWebsearch: true
    })
  }
)

const { data } = await createRes.json()
const jobId = data.jobId

3. Poll for Completion

async function waitForJob(jobId) {
  while (true) {
    const res = await fetch(
      'https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/get',
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ page: 1, limit: 100 })
      }
    )

    const { data } = await res.json()
    const job = data.jobs.find(j => j.id === jobId)

    if (
      job &&
      ['completed', 'completed_with_errors', 'failed', 'stopped'].includes(
        job.status
      )
    ) {
      return job
    }

    await new Promise(r => setTimeout(r, 5000))
  }
}

const finalJob = await waitForJob(jobId)

4. Fetch Enriched Items

const itemsRes = await fetch(
  `https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/${jobId}/items/get`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ page: 1, limit: 50 })
  }
)

const { data } = await itemsRes.json()
console.log(data.items)

5. Or Download the Enriched CSV

const csvRes = await fetch(
  `https://catalog-ai.tdcapps.com/api/your-org/brand-enrichment-jobs/${jobId}/download`,
  { headers: { Authorization: `Bearer ${API_KEY}` } }
)

const csv = await csvRes.text()
fs.writeFileSync('enriched-brands.csv', csv)

Best Practices

  1. Include a recognised name column — the row must have one of name, brand, brand_name, or brandName; this is used to identify the brand.
  2. Link products before enriching — brands with linked catalogue products produce richer, more accurate output than web search mode; the AI samples up to 10 products per brand.
  3. Enable useWebsearch for unlinked brands — without linked products and with websearch off, those items will fail immediately.
  4. Use attributeSetId — restrict the job to a named Attribute Set when you only need to refresh specific fields; faster and cheaper.
  5. Stay under 2,000 rows per job — split larger brand lists into multiple jobs.
  6. Poll every 5–10 seconds — enrichment is asynchronous; avoid hammering the endpoint.
  7. Check failedCount and item errorMessage — common failures are no linked products with websearch off, or credit exhaustion mid-job.
  8. Use pro-v1 for flagship brands — for brands where content quality matters most, the Pro model produces noticeably better output.

Error Responses

400 Bad Request

Invalid request body or missing required fields:

{
  "success": false,
  "message": "Invalid request body: ..."
}

401 Unauthorized

Missing API key:

{
  "success": false,
  "message": "Missing API Key"
}

403 Forbidden

Invalid or revoked API key, or the key does not have access to the specified organisation:

{
  "success": false,
  "message": "Invalid API Key"
}

409 Conflict — Job Already in Progress

A job is already pending or processing for this organisation:

{
  "success": false,
  "message": "A brand enrichment job is already in progress. Please wait for it to complete before starting a new one."
}

402 Payment Required — Credit Balance Exhausted

Triggered at job creation if the credit balance is zero:

{
  "success": false,
  "message": "Credit limit reached. Please top up your credits to start a new enrichment job."
}

If credits exhaust mid-job, the job continues processing but remaining items fail with the error "Credit balance limit has been reached." The job's errorSummary is set to "Credit balance limit has been reached." Top up and create a new job to continue.

500 Internal Server Error

{
  "success": false,
  "message": "Internal Server Error"
}