The adapter framework is the layer that decouples the import orchestrator from supplier-specific protocol details. Every supplier, regardless of whether it speaks SOAP, REST, or GraphQL, presents the same four abstract methods to the orchestrator. The registry maps a plain string stored in the database to the correct class at runtime, so adding a new supplier type never requires changes to the import pipeline.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/VisualGraphxLLC/API-HUB/llms.txt
Use this file to discover all available pages before exploring further.
BaseAdapter
BaseAdapter is an abstract base class defined in backend/modules/import_jobs/base.py. Every adapter must subclass it and implement three abstract methods. A fourth method, discover_closeouts, has a default implementation that raises NotImplementedError and only needs to be overridden by adapters whose suppliers support closeout feeds.
discover() first to get a list of ProductRef objects, then calls hydrate_product() for each ref to fetch full details. ProductRef is a lightweight model holding just the supplier_sku and an optional part_id.
product_type
Setproduct_type as a class-level attribute to either "apparel" or "print". The normalizer uses this to route the ProductIngest through the correct schema branch. PromoStandards adapters default to "apparel"; FourOverAdapter and OPSAdapter use "print".
DiscoveryMode
DiscoveryMode is a string enum. The import orchestrator accepts a mode string from the API request and passes the resolved enum value to adapter.discover().
FULL — complete catalog sync
FULL — complete catalog sync
Discovers every product the supplier exposes. This is the most data-intensive mode and is typically run once at onboarding or after a prolonged gap. On PromoStandards adapters,
FULL is not explicitly implemented — use FULL_SELLABLE instead, which calls getProductSellable.DELTA — changed products only
DELTA — changed products only
Discovers products modified since
supplier.last_delta_sync (or last_full_sync if last_delta_sync is null, or 2000-01-01 if neither is set). Calls discover_changed() internally. Use this for daily or hourly incremental syncs.On suppliers that do not expose a modified-since endpoint (e.g. 4Over), DELTA falls back to full discovery automatically.FIRST_N — first N products
FIRST_N — first N products
Returns the first
limit products from the supplier’s sellable list. The orchestrator passes limit from the API request body. Minimum is 1, maximum is 10,000.Use this mode for a smoke-test import when adding a new supplier: mode=first_n, limit=5.EXPLICIT_LIST — specific product IDs
EXPLICIT_LIST — specific product IDs
Imports only the product IDs you list in
explicit_list. Requires the explicit_list field in the request body; the request is rejected at the schema layer if the list is absent.FILTERED_SAMPLE — sellable list filtered to explicit IDs
FILTERED_SAMPLE — sellable list filtered to explicit IDs
Fetches the full sellable list from the supplier, then filters it to the IDs in
explicit_list (or protocol_config.explicit_list if not provided in the request). Useful when you want to verify that specific SKUs are in the sellable feed before importing them.FULL_SELLABLE — all sellable products
FULL_SELLABLE — all sellable products
Calls
getProductSellable (for PS adapters) and returns every product flagged as sellable. This is the standard mode for full PromoStandards syncs. Products with isSellable: false are excluded.CLOSEOUTS — discontinued or clearance products
CLOSEOUTS — discontinued or clearance products
Calls
discover_closeouts(), which maps to getProductCloseOut on PS adapters. Only implement this if the supplier’s API supports a closeout endpoint. The base implementation raises NotImplementedError.Error types
Three error types control how the import pipeline handles failures. All inherit fromAdapterError, which accepts an optional code string alongside the message.
AuthError
Authentication failed. This is a fatal error for the import job. The job stops immediately and marks the supplier as needing attention. Raised when PS SOAP fault codes
100, 104, or 110 are received, or when required credentials are missing from auth_config.SupplierError
The supplier returned an error for a specific product. The pipeline logs the error and skips that product, continuing with the rest of the batch. One broken product does not abort a sync of thousands.
TransientError
A network timeout, connection reset, or 5xx response that may succeed on retry. The pipeline retries up to three times with exponential backoff: delays of 4 s, 2 s, and 1 s (
2 ** (2 - attempt) seconds). If all retries fail, the product is skipped and logged.Retry logic
The adapter registry
The registry is a module-level dict inbackend/modules/import_jobs/registry.py. It maps the string stored in suppliers.adapter_class to the concrete class.
Self-registration pattern
Each adapter module callsregister_adapter at the bottom of its file, immediately after the class definition. This means the adapter registers itself the moment the module is imported — no central configuration file needed.
main.py imports all adapter modules on startup. By the time FastAPI mounts the import routes, ADAPTERS is fully populated.
Registry lookup
AdapterNotConfiguredError) and a value that references a class that was never registered (AdapterNotRegisteredError). The latter error message includes the list of known adapter names to help diagnose typos.
Choosing a discovery mode
| Scenario | Recommended mode |
|---|---|
| First import after adding a supplier | first_n with limit=5 |
| Full catalog load at onboarding | full_sellable |
| Daily incremental sync | delta |
| Re-import specific SKUs after a data issue | explicit_list |
| Verify specific SKUs are in the sellable feed | filtered_sample |
| Import clearance products | closeouts |
Triggering an import via API
202 Accepted immediately. The import runs in a background task managed by FastAPI’s BackgroundTasks. The response includes a sync_job_id you can use to poll status:
If a job with the same
supplier_id and mode is already pending or running, the endpoint returns 409 Conflict instead of queuing a second job. This prevents duplicate concurrent imports for the same supplier and mode combination.