> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xapichina.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript integration

> Use Node.js fetch for supported China searches, pagination, details, and report coverage.

Run these examples on a Node.js server with built-in `fetch`, not in customer-facing browser JavaScript. This is a raw HTTP integration, not a China SDK.

## Setup

```bash theme={"system"}
export XAPICHINA_API_KEY="xcn_YOUR_KEY"
```

## Request helper

```javascript theme={"system"}
const apiKey = process.env.XAPICHINA_API_KEY
if (!apiKey) throw new Error('Set XAPICHINA_API_KEY')

const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds))

async function getJson(path, params = {}) {
  const url = new URL(path, 'https://api.xapichina.com')
  url.search = new URLSearchParams(
    Object.entries(params).map(([name, value]) => [name, String(value)])
  )
  for (let attempt = 0; attempt < 3; attempt++) {
    const response = await fetch(url, {
      headers: { 'X-API-Key': apiKey },
      signal: AbortSignal.timeout(45_000)
    })
    const retryAfter = response.headers.get('Retry-After')
    const transient = [502, 503].includes(response.status)
    const throttled = response.status === 429 && retryAfter !== null
    if (attempt < 2 && (transient || throttled)) {
      const hinted = retryAfter !== null ? Number(retryAfter) : NaN
      const delay = Number.isFinite(hinted) ? Math.max(1, hinted) : 2 ** attempt
      await response.arrayBuffer()
      await sleep(delay * 1000 + Math.random() * 250)
      continue
    }
    const contentType = response.headers.get('Content-Type') ?? ''
    const body = contentType.includes('application/json')
      ? await response.json()
      : { detail: await response.text() }
    if (!response.ok) {
      throw new Error(`XAPI China HTTP ${response.status}: ${JSON.stringify(body.detail ?? body)}`)
    }
    return body
  }
}
```

Monthly-quota errors without `Retry-After` fail rather than loop. A shared account queue remains necessary when several workers use the same key or account.

## Search within a budget

```javascript theme={"system"}
const allowance = await getJson('/v1/me')
console.log(allowance.plan, allowance.remaining)

const result = await getJson('/v1/search', {
  brand: 'BMW', currency: 'eur', price_min: 15000, price_max: 30000,
  page: 1, lang: 'en'
})
for (const car of result.results) {
  console.log(car.id, car.title, car.price_cny, car.price_eur)
}
```

EUR budget bounds [round inward](/currencies-and-prices). China search has no `limit` or year-bound parameters.

## Paginate with a request budget

```javascript theme={"system"}
async function* searchPages(filters, maximumPages = 3, spacingMs = 12_000) {
  let page = 1
  const seen = new Set()
  for (let count = 0; count < maximumPages; count++) {
    const result = await getJson('/v1/search', { ...filters, page })
    for (const car of result.results) {
      if (!seen.has(car.id)) {
        seen.add(car.id)
        yield car
      }
    }
    page = result.next_page
    if (page === null) return
    await sleep(spacingMs)
  }
}

for await (const car of searchPages({ brand: 'BMW', lang: 'en' })) {
  console.log(car.id, car.title)
}
```

The default spacing illustrates one Free-plan worker. Count allowance checks, previous requests, and other workers when setting your actual pacing.

## Read source and report data

```javascript theme={"system"}
const carId = '59967821' // replace with a current search result
const detail = await getJson(`/v1/cars/${carId}`, { lang: 'en' })
console.log(detail.photos, detail.che168?.electric_vehicle)

const report = await getJson(`/v1/cars/${carId}/inspection`, {
  lang: 'en', view: 'full'
})
console.log(report.available, report.data_available, report.parse_status)
for (const category of report.categories) {
  for (const item of category.items) {
    console.log(category.name, item.name, item.status, item.source_status)
  }
}
```

Every successful detail/report request counts. Pace the calls and retain unknown values. Read the [provider guide](/inspection-providers) before interpreting category counts or grades.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.