Bắt đầu nhanh
Bạn cần tài khoản quản trị đơn vị trên eDevice và đơn vị đã có sản lượng eID.
1. Tạo ứng dụng và lấy API key
- Đăng nhập eDevice, mở mục Tích hợp API.
- Tạo ứng dụng mới. Bạn có thể đặt ngày hết hạn và giới hạn IP được gọi.
- Sao chép API key ngay khi hiện ra. Key chỉ hiển thị một lần. Nếu mất key, dùng Tạo lại khoá để lấy key mới.
Mỗi đơn vị tạo được tối đa 5 ứng dụng (VTS có thể điều chỉnh).
2. Đặt biến môi trường
Mọi ví dụ trong tài liệu đọc key và địa chỉ API từ hai biến sau:
export EVERIFY_API_KEY="evf_live_..." # key vừa sao chép
export EVERIFY_BASE_URL="https://everify.vtsi.vn/api/v1"
Kiểm tra key bằng cách xem số dư:
curl -sS "$EVERIFY_BASE_URL/balance" -H "X-API-Key: $EVERIFY_API_KEY"
3. Chuẩn bị dữ liệu chip
Tạo file request.json. Các giá trị chip.* là base64 chuẩn của từng data group đọc từ chip:
{
"chip": {
"sod": "<base64 SOD từ chip>",
"dg1": "<base64 DG1 từ chip>",
"dg13": "<base64 DG13 từ chip>"
},
"client_ref": "HS-2026-000123"
}
Không có bộ dữ liệu mẫu dùng chung. Bộ Công an chỉ xác nhận dữ liệu đọc từ chip của một thẻ CCCD thật, nên bạn cần đọc thẻ bằng thiết bị hoặc SDK của mình.
- Dữ liệu sai định dạng hoặc hỏng bị từ chối với mã
400và không trừ lượt. - Dữ liệu đúng định dạng nhưng không phải của thẻ thật vẫn được gửi đi xác thực. Kết quả thường là
INVALIDvà vẫn trừ 1 lượt.
Cách đọc chip xem tại eID C06.
4. Gọi xác thực
Chọn ngôn ngữ. Lựa chọn được ghi nhớ trên các trang khác.
- curl
- Node.js
- Python
- Java
- C#
- PHP
curl -sS -X POST "$EVERIFY_BASE_URL/eid/verify" \
-H "X-API-Key: $EVERIFY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
--max-time 30 \
--data @request.json
import { randomUUID } from 'node:crypto';
import { readFile } from 'node:fs/promises';
const baseUrl = process.env.EVERIFY_BASE_URL ?? 'https://everify.vtsi.vn/api/v1';
// Giữ key này nếu cần gửi lại cùng thao tác.
const idempotencyKey = randomUUID();
const res = await fetch(`${baseUrl}/eid/verify`, {
method: 'POST',
headers: {
'X-API-Key': process.env.EVERIFY_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: await readFile('request.json', 'utf8'),
signal: AbortSignal.timeout(30_000),
});
const body = await res.json();
if (body.error) {
// Không trừ lượt. Lỗi tạm thời thì gửi lại với cùng idempotencyKey.
console.error(res.status, body.error.code, body.error.message, body.request_id);
process.exit(1);
}
console.log(body.data.result, body.data.reason, body.data.billing);
import os
import sys
import uuid
import requests
base_url = os.environ.get("EVERIFY_BASE_URL", "https://everify.vtsi.vn/api/v1")
idempotency_key = str(uuid.uuid4()) # giữ key này nếu cần gửi lại cùng thao tác
with open("request.json", "rb") as f:
payload = f.read()
res = requests.post(
f"{base_url}/eid/verify",
headers={
"X-API-Key": os.environ["EVERIFY_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": idempotency_key,
},
data=payload,
timeout=30,
)
body = res.json()
if body["error"] is not None:
# Không trừ lượt. Lỗi tạm thời thì gửi lại với cùng idempotency_key.
err = body["error"]
sys.exit(f"{res.status_code} {err['code']}: {err['message']} ({body['request_id']})")
print(body["data"]["result"], body["data"]["reason"], body["data"]["billing"])
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Objects;
import java.util.UUID;
public class VerifyEid {
public static void main(String[] args) throws Exception {
String baseUrl = Objects.requireNonNullElse(System.getenv("EVERIFY_BASE_URL"), "https://everify.vtsi.vn/api/v1");
// Giữ key này nếu cần gửi lại cùng thao tác.
String idempotencyKey = UUID.randomUUID().toString();
HttpRequest req = HttpRequest.newBuilder(URI.create(baseUrl + "/eid/verify"))
.timeout(Duration.ofSeconds(30))
.header("X-API-Key", System.getenv("EVERIFY_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", idempotencyKey)
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("request.json")))
.build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
// Thành công: "error": null và data.result là VALID hoặc INVALID.
// Có lỗi: không trừ lượt; lỗi tạm thời thì gửi lại với cùng idempotencyKey.
System.out.println(res.statusCode() + " " + res.body());
}
}
using System.Text;
using System.Text.Json;
var baseUrl = Environment.GetEnvironmentVariable("EVERIFY_BASE_URL") ?? "https://everify.vtsi.vn/api/v1";
// Giữ key này nếu cần gửi lại cùng thao tác.
var idempotencyKey = Guid.NewGuid().ToString();
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
using var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/eid/verify")
{
Content = new StringContent(File.ReadAllText("request.json"), Encoding.UTF8, "application/json"),
};
req.Headers.Add("X-API-Key", Environment.GetEnvironmentVariable("EVERIFY_API_KEY"));
req.Headers.Add("Idempotency-Key", idempotencyKey);
using var res = await http.SendAsync(req);
using var doc = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
var root = doc.RootElement;
if (root.GetProperty("error").ValueKind != JsonValueKind.Null)
{
// Không trừ lượt. Lỗi tạm thời thì gửi lại với cùng idempotencyKey.
var err = root.GetProperty("error");
Console.Error.WriteLine($"{(int)res.StatusCode} {err.GetProperty("code")}: {err.GetProperty("message")}");
return 1;
}
Console.WriteLine(root.GetProperty("data").GetProperty("result"));
return 0;
<?php
$baseUrl = getenv('EVERIFY_BASE_URL') ?: 'https://everify.vtsi.vn/api/v1';
// Giữ key này nếu cần gửi lại cùng thao tác.
$idempotencyKey = bin2hex(random_bytes(16));
$ch = curl_init($baseUrl . '/eid/verify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . getenv('EVERIFY_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . $idempotencyKey,
],
CURLOPT_POSTFIELDS => file_get_contents('request.json'),
]);
$raw = curl_exec($ch);
if ($raw === false) {
// Lỗi mạng: gửi lại với cùng $idempotencyKey.
exit('Network error: ' . curl_error($ch) . PHP_EOL);
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$body = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
if ($body['error'] !== null) {
// Không trừ lượt. Lỗi tạm thời thì gửi lại với cùng $idempotencyKey.
exit("$status {$body['error']['code']}: {$body['error']['message']}" . PHP_EOL);
}
echo $body['data']['result'], PHP_EOL;
5. Đọc kết quả
Khi có kết luận, API trả HTTP 200:
{
"request_id": "req_01JBF8...",
"data": {
"transaction_id": "txn_01JBF8...",
"client_ref": "HS-2026-000123",
"product": "eid.verify",
"result": "VALID",
"reason": null,
"id_number_masked": "0370****8043",
"verified_at": "2026-10-28T16:30:00.123Z",
"billing": { "quota_type": "eid_verify", "charged": 1, "balance_after": 4999 }
},
"error": null
}
data.resultlàVALIDhoặcINVALID. VớiINVALID, xem lý do ởdata.reason.code:CARD_NOT_VERIFIEDhoặcID_NUMBER_NOT_MATCHED.- Cả
VALIDvàINVALIDđều trừ 1 lượt (billing.charged). - Nếu
errorkhácnull, request không được xử lý và không trừ lượt. Xem Mã lỗi. - Lưu
request_idvàtransaction_idđể đối soát hoặc gửi cho bộ phận hỗ trợ.
Gửi thử và công cụ
Mỗi trang trong Tham chiếu API có khung Gửi thử để gọi API ngay trên trình duyệt.
Có kết luận là trừ lượt, và cần dữ liệu chip thật. Nên tạo một ứng dụng riêng để thử và thu hồi key sau khi xong. Không dán key vào máy dùng chung.
Nếu muốn dùng công cụ riêng, tải các file dưới đây và nhập vào Postman, VS Code hoặc JetBrains. Các file có sẵn request cho mọi endpoint: xác thực eID, số dư, giao dịch, sổ biến động và tổng hợp sử dụng.
Tiếp theo
- Gửi lại an toàn: dùng
Idempotency-Keyđể retry mà không bị trừ hai lần. - Giới hạn: rate limit, kích thước body, timeout.
- Tham chiếu API: schema đầy đủ của từng endpoint.