Skip to main content
Status Sign in

Data ingest

Most powersport brands and importers carry catalog data in whatever shape their internal systems produce. CSVs in five different column orderings, REST APIs with custom auth, XML feeds with bespoke schemas. PowersportOS handles the translation step so retailers downstream consume one normalised data shape regardless of upstream source. This doc covers what's live today, what's added per data-provider relationship, and how the underlying brand-permission model gates writes to the central catalog.

Two ways data lands in PowersportOS today

Both paths write to the same central catalog and respect the same brand-permission gate (see below). The difference is just how the data physically gets here.

CSV upload
Live for all tenants. Data provider downloads a CSV template, fills it in (or exports from their own system), uploads via the portal. Backend parses, validates, applies brand-permission gating per row, and writes to central Part rows. Same column shape as the in-app downloadable template. Asset URLs (images, manuals) are mirrored to our object storage on import.
Direct API
Live for all tenants. POST / PUT / DELETE against /api/app/managed-brands and /api/app/managed-parts with the tenant's X-API-Key. JSON in, JSON out. Same brand-permission gating. Useful for tenants who already have an internal export pipeline and want to stream catalog updates on a schedule.

Per-provider adapters: built per relationship

Brands that ship data in formats outside CSV or JSON (XML feeds, custom REST APIs, FTP drops, TecDoc / ACES&PIES dumps, etc.) get a dedicated adapter on the PowersportOS side. The adapter's job is to pull from the source on a configured cadence, normalise the response into our internal data shape, and run it through the same write pipeline the CSV and API paths use.

We don't ship a generic XML importer or a universal format-detection layer. Each adapter is built for one provider, against their actual API or feed, with their actual data quirks accounted for. Realistic build time is roughly one to two weeks per source after the technical conversation with the provider lands.

When you'd want one
Your data is in a non-CSV format and you don't want to maintain a CSV export. Or your data updates often enough that scheduled syncs from the source-of-truth make more sense than file uploads. Or you already have a dealer-data API your existing partners use.
What we need from you
Technical access to your API or feed (credentials, sandbox if available), documentation of pagination and rate limits, a clear answer on whether IDs are stable across releases, and the recommended polling cadence. We bring the rest of the integration work.
What you get out
Your data lands cleanly in PowersportOS under your brand permissions. Every retailer running on PowersportOS sees your catalog in the same structural shape as every other brand. You stay the source of truth; we're a normalised mirror that serves it onward.

What's live today

The first per-provider adapter is live in production as of July 2026, syncing a UK aftermarket brand's dealer API into central catalog rows. Around 6,600 products, 977,000 fitments, and 22 brands (the source distributes third-party brands alongside their own) landed via automated pull, with images and PDF manuals mirrored to our object storage in the same pass. Downstream retailers on the platform see this data through the same central-catalog shape as any CSV-uploaded row.

Additional adapters are on the roadmap and will be built as data-provider relationships come online.

How adapters run

Every adapter follows a small, consistent set of run types so operators know what to expect regardless of which source they're monitoring:

bootstrap
First-time full setup. Pulls the taxonomy the adapter's data references (makes, models, vehicles, categories, brands). Fast, typically one to three minutes. Run once at onboarding, then re-run only when the source's taxonomy shifts materially.
product-bootstrap
Full product-catalog import. Slower: upstream rate limits and per-item asset rehosting dominate. Idempotent: safe to re-run to fill gaps.
brand-sync
Brand-metadata refresh only. Under a minute. Used when the upstream updates logos or descriptions.
retry-failed-categories
Reads the last run's errors and re-attempts only the specific endpoints that failed. Cheaper than re-running the full product-bootstrap when a handful of categories failed on a network blip.
delta (planned)
Incremental sync via updatedAfter, scheduled daily. Keeps the catalog fresh without operator intervention.
full-sweep (planned)
Full pass across the upstream catalog for deletion detection, scheduled weekly.

Operator surface

PowersportOS staff monitor and manually trigger adapter runs from an internal Data ingest page in the admin. Every run creates an audit row capturing status, request count, per-entity counters, and full error detail. History is retained indefinitely so operators can trace catalog changes back to specific runs when a downstream question surfaces months later.

A tenant-visible view of these runs, scoped to just the data-provider's own runs with no cross-tenant visibility, is on the roadmap.

The brand-permission gate

Every write to the central catalog, regardless of which ingest path it came in through, is checked against the calling tenant's brand permissions. A data provider can only create, update, or deprecate Part rows under brands they've been granted write access to. This protects the catalog from cross-brand writes and audit-logs every change with the tenant identity attached.

READ
Tenant can see central data for this brand but cannot write. Useful for review-only relationships.
WRITE
Tenant can create and edit Part rows under this brand. Default role for data providers.
OWNER
WRITE plus the right to edit Brand metadata (logo, description, country, website).

Permissions are granted by PowersportOS staff per (tenant, brand) pair from the admin portal. Multiple tenants can hold permissions on the same brand, though the conventional setup is one data provider per brand.

What lifecycle looks like

Data providers don't hard-delete Part rows from the central catalog. A Part that retailers have already activated carries dependencies (their activation rows, fitments, Shopify product mappings, etc.) that get destroyed by a cascade. The right tool when an SKU is going away is the lifecycle status.

ACTIVE
Default. Part is current and orderable.
DEPRECATED
Still sold, but a successor exists. Storefront shows a 'Replaced by X' hint when the part links to a successor via replacedById.
DISCONTINUED
No longer in production. Retailers keep their activation rows; the storefront can decide how to display.
DRAFT
Not yet released. Useful for staging new SKUs before announcement.

A new Part with no retailer activations yet can still be deleted (cleans up a typo on create). Past that point, lifecycle is the path.

What's normalised, what stays as-is

Country of origin
Normalised to ISO 3166-1 alpha-2 codes (SE, TW, US, DE). Importer accepts common country names and maps them automatically.
HS code
Validated for 6, 8, or 10-digit format. Maps cleanly to Shopify variant.harmonizedSystemCode at push time.
Description HTML
Sanitised server-side through a tight whitelist (paragraphs, headings, lists, basic formatting, https-only images). Plain text gets wrapped in paragraphs automatically.
Year ranges in fitments
Expand single-year or compressed-range syntax (2020-2024 or 2012-2016,2018-2023) into individual Fitment rows per year.
Images and manuals
Source URLs are fetched server-side and mirrored to our object storage. Original URL stored alongside so re-imports dedupe and re-fetch only when needed.
Part numbers, brand strings, OEM references
Preserved verbatim. We don't enforce a global SKU schema across providers; brand strings stay as the provider names them, and OEM cross-references are stored per-row.

Cadence and stability

CSV upload is operator-triggered. API push runs whenever the data provider's backend sends it. Per-provider adapters run on a daily incremental schedule once the initial bootstrap is complete, with weekly full-sweep passes catching deletions. The cadence is configurable per relationship depending on the source's own update rhythm and rate-limit posture.

The data shape retailers consume from /api/t/* endpoints is stable across all ingest paths. Catalog rows look identical to a downstream consumer whether the data came from a CSV upload last week or an adapter sync 30 seconds ago.

Related documentation

  • Tenant types covers DATA_PROVIDER, MANUFACTURER, DISTRIBUTOR and which surfaces each get.
  • Two-layer data model explains where central catalog data lives versus tenant-owned data.
  • PIM-Light details the structured product data shape every ingest path normalises into.
  • CSV import format covers the column shape, year-range syntax, and quoting rules.