Products, your dealer pricing, stock levels and a change feed — served from https://api.elitecore.com.
Sign in to your Elite Core account and open Account › API Access to issue your own key. The key is shown once, at the moment you create it — we store only a hash of it and there is no way to display it again. Lost a key? Revoke it on that page and create another.
Send it on every request as Authorization: Bearer eck_live_…. This is a server‑to‑server API: do not call it from a browser, where your key would be visible to every visitor.
Not a developer? The same page has a catalog browser with search, filters and a CSV/JSON export — no key required.
This key is public and it works:
curl -sS "https://api.elitecore.com/v1/products?limit=1" -H "Authorization: Bearer eck_demo_publiccatalog2026"
It is a shared sandbox, so everyone evaluating the API is using the same one. It reads the catalog endpoints only, it never carries dealer pricing, it cannot fetch the export feeds, and it is rate limited far harder than a real key. Create your own key above for the real thing.
If you run a storefront platform rather than your own integration, take the catalog as a file it already understands:
https://api.elitecore.com/v1/exports/woocommerce.csvhttps://api.elitecore.com/v1/exports/google.tsv
Both are built live from the same snapshot as the rest of the API, so a feed is never older than an API call. The WooCommerce file uses that importer's own column names and carries one variable parent row plus a variation row per variant; the Google file uses Merchant Center attribute names, one row per variant grouped by item_group_id. Your dealer price rides in Meta: _elite_core_dealer_price and cost_of_goods_sold respectively, when your credential carries the pricing scope.
Feed tokens. A shopping platform is given a URL and has nowhere to put an Authorization header, so mint a feed token on your account page and paste the URL it gives you. A feed token appended as ?token=eck_feed_… works on these two endpoints and is refused with 403 on every other route. Revoke it from the same page and the next fetch stops immediately. Treat the URL as the secret it contains.
Google needs a link for every row and we do not know your storefront, so there is no default: pass link_template=https://example.com/products/{sku} and we substitute each SKU, or leave it off and the column is empty.
Discontinued products are excluded by default from these files, unlike /v1/products. A feed becomes listings, and a listing for something we stopped making is a bad order. Pass include_discontinued=1 if you want them.
How fresh a file is rides in its response headers, since neither format has room for a snapshot block: X-Elite-Core-Snapshot-Generated-At, X-Elite-Core-Snapshot-Age-Seconds and X-Elite-Core-Snapshot-Stale. Run curl -I against the feed URL to read them without downloading a catalog.
If anything goes wrong once a feed has started sending, we abort the transfer rather than finishing it short. Your fetcher will report a failed download, which is a retry. We will never hand you a file that looks complete and is not.
Every response carries an Elite-Core-Version header holding the date of the API you are talking to. If a sync started behaving differently on a Tuesday, compare that header in Monday's and Tuesday's logs before anything else.
https://api.elitecore.com/v1/changelog lists what changed and when, newest first, with no key needed. Add ?since=2026-09-08 to see only what has happened since you wrote your integration. Every entry says whether there is anything to do: none, optional, or required with a date. Poll requires_action and wake somebody on that alone.
Successful responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the window resets). Pace your sync from those rather than waiting for a 429: a quota you only learn about by exceeding it is a trap, and the retry storm that follows a surprise refusal costs both of us more than the requests it replaced.
600 requests per minute per key. Over it you get 429 with a Retry-After header saying how long to wait. A nightly or hourly sync paging at limit=250 is nowhere near this.
A feed token gets 60 fetches an hour, which is far more than any platform needs, and the public sandbox key gets 30 requests a minute because everyone shares it.
Everything — inventory included — is served from a nightly catalog snapshot. This is not a live stock check. Every response carries a snapshot block with generated_at, age_seconds and stale, so you can always see how old the answer is. Read it; do not assume the numbers are current.
For incremental syncs, poll /v1/changes with the cursor from your previous call rather than re‑pulling the whole catalog.
Handle delist events, not just upsert ones. A delist means that SKU has left the catalog you may sell and the listing should come down. Whole brands leave the same way, as one ordinary delist per product, so there is nothing extra to build for them. If one comes back you get an upsert for each product.
MAP = Minimum Advertised Price. Advertise and list every product at or above map_price. Dealer pricing is your cost basis and must never be displayed publicly. Products marked discontinued should be removed from sale; replaced_by_sku names the successor.
https://api.elitecore.com/img/{sku}/{n} is the image link to save. It redirects to wherever that picture currently lives, so if we ever re-host our images your saved links keep working. Save it in preference to the url_standard / url_zoom links beside it, which point at our storefront and would go dead.
Add ?w= for a narrower rendition, e.g. https://api.elitecore.com/img/PC12-AB/1?w=400. Widths from 16 to 1600 pixels are accepted; anything else is refused by name rather than rounded. Height follows the image's own aspect ratio, and we never upscale past the original, so asking for more pixels than a photograph has returns the photograph.
There is no format parameter. Our image host serves the format the picture was uploaded in and does not convert, so a fmt= would either be ignored or be a lie. If WebP or AVIF matters to you, convert on your own side after fetching.
dealer_priceWhen your key carries the pricing scope and your account’s price list covers a SKU, dealer_price is present. Otherwise the field is absent — never null, never 0. Check for its presence rather than its value, so an unpriced SKU can never import into your store at $0.00.