SA

REST API - v1

Build with salvage auction data.

One normalized REST API over IAA US/CA, Copart US/CA/UK/DE and GovDeals US. JSON in, JSON out, fast cache hits, HMAC-signed webhooks and free credits to start.

Base URL https://salvagealert.com/api/v1OpenAPI 3.0

3 steps to first call

Quick start

  1. 1Create a free account. 50 credits are granted automatically.
  2. 2Open your API dashboard, copy the sa_live_* key and store it as an environment variable.
  3. 3Run the first request. Your account profile should come back in under 200 ms on a cache hit.
curl https://salvagealert.com/api/v1/me \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "user_id": "u_abc123",
  "email": "you@example.com",
  "enrolled_at": 1780000000,
  "credit_balance": 50,
  "rate_limit_per_minute": 60
}

Authentication

Every request must send your secret key as a Bearer token in the Authorization header.

Authorization: Bearer sa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Create keys from the API dashboard or rotate them with POST /api-keys/rotate. The full secret is shown once; only a SHA-256 hash is stored.
HeaderDescription
X-Request-IdUUID for this request. Quote it when contacting support.
X-Credits-ChargedCredits consumed by this call.
X-Credits-BalanceRemaining credits after this call.
X-RateLimit-LimitPer-minute call ceiling for your key.

Errors

Errors always use the same JSON shape and a stable error.code that you can handle programmatically.

{
  "error": {
    "code": "insufficient_credits",
    "message": "This call costs 1 credit; your balance is 0."
  },
  "request_id": "5f3d6e92-1234-5678-9abc-def012345678"
}
StatuscodeWhen
400invalid_body / invalid_sourceMalformed body or unknown enum value.
400non_https / private_addressWebhook URL fails the SSRF safety check.
401missing_credentials / invalid_credentialsBad or missing key, inactive account.
402insufficient_creditsTop up before making more paid calls.
403api_disabledAPI access is disabled for this account.
404not_found / lot_not_foundThe resource does not exist or is not owned by this key.
429rate_limitPer-minute ceiling exceeded.
500internal_errorQuote request_id when reporting.

Rate limits

Each API key is limited to 60 requests per minute on a sliding window. Over-limit requests return 429 without charging credits. Contact support if you need higher throughput.

Credits & pricing

Credits are spent only on calls that fetch auction data. Account, reference and webhook management calls are free. Cache hits on search calls cost 0 credits.

EndpointCreditsNotes
POST /lots/search10 on cache hit.
GET /lots/{source}/{lot_key}1Always fresh; bypasses cache.
GET /lots/{source}/{lot_key}/images4IAA only. 50 URLs per prefix.
GET /lots/{source}/{lot_key}/images.zip8IAA only. ZIP archive.
GET /inventory1Archived index; paginated browse.
GET /inventory/sources0Per-source active-lot counts.
GET /me, /usage, /api-keys/*0Account management.
GET /makes, /models, /yards0Cached catalogue data.
ALL /webhooks/*, /watches/*0Subscription management is free.
GET /vehicles/*, /fx0.2VIN, safety, fuel economy and FX lookups.
50 credits are granted on signup. For more volume, open a support ticket and we will respond within one business day.

Sources & currencies

Use one source identifier per call. The Lot schema stays the same; currency and location format vary by source.

sourceRegionCurrencyLocation format
iaai_usIAA - USAUSDState codes, e.g. US-FL
iaai_caIAA - CanadaCADProvincial branches
copart_usCopart - USAUSDState codes, e.g. US-TX
copart_caCopart - CanadaCADProvince codes, e.g. CA-QC
copart_ukCopart - UKGBPNation codes
copart_deCopart - GermanyEURBundesland codes

No credits required

Free to test

You can wire up and verify your whole integration without spending a single credit. The endpoints below always cost 0, so confirm your key, headers and JSON parsing before touching paid auction data. Every signup also includes 50 free credits to spend when you are ready.

Always free — 0 credits

EndpointNotes
GET /meConfirms your key works and returns your credit balance.
GET /usagePer-day call and credit history.
GET /makesFull make catalogue.
GET /models?make_id=230Models for one make (Honda = 230).
GET /yards?source=copart_usYard list for a source.
POST /lots/searchFree on any cache hit — see the note below.

Verify your key — 0 credits

# 0 credits — confirm your key, then list the make catalogue
curl https://salvagealert.com/api/v1/me \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"

curl https://salvagealert.com/api/v1/makes \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"

Known-good test fixtures

When you are ready to spend a credit, use these verified values so your first paid call returns real data instead of an empty result.

FixtureValueNotes
VIN decode1HGCM82633A0043522003 Honda Accord — decodes fully.
Copart US lot50567636GET /lots/copart_us/50567636.
IAA US lot50567636Has an enumerable image gallery.
SafetyHonda / Accord / 2018Recalls + NHTSA ratings.
Fuel economyToyota / Camry / 2020EPA MPG, fuel type and CO2.
FX ratesbase=USD&symbols=EUR,CAD,GBPDaily reference rates.
Every search response includes a cached boolean and an X-Credits-Charged header. When cached is true the call cost you nothing — popular queries are shared across all users, so a repeat of the example query above is usually free.

Lots

POST/v1/lots/search1 cr (0 on cache hit)

Search lots from one source with filter pushdown. Returns normalized Lot objects per page.

Body parameters

FieldTypeReqDescription
sourcestringrequirediaai_us / iaai_ca / copart_us / copart_ca / copart_uk / copart_de
keywordstringFree text matched against make, model and brand.
makesstring[]Example: HONDA, TOYOTA.
modelsstring[]Example: CIVIC.
year_min, year_maxintegerInclusive year range.
locationsstring[]State, province, nation or emirate codes.
title_typesstring[]clean, salvage, rebuilt, parts.
buy_now_onlybooleanRestrict to Buy Now lots.
min_buy_now / max_buy_nownumberBuy Now range in source currency.
min_high_bid / max_high_bidnumberCurrent bid range.
min_odometer_km / max_odometer_kmnumberOdometer range in km.
damage_keywordsstring[]Substring match on primary damage.
pageinteger1-based. Default 1.
page_sizeinteger1 to 100. Default 25.

Example

curl https://salvagealert.com/api/v1/lots/search \
  -H "Authorization: Bearer $SALVAGEALERT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "copart_de",
    "makes": ["MERCEDES-BENZ"],
    "year_min": 2020,
    "title_types": ["salvage"],
    "page_size": 10
  }'
ResponseJSON
{
  "source": "copart_de",
  "page": 1,
  "page_size": 10,
  "total_estimate": 1042,
  "cached": false,
  "lots": [{ "stockNum": "EU52836712", "year": 2021, "make": "MERCEDES-BENZ" }]
}
GET/v1/lots/{source}/{lot_key}1 cr (always fresh)

Single-lot detail. Bypasses cache so bid and sale events are live.

curl https://salvagealert.com/api/v1/lots/copart_us/50567636 \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
GET/v1/lots/{source}/{lot_key}/images4 cr (IAA only)

Enumerate every full-resolution gallery URL IAA exposes for the lot — far more than the listing-page thumbnail. Optional width/height/limit query params.

curl https://salvagealert.com/api/v1/lots/iaai_us/50567636/images \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "source": "iaai_us",
  "lot_key": "50567636",
  "count": 42,
  "width": 1600,
  "height": 1200,
  "images": [
    "https://vis.iaai.com/resizer?imageKeys=50567636~SID~B12~S0~I1&width=1600&height=1200",
    "https://vis.iaai.com/resizer?imageKeys=50567636~SID~B12~S0~I2&width=1600&height=1200"
  ]
}
GET/v1/lots/{source}/{lot_key}/images.zip8 cr (IAA only)

Stream a server-built ZIP archive of every photo IAA exposes for the lot. application/zip with Content-Disposition attachment; X-Photos-Included reports how many made it in.

curl -O -J https://salvagealert.com/api/v1/lots/iaai_us/50567636/images.zip \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"

Inventory

Browse the public archived-inventory index — the same continuously-crawled catalogue behind our /lots pages. It reads pre-archived stock, so it is the cheap, stable way to mirror GovDeals and every other source onto your own site.

GET/v1/inventory1 cr

Page through the archived-inventory index. Filter by source, make, model, year and mileage; sort and paginate.

curl "https://salvagealert.com/api/v1/inventory?source=govdeals_us&page_size=20" \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "source": "govdeals_us",
  "page": 1,
  "page_size": 20,
  "total": 3184,
  "sort": "ending",
  "lots": [{
    "source": "govdeals_us",
    "lot_key": "18421-098",
    "year": 2016,
    "make": "FORD",
    "model": "F-250",
    "currency": "USD",
    "current_bid": "$4,250",
    "sale_date_utc": 1781990400000,
    "image_url": "https://...",
    "listing_url": "https://salvagealert.com/lots/2016-ford-f-250-govdeals-us-18421-098"
  }]
}
GET/v1/inventory/sources0 cr

Live active-lot counts per source in the archived-inventory index. Discover how much GovDeals and other stock is available.

curl https://salvagealert.com/api/v1/inventory/sources \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "total": 184302,
  "sources": [
    { "source": "govdeals_us", "label": "GovDeals", "currency": "USD", "active_lots": 3184 },
    { "source": "iaai_us", "label": "IAA USA", "currency": "USD", "active_lots": 98211 }
  ]
}

Account

GET/v1/me0

Profile, current credit balance and rate limit.

ResponseJSON
{"credit_balance":47,"rate_limit_per_minute":60}
GET/v1/usage?days=300

Daily and per-endpoint API usage for the selected window.

ResponseJSON
{"days":30,"per_day":[{"day":"2026-05-01","calls":12,"credits_spent":8}]}
POST/v1/api-keys/rotate0

Revokes active keys and returns one fresh secret exactly once.

curl -X POST https://salvagealert.com/api/v1/api-keys/rotate \
  -H "Authorization: Bearer $SALVAGEALERT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"Production rotated"}'

Reference data

GET/v1/makes0

Vehicle make catalogue.

ResponseJSON
{"makes":[{"id":160,"name":"FORD","count":120453}]}
GET/v1/models?make_id=2300

Model list for one make.

ResponseJSON
{"make_id":230,"models":[{"id":40510,"name":"CIVIC","count":18230}]}
GET/v1/yards?source=copart_us0

Yard or branch catalogue per source.

ResponseJSON
{"source":"copart_us","yards":[{"code":"DALLAS","name":"Dallas","region":"TX"}]}

Vehicle data

Decode VINs, pull open recalls and crash-test ratings, and look up fuel economy — plus daily reference exchange rates. Each call costs 0.2 credits.

GET/v1/vehicles/vin/{vin}0.2 cr

Decode a 17-character VIN into a structured vehicle spec: year, make, model, trim, body, engine and drivetrain. Pass ?year= to disambiguate older VINs.

curl https://salvagealert.com/api/v1/vehicles/vin/1HGCM82633A004352 \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "vin": "1HGCM82633A004352",
  "year": 2003,
  "make": "HONDA",
  "model": "Accord",
  "trim": "EX",
  "body_class": "Coupe",
  "doors": 2,
  "drive_type": "FWD",
  "engine": { "cylinders": 6, "displacement_l": 3, "horsepower": 240, "fuel_type": "Gasoline" },
  "plant": { "country": "UNITED STATES", "city": "MARYSVILLE", "state": "OHIO" }
}
GET/v1/vehicles/safety0.2 cr

Open recall campaigns plus crash-test safety ratings for a year/make/model.

curl "https://salvagealert.com/api/v1/vehicles/safety?make=Honda&model=Accord&year=2018" \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "make": "HONDA",
  "model": "ACCORD",
  "year": 2018,
  "recalls": {
    "count": 1,
    "items": [{ "campaign": "18V268000", "component": "AIR BAGS", "summary": "..." }]
  },
  "ratings": { "overall": "5", "overall_front": "5", "overall_side": "5", "rollover": "4" }
}
GET/v1/vehicles/fuel-economy0.2 cr

MPG, fuel type, CO2 and estimated annual fuel cost for a year/make/model.

curl "https://salvagealert.com/api/v1/vehicles/fuel-economy?make=Toyota&model=Camry&year=2020" \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "make": "TOYOTA",
  "model": "CAMRY",
  "year": 2020,
  "trims_available": 4,
  "trim": "Auto (S8)",
  "fuel_type": "Regular Gasoline",
  "mpg": { "city": 29, "highway": 41, "combined": 34 },
  "annual_fuel_cost_usd": 1450,
  "co2_g_per_mile": 261
}
GET/v1/fx0.2 cr

Daily reference exchange rates across the currencies SalvageAlert lots trade in. Defaults to a USD base against USD, EUR, CAD and GBP.

curl "https://salvagealert.com/api/v1/fx?base=USD&symbols=EUR,CAD,GBP" \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
ResponseJSON
{
  "base": "USD",
  "date": "2026-05-30",
  "rates": { "EUR": 0.92, "CAD": 1.37, "GBP": 0.79 }
}

Webhooks

Subscribe to events and receive HMAC-signed POST requests when new lots match your watches. Retries use exponential backoff.

POST/v1/webhooks0

Create a webhook. The HMAC secret is returned exactly once.

curl -X POST https://salvagealert.com/api/v1/webhooks \
  -H "Authorization: Bearer $SALVAGEALERT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-app.com/webhooks/salvagealert","events":["lot.matched"]}'

List, update, delete

curl https://salvagealert.com/api/v1/webhooks \
  -H "Authorization: Bearer $SALVAGEALERT_KEY"
POST/v1/webhooks/{id}/test0

Synchronous test delivery. Not persisted and not retried.

ResponseJSON
{"ok":true,"status":200,"body_preview":"OK"}
GET/v1/webhooks/{id}/deliveries0

Most recent deliveries with attempts, status, latency and redacted preview.

Query params: limit (1-200, default 50), status (pending, delivered, failed or dead).

Only successful response previews are stored. Failed responses get opaque tags so webhook receivers cannot become exfiltration channels.
POST/v1/watches0

A saved filter set that decides which new lots fire lot.matched.

Supported filters include keyword, make/model ids or names, year range, damage keywords, title types, buy-now, bid and odometer ranges.

Security

Verifying signatures

Every delivery includes X-Salvagealert-Signature. Compute HMAC_SHA256(secret, ts.raw_body), compare it with v1, and reject timestamps older than five minutes.

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyWebhook(secret, rawBody, header) {
  const m = /t=(\d+),v1=([a-f0-9]+)/.exec(header ?? '');
  if (!m) return false;
  const [, ts, v1] = m;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
  return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(v1, 'hex'));
}

Lot object

Every endpoint that returns lots uses the same object shape. Null or missing values mean the source did not provide that field.

ResponseJSON
{
  "stockNum": "50567636",
  "vin": "1HGCY1F32RA******",
  "year": 2024,
  "make": "HONDA",
  "model": "ACCORD EX",
  "brand": "CLEAN TITLE",
  "odometerReading": 22215,
  "primaryDamage": "FRONT END",
  "estimatedRetailValue": 26125,
  "imageUrl": "https://cs.copart.com/..."
}