หลัง embed บนเบราว์เซอร์เสร็จ เซิร์ฟเวอร์ของคุณต้องยืนยันผลลัพธ์ด้วย site API key ก่อนอนุญาตการสมัคร ชำระเงิน หรือการดำเนินการที่ปกป้อง
ช่องข้อมูลที่ซ่อนอยู่ อาจมีชื่อว่า checkify_token แต่ค่าของมันคือ request_id ของ Checkify
ในแดชบอร์ดธุรกิจ เปิด นักพัฒนา และสร้าง site API key สำหรับไซต์ที่คุณกำลังเชื่อมต่อ เก็บไว้ในตัวแปรสภาพแวดล้อมของเซิร์ฟเวอร์เท่านั้น — ห้ามส่งไปยังเบราว์เซอร์
คุณไม่จำเป็นต้องเรียกใช้คำสั่ง GET /v1/qr/pass/{PASS_ID}/start ด้วยตนเอง ส่วนประกอบ Checkify JavaScript จะเริ่มต้นเซสชัน รับ request_id และเขียนลงในฟอร์มของคุณโดยอัตโนมัติ
ระบบแบ็กเอนด์ของคุณจำเป็นต้องมีเพียงแค่:
ส่วนหน้า SDK จะเขียน request_id ของ Checkify ลงในช่องฟอร์มที่ซ่อนอยู่หลังจากที่ผู้ใช้ยืนยันเสร็จสิ้น ชื่อช่องเริ่มต้นคือ checkify_token ซึ่งเป็นชื่อช่อง ไม่ใช่ประเภทโทเค็นแยกต่างหาก ส่งค่าช่องนี้ไปยังเอนด์พอยต์ verify เป็น request_id
การส่งต่อแอปบนมือถืออาจส่งค่า checkify_request_id กลับมาใน URL ของหน้าเว็บ SDK จะอ่านค่านี้เมื่อโหลดหน้าเว็บ และเซิร์ฟเวอร์ของคุณจะยังคงตรวจสอบค่า request_id เดิมอยู่
ส่งฟอร์ม POST จากฝั่ง frontend ของคุณ
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
ตรวจสอบคำขอจากระบบแบ็กเอนด์ของคุณ
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
การผสานรวมส่วนหน้าด้วยตนเองเท่านั้น
โดยปกติแล้วนักพัฒนาแบ็กเอนด์จะไม่เรียกใช้ /start ให้ใช้ส่วนนี้เฉพาะเมื่อสร้างฟรอนต์เอนด์แบบกำหนดเองหรือทดสอบโดยไม่ใช้การฝัง ใส่เครื่องหมายอัญประกาศใน URL ใน zsh/bash เพื่อไม่ให้ ? ถูกมองว่าเป็นรูปแบบ glob
คำสั่ง Pass start ใช้ได้เฉพาะกับโดเมนเว็บไซต์ที่ลงทะเบียนไว้เท่านั้น เบราว์เซอร์จะส่ง Origin โดยอัตโนมัติ แต่ cURL ไม่ได้ทำเช่นนั้น คุณต้องส่ง Origin (หรือ X-Checkify-Site-Url) พร้อมกับชื่อโฮสต์ที่อยู่ในรายการภายใต้ Sites → allowed domains ชื่อโฮสต์ต้องตรงกันทุกประการ — checkify.me และ www.checkify.me นั้นแตกต่างกัน
ปัญหาการทดสอบที่พบบ่อยที่สุด
หากคำสั่ง /start ส่งคืน HTTP 403 รหัสผ่านของคุณอาจยังคงใช้งานได้ สาเหตุทั่วไปคือโดเมนที่ร้องขอไม่อยู่ในรายการโดเมนที่อนุญาต หรือ www.example.com ถูกจดทะเบียนแต่ใช้ example.com แทน (หรือในทางกลับกัน)
ใช้ไซต์ทดสอบเฉพาะและผ่านแดชบอร์ด Checkify ของคุณสำหรับการทดสอบการบูรณาการ คีย์ไซต์ API ใช้คำนำหน้า csk_ ไม่มีรูปแบบคีย์ทดสอบแยกต่างหาก อย่าทดสอบกับระบบชำระเงินจริงจนกว่าคุณจะยืนยันทั้งขั้นตอนที่สำเร็จและขั้นตอนที่ถูกปฏิเสธแล้ว
# Step A — start a session (replace PASS_ID and YOUR_REGISTERED_DOMAIN)
curl -sS \
-H "Accept: application/json" \
-H "Origin: https://YOUR_REGISTERED_DOMAIN" \
"https://checkify.me/v1/qr/pass/chk_live_YOUR_PASS_ID/start?request_type=human"
# Response includes request_id and qr_url — open qr_url and complete verification
# Step B — verify on your server (after the user completes verification)
curl -sS -X POST "https://checkify.me/v1/qr/results/verify" \
-H "Authorization: Bearer $CHECKIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_id": "PASTE_request_id_FROM_STEP_A",
"required_claims": ["human_verified"],
"consume": true
}'
ใช้คีย์ API ของเว็บไซต์ของคุณในการโทรยืนยันเท่านั้น ทำการยืนยันในแอปให้เสร็จสมบูรณ์ก่อนโทรยืนยัน มิเช่นนั้นสถานะจะเป็น "รอดำเนินการ"
ตั้งค่า required_claims ให้ตรงกับหลักฐานที่การดำเนินการที่ได้รับการปกป้องของคุณต้องการ ชื่อการอ้างสิทธิ์ต้องตรงกับที่ Checkify อนุมัติสำหรับเซสชันการตรวจสอบนั้น การตรวจสอบอายุใช้ age_over_{N} (ตัวอย่างเช่น age_over_18) รองรับเกณฑ์แบบไดนามิกตั้งแต่ 10 ถึง 110 เมื่อการฝังร้องขอประเภทคำขอที่ตรงกัน
| กรณีศึกษา | ข้อเสนอแนะเกี่ยวกับข้อเรียกร้องที่จำเป็น | หมายเหตุ |
|---|---|---|
| บอท / CAPTCHA ทดแทน | ["human_verified"] |
ยืนยันว่าผู้ใช้จริงได้ดำเนินการตามขั้นตอน Checkify เสร็จสมบูรณ์แล้ว |
| เนื้อหาสำหรับผู้ที่มีอายุ 13 ปีขึ้นไป หรือผลิตภัณฑ์ที่มุ่งเน้นกลุ่มเยาวชน | ["age_over_13"] |
ใช้เมื่อโปรแกรม Pass ของคุณกำหนดให้ต้องมีอายุมากกว่า 13 ปี |
| เนื้อหาสำหรับผู้ที่มีอายุ 16 ปีขึ้นไป หรือข้อกำหนดด้านอายุในแต่ละภูมิภาค | ["age_over_16"] |
ใช้เมื่อโปรแกรม Pass ของคุณกำหนดให้ต้องมีอายุมากกว่า 16 ปี |
| การชำระเงินสำหรับบุหรี่ไฟฟ้า เครื่องดื่มแอลกอฮอล์ หรือสินค้าสำหรับผู้ที่มีอายุ 18 ปีขึ้นไป | ["age_over_18"] |
กำหนดช่วงอายุที่เหมาะสมให้ตรงกับผลิตภัณฑ์และกลุ่มเป้าหมายของคุณ |
| สินค้าที่จำกัดสำหรับผู้ที่มีอายุ 21 ปีขึ้นไป (ในกรณีที่เกี่ยวข้อง) | ["age_over_21"] |
ใช้เมื่อโปรแกรม Pass ของคุณกำหนดให้ต้องมีอายุมากกว่า 21 ปี |
| นโยบายการค้าปลีกที่เข้มงวดกว่า เช่น Challenge 25 | ["age_over_25"] |
ใช้เมื่อโปรแกรม Pass ของคุณกำหนดให้ต้องมีอายุมากกว่า 25 ปี |
| เกณฑ์อายุที่กำหนดเอง | ["age_over_N"] |
ใช้ age_over_N โดยที่ N มีค่าอยู่ระหว่าง 10–110 ซึ่งสอดคล้องกับประเภทคำขอฝังข้อมูลของคุณ |
ประเภทคำขอของเบราว์เซอร์ต้องตรงกับข้อมูลที่คุณตรวจสอบฝั่งเซิร์ฟเวอร์
| ประเภทคำขอฝังตัว | การเรียกร้องที่จำเป็น |
|---|---|
human | ["human_verified"] |
age_over_13 | ["age_over_13"] |
age_over_16 | ["age_over_16"] |
age_over_18 | ["age_over_18"] |
age_over_21 | ["age_over_21"] |
age_over_25 | ["age_over_25"] |
age_over_N | ["age_over_N"] (N = 10–110) |
นอกจาก required_claims คุณอาจกำหนดฟิลด์อัตลักษณ์ที่อนุมัติแล้ว (เช่น ประเทศหรือช่วงอายุ) เมื่อการเชื่อมต่อเก็บข้อมูลนั้นแล้ว ส่งชื่อฟิลด์ใน required_fields — หากขาดในผลที่อนุมัติ verify จะคืน missing_required_fields พร้อม missing_fields ใน error.details
เรียกใช้ POST /v1/qr/results/verify ด้วยคีย์ API ของเว็บไซต์ของคุณก่อนที่จะอนุญาตการเข้าถึง ให้ถือว่าข้อมูลอ้างอิงของเบราว์เซอร์ (request_id หรือโทเค็นการสำรวจแบบเดิม) ไม่น่าเชื่อถือจนกว่า Checkify จะยืนยันผลลัพธ์
POST https://checkify.me/v1/qr/results/verify
Authorization: Bearer YOUR_SITE_API_KEY
Content-Type: application/json
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"consume": true
}
คุณสามารถส่งได้เช่นกัน
token
แทนที่จะ
request_id.
คีย์ API มีขอบเขตเฉพาะสำหรับไซต์ Checkify ของคุณ — คุณไม่ต้องส่ง site_id ในเนื้อหาคำขอ
# checkify_token from your form POST is sent as request_id
curl -sS -X POST "https://checkify.me/v1/qr/results/verify" \
-H "Authorization: Bearer $CHECKIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"consume": true
}'
import express from "express";
const app = express();
app.use(express.json());
const CHECKIFY_API_KEY = process.env.CHECKIFY_API_KEY;
const CHECKIFY_BASE_URL = process.env.CHECKIFY_BASE_URL || "https://checkify.me";
async function verifyCheckifyResult(requestId, requiredClaims = ["human_verified"]) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
try {
const res = await fetch(`${CHECKIFY_BASE_URL}/v1/qr/results/verify`, {
method: "POST",
headers: {
Authorization: `Bearer ${CHECKIFY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
request_id: requestId,
required_claims: requiredClaims,
consume: true,
}),
signal: controller.signal,
});
let body = null;
try {
body = await res.json();
} catch {
body = null;
}
if (!res.ok) {
const details = body?.error?.details || {};
console.warn("Checkify verification failed", {
requestId,
code: body?.error?.code,
missingClaims: details.missing_claims,
missingFields: details.missing_fields,
reason: details.reason,
});
return {
allow: false,
reason: body?.error?.code || "verification_failed",
userMessage: "Verification could not be completed for this action.",
};
}
if (!body || body.status === "pending" || body.success === false) {
return {
allow: false,
reason: body?.status || "pending",
userMessage: "Verification could not be completed for this action.",
};
}
const approved = requiredClaims.every(
(claim) => body.approved_claims?.[claim] === true
);
return {
allow: approved,
reason: approved ? "approved" : "verification_failed",
userMessage: approved
? null
: "Verification could not be completed for this action.",
result: body,
};
} finally {
clearTimeout(timeout);
}
}
app.post("/signup", async (req, res) => {
const requestId = (req.body.checkify_token || "").trim();
if (!requestId) {
return res.status(403).json({ error: "Verification required" });
}
try {
const verdict = await verifyCheckifyResult(requestId);
if (!verdict.allow) {
return res.status(403).json({ error: verdict.userMessage });
}
return res.json({ ok: true });
} catch (err) {
console.error("Checkify verification unavailable", err);
return res.status(403).json({
error: "Verification is temporarily unavailable. Please try again.",
});
}
});
import { Checkify } from "@checkify/server";
const checkify = new Checkify({
apiKey: process.env.CHECKIFY_SITE_API_KEY,
});
app.post("/signup", async (req, res) => {
const requestId = String(req.body.checkify_token || "").trim();
if (!requestId) {
return res.status(403).json({ error: "Verification required" });
}
try {
const result = await checkify.verifyHuman({ requestId, consume: true });
if (!result.success || !result.approved) {
return res.status(403).json({
error: "Verification could not be completed for this action.",
});
}
return res.json({ ok: true });
} catch (err) {
console.error("Checkify verification failed", err);
return res.status(403).json({
error: "Verification is temporarily unavailable. Please try again.",
});
}
});
import os
import httpx
from fastapi import FastAPI, HTTPException
app = FastAPI()
CHECKIFY_API_KEY = os.environ["CHECKIFY_API_KEY"]
CHECKIFY_BASE_URL = os.getenv("CHECKIFY_BASE_URL", "https://checkify.me")
USER_MESSAGE = "Verification could not be completed for this action."
UNAVAILABLE = "Verification is temporarily unavailable. Please try again."
def verify_checkify_result(request_id: str, required_claims=None) -> dict:
required_claims = required_claims or ["human_verified"]
try:
response = httpx.post(
f"{CHECKIFY_BASE_URL}/v1/qr/results/verify",
headers={
"Authorization": f"Bearer {CHECKIFY_API_KEY}",
"Content-Type": "application/json",
},
json={
"request_id": request_id,
"required_claims": required_claims,
"consume": True,
},
timeout=10.0,
)
except httpx.RequestError as exc:
print("Checkify verification unavailable", exc)
return {"allow": False, "reason": "unavailable", "user_message": UNAVAILABLE}
try:
body = response.json()
except ValueError:
body = None
if response.status_code >= 400:
error = (body or {}).get("error") if isinstance(body, dict) else None
details = (error or {}).get("details", {})
print(
"Checkify verification failed",
{
"request_id": request_id,
"code": (error or {}).get("code"),
"missing_claims": details.get("missing_claims"),
"missing_fields": details.get("missing_fields"),
"reason": details.get("reason"),
},
)
return {
"allow": False,
"reason": (error or {}).get("code", "verification_failed"),
"user_message": USER_MESSAGE,
}
if not isinstance(body, dict) or body.get("status") == "pending" or body.get("success") is False:
return {"allow": False, "reason": "pending", "user_message": USER_MESSAGE}
approved = all((body.get("approved_claims") or {}).get(claim) is True for claim in required_claims)
return {
"allow": approved,
"reason": "approved" if approved else "verification_failed",
"user_message": None if approved else USER_MESSAGE,
"result": body,
}
@app.post("/signup")
def signup(email: str, checkify_token: str):
request_id = (checkify_token or "").strip()
if not request_id:
raise HTTPException(status_code=403, detail="Verification required")
verdict = verify_checkify_result(request_id)
if not verdict["allow"]:
raise HTTPException(status_code=403, detail=verdict["user_message"])
return {"ok": True}
<?php
$checkifyApiKey = getenv('CHECKIFY_API_KEY');
$baseUrl = getenv('CHECKIFY_BASE_URL') ?: 'https://checkify.me';
function verify_checkify_result(string $requestId, array $requiredClaims = ['human_verified']): array {
global $checkifyApiKey, $baseUrl;
$payload = json_encode([
'request_id' => $requestId,
'required_claims' => $requiredClaims,
'consume' => true,
]);
$ch = curl_init($baseUrl . '/v1/qr/results/verify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $checkifyApiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_TIMEOUT => 10,
]);
$raw = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($raw === false) {
error_log('Checkify verification unavailable');
return ['allow' => false, 'user_message' => 'Verification is temporarily unavailable. Please try again.'];
}
$body = json_decode($raw ?: 'null', true);
if ($status >= 400) {
$error = is_array($body) ? ($body['error'] ?? null) : null;
$details = is_array($error) ? ($error['details'] ?? []) : [];
error_log('Checkify verification failed: ' . json_encode([
'code' => is_array($error) ? ($error['code'] ?? null) : null,
'missing_claims' => $details['missing_claims'] ?? null,
]));
return ['allow' => false, 'user_message' => 'Verification could not be completed for this action.'];
}
if (!is_array($body) || ($body['status'] ?? '') === 'pending' || ($body['success'] ?? true) === false) {
return ['allow' => false, 'user_message' => 'Verification could not be completed for this action.'];
}
foreach ($requiredClaims as $claim) {
if (($body['approved_claims'][$claim] ?? false) !== true) {
return ['allow' => false, 'user_message' => 'Verification could not be completed for this action.'];
}
}
return ['allow' => true, 'result' => $body];
}
$requestId = trim($_POST['checkify_token'] ?? '');
if ($requestId === '') {
http_response_code(403);
echo json_encode(['error' => 'Verification required']);
exit;
}
$verdict = verify_checkify_result($requestId);
if (!$verdict['allow']) {
http_response_code(403);
echo json_encode(['error' => $verdict['user_message']]);
exit;
}
// continue protected action...
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"time"
)
type verifyResponse struct {
Success bool `json:"success"`
Status string `json:"status"`
Message string `json:"message"`
ApprovedClaims map[string]bool `json:"approved_claims"`
}
type errorResponse struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
Details map[string]interface{} `json:"details"`
} `json:"error"`
}
func verifyCheckifyResult(requestID string, requiredClaims []string) (bool, string, error) {
apiKey := os.Getenv("CHECKIFY_API_KEY")
baseURL := os.Getenv("CHECKIFY_BASE_URL")
if baseURL == "" {
baseURL = "https://checkify.me"
}
payload, _ := json.Marshal(map[string]interface{}{
"request_id": requestID,
"required_claims": requiredClaims,
"consume": true,
})
req, err := http.NewRequest(http.MethodPost, baseURL+"/v1/qr/results/verify", bytes.NewReader(payload))
if err != nil {
return false, "", err
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 10 * time.Second}
res, err := client.Do(req)
if err != nil {
return false, "", err
}
defer res.Body.Close()
if res.StatusCode >= 400 {
var errBody errorResponse
_ = json.NewDecoder(res.Body).Decode(&errBody)
fmt.Printf("Checkify verification failed code=%s details=%v\n", errBody.Error.Code, errBody.Error.Details)
return false, "Verification could not be completed for this action.", nil
}
var body verifyResponse
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
return false, "Verification could not be completed for this action.", nil
}
if body.Status == "pending" || !body.Success {
return false, "Verification could not be completed for this action.", nil
}
for _, claim := range requiredClaims {
if !body.ApprovedClaims[claim] {
return false, "Verification could not be completed for this action.", nil
}
}
return true, "", nil
}
func signupHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, "invalid form", http.StatusBadRequest)
return
}
requestID := strings.TrimSpace(r.FormValue("checkify_token"))
if requestID == "" {
http.Error(w, "Verification required", http.StatusForbidden)
return
}
allowed, message, err := verifyCheckifyResult(requestID, []string{"human_verified"})
if err != nil {
fmt.Println("Checkify verification unavailable", err)
http.Error(w, "Verification is temporarily unavailable. Please try again.", http.StatusForbidden)
return
}
if !allowed {
http.Error(w, message, http.StatusForbidden)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"ok":true}`))
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var apiKey = Environment.GetEnvironmentVariable("CHECKIFY_API_KEY");
var baseUrl = Environment.GetEnvironmentVariable("CHECKIFY_BASE_URL") ?? "https://checkify.me";
async Task<(bool Allow, string UserMessage)> VerifyCheckifyAsync(string requestId)
{
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
using var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/v1/qr/results/verify");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
req.Content = new StringContent(JsonSerializer.Serialize(new
{
request_id = requestId,
required_claims = new[] { "human_verified" },
consume = true,
}), Encoding.UTF8, "application/json");
HttpResponseMessage res;
try
{
res = await client.SendAsync(req);
}
catch (Exception ex)
{
Console.Error.WriteLine($"Checkify verification unavailable: {ex.Message}");
return (false, "Verification is temporarily unavailable. Please try again.");
}
var raw = await res.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(string.IsNullOrWhiteSpace(raw) ? "{}" : raw);
var root = doc.RootElement;
if (!res.IsSuccessStatusCode)
{
if (root.TryGetProperty("error", out var err) && err.TryGetProperty("details", out var details))
{
Console.WriteLine($"Checkify verification failed details={details}");
}
return (false, "Verification could not be completed for this action.");
}
if (root.TryGetProperty("status", out var status) && status.GetString() == "pending")
{
return (false, "Verification could not be completed for this action.");
}
if (root.TryGetProperty("approved_claims", out var claims)
&& claims.TryGetProperty("human_verified", out var human)
&& human.GetBoolean())
{
return (true, string.Empty);
}
return (false, "Verification could not be completed for this action.");
}
// In your signup endpoint:
// var requestId = form["checkify_token"];
// var (allow, message) = await VerifyCheckifyAsync(requestId);
// if (!allow) return Results.Forbid();
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class CheckifyVerify {
private static final String API_KEY = System.getenv("CHECKIFY_API_KEY");
private static final String BASE_URL =
System.getenv().getOrDefault("CHECKIFY_BASE_URL", "https://checkify.me");
private static final ObjectMapper MAPPER = new ObjectMapper();
static boolean verifyCheckifyResult(String requestId) {
String payload = "{\"request_id\":\"" + requestId + "\","
+ "\"required_claims\":[\"human_verified\"],\"consume\":true}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/v1/qr/results/verify"))
.timeout(Duration.ofSeconds(10))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
try {
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
JsonNode root = MAPPER.readTree(response.body() == null ? "{}" : response.body());
if (response.statusCode() >= 400) {
System.err.println("Checkify verification failed: " + root);
return false;
}
if ("pending".equals(root.path("status").asText()) || !root.path("success").asBoolean(false)) {
return false;
}
return root.path("approved_claims").path("human_verified").asBoolean(false);
} catch (Exception ex) {
System.err.println("Checkify verification unavailable: " + ex.getMessage());
return false;
}
}
}
ใช้ consume: true สำหรับการดำเนินการที่ได้รับการป้องกันขั้นสุดท้าย — การชำระเงิน, การสมัครสมาชิก, การรีเซ็ตรหัสผ่าน, การซื้อที่จำกัดอายุ, การเข้าถึงเนื้อหาที่ได้รับการป้องกัน
ใช้ consume: false เฉพาะสำหรับ — การทดสอบ การแก้ไขข้อผิดพลาด หรือการตรวจสอบที่ไม่ใช่ขั้นสุดท้าย ซึ่งต้องตรวจสอบผลลัพธ์อีกครั้งในภายหลัง
สำหรับการดำเนินการที่มีการควบคุมหรือมีความเสี่ยงสูง ควรเลือก consume: true เพื่อป้องกันไม่ให้ผลการตรวจสอบเดียวกันถูกนำไปใช้ซ้ำสำหรับการตัดสินใจที่ได้รับการปกป้องหลายรายการ
หากระบบแบ็กเอนด์ของคุณไม่สามารถเชื่อมต่อกับ Checkify ได้ ห้ามอนุญาตให้ทำการชำระเงินที่จำกัดอายุ การเข้าถึงการพนัน การเข้าถึงเนื้อหาสำหรับผู้ใหญ่ การซื้อบุหรี่ไฟฟ้าหรือเครื่องดื่มแอลกอฮอล์ หรือการกระทำอื่น ๆ ที่ได้รับการป้องกันโดยไม่มีผลลัพธ์ที่ยืนยันจากฝั่งเซิร์ฟเวอร์
ใช้ค่าหมดเวลา HTTP สั้นๆ (เช่น 10 วินาที) ลองเชื่อมต่อใหม่หนึ่งหรือสองครั้งสำหรับข้อผิดพลาด 5xx ชั่วคราวหรือข้อผิดพลาดเครือข่าย จากนั้นปฏิเสธการเข้าถึง บันทึกเหตุการณ์ที่ฝั่งเซิร์ฟเวอร์และแสดงข้อความที่ปลอดภัยสำหรับผู้ใช้ อย่าเปิดเผยรายละเอียดข้อผิดพลาด Checkify ภายในให้กับลูกค้า
try {
const verdict = await verifyCheckifyResult(requestId);
if (!verdict.allow) {
return res.status(403).json({ error: "Verification required" });
}
// Continue protected action
} catch (err) {
console.error("Checkify verification unavailable", err);
return res.status(403).json({
error: "Verification is temporarily unavailable. Please try again.",
});
}
The Checkify monorepo includes @checkify/server (Node.js) and checkify-server (Python) packages for server-side verify calls. There is no published OpenAPI spec or Postman collection yet — use the examples on this page and POST /v1/qr/results/verify directly.
@checkify/server v1.0.0 ได้ถูกเผยแพร่บน npm แล้ว แพ็กเกจ checkify-server สำหรับ Python นั้นรวมอยู่ใน monorepo Checkify SDK
การตรวจสอบที่เสร็จสมบูรณ์จะหมดอายุหลังจาก QR_RESULT_MAX_AGE_SECONDS (ค่าเริ่มต้น 900 วินาที / 15 นาที) หลังจากหมดอายุ การตรวจสอบจะส่งคืนค่า result_expired — โปรดขอให้ผู้ใช้ตรวจสอบอีกครั้ง
JavaScript SDK จัดการสถานะเซสชันสำหรับฝังมาตรฐาน ใช้สิ่งเหล่านี้เฉพาะเมื่อคุณสร้างส่วนหน้าแบบกำหนดเองที่เรียกใช้ GET /v1/qr/pass/{pass_id}/start ด้วยตนเอง
GET /v1/qr/status?token={poll_token}GET /v1/qr/status/request/{request_id}?status_token={status_token}เมื่อสำเร็จ Checkify จะส่งคืน HTTP 200 พร้อม success: true และ status: completed อนุญาตการเข้าถึงเฉพาะเมื่อมีคุณสมบัติที่จำเป็นครบถ้วน (เช่น human_verified: true)
{
"success": true,
"status": "completed",
"message": "Verification result confirmed",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"site_id": "YOUR_SITE_ID",
"business_id": "YOUR_BUSINESS_ID",
"approved_claims": {
"human_verified": true
},
"approved_fields": [],
"signed_result": {
"payload": { "...": "..." },
"signature": "...",
"signature_algorithm": "EdDSA",
"key_id": "checkify:default"
}
}
ออบเจ็กต์ signed_result ให้แบ็กเอนด์เก็บบันทึกตรวจสอบที่ป้องกันการปลอมแปลงว่า Checkify อนุมัติ claim ที่ต้องการตอนยืนยัน ระบบส่วนใหญ่ต้องการเพียง approved_claims ธุรกิจที่มีการกำกับดูแลหรือความเสี่ยงสูงอาจเก็บ signed_result ด้วย proof_metadata ที่ซ้อนกันอาจมีหลักฐานเชิงคริปโตหรือเชิงปฏิบัติการ (เช่น เมทาดาทา assurance ประเภทหลักฐาน หรือแฮชความยินยอม) — ไม่ใช่เอกสารประจำตัวหรือวันเกิดดิบ อย่าถือว่าฟิลด์ assurance ที่ซ้อนเป็นใบรับรองหรือการรับประกันความเชื่อถือ ตรวจสอบ certification_status และนโยบายของคุณ อย่าเก็บข้อมูลส่วนบุคคลเกินจำเป็น
หากลูกค้ายังใช้งานแอปไม่เสร็จสิ้น Checkify จะส่งคืน HTTP 200 พร้อม success: false และ status: pending ปฏิเสธการดำเนินการที่ได้รับการป้องกัน และขอให้ผู้ใช้ทำการยืนยันตัวตนให้เสร็จสิ้น
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| สนาม | ความหมาย |
|---|---|
success | true เมื่อการยืนยันเสร็จและตรงตามข้อกำหนด |
status | completed หรือ pending |
approved_claims | Claims ที่ Checkify อนุมัติ เช่น human_verified: true |
signed_result | Signed payload ไม่บังคับสำหรับ audit trail |
เมื่อการตรวจสอบไม่สามารถดำเนินการต่อได้ Checkify จะส่งคืน HTTP 4xx/5xx พร้อมด้วยเนื้อหา JSON ที่มีโครงสร้าง ตรวจสอบ error.code และบันทึก error.details ฝั่งเซิร์ฟเวอร์ ส่งข้อความทั่วไปกลับไปยังผู้ใช้ปลายทาง
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| รหัส | ทศนิยม | ความหมาย | การดำเนินการที่แนะนำ |
|---|---|---|---|
missing_authorization | 401 | ไม่มีการส่งส่วนหัวการอนุญาต (Authorization header) | ส่งคำอนุญาต: Bearer YOUR_SITE_API_KEY จากโค้ดฝั่งเซิร์ฟเวอร์เท่านั้น |
invalid_token | 401 | โทเค็น Bearer หายไป รูปแบบไม่ถูกต้อง หรือไม่ใช่คีย์ API ของไซต์ที่ถูกต้อง | ตรวจสอบรหัสสำคัญในแดชบอร์ดธุรกิจของคุณและบันทึกไว้ในตัวแปรสภาพแวดล้อม |
expired_token | 401 | คีย์เว็บไซต์ API ถูกยกเลิกแล้ว | สร้างคีย์ไซต์ใหม่ชื่อ API แล้วหมุนเวียนคีย์นั้นบนเซิร์ฟเวอร์ของคุณ |
missing_required_field | 400 / 422 | request_id หรือ token หายไปจาก body ของ JSON | ส่งค่า request_id จากช่องข้อมูลที่ซ่อนอยู่ในฟอร์มของคุณ หรือโทเค็นแบบสำรวจหากการเชื่อมต่อของคุณยังคงใช้โทเค็นอยู่ |
invalid_request_id | 400 | ไม่สามารถแยกวิเคราะห์ข้อมูลอ้างอิงได้ หรือข้อมูลอ้างอิงว่างเปล่าหลังจากทำการปรับให้เป็นมาตรฐานแล้ว | ตรวจสอบให้แน่ใจว่าฝั่ง frontend ของคุณส่ง request_id Checkify โดยไม่เปลี่ยนแปลง |
result_not_found | 404 | ไม่มีคำขอตรวจสอบความถูกต้องสำหรับข้อมูลอ้างอิงนั้น | ปฏิเสธการดำเนินการ ผู้ใช้อาจแก้ไขข้อมูลในช่องที่ซ่อนไว้ หรือส่งข้อมูลจากเซสชันเก่า |
result_expired | 410 | การตรวจสอบเสร็จสิ้นไปนานเกินไปแล้ว จึงไม่น่าเชื่อถือสำหรับการดำเนินการนี้ | ขอให้ผู้ใช้สแกนอีกครั้งและเรียกใช้ฟังก์ชันตรวจสอบโดยใช้ request_id ใหม่ |
verification_failed | 403 / 409 | ไซต์/ธุรกิจไม่ตรงกัน ผลลัพธ์ถูกใช้แล้ว (HTTP 409) หรือการยืนยันล้มเหลวทั่วไป | ปฏิเสธการเข้าถึง ตรวจ error.details สำหรับช่องว่างของ claim/ฟิลด์ ดู missing_required_claims และ missing_required_fields |
missing_required_claims | 403 | developers_server.err_missing_required_claims_meaning | developers_server.err_missing_required_claims_action |
missing_required_fields | 403 | developers_server.err_missing_required_fields_meaning | developers_server.err_missing_required_fields_action |
unknown_required_attributes | 400 | developers_server.err_unknown_required_attributes_meaning | developers_server.err_unknown_required_attributes_action |
business_not_operational | 403 | บัญชีธุรกิจถูกล็อก เก็บถาวร หรือไม่สามารถใช้งานได้ | ติดต่อเจ้าของธุรกิจหรือฝ่ายสนับสนุนของ Checkify อย่าอนุญาตให้ดำเนินการที่ได้รับการป้องกันจนกว่าบัญชีจะเปิดใช้งาน |
validation_errors | 422 | การตรวจสอบความถูกต้องของ Schema ในเนื้อหา JSON ไม่ผ่าน (HTTP 422) | ตรวจสอบ error.details.validation_errors เพื่อดูข้อความระดับฟิลด์ แก้ไขประเภท request_id, required_claims หรือ required_fields ก่อนลองใหม่อีกครั้ง |
rate_limited | 429 | มีการตรวจสอบยืนยันข้อมูลมากเกินไปในช่วงเวลาสั้นๆ | ลองใหม่โดยใช้การหน่วงเวลาแบบทวีคูณ ตรวจสอบเฉพาะการกระทำที่ได้รับการป้องกัน ไม่ใช่ทุกครั้งที่ดูหน้าเว็บ |
server_error | 500+ | ไม่สามารถทำการตรวจสอบ Checkify ให้เสร็จสมบูรณ์ได้เนื่องจากปัญหาเซิร์ฟเวอร์ชั่วคราว | ลองใหม่สักครั้งหรือสองครั้ง จากนั้นปิดโปรแกรมและบันทึกเหตุการณ์ |
ปัจจุบัน การตรวจสอบเซิร์ฟเวอร์เป็นแบบซิงโครนัส: แบ็กเอนด์ของคุณจะตรวจสอบ request_id เมื่อผู้ใช้ส่งการกระทำที่ได้รับการป้องกัน สำหรับขั้นตอนการชำระเงิน การลงทะเบียน และการควบคุมการเข้าถึง นี่คือวิธีการที่แนะนำ เว็บฮุคสำหรับการตรวจสอบทั่วไปไม่จำเป็นสำหรับการผสานรวมมาตรฐาน GoHighLevel และการผสานรวมพันธมิตรอื่นๆ อาจใช้การกำหนดค่าเว็บฮุคขาออกแยกต่างหากในแดชบอร์ดทางธุรกิจ
ถือว่าฟิลด์ที่ซ่อนเป็น reference ที่ไม่น่าเชื่อถือ ไม่ใช่หลักฐาน ต้องยืนยันด้วย site API key บนเซิร์ฟเวอร์ก่อนให้สิทธิ์เข้าถึง ใช้
consume: true
สำหรับการดำเนินการครั้งเดียว เช่น สมัครสมาชิกหรือรีเซ็ตรหัสผ่าน