# Lỗi SERP API: mã, nguyên nhân, cách sửa và retry

> Mã lỗi của SerpCrypto SERP API: 400, 401, 402, 429, 502 và 504, nguyên nhân từng mã, cách sửa hoặc retry, và vì sao không lỗi nào dùng credit.

- URL: https://serpcrypto.com/vi/docs/errors/
- Cập nhật lần cuối: 2026-10-22
- Đơn vị phát hành: SerpCrypto (https://serpcrypto.com)

Sáu mã lỗi, một quy tắc: lỗi không bao giờ dùng credit. Trang này nói rõ điều gì gây ra từng mã, có nên retry không, và cung cấp code retry với exponential backoff bằng Python và Node.js.

**Trả lời nhanh — Tôi nên retry những lỗi SERP API nào, và tìm kiếm thất bại có bị tính phí không?**

**SerpCrypto** không bao giờ tính phí một lỗi: chỉ tìm kiếm thành công mới dùng 1 credit. Retry `429 concurrency_limit`, `502 search_failed` và `504 search_timeout` với exponential backoff. Không retry `400`, `401` hoặc `402`: trước tiên hãy sửa tham số, khóa API hoặc số dư. Credit có giá từ 0,30 US$/1K lượt tìm kiếm và không bao giờ hết hạn; thanh toán bằng crypto, không cần KYC.

## Mỗi mã lỗi có nghĩa là gì?

Không dòng nào trong bảng này dùng credit. 1 credit = 1 truy vấn tìm kiếm thành công, trả về một trang kết quả trên bất kỳ engine nào được hỗ trợ. Truy vấn thất bại không bị tính phí.

| HTTP | `code` | Nguyên nhân | Cần làm gì | Thử lại? |
| --- | --- | --- | --- | --- |
| 400 | `invalid_parameter` | Thiếu `q`, hoặc giá trị nằm ngoài danh sách cho phép | Sửa truy vấn; thông báo lỗi nêu tên tham số | Không |
| 401 | `invalid_api_key` | Không có khóa, khóa gõ sai hoặc khóa đã bị thu hồi | Kiểm tra header hoặc `api_key`; tạo khóa mới nếu cần | Không |
| 402 | `insufficient_credits` | Tài khoản có 0 credit | Mua một pack bằng số dư của bạn | Sau khi mua |
| 429 | `concurrency_limit` | Số truy vấn chạy cùng lúc vượt mức tài khoản cho phép | Chờ, giảm số chạy song song, hoặc liên hệ hỗ trợ để tăng giới hạn | Có, kèm backoff |
| 502 | `search_failed` | Engine hoặc collection thất bại với truy vấn này | Thử lại đúng truy vấn đó | Có, kèm backoff |
| 504 | `search_timeout` | Không có phản hồi kịp thời | Thử lại đúng truy vấn đó | Có, kèm backoff |

## Một câu trả lời lỗi trông như thế nào?

Mọi lỗi đều có cùng một JSON body nhỏ gọn với `code` ổn định và `message` dễ đọc cho người. Rẽ nhánh theo `code` trong chương trình của bạn và ghi log `message` cho người đọc. HTTP status khớp với bảng ở trên.

*Body của câu trả lời 402*

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your account has no search credits left."
  }
}
```

## Vì sao tôi nhận 400 invalid_parameter?

Thiếu một giá trị bắt buộc hoặc có giá trị nằm ngoài danh sách API chấp nhận. Nguyên nhân thường gặp là `q` rỗng, tên engine gõ sai như `google-news` thay vì `google_news`, `page` lớn hơn 10, hoặc `device` khác `desktop` và `mobile`.

`message` chỉ ra tham số bị lỗi. Đối chiếu truy vấn của bạn với [tài liệu API](https://serpcrypto.com/vi/docs/search/); không bị tính phí nên bạn có thể sửa và gửi lại ngay.

## Vì sao tôi nhận 401 invalid_api_key?

Khóa không đến được API, hoặc khóa không hợp lệ. Kiểm tra header đúng chính xác là `Authorization: Bearer YOUR_KEY`, có dấu cách sau `Bearer`. Đồng thời kiểm tra biến môi trường đã được đặt trong shell hoặc service chạy code, không chỉ trong terminal của bạn. Khóa đã bị thu hồi sẽ tiếp tục lỗi: tạo khóa mới trong dashboard.

## Tôi nên làm gì với 402 insufficient_credits?

Mua một pack credit bằng số dư của bạn rồi gửi lại. Nếu số dư quá thấp, nạp thêm bằng crypto trước; mức nạp tối thiểu là 25 US$. Đọc `credits_remaining` từ `GET https://serpcrypto.com/api/v1/credits` trước khi chạy job lớn để tránh dừng giữa chừng: lệnh gọi đó miễn phí.

## Làm sao xử lý 429 concurrency_limit?

Hãy chậm lại thay vì dừng. Giới hạn này đếm số truy vấn chạy cùng lúc, không phải số truy vấn mỗi ngày. Mỗi tài khoản có thể chạy một số lượng truy vấn tìm kiếm cùng lúc; giới hạn được hiển thị trong dashboard và có thể tăng theo yêu cầu. Đọc `concurrency_limit` từ endpoint credits và chỉnh kích thước pool worker theo đó; các trang [Python](https://serpcrypto.com/vi/docs/python/) và [Node.js](https://serpcrypto.com/vi/docs/node/) có ví dụ pool không bao giờ vượt giới hạn.

## Khi nào trả về 502 và 504?

`502 search_failed` nghĩa là truy vấn không thể hoàn tất với yêu cầu này; `504 search_timeout` nghĩa là truy vấn không hoàn tất kịp thời. Cả hai đều miễn phí và đều đáng thử lại. Chờ lâu hơn một chút trước mỗi lần thử mới, như code bên dưới làm, và bỏ cuộc sau năm lần thử để job bị kẹt không lặp mãi.

*Python: thử lại 429, 502 và 504 với exponential backoff*

```python
import os
import random
import time

import requests

API_URL = "https://serpcrypto.com/api/v1/search"
RETRYABLE = {429, 502, 504}


def search(params, max_attempts=5):
    headers = {"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]}
    for attempt in range(1, max_attempts + 1):
        r = requests.get(API_URL, params=params, headers=headers, timeout=90)
        if r.status_code == 200:
            return r.json()
        error = r.json().get("error", {})
        if r.status_code not in RETRYABLE or attempt == max_attempts:
            raise RuntimeError(f"{r.status_code} {error.get('code')}: {error.get('message')}")
        # exponential backoff with jitter: about 1 s, 2 s, 4 s, 8 s
        time.sleep(2 ** (attempt - 1) + random.random())
    raise RuntimeError("unreachable")


print(search({"q": "solar panel installers", "gl": "au", "hl": "en"})["search_metadata"])
```

*Node.js: logic tương tự với fetch*

```javascript
// retry.mjs — Node.js 18+
const API_URL = "https://serpcrypto.com/api/v1/search";
const RETRYABLE = new Set([429, 502, 504]);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export async function search(params, maxAttempts = 5) {
  const url = `${API_URL}?${new URLSearchParams(params)}`;
  const headers = { Authorization: `Bearer ${process.env.SERPCRYPTO_API_KEY}` };
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetch(url, { headers });
    if (res.ok) return res.json();
    const body = await res.json().catch(() => ({}));
    const code = body.error?.code ?? "unknown";
    if (!RETRYABLE.has(res.status) || attempt === maxAttempts) {
      throw new Error(`${res.status} ${code}: ${body.error?.message ?? ""}`);
    }
    // exponential backoff with jitter: about 1 s, 2 s, 4 s, 8 s
    await sleep(1000 * 2 ** (attempt - 1) + Math.random() * 1000);
  }
  throw new Error("unreachable");
}

console.log((await search({ q: "solar panel installers", gl: "au", hl: "en" })).search_metadata);
```

## HTTP timeout của tôi nên ngắn hay dài?

Đủ dài để một truy vấn hoàn tất: truy vấn chạy trực tiếp, nên đặt timeout phía client là 60 đến 90 giây thay vì vài giây. Client bỏ cuộc quá sớm sẽ gửi truy vấn thứ hai khi truy vấn đầu vẫn đang chạy, vừa lãng phí một slot chạy song song, vừa tốn hai credit nếu cả hai đều thành công.

## Câu hỏi về lỗi

### Nếu chương trình của tôi gặp sự cố trước khi đọc câu trả lời thì lượt tìm kiếm có bị tính phí không?

Có, nếu API đã hoàn tất tìm kiếm và trả về 200: credit bị trừ khi lượt tìm kiếm thành công, chứ không phải khi bạn đọc kết quả. Đó là một lý do nữa để đặt timeout phía client đủ dài.

### Thử lại có tốn thêm phí không?

Chỉ lần thử thành công mới dùng một credit. Các lần thử thất bại với 429, 502 hoặc 504 là miễn phí, nên một yêu cầu thành công ở lần thử thứ ba chỉ tốn tổng cộng 1 credit.

### Tôi báo lỗi cứ tái diễn ở đâu?

Hãy gửi email tới support@serpcrypto.com kèm `search_metadata.id` của một lượt tìm kiếm thành công hoặc thời điểm, engine và tham số của lượt bị lỗi. Phản hồi email trong vòng 12 giờ, 7 ngày một tuần, bao gồm cả hỗ trợ tích hợp API.

---

SerpCrypto: SerpCrypto là SERP API cho lập trình viên và AI agent, trả về kết quả Google và Bing dưới dạng JSON, thanh toán bằng crypto mà không cần tải lên giấy tờ tùy thân. Credit tìm kiếm trả trước từ 0,30 US$/1K lượt tìm kiếm không bao giờ hết hạn. Không cần KYC — không ID, không selfie, không giấy tờ. Thanh toán bằng crypto.
