Custom Connector — Developer Guide
Build a CMS connector against the AACsearch Connector API. Covers token usage, full/delta/delete sync, document shape, mapping rules and required error handling.
If your CMS or product catalog is not in the supported platform list, you can ship your own connector against the public Connector API. This page describes the minimum surface a connector must implement to be considered production-ready.
The API itself is fully documented in Connector API Lifecycle. This page focuses on the developer responsibilities that live on the CMS side.
What "production-ready" means
A connector is production-ready when it:
- Authenticates every request with an
ss_connector_*Bearer token. - Runs a handshake on install and config save, and persists the returned
projectIdandindexSlug. - Performs an initial full sync, batched at ≤1000 documents per request.
- Performs delta syncs on every product create / update / stock or price change, batched at ≤100 documents per request.
- Issues a delete on every product deletion.
- Sends a heartbeat at least every 5 minutes from a background task.
- Reports diagnostics after every full sync, after sync failures, and on a daily timer.
- Maps the CMS entity into the shared product document shape (below) using all available fields.
- Implements the retry strategy.
- Surfaces a Test connection action in its admin UI.
A connector that ships steps 1–6 only is acceptable as an Early preview. Items 7–10 are required for Beta, and observed reliability over at least 3 release cycles is required for Supported.
Project layout
You can host your connector wherever it makes sense for the target platform. The reference implementations in this monorepo follow one of three templates documented in wiki/tasks/cms-platform-expansion.md:
- Template A — PHP CMS module (PrestaShop, Bitrix, WordPress, OpenCart, Magento, Drupal, Joomla)
- Template B — TypeScript server-side connector (Shopify, InSales)
- Template C — npm headless CMS plugin (Strapi, Sanity, Contentful, Directus, Payload)
The minimum file set for any template:
your-connector/
├── client.{ts,php} ← HTTP client around the Connector API
├── product-mapper.{ts,php} ← Platform entity → SyncProductInput
├── full-sync.{ts,php} ← Paginated catalog export
├── delta-sync.{ts,php} ← Event handler for create/update/delete
├── diagnostics.{ts,php} ← Heartbeat + error reporting
└── admin/
├── settings.{tsx,php} ← Token + project ID form
└── test-connection.{tsx,php}Use the existing modules as references:
packages/strapi-plugin/src/server/services/aacsearch.ts— TypeScript service with full and delta syncmodules/bitrix/aac.search/lib/aacsearch/ConnectorClient.php— PHP API clientmodules/prestashop/aacsearch/— PrestaShop module structurepackages/shopify-connector/src/— OAuth-based connector with webhooks
Document shape
Every product sent to AACsearch maps to SyncProductInput. Required fields are external_id and title; everything else is optional but strongly recommended.
type SyncProductInput = {
external_id: string; // stable platform ID
title: string;
description?: string;
sku?: string;
brand?: string;
categories?: string[]; // human-readable category path
category_ids?: string[]; // platform category IDs for filters
tags?: string[];
price?: number; // major units (e.g. 99.99 USD)
sale_price?: number;
currency?: string; // ISO 4217, 3 letters
image_url?: string;
product_url?: string;
availability?: "in_stock" | "out_of_stock" | "preorder";
stock_quantity?: number;
attributes?: Record<string, unknown>;
locale?: "en" | "de" | "es" | "fr" | "ru";
created_at?: string; // ISO 8601
updated_at?: string; // ISO 8601
};Mapping rules
external_id— must be stable across the product's lifetime. Use the CMS primary key, never a slug or SKU.title— use the localized title for the configuredlocale. Strip HTML and normalize whitespace.description— same rule. Strip HTML, leave the plain text. AACsearch will tokenize.categories— full breadcrumb path, top → leaf.["Shoes", "Running", "Trail"]is better than["Trail"].price/sale_price— major units in the connector wire format. The AACsearch ingest pipeline normalizes to minor units (kopecks-style BigInt) on the storage side. Do not pre-multiply by 100.attributes— anything that is filterable or facetable but does not have a dedicated column. Keys are free-form strings. Numeric attributes (size, length, capacity) should be sent as numbers, not strings — AACsearch will infer the index type from the first batch.locale— if the CMS has localized catalogs, send one document per locale per product, each with a differentexternal_idsuffix (for example,prod-123:en,prod-123:de). Do not collapse locales into a single document.
Multi-currency catalogs
If your CMS supports multiple currencies, send the customer-facing currency as currency and an attributes.price_by_currency object for the rest:
{
"currency": "USD",
"price": 99.99,
"attributes": {
"price_by_currency": { "EUR": 92.5, "GBP": 79.99 }
}
}AACsearch will index the alternative prices as numeric attributes so the storefront can switch currency without re-indexing.
Required endpoints
A minimum viable connector calls these endpoints in this order:
POST /api/connectors/handshakeon install and on every config save.POST /api/projects/:projectId/sync/fullfor the initial catalog export and for a manual "Resync everything" action.POST /api/projects/:projectId/sync/deltaon every product event in the CMS.DELETE /api/projects/:projectId/products/:externalIdon product deletion.POST /api/connectors/:connectorId/heartbeatevery 5 minutes.POST /api/projects/:projectId/diagnosticsafter each full sync and on a daily timer.
All payload shapes, error codes, and the lifecycle order are in Connector API Lifecycle.
Auth, scopes, and tenant isolation
The Connector API enforces three invariants that connector authors do not need to reimplement but must not work around:
- Every call is bound to the organization that owns the token. The
:projectIdin the URL must match the token's organization. A 404 means the merchant pasted the wrong token, not that AACsearch lost data. - The token's
connector_writescope is the only scope checked. Connector tokens cannot read search results, manage indexes, or read analytics. Use ass_search_*token from the storefront for search queries. - Documents are written to
SearchIngestBufferfirst, then to Typesense by the background worker. A 200 means buffered — the document may not be queryable for a few hundred milliseconds.
Never call Typesense, the AACsearch admin search key, or any internal storage directly. The Connector API is the only supported write path. Direct writes bypass tenant isolation, quota tracking, and the buffer that absorbs retries — they will break in non-obvious ways under load.
Webhook receiver
Connectors that operate from the CMS server can choose between two patterns:
- Outbound push — the module reacts to CMS events and calls the AACsearch sync endpoints directly. Simple, used by every existing PHP module.
- Webhook receiver — AACsearch sends webhooks to the platform when documents are reindexed, useful for cache invalidation or analytics. Endpoint:
POST /api/webhooks/sync/:indexSlug, HMAC-signed with the connector token secret.
Most CMS connectors do not need the receiver. Use it when you want the platform's own cache or CDN to know that the search index has changed.
Local development
For a fast loop:
- Run AACsearch with
bun run dev— the API mounts athttp://localhost:3000/api. - Create a connector token from the dashboard and copy it.
- Point your CMS module at
http://localhost:3000/api. - Use the
/api/projects/:projectId/sync/jobs/:jobIdendpoint or Dashboard → Connectors → Sync history to watch documents land. - Use Search → Test Search in the dashboard to confirm documents are indexed under the right tenant.
If you ship a hosted version, prefer https://api.aacsearch.com/api and let merchants paste the connector token as-is.
Submitting your connector
If you want your connector to appear in the platform support matrix:
- Open an issue describing the platform and target template (A, B, or C).
- Submit a PR that adds the connector under
modules/<platform>/orpackages/<platform>-connector/, plus a dedicated docs page inapps/docs/content/docs/{en,de,es,fr,ru}/connectors/<platform>.mdx. - Tag the docs page status as Early preview initially. Promotion to Beta and Supported is gated by reliability over multiple release cycles.
Related pages
Connector Diagnostics
Test connection flow, the diagnostics endpoint, retry behavior, and how to read connector status from the dashboard.
Connector Field Mapping Reference
Per-entity mapping rules: products, categories, variants, prices, stock, images and locales. The contract every CMS module follows when shipping data into AACsearch.