FlashFender · Public docs
Inventory embed & API
Same Active lot, three ways to consume it: WordPress HTML tag, React mount of that tag, or JSON (public token or v1 API key). Lists are newest first by listed_at. One token or key is one rooftop — never another dealer’s stock.
Copy your embed token from Settings → Website inventory embed. Do not commit live tokens. Example rooftop id (Drip): 4d43b08c-3d56-4b3f-b465-c8dd5d50e62e.
WordPress (Custom HTML)
Paste into a Custom HTML block. Cards open the hosted VDP unless you set data-vdp-base. data-theme="auto" inherits the host page. New cars get a badge when listed_at is within data-new-days (default 14). Replace the token with yours from Settings.
<!-- FlashFender inventory embed -->
<div
data-adaptus-inventory
data-dealership="4d43b08c-3d56-4b3f-b465-c8dd5d50e62e"
data-token="YOUR_EMBED_TOKEN"
data-limit="24"
data-theme="auto"
data-new-days="14"
></div>
<script async src="https://app.flashfender.com/embed/inventory.js"></script>Iframe alternative (when the CMS blocks third-party scripts) is on Settings → Website. Allow script or iframe from https://app.flashfender.com.
React: mount the same tag
This is a DOM widget, not a React component. Render the div, then load inventory.js once in useEffect. Theme inherit still applies. Prefer native fetch (next section) if you want your own cards and routing.
import { useEffect } from "react";
export function InventoryWidget() {
useEffect(() => {
const src = "https://app.flashfender.com/embed/inventory.js";
if (document.querySelector(`script[src="${src}"]`)) {
window.AdaptusInventoryEmbed?.refresh();
return;
}
const script = document.createElement("script");
script.src = src;
script.async = true;
document.body.appendChild(script);
}, []);
return (
<div
data-adaptus-inventory
data-dealership="YOUR_DEALERSHIP_ID"
data-token="YOUR_EMBED_TOKEN"
data-limit="24"
data-theme="auto"
data-new-days="14"
/>
);
}React: fetch JSON
Recommended for a React site. Public API is CORS-open, Active-only, VIN masked. Sort is newest-first (sort=listed_at desc). Use since for units listed after a timestamp.
const params = new URLSearchParams({
token: "YOUR_EMBED_TOKEN",
dealership_id: "YOUR_DEALERSHIP_ID",
sort: "listed_at",
limit: "50",
offset: "0",
});
// Incremental new units (ISO 8601). Alias: listed_after
params.set("since", lastListedAtIso);
const res = await fetch(
`https://app.flashfender.com/api/vehicles/public?${params}`,
{ credentials: "omit" }
);
const json = await res.json();
// json.data: { id, year, make, model, listed_at, updated_at, photos, … }
// json.count, json.limit, json.offset — newest listed_at firstPublic API (embed token)
GET https://app.flashfender.com/api/vehicles/public
- Auth:
token=your token from Settings (query param). Scope withdealership_idorslug. - CORS:
Access-Control-Allow-Origin: *, GET/OPTIONS only. - Payload: Active vehicles only.
listed_at(flash / lot date, ISO 8601),updated_at, masked VIN. Default order: newestlisted_atfirst. - Dates:
since/listed_after→listed_at > since.updated_since→ price/photo edits. - Filters: make, model, year, q, min_price, max_price, min_km, max_km, body_style, transmission, drivetrain, fuel_type, exterior_color, condition.
- Pagination:
limit(max 100) andoffset. Response includescount.
v1 API (X-API-Key)
For third-party apps. Create a key in Settings → API Keys. The key is scoped to one rooftop. Same since / updated_since as the public list; newest-first.
curl -sS "https://app.flashfender.com/api/v1/inventory?limit=50&since=2026-08-01T00:00:00.000Z" \
-H "X-API-Key: YOUR_API_KEY"CORS allows X-API-Key. Rate limit is 100 requests/minute per key. Sending another dealer’s id in the path returns 403 — the key cannot read other tenants.
Incremental sync
Poll every N minutes with updated_since. Merge by id. Use since only when you care about brand-new listings, not price/photo edits.
const byId = new Map(); // persist across polls
let cursor = localStorage.getItem("ff_updated_since") || "1970-01-01T00:00:00.000Z";
async function poll() {
const url = new URL("https://app.flashfender.com/api/vehicles/public");
url.searchParams.set("token", "YOUR_EMBED_TOKEN");
url.searchParams.set("updated_since", cursor);
url.searchParams.set("limit", "100");
const { data = [] } = await (await fetch(url, { credentials: "omit" })).json();
for (const v of data) byId.set(v.id, v);
for (const v of data) {
if (v.updated_at && v.updated_at > cursor) cursor = v.updated_at;
}
localStorage.setItem("ff_updated_since", cursor);
}Isolation: Drip’s token or API key only returns Drip (4d43b08c-3d56-4b3f-b465-c8dd5d50e62e). A second rooftop’s credentials never include those rows.
Widget source: https://app.flashfender.com/embed/inventory.js. Dealers: Settings → Website.