SERP API cho phép bạn lấy dữ liệu kết quả tìm kiếm Google dưới dạng JSON thô, dùng chung hạ tầng cào và cùng đơn giá với SERP Checker. Tài liệu này mô tả đầy đủ cách xác thực, các endpoint, định dạng dữ liệu trả về, webhook và bảng mã lỗi.
Thông tin cơ bản
- Base URL:
https://app.serpupdate.com/api/v1 - Xác thực: header
X-API-KEY - Công cụ tìm kiếm: Google (giai đoạn hiện tại)
- Định dạng: JSON thô, dùng mã trạng thái HTTP thật
1. Quy trình tích hợp
- Lấy API key trong app, mục SERP API, tab API Keys.
- Khai báo Pingback URL và Pingback Token ở cùng tab đó.
- Gọi
POST /serp-api/triggerkèm từ khóa, nhận vềsnapshot_id. - Chờ SERPUPDATE gọi webhook về máy chủ của bạn khi snapshot xong.
- Gọi
GET /serp-api/{snapshot_id}để lấy dữ liệu.
Nên dùng webhook thay vì hỏi liên tục
Hỏi liên tục tốn lượt gọi và chậm hơn. Pingback webhook sẽ tự gọi về máy chủ của bạn ngay khi có kết quả.
2. Xác thực
Mọi lượt gọi đều gửi kèm header X-API-KEY. Key là chuỗi 32 ký tự hex thường, không dấu gạch.
curl -X GET https://app.serpupdate.com/api/v1/serp-api/languages
-H "X-API-KEY: 3f9a1c7e4b2d48a6915e0c83d7f6b214"Tạo key mới là vô hiệu key cũ ngay lập tức
Bấm “Lấy key mới” sẽ khóa key hiện tại tức thì và không hoàn tác được. Mọi tích hợp còn dùng key cũ sẽ lỗi cho tới khi bạn cập nhật.
3. Danh sách endpoint
3.1. Tạo snapshot
POST /serp-api/trigger
Đây là lệnh gọi tính phí. Mỗi lượt gọi nhận đúng một từ khóa. Trả về snapshot_id ngay lập tức, dữ liệu lấy sau.
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
keyword |
string | Có | Từ khóa cần crawl, 1 đến 500 ký tự. |
language |
string | Không | Mã ngôn ngữ, ví dụ vi, en. Lấy từ endpoint languages. |
country |
string | Không | Mã quốc gia ISO-2, ví dụ VN, US. |
device |
string | Không | desktop hoặc mobile. Mặc định desktop. |
start_page |
number | Không | Trang SERP bắt đầu, từ 1. Mặc định 1. |
end_page |
number | Không | Trang SERP kết thúc, tối đa 10. Mặc định 10, tức trọn Top 100. |
location |
string | Không | Tên vị trí lấy từ endpoint locations. Bỏ trống nếu đã gửi uule. |
uule |
string | Không | Chuỗi UULE đã mã hóa sẵn. Bỏ trống để hệ thống tự suy ra từ location. |
include_aio |
boolean | Không | true để lấy thêm AI Overview và danh sách nguồn trích dẫn. |
custom_id |
string | Không | ID riêng của bạn, dùng để đối chiếu. |
Giá tính phẳng theo lệnh gọi
Lấy 1 trang hay đủ 10 trang đều cùng một mức giá. Không nên giảm end_page để tiết kiệm, vì không tiết kiệm được gì. Chỉ include_aio mới làm đổi đơn giá, và là giá thay thế chứ không cộng thêm.
Ví dụ lệnh gọi
curl -X POST https://app.serpupdate.com/api/v1/serp-api/trigger
-H "X-API-KEY: 3f9a1c7e4b2d48a6915e0c83d7f6b214"
-H "Content-Type: application/json"
-H "Idempotency-Key: order-8841"
-d '{
"input": [
{
"keyword": "sàn nhựa giả gỗ",
"language": "vi",
"country": "VN",
"device": "desktop",
"start_page": 1,
"end_page": 10,
"include_aio": true
}
]
}'Phản hồi
{ "snapshot_id": "sd_abc123xyz" }Chỉ 1 từ khóa mỗi lượt
Trường input là mảng nhưng giai đoạn này chỉ nhận đúng một phần tử. Gửi nhiều hơn sẽ nhận mã lỗi TOO_MANY_INPUTS.
3.2. Chống tính phí trùng
Gửi kèm header Idempotency-Key (tùy chọn, tối đa 64 ký tự) khi gọi trigger. Nếu mạng lỗi và bạn phải gọi lại cùng một key, hệ thống nhận ra và không chạy thêm một lượt tính phí nữa. Nên dùng một giá trị duy nhất cho mỗi lượt nghiệp vụ, ví dụ mã đơn hàng hoặc UUID.
3.3. Lấy kết quả
GET /serp-api/{snapshot_id}
| Mã HTTP | Ý nghĩa |
|---|---|
200 |
Đã xong, thân phản hồi là mảng JSON kết quả. |
202 |
Đang chạy, chưa có dữ liệu. Chờ webhook hoặc hỏi lại sau. |
404 |
Không tìm thấy snapshot. |
410 |
Snapshot đã quá hạn lưu trữ, dữ liệu đã bị xóa. |
422 |
Lượt crawl thất bại, xem error_code trong thân phản hồi. |
curl https://app.serpupdate.com/api/v1/serp-api/sd_abc123xyz
-H "X-API-KEY: 3f9a1c7e4b2d48a6915e0c83d7f6b214"3.4. Tra cứu địa điểm và ngôn ngữ
GET /serp-api/locations nhận các tham số truy vấn: name (khớp gần đúng), country (ISO-2), page (đánh số từ 0), size.
GET /serp-api/languages không có tham số, trả về toàn bộ danh sách ngôn ngữ Google hỗ trợ.
Dùng hai endpoint này để lấy giá trị hợp lệ cho location và language trước khi gọi trigger.
4. Cấu trúc dữ liệu trả về
Thân phản hồi là một mảng, mỗi phần tử ứng với một từ khóa. Hiện tại luôn có đúng một phần tử.
[
{
"keyword": "best protein powder for muscle gain",
"organic": [
{
"rank": 1,
"title": "Protein Powders For Muscle Growth Support",
"url": "https://www.gnc.com/buy/protein-powders-for-muscle-growth",
"domain": "gnc.com",
"description": "Whey protein is often chosen for its rapid absorption..."
}
],
"aio_text": "Nội dung AI Overview dạng markdown, kèm chỉ dẫn nguồn [[1]](https://...)",
"aio_reference": [
{
"rank": 1,
"url": "https://www.healthline.com/nutrition/best-protein-powder-to-build-muscle",
"domain": "healthline.com",
"title": "The 10 Best Protein Powders to Build Muscle",
"description": "Protein powders, especially when combined with resistance training..."
}
]
}
]| Trường | Kiểu | Ý nghĩa |
|---|---|---|
keyword |
string | Từ khóa đã crawl, trả lại đúng như bạn gửi. |
organic |
array | Kết quả tự nhiên, sắp theo thứ hạng. |
organic[].rank |
number | Vị trí trên SERP, đánh số từ 1 và chạy xuyên suốt các trang. |
organic[].title |
string | Tiêu đề hiển thị trên Google. |
organic[].url |
string | URL đích thật, không phải link chuyển hướng của Google. |
organic[].domain |
string | Tên miền rút gọn của URL. |
organic[].description |
string | Đoạn mô tả hiển thị dưới tiêu đề. |
aio_text |
string | Nội dung AI Overview dạng markdown, có chỉ dẫn nguồn dạng [[n]]. |
aio_reference |
array | Danh sách nguồn mà AI Overview trích dẫn, cùng cấu trúc với organic. |
Hai trường AI Overview có thể không xuất hiện
aio_text và aio_reference chỉ có khi bạn gửi include_aio: true và Google thật sự hiển thị AI Overview cho truy vấn đó. Nếu không, hai khóa này vắng mặt hoàn toàn chứ không phải bằng rỗng. Bộ phân tích phía bạn cần chấp nhận trường hợp thiếu khóa.
5. Pingback webhook
Khi snapshot xong hoặc thất bại, SERPUPDATE gửi một lệnh POST tới URL bạn khai báo. Đây là chiều SERPUPDATE gọi vào máy chủ của bạn, không phải endpoint bạn gọi.
POST https://your-server.com/webhook/serpupdate
User-Agent: SerpUpdate-Webhook/1.0
X-SerpUpdate-Delivery: dlv_a1b2c3d4e5f6
X-SerpUpdate-Token: token bạn đặt ở tab API Keys
Content-Type: application/json
{
"snapshot_id": "sd_abc123xyz",
"status": "ready",
"keyword": "sàn nhựa giả gỗ",
"collect_time_ms": 18450
}status nhận giá trị ready khi thành công và failed khi thất bại. Trường collect_time_ms là thời gian thu thập tính bằng mili giây.
Luôn kiểm tra token trước khi tin nội dung
So sánh header X-SerpUpdate-Token với token bạn đã đặt. Nếu không khớp, trả về 401 và bỏ qua lượt gọi đó. Không có bước này thì bất kỳ ai biết URL cũng có thể giả mạo dữ liệu gửi vào hệ thống của bạn.
Máy chủ của bạn phải trả về mã 2xx. Nếu không, SERPUPDATE thử lại tối đa 3 lần, cách nhau 30 giây, 5 phút và 30 phút.
Ví dụ xử lý webhook bằng Node.js
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhook/serpupdate", (req, res) => {
if (req.get("X-SerpUpdate-Token") !== process.env.SERPUPDATE_PINGBACK_TOKEN) {
return res.sendStatus(401);
}
const { snapshot_id: id, status } = req.body;
if (status === "ready") {
console.log("snapshot ready:", id);
}
res.sendStatus(200);
});Yêu cầu cấu hình
- Pingback URL bắt buộc dùng
https://. Hệ thống chặn các địa chỉ nội bộ nhưlocalhost,127.0.0.1, dải10.x,192.168.x,172.16.xđến172.31.x. - Pingback Token dài từ 16 đến 128 ký tự.
- Trong app có nút Test pingback để bắn thử một lượt gọi và xem máy chủ của bạn trả về mã gì.
- Nếu một lần gửi thất bại, bảng Request logs có nút gửi lại thủ công.
6. Bảng mã lỗi
| Mã lỗi | Ý nghĩa |
|---|---|
INVALID_REQUEST |
Yêu cầu không hợp lệ, thiếu dữ liệu hoặc sai định dạng JSON. |
INVALID_INPUT |
Một trường dữ liệu không hợp lệ. |
TOO_MANY_INPUTS |
Giai đoạn này chỉ hỗ trợ 1 từ khóa mỗi lượt chạy. |
INVALID_IDEMPOTENCY_KEY |
Khóa Idempotency-Key quá dài, tối đa 64 ký tự. |
UNAUTHORIZED |
Xác thực không hợp lệ, kiểm tra lại API key. |
INSUFFICIENT_BALANCE |
Số dư ví không đủ, vui lòng nạp thêm. |
FEATURE_DISABLED |
Tính năng SERP API đang bị tạm khóa cho tài khoản này. |
SNAPSHOT_EXPIRED |
Snapshot đã hết hạn lưu trữ, dữ liệu đã bị xóa. |
SNAPSHOT_FAILED |
Snapshot thất bại. |
COLLECTION_ERROR |
Yêu cầu không được chấp nhận. |
COLLECTION_TIMEOUT |
Hệ thống không phản hồi kịp thời. |
COLLECTION_UNAVAILABLE |
Hệ thống crawl hiện không khả dụng, thử lại sau. |
TRIGGER_TIMEOUT |
Yêu cầu không khởi tạo được. |
INTERNAL_ERROR |
Lỗi hệ thống, thử lại hoặc liên hệ hỗ trợ. |
Vượt hạn mức gọi
Khi vượt hạn mức, hệ thống trả về HTTP 429 kèm header Retry-After tính bằng giây. Hãy chờ đúng khoảng đó rồi gọi lại thay vì thử liên tục.
Lượt chạy lỗi không tự động hoàn tiền
Phần lớn mã lỗi ở trên không kèm hoàn phí tự động. Nếu bạn cần đối soát, hãy liên hệ hỗ trợ kèm snapshot_id.
7. Vòng đời và giới hạn
- Thời gian lưu trữ: 30 ngày kể từ lúc snapshot hoàn tất. Sau đó gọi lại sẽ nhận mã
410. - Cảnh báo sắp hết hạn: bảng Request logs gắn nhãn khi còn dưới 3 ngày.
- Trạng thái snapshot:
running,ready,failed,expired. - Không xóa được snapshot thủ công. Hệ thống tự dọn theo chính sách lưu trữ.
- Số trang:
start_pagevàend_pagenằm trong khoảng 1 đến 10.
Giữ nguyên chuỗi JSON gốc nếu cần đối chiếu
Nếu bạn lưu lại phản hồi để kiểm toán hoặc băm chữ ký, hãy giữ đúng chuỗi thô nhận được. Việc phân tích rồi ghi lại thành JSON mới sẽ đổi thứ tự khóa và khoảng trắng, làm sai kết quả đối chiếu.

