Getting Started
Start using the BDS Chat API in three steps. Endpoints return JSON over HTTPS and expose rate-limit headers for integration testing.
Register for an API Key
Create a free account to get your API key. Free tier includes 100 requests/day.
Make Your First Request
Add your key as a Bearer token and search listings: GET /listings?district=Binh+Tan&limit=5
Enrich with Reference Data
Use /meta/gov-land-price, /meta/zoning, and /meta/risk/check to add risk and reference context.
https://api.bds.chat. All responses are JSON with Content-Type: application/json. Every response includes an X-Request-ID header for traceability.Authentication
The BDS Chat API uses Bearer token authentication. Include your API key in the Authorization header of every request.
Access Tiers
| Tier | Daily Limit | Endpoints | Features |
|---|---|---|---|
| Anonymous | 10 req/day | /health, /openapi.yaml | Read-only public |
| Free | 100 req/day | + /listings, /listings/{id} | Search + detail |
| Pro | 10,000 req/day | + /meta/*, /listings/{id}/chat | Full API + chat |
| Partner | Custom | All + /admin/* | Sync, enrichment |
Auth Header Format
Authorization: Bearer bds_live_abc123def456...Rate Limiting
Every API response includes rate limit headers so you can track usage in real time.
Response Headers
| Header | Description |
|---|---|
X-RateLimit-Limit | Your daily request quota |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | UTC epoch when the window resets |
Retry-After | Seconds to wait (only on 429) |
X-Request-ID | Unique request identifier (UUID v7) |
Handling 429 Too Many Requests
When you exceed your rate limit, the API returns 429 with a Retry-After header. Implement exponential backoff.
Search and filter real estate listings across Ho Chi Minh City. Supports district, price, area, legal status, and seller type filters with configurable sorting and pagination.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
district | string | Optional | District name (diacritic-insensitive) |
ward | string | Optional | Ward name within district |
min_price | integer | Optional | Minimum price in VND |
max_price | integer | Optional | Maximum price in VND |
min_area | number | Optional | Minimum area in m² |
max_area | number | Optional | Maximum area in m² |
legal_status | string | Optional | so_do_so_hong, so_hong, so_hong_rieng, dang_cho_so, giay_tay |
seller_type | string | Optional | chinh_chu (direct owner) or moi_gioi (broker) |
sort | string | Optional | price_asc, price_desc, area_asc, area_desc, newest (default) |
limit | integer | Optional | Results per page (default: 20, max: 100) |
offset | integer | Optional | Pagination offset (default: 0) |
immutable_unaccent() so "Binh Tan" matches "Bình Tân" automatically.Retrieve complete details for a single listing including trust_grade, quality_score, risk_score, risk_band, gov_price_per_m2, market_gov_ratio, images, and provenance data.
Try it in Scalar →Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Required | Listing UUID. E.g. 985fafb9-8503-4e86-9056-d385851708ac |
Create a new listing. Requires Partner tier. Automatic deduplication on source + source_listing_id returns 409 Conflict if duplicate.
Try it in Scalar →Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Required | Listing title (Vietnamese) |
price_vnd | integer | Required | Price in VND |
area_m2 | number | Required | Area in square meters |
district | string | Required | District name |
ward | string | Optional | Ward name |
legal_status | string | Optional | Legal document status code |
seller_type | string | Optional | chinh_chu or moi_gioi |
source | string | Optional | Source platform identifier |
source_listing_id | string | Optional | External listing ID (for dedup) |
Look up state land prices from NQ 87/2025. Covers 30,775 street-level records across HCMC with price per m² by street, position, and road width.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
street | string | Optional | Street name (diacritic-insensitive) |
district | string | Optional | District name to narrow results |
limit | integer | Optional | Max results (default: 20) |
Compare a listing's asking price against the state land-price benchmark. Returns ratio, differential, and assessment.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
listing_id | string (UUID) | Required | Listing to compare |
Query zoning and urban planning data for a geographic coordinate. Returns zone code, LBCS classification, DGT road risk, and development constraints.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
lat | number | Required | Latitude (EPSG:4326) |
lon | number | Required | Longitude (EPSG:4326) |
Check zoning for a specific listing. Combines listing coordinates with zoning data to assess land use compatibility and planning constraints.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
listing_id | string (UUID) | Required | Listing to check |
Full risk assessment with 9 subscores and 5 blocking risk flags. Returns a final risk band from low to critical. Checks price reasonableness, location quality, listing completeness, source reputation, gov price alignment, and more.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
listing_id | string (UUID) | Required | Listing to assess |
Ask a natural-language question about a specific listing. Returns a streaming SSE response with AI-generated analysis grounded in listing data, government benchmarks, and zoning info.
Try it in Scalar →Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Required | Listing UUID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
question | string | Required | Natural language question about this listing |
Health check endpoint. Returns service status and version. No authentication required.
Try it in Scalar →Returns the full OpenAPI 3.1.0 specification. Useful for code generation, client SDKs, and API exploration. No authentication required.
Normalize ward names with 2025 ward reform awareness. Maps old ward names to current administrative units.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
ward | string | Required | Ward name to resolve |
district | string | Required | District context |
Look up legal references (decisions, decrees, circulars) relevant to real estate transactions.
Try it in Scalar →Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
topic | string | Optional | Filter by topic: land_price, zoning, construction, tax |
Streaming (SSE)
POST /listings/{id}/chat uses Server-Sent Events to stream listing-scoped responses. The answer should stay within returned listing data, citations, and visible gaps.
Event Types
| Type | Description | Payload |
|---|---|---|
text | Text chunk | {"type":"text","content":"..."} |
done | Stream complete | {"type":"done","tokens_used":87} |
error | Stream error | {"type":"error","message":"..."} |
Handling SSE in JavaScript
const res = await fetch(url, {
method: "POST",
headers: { "Authorization": `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({ "question": "Pháp lý listing này thế nào?" })
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// Parse SSE lines: event: type\ndata: {...}
}Error Handling
The API uses standard HTTP status codes. Error responses include JSON fields your integration can log and show without exposing internal details.
Status Codes
| Code | Meaning | When |
|---|---|---|
| 200 | OK | Successful request |
| 201 | Created | Resource created (POST /listings) |
| 400 | Bad Request | Invalid parameters or malformed JSON |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Insufficient tier for this endpoint |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Duplicate listing (dedup match) |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Error | Server error (report via X-Request-ID) |
Error Response Format
{
"error": "forbidden",
"message": "Pro tier required for /meta/* endpoints",
"request_id": "019726a3-4b5c-7d8e-9f0a-1b2c3d4e5f6a"
}Code Examples
curl "https://api.bds.chat/listings?district=Binh+Tan&max_price=5000000000&limit=10" \
-H "Authorization: Bearer bds_live_abc123"Resources
- OpenAPI Specification (machine-readable)
- Scalar Interactive Docs
- API Health Check
- Contact Support
Standards
- RESO Data Dictionary -- Property field naming conventions
- ISO 4217 -- VND currency code
- ISO 3166-2:VN -- VN-SG (Ho Chi Minh City)
- ISO 8601 -- Date/time formatting
- GeoJSON RFC 7946 -- Geographic data (EPSG:4326)
- APA LBCS -- Land-based classification codes
- W3C PROV -- Data provenance tracking