# GovDeals — US government surplus auctions (vehicles, heavy equipment, land)

> Search LIVE GovDeals lots — the auction marketplace US state and city agencies, school districts, police departments, transit authorities and utilities use to sell surplus trucks, heavy equipment, buses, patrol cars, generators, lab gear and land (~25 000 open lots across 59 states and provinces, measured 2026-10-06). Every row carries the auction facts a price alone cannot give you: current bid with its basis, bid increment, reserve state, the resolved end time in UTC, the selling agency and where the lot physically is. Give query, or category_id, or seller_id, or state, or zip (at least one).
> ReefAPI engine `govdeals` · 9 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/govdeals/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http). Send the key as `Authorization: Bearer <key>`, or put it in the URL (`?key=<key>`) when the client has no header field, as ChatGPT does.

## Endpoints

### POST https://api.reefapi.com/govdeals/v1/search — 2 credits
Search LIVE GovDeals lots — the auction marketplace US state and city agencies, school districts, police departments, transit authorities and utilities use to sell surplus trucks, heavy equipment, buses, patrol cars, generators, lab gear and land (~25 000 open lots across 59 states and provinces, measured 2026-10-06). Every row carries the auction facts a price alone cannot give you: current bid with its basis, bid increment, reserve state, the resolved end time in UTC, the selling agency and where the lot physically is. Give query, or category_id, or seller_id, or state, or zip (at least one).

**Parameters:**
- `query` (string, optional) — Keyword text, 1-200 characters, matched against the lot title. Use * for everything. At least one of query, category_id, seller_id, state or zip is required.
- `category_id` (string, optional) — GovDeals category code from the categories action, for example 64I (Trucks, Miscellaneous), 94C (Trucks), 57 (Laboratory Equipment). Codes mix digits and letters, so pass it as a string.
- `state` (string, optional) — Two-letter US state or Canadian province code of the lot's physical location, for example TX, OH, CA, ON. 59 values are live; the locations action lists them with counts.
- `zip` (string, optional) — Five-digit US ZIP to search around. Combine with radius_miles; on its own the source applies its default radius.
- `radius_miles` (integer, optional) — Search radius in miles around zip. Measured to bite: a truck search around 30301 went from 6 954 lots to 918 at 50 miles.
- `seller_id` (integer, optional) — Numeric selling-agency id (the source's accountId) as search rows and the sellers action return it.
- `seller_type` (enum, optional) — Restrict to one class of seller. Omit for all three. [one of: government, commercial, nonprofit]
- `condition` (enum, optional) — The source's own condition code. GovDeals publishes the code only, never a label, so the codes are passed through unchanged and the live counts above are the measurement. [one of: SD, N, S]
- `auction_type` (enum, optional) — Sale format. Omit for every format. [one of: auction, make_offer, buy_now]
- `currency` (enum, optional) — Restrict to lots priced in one currency. [one of: usd, cad]
- `make` (string, optional) — Manufacturer or brand as the agency typed it, for example Ford, Caterpillar, John Deere. Measured to bite: truck + Ford went from 6 954 to 661 lots.
- `model` (string, optional) — Model designation as the agency typed it, for example F-350, 320CL.
- `model_year` (integer, optional) — Model year. Measured to bite: truck + 2015 went from 6 954 to 152 lots.
- `min_price` (number, optional) — Lowest current bid, inclusive, in the lot's own currency. Verified against the rows, not only the count: min_price 10000 returned rows whose cheapest current bid was exactly 10000.00.
- `max_price` (number, optional) — Highest current bid, inclusive.
- `reserve_not_met` (boolean, optional, default false) — Only lots that carry a reserve the bidding has NOT yet reached — where a bid can still win below the agency's floor. Verified on the rows: 48/48 returned lots had a reserve and it was unmet.
- `closing_within_days` (integer, optional) — Only lots whose auction closes within this many days. Measured to bite: 1 day 23 lots, 3 days 83, 7 days 259 for the same keyword. Cannot be combined with listed_within_days.
- `listed_within_days` (integer, optional) — Only lots first listed within this many days. Measured to bite: 3 days 152 lots, 7 days 167. Cannot be combined with closing_within_days.
- `sort` (enum, optional, default "best_match") — Result ordering. Each value was verified to actually reorder the result; the source's lotnumber sort reproduced price_high and is therefore not published. [one of: best_match, ending_soonest, ending_latest, price_low, price_high, newest]
- `page` (integer, optional, default 1) — One-based result page. last_page in the response is the final page that carries rows; past it the source answers with zero rows rather than repeating the last page (measured).
- `limit` (integer, optional, default 24) — Rows per page, 1 to 200. A real handle: every value from 1 to 200 was honoured exactly.

**Returns:** total (the source's own uncapped result count), page, limit, last_page, has_more, page_beyond_last, measured_at_utc, and listings[]: item_id (asset-account), asset_id, account_id, auction_id, title, url, lot_number, current_bid with price_basis (current_bid or final_price), currency, bid_increment, buy_now_price, has_reserve, reserve_met, next_bid_meets_reserve, reserve_reduced, ends_at (ISO-8601 UTC, from the source's own UTC field), ends_at_local (the raw US Eastern string), ends_at_zone_label, ends_at_offset_hours, starts_at_local, seconds_remaining, ended, is_sold, source_time_remaining, auction_type, sale_event_id, seller, seller_id, category_id, category_name, make, model, model_year, city, state, state_name, zip, country, is_new_listing and image_url. Measured on 384 rows over eight queries: every field above is populated except make (259/384), model (231/384), model_year (184/384), sale_event_id (50/384) and next_bid_meets_reserve (104/384, only lots with a reserve). The source does NOT carry a bid count in its search payload (null on 384/384 rows) — the detail action fetches it.

**Example request body:**
```json
{
  "query": "dump truck",
  "sort": "ending_soonest",
  "limit": 24
}
```

### POST https://api.reefapi.com/govdeals/v1/sold — 2 credits
Closed GovDeals auctions — the same rows after the hammer, where current_bid is the FINAL price the lot sold for and price_basis says final_price. A sold-price comparable set for valuing used municipal fleet and equipment: 124 055 closed lots were reachable when measured. Sort ending_latest for the most recently closed first.

**Parameters:**
- `query` (string, optional) — Keyword text, 1-200 characters. Use * for everything. At least one of query, category_id, seller_id, state or zip is required.
- `category_id` (string, optional) — GovDeals category code from the categories action.
- `state` (string, optional) — Two-letter state or province code of the lot's location.
- `zip` (string, optional) — Five-digit US ZIP to search around.
- `radius_miles` (integer, optional) — Search radius in miles around zip.
- `seller_id` (integer, optional) — Numeric selling-agency id (the source's accountId).
- `seller_type` (enum, optional) — Restrict to one class of seller. [one of: government, commercial, nonprofit]
- `condition` (enum, optional) — The source's own condition code, passed through unchanged. [one of: SD, N, S]
- `auction_type` (enum, optional) — Sale format. [one of: auction, make_offer, buy_now]
- `currency` (enum, optional) — Restrict to lots priced in one currency. [one of: usd, cad]
- `make` (string, optional) — Manufacturer or brand as the agency typed it.
- `model` (string, optional) — Model designation as the agency typed it.
- `model_year` (integer, optional) — Model year.
- `min_price` (number, optional) — Lowest final price, inclusive.
- `max_price` (number, optional) — Highest final price, inclusive.
- `sort` (enum, optional, default "ending_latest") — Result ordering; ending_latest is the useful one for a comparable set. [one of: ending_latest, ending_soonest, price_high, price_low, best_match, newest]
- `page` (integer, optional, default 1) — One-based result page.
- `limit` (integer, optional, default 24) — Rows per page, 1 to 200.

**Returns:** The same listing shape as search, with current_bid carrying the FINAL sale price, price_basis final_price, is_sold true, ended true and a negative seconds_remaining; plus total, page, limit, last_page, has_more and page_beyond_last. The source does NOT accept a 'closed within N days' window on this surface (1, 7 and 30 days all returned the identical 124 055), so no such parameter is published — use sort=ending_latest.

**Example request body:**
```json
{
  "query": "truck",
  "sort": "ending_latest",
  "limit": 24
}
```

### POST https://api.reefapi.com/govdeals/v1/detail — 2 credits
Everything GovDeals publishes about one lot, including the live auction state its search payload leaves out. Two upstream calls: the lot record (full description, every photo, VIN or serial, odometer, the agency's payment / removal / inspection terms, the physical address with coordinates) and the bid box (bid COUNT, current bid, masked high bidder, buyer premium percentage, watcher and view counters, auto-extension, and the end time in UTC).

**Parameters:**
- `asset_id` (string, required) — The lot's asset id. The combined item_id search returns ('276-23609') is also accepted here on its own and fills account_id.
- `account_id` (integer, optional) — The selling agency's numeric id. Required unless asset_id was given in the combined asset-account form; a GovDeals lot is identified by the pair, not by the asset id alone.

**Returns:** item_id, asset_id, account_id, auction_id, title, url, description, lot_number, quantity, quantity_available, quantity_unit, condition_code, category_id / category_name / parent_category_id / parent_category_name / category_path[], make, model, model_year, vin_or_serial, meter_unit, meter_reading, weight, nsn, sku, inventory_id, title_restriction, restriction, will_ship, attributes[] (the agency's own label/value groups), images[], image_count, question_count, sale_event_id, sale_event_title, seller{seller_id, name, type_code, department, website, logo_url}, location{address, city, state, zip, country, latitude, longitude, warehouse}, payment_instructions, removal_instructions, inspection_instructions, special_instructions, is_cross_listed, status_code, measured_at_utc, and auction{current_bid, bid_count, high_bidder (source-masked), opening_bid, bid_increment, buy_now_price, buyer_premium_percent, auto_extension, watchers, page_views, ends_at, ends_at_local, ends_at_zone_label, ends_at_offset_hours, starts_at, seconds_remaining, ended, status_code}.

**Example request body:**
```json
{
  "asset_id": "38552-767",
  "account_id": 767
}
```

### POST https://api.reefapi.com/govdeals/v1/bids — 2 credits
The public bid log for one lot: every bid with the source-masked bidder handle, the amount and the timestamp, plus the source's own bid count. Works on live auctions as well as closed ones — on a closed lot the highest row IS the hammer price, cross-checked against the sold row and the bid box on three lots.

**Parameters:**
- `asset_id` (string, required) — The lot's asset id, or the combined item_id search returns ('38552-767').
- `account_id` (integer, optional) — The selling agency's numeric id. Required unless asset_id was given in the combined form.
- `auction_id` (integer, optional) — Which auction round of this lot to read. Omit and the engine reads it off the lot record first, so the count matches the auction currently shown on the site; relisted lots have more than one round.
- `all_auctions` (boolean, optional, default false) — Return every bid the lot ever received across all of its auction rounds instead of just the current one. Measured on one relisted lot: 1 bid in the current round, 7 across all rounds.
- `page` (integer, optional, default 1) — One-based page of the bid log.
- `limit` (integer, optional, default 100) — Bid rows per page, 1 to 200.

**Returns:** item_id, asset_id, account_id, auction_id, url, total (the source's own bid count for this scope), page, limit, returned, highest_bid, all_auctions, and bids[]: bidder (source-masked, for example te*****), bid_amount, placed_at_local (the source's raw US Eastern string), placed_at_zone_label and is_highest_bid. The source publishes bid timestamps only as naive local strings on this endpoint, with no UTC twin, so no UTC form is invented.

**Example request body:**
```json
{
  "asset_id": "38552-767",
  "account_id": 767
}
```

### POST https://api.reefapi.com/govdeals/v1/questions — 1 credit
The public question-and-answer thread on one lot: what other bidders asked the selling agency and what the agency answered. This is where the facts that are missing from the listing live — capacity, hours, faults, whether it runs.

**Parameters:**
- `asset_id` (string, required) — The lot's asset id, or the combined item_id search returns ('276-23609').
- `account_id` (integer, optional) — The selling agency's numeric id. Required unless asset_id was given in the combined form.

**Returns:** item_id, asset_id, account_id, url, total and questions[]: question, answer, asked_by (the handle the source itself publishes), asked_at_local, answered_at_local and is_answered. An empty questions[] with total 0 is an honest answer, not an error — most lots have none.

**Example request body:**
```json
{
  "asset_id": "276-23609",
  "account_id": 23609
}
```

### POST https://api.reefapi.com/govdeals/v1/categories — 2 credits
The GovDeals category tree with the live lot count on every node: 14 top-level segments and 629 nodes in all when measured. The id on each node is exactly what the search action's category_id takes.

**Parameters:**
- `top_level_only` (boolean, optional, default false) — Return only the 14 top-level segments without their children.
- `flat` (boolean, optional, default false) — Return every node in one flat list (each with its parent_id and level) instead of nested.

**Returns:** categories[]: id, name, slug, parent_id, level, live_lot_count and nested children[] of the same shape; plus top_level_count and total_count.

**Example request body:**
```json
{
  "top_level_only": false
}
```

### POST https://api.reefapi.com/govdeals/v1/locations — 1 credit
Where the live lots physically are: the source's own region / country / state tree with a live lot count on every node (59 state and province nodes when measured). The state code on each leaf is what the search action's state parameter takes.

**Parameters:**
- `flat` (boolean, optional, default false) — Return every node in one flat list instead of nested.

**Returns:** locations[]: id (the state or province code on a leaf), name, slug, parent_id, level, live_lot_count and nested children[]; plus total_count. sale_types[] is served by the same action: id, name, slug and live_lot_count for each sale format (online auction, make offer, buy now).

**Example request body:**
```json
{
  "flat": false
}
```

### POST https://api.reefapi.com/govdeals/v1/sellers — 1 credit
Selling agencies near a US ZIP code, with how far away each one is and how many lots it currently has open — the way to find every surplus auction within driving distance, which matters because most GovDeals lots are pickup-only. Measured: 100 miles around 30301 returned 85 agencies.

**Parameters:**
- `zip` (string, required) — Five-digit US ZIP to search around.
- `radius_miles` (integer, optional, default 100) — Radius in miles. Measured to bite: 25 miles 23 agencies, 100 miles 85.
- `min_lots` (integer, optional) — Drop agencies with fewer than this many open lots.

**Returns:** zip, radius_miles, total, returned and sellers[]: seller_id (the id the search action's seller_id takes), name, location_id, open_lot_count, distance_miles, has_new_listing, address{address1, address2, city, state, zip}, latitude, longitude.

**Example request body:**
```json
{
  "zip": "30301",
  "radius_miles": 100
}
```

### POST https://api.reefapi.com/govdeals/v1/suggest — 1 credit
What GovDeals buyers actually search for: the site's own autocomplete, returning trending search phrases and matching lot titles for a prefix. A keyword corpus straight from the source, useful for building the query a search call should run.

**Parameters:**
- `query` (string, required) — Partial keyword, 1-100 characters.

**Returns:** query, total and suggestions[]: term, kind (trend for a search phrase the source is trending, product for a matching lot title), source_id and score as the source ranks them.

**Example request body:**
```json
{
  "query": "trac"
}
```

## At scale
- **Volume:** 5M+ requests a day, measured at 60 requests a second across the fleet with no
  central bottleneck. Per-key limits are raised for high-volume accounts; volume pricing on request.
- **Missing a source:** tell us a site we do not cover and it becomes an engine. A customer asked
  for bestprice.gr on 21 Sep 2026 and it was in the catalog on 22 Sep.
- **Support:** 2 minute median time from a question in the live chat to the first answer. Setup
  help included, no support tier to buy.
- **One key, one credit pool** across every API. No per-site plans, no separate subscriptions.

## More
- Try it live, no code: https://reefapi.com/playground?engine=govdeals
- Human docs page: https://reefapi.com/docs/govdeals
- Overview page: https://reefapi.com/govdeals-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
