Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: encarapi Discovery API
version: 1.3.0
description: 'Real-time Korean used-car data from the full Encar inventory, served as clean JSON. Filter the whole catalog with simple **English** query parameters (or the advanced `q` query syntax). Add `lang=en` to receive every value in English. Discover all valid filter values at `/api/enums`. ## SDKs & AI agents
- Node.js: `npm install encarapi`
- Python: `pip install encarapi`
- AI agents (Claude, ChatGPT, Cursor, VS Code): add the MCP server `https://mcp.encarapi.com/mcp` and sign in with your API key in the browser. Claude Code: `claude mcp add --transport http encarapi https://mcp.encarapi.com/mcp`
## Catalog scope
`/api/catalog` covers standard-sale listings only (Encar''s "일반" sell type). Lease-takeover ("리스") and rental ("렌트") listings are a separate endpoint, `/api/catalog/leasing` - they price by monthly payment rather than a purchase price, so mixing them into `/api/catalog` would distort `Price`. For a brand with e.g. 16,000 total Encar listings, expect roughly 5-10% to be lease/rental. ## Caching
Recommended cache times:
- `/api/enums`, the taxonomy CSVs and `/api/nav`: 24 hours (makes, models, badges and filter values barely change)
- `/api/catalog` listings: 4 to 6 hours
- `/api/vehicle/{id}` details: 24 hours (a listing''s specs change rarely; it only drops out when sold)
Serve listings from your own database and refresh periodically rather than calling live on every user click. Fair use applies. ## Live queries vs. a local copy
There are two supported ways to use this API - pick the one that matches what you are building:
- **Starter - live queries.** Call `/api/catalog` with the filters your users actually search for and cache each response for the times above. This is the default, and it is what the per-key daily catalog-row cap protects (re-pulling the entire catalog on this plan will eventually hit it). - **Business / Scale - a local copy.** Pull `/api/catalog/export` once for a full baseline (does not count against the daily cap), then keep it current with `/api/catalog/changes?since=` instead of re-dumping the whole catalog. Scale additionally has no daily catalog-row cap. Both are 403 on Starter. ## Duplicate listings
Korean dealers commonly list the same physical car twice (sometimes more) under different listing IDs for extra visibility. We detect these and flag the extra copies with `IsDuplicate: true` and `DuplicateOf: ` on the catalog item; the original listing is left unflagged. Duplicates are flagged, not removed, so you can decide how to treat them. `/api/catalog` and `/api/catalog/leasing` accept `exclude_duplicates=true` to filter them out server-side. `/api/catalog/changes` stays a complete, lossless event log (no filtering there) - it still carries `IsDuplicate`/`DuplicateOf` on every item, so filter client-side if you keep a local copy of the catalog. ## Data sources - Encar, KB Chachacha and K Car
The API serves listings from three Korean platforms:
| Source | Platform | Live listings | Depth |
|---|---|---|---|
| `encar` | Encar (encar.com) | 190,000+ | full detail, inspection and insurance reports (default) |
| `kbc` | KB Chachacha (kbchachacha.com) | 110,000+ | catalog plus public history block |
| `kcar` | K Car (kcar.com, direct-sale channel) | 5,000+ | full detail incl. VIN and accident history |
**Plans.** Encar is part of every plan. KB Chachacha and K Car are included in Business and Scale and in the 5-day trial, and are an add-on for Starter. A key without them gets 403 with a hint on `source=kbc`, `kcar` or `all`. **Trial.** The trial includes 100,000 catalog rows and 2,000 detail lookups in total, with at most 1,000 detail lookups per day. Catalog rows are counted over the whole trial across `/api/catalog`, `/api/catalog/leasing` and the items of `/api/catalog/changes`, with at most 100 items per request; detail lookups are `/api/vehicle/{id}`, `/api/inspection/{id}` and `/api/record/{id}` together - the daily budget resets at 00:00 UTC, the totals do not.'
contact:
name: encarapi
url: https://encarapi.com
servers:
- url: https://api.encarapi.com
description: Production
security:
- ApiKeyHeader: []
- ApiKeyQuery: []
tags:
- name: Discovery
description: Filter facets & valid values
paths:
/api/enums:
get:
tags:
- Discovery
summary: Valid filter values
description: 'Every valid English value per filter field, with live counts. Ideal for building filter menus. Also lists `region` (every region code with name and count) and `city` (Encar cities: `value` for ?city=, English `name`, Korean `ko`, `region`, `count`). With ?source= set, every value additionally carries a per-source `sources` breakdown and the response gains a top-level `source` list with live counts per platform (`region` and `city` are listed on the default /api/enums only). With `lang=ru`, every value also carries `nameRu` (its Russian label) and the response lists the `drivetrain` and `sell_type` values the filters take, each with `nameRu`. With `lang=de` the same with `nameDe` (German).'
parameters:
- name: source
in: query
schema:
type: string
default: encar
example: all
description: 'Data source(s): `encar` (default), `kcar`, `kbc`, a comma-separated list (`encar,kbc`), or `all`. Omitted = Encar only, byte-identical to pre-1.1.0 responses. When set, each item carries a `Source` field (plus `Url`, `Transmission`, `Color`, `Options`, `SeatCount` on K Car / KB Chachacha items). Filtering on a field a source does not provide excludes that source''s vehicles (see "Data sources" above).'
- name: lang
in: query
schema:
type: string
enum:
- ru
- de
description: ru = add the Russian label `nameRu` to every value and list `drivetrain` and `sell_type`; de = the same with the German label `nameDe`.
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EnumsResponse'
operationId: getApiEnums
x-operation-id-source: derived
/api/nav:
get:
tags:
- Discovery
summary: Filter facets (iNav tree)
description: Available facet values with counts for the current selection. Respects `lang=en` and `lang=ru` (Russian `DisplayValue`; `Value` stays the English code for filtering). Accepts ?source= for cross-platform make/model facets.
parameters:
- name: manufacturer
in: query
description: Brand. Comma-separated = OR.
schema:
type: string
example: bmw
- name: model_group
in: query
description: Model line (English name or Korean token).
schema:
type: string
example: 3-series
- name: model
in: query
description: Specific generation.
schema:
type: string
- name: fuel
in: query
description: Fuel type.
schema:
type: string
enum:
- gasoline
- diesel
- hybrid
- diesel-hybrid
- lpg-hybrid
- gasoline-lpg
- cng
- electric
- lpg
- hydrogen
- other
example: diesel
- name: transmission
in: query
description: Transmission type.
schema:
type: string
enum:
- automatic
- manual
- cvt
- semi-automatic
- other
example: automatic
- name: color
in: query
description: Exterior / paint color.
schema:
type: string
enum:
- white
- black
- gray
- blue
- silver
- silver-gray
- pearl
- red
- sky-blue
- green
- dark-green
- light-green
- brown
- yellow
- orange
- purple
- maroon
- turquoise
- gold
- pink
example: black
- name: seat_color
in: query
description: Interior / seat color.
schema:
type: string
enum:
- black
- brown
- beige
- gray
- red
- white
- blue
- green
- orange
- yellow
example: beige
- name: category
in: query
description: Body category.
schema:
type: string
enum:
- suv
- rv
- large
- midsize
- compact
- small
- kei
- van
- light-van
- truck
- sports
- other
example: suv
- name: seats
in: query
description: Number of seats. Comma = OR (e.g. 5,7).
schema:
type: string
example: 7,9
- name: min_seats
in: query
description: Minimum seats.
schema:
type: integer
- name: max_seats
in: query
description: Maximum seats.
schema:
type: integer
- name: options
in: query
description: Equipment codes; the car must have all listed. Comma-separated.
schema:
type: string
example: 001,024
- name: min_price
in: query
description: Min price in 만원 (1 = 10,000 KRW).
schema:
type: integer
example: 2000
- name: max_price
in: query
description: Max price in 만원 (1 = 10,000 KRW).
schema:
type: integer
example: 5000
- name: min_year
in: query
description: Min model year (4-digit).
schema:
type: integer
example: 2021
- name: max_year
in: query
description: Max model year (4-digit).
schema:
type: integer
- name: min_mileage
in: query
description: Min mileage in km.
schema:
type: integer
- name: max_mileage
in: query
description: Max mileage in km.
schema:
type: integer
example: 100000
- name: lang
in: query
description: Set to 'en' for English values, 'ru' for Russian or 'de' for German ones (English where no Russian or German label exists).
schema:
type: string
enum:
- en
- ru
- de
example: en
- name: q
in: query
description: Advanced query syntax (alternative to the flat parameters above).
schema:
type: string
- name: badge_group
in: query
schema:
type: string
example: c43-amg-4matic-coupe
description: Badge / trim group - this is where the body-style split lives (Coupe vs Sedan vs Cabriolet). Use a value from /api/taxonomy/badges.csv or /api/nav; filter on this instead of parsing the title.
- name: badge
in: query
schema:
type: string
description: Exact badge (finest trim level), value from /api/nav.
- name: drivetrain
in: query
schema:
type: string
example: 4wd
description: Drivetrain (e.g. 2wd / 4wd). Values from /api/nav.
- name: model_search
in: query
schema:
type: string
example: s63 coupe
description: Cross-brand free-text model search. ";"-separated phrases are OR-combined (e.g. "s63 coupe;m5"). Matches make/model/badge names. See also GET /api/model-search for autocomplete.
- name: min_ps
in: query
schema:
type: integer
description: Minimum engine power in PS.
- name: max_ps
in: query
schema:
type: integer
description: Maximum engine power in PS.
- name: max_owners
in: query
schema:
type: integer
example: 1
description: Maximum number of previous owners.
- name: frame_clean
in: query
schema:
type: boolean
example: true
description: true = only accident-free cars (clean chassis frame).
- name: no_damage_cost
in: query
schema:
type: boolean
description: true = only cars with zero insurance-reported repair cost. A missing insurance record counts as zero - combine with has_record=true to drop cars whose history is unknown.
- name: max_damage_eur
in: query
schema:
type: integer
example: 3000
description: Maximum insurance-reported repair cost in EUR (own + caused). A missing insurance record counts as zero - combine with has_record=true to drop cars whose history is unknown.
- name: no_repairs
in: query
schema:
type: boolean
description: true = only cars with no recorded panel repairs. A missing inspection report counts as zero repairs - combine with has_inspection=true to drop cars without a report.
- name: exclude_prices
in: query
schema:
type: string
example: 1111,9999
description: Comma-separated prices (in 10,000 KRW) to exclude. Korean dealers mark reserved cars with placeholder prices such as 1111 or 9999; pass them here to hide those listings server-side so Count and paging stay correct. Max 50 values.
- name: has_record
in: query
schema:
type: boolean
description: true = only cars with an insurance history record (GET /api/record/{id} available). Encar sellers can withhold the record; those cars have unknown damage cost and are otherwise included by no_damage_cost / max_damage_eur.
- name: has_inspection
in: query
schema:
type: boolean
description: true = only cars with an official inspection report (GET /api/inspection/{id} available). Encar listings only.
- name: usage_change
in: query
schema:
type: string
example: rental,commercial
description: 'Comma-separated usage changes recorded on the official inspection report (용도변경): `rental` (렌트), `commercial` (영업용), `government` (관용). Returns cars with ANY of the listed changes. Source field: `master.detail.usageChangeTypes` in GET /api/inspection/{id}. Encar listings only - K Car and KB Chachacha listings drop out when this filter is set.'
- name: no_usage_change
in: query
schema:
type: boolean
description: true = only cars whose inspection report lists no usage change (never a rental, commercial or government vehicle). Cars without an inspection report are excluded. Encar listings only.
- name: has_photos
in: query
schema:
type: boolean
description: true = only listings that have photos.
- name: min_first_seen
in: query
schema:
type: string
format: date-time
example: '2026-09-01T00:00:00Z'
description: Only listings we have known about since this ISO 8601 timestamp or later - filter the live catalog by discovery date without calling /api/catalog/changes.
- name: exclude_duplicates
in: query
schema:
type: boolean
description: true = exclude listings we have detected as a duplicate of another listing (see the "Duplicate listings" section above). Off by default - duplicates are flagged, not hidden, unless you opt in.
- name: region
in: query
schema:
type: string
example: gyeonggi,seoul
description: 'Comma-separated region codes (also accepts the English or Korean name): seoul, gyeonggi, incheon, busan, daegu, daejeon, ulsan, gwangju, sejong, gangwon, chungbuk, chungnam, jeonbuk, jeonnam, gyeongbuk, gyeongnam, jeju. Works on Encar (no ?source=) and on one single source (?source=kbc or ?source=kcar); a mix of sources (e.g. encar,kbc or all) answers 400. Unknown values answer 400. See "Region and city" above.'
- name: city
in: query
schema:
type: string
example: suwon
description: 'Comma-separated cities: the `value` from /api/enums -> city (e.g. `suwon`, `gangnam`), the English name (`Suwon-si`) or the Korean name (`수원시`). Encar listings only (KB Chachacha and K Car publish the province only; with ?source= set the filter answers 400 - use ?region= there). Names shared by several cities (e.g. `jung` = every Jung-gu) match all of them - combine with ?region= to pick one.'
- name: source
in: query
schema:
type: string
default: encar
example: all
description: 'Data source(s): `encar` (default), `kcar`, `kbc`, a comma-separated list (`encar,kbc`), or `all`. Omitted = Encar only, byte-identical to pre-1.1.0 responses. When set, each item carries a `Source` field (plus `Url`, `Transmission`, `Color`, `Options`, `SeatCount` on K Car / KB Chachacha items). Filtering on a field a source does not provide excludes that source''s vehicles (see "Data sources" above).'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
operationId: getApiNav
x-operation-id-source: derived
/api/model-search:
get:
tags:
- Discovery
summary: Model autocomplete
description: 'Cross-brand free-text suggestions for a search box. Given text like "s63" or "m3 coupe", returns distinct make / model / badge matches with counts, each with an English and a German label. Input is multilingual: besides the Korean names and Latin tokens from the raw data ("a6", "s63", "bmw"), English and German make / model names are resolved to the Korean values through our translation tables (tokens of 3+ characters), so "audi a6", "mercedes s63", "volkswagen golf" or "c-klasse" return results. `results` lists make / model line / badge group matches; `groups` lists the matching model lines (max 8) with exact counts, so you can offer the whole line above its variants. Use the returned values as ?model_search= (or ?manufacturer=/?model_group=) on /api/catalog. Pass the same exclude_duplicates / has_photos / exclude_prices / min_price you send to /api/catalog so the suggestion counts match your filtered result list. Accepts ?source=, but suggestions are grouped on badge_group, which only Encar provides - so in practice matches come from Encar listings only. Use /api/nav with ?source= for cross-platform make/model discovery.'
parameters:
- name: search
in: query
required: true
schema:
type: string
example: s63 coupe
description: Free-text query.
- name: limit
in: query
schema:
type: integer
default: 20
description: Max suggestions (max 50).
- name: exclude_duplicates
in: query
schema:
type: boolean
description: true = count only listings that are not flagged as a duplicate - same meaning as on /api/catalog. Optional, off by default.
- name: has_photos
in: query
schema:
type: boolean
description: true = count only listings that have photos - same meaning as on /api/catalog. Optional, off by default.
- name: exclude_prices
in: query
schema:
type: string
example: 1111,9999
description: Comma-separated placeholder prices (in 10,000 KRW) to leave out of the counts - same meaning as on /api/catalog. Max 50 values.
- name: min_price
in: query
schema:
type: integer
description: Count only listings at or above this price (in 10,000 KRW) - same meaning as on /api/catalog.
- name: source
in: query
schema:
type: string
default: encar
example: all
description: 'Data source(s): `encar` (default), `kcar`, `kbc`, a comma-separated list (`encar,kbc`), or `all`. Omitted = Encar only, byte-identical to pre-1.1.0 responses. When set, each item carries a `Source` field (plus `Url`, `Transmission`, `Color`, `Options`, `SeatCount` on K Car / KB Chachacha items). Filtering on a field a source does not provide excludes that source''s vehicles (see "Data sources" above).'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/ModelSearchResponse'
'401':
$ref: '#/components/responses/Unauthorized'
operationId: getApiModelSearch
x-operation-id-source: derived
components:
schemas:
ModelSearchGroup:
type: object
description: One model line matching the search, with its exact live listing count.
properties:
manufacturer:
type: string
example: 아우디
manufacturerEn:
type: string
example: Audi
modelGroup:
type: string
example: A6
modelGroupEn:
type: string
example: A6
modelGroupDe:
type: string
example: A6
count:
type: integer
example: 1240
EnumsResponse:
type: object
properties:
fuel:
type: array
items:
$ref: '#/components/schemas/EnumValue'
transmission:
type: array
items:
$ref: '#/components/schemas/EnumValue'
color:
type: array
items:
$ref: '#/components/schemas/EnumValue'
seat_color:
type: array
items:
$ref: '#/components/schemas/EnumValue'
category:
type: array
items:
$ref: '#/components/schemas/EnumValue'
seats:
type: array
items:
$ref: '#/components/schemas/EnumValue'
source:
type: array
description: Only present when the request sets ?source=. Always lists all three valid values for the ?source= param (encar, kcar, kbc) with total live listing counts per platform - regardless of which sources were requested.
items:
$ref: '#/components/schemas/EnumValue'
ModelSearchResponse:
type: object
properties:
results:
type: array
description: Suggestions, most listings first (up to `limit`).
items:
$ref: '#/components/schemas/ModelSearchResult'
groups:
type: array
description: Model lines matching the search with exact counts, most listings first (max 8). Absent when `search` is empty.
items:
$ref: '#/components/schemas/ModelSearchGroup'
ModelSearchResult:
type: object
description: 'One suggestion: a make / model line / badge group combination with its live listing count.'
properties:
manufacturer:
type: string
example: 아우디
manufacturerEn:
type: string
example: Audi
modelGroup:
type: string
example: A6
modelGroupEn:
type: string
example: A6
modelGroupDe:
type: string
description: German model line label (falls back to the English label).
example: A6
badgeGroup:
type: string
example: 45 TFSI 콰트로
badgeGroupEn:
type: string
example: 45 TFSI Quattro
badgeGroupDe:
type: string
description: German badge group label (falls back to the English label).
example: 45 TFSI Quattro
count:
type: integer
example: 212
EnumValue:
type: object
properties:
value:
type: string
count:
type: integer
sources:
type: object
description: 'Per-source share of `count`. Only present when the request sets ?source=, and contains only the requested sources (e.g. { "encar": 61200, "kbc": 1901 } for source=encar,kbc). Default responses omit it.'
additionalProperties:
type: integer
responses:
Unauthorized:
description: Missing or invalid API key.
securitySchemes:
ApiKeyHeader:
type: apiKey
in: header
name: x-api-key
description: Your API key.
ApiKeyQuery:
type: apiKey
in: query
name: api_key
description: Your API key (alternative to the header).