بعد اكتمال تضمين المتصفح، يجب على الخادم الخاص بك التحقق من النتيجة باستخدام مفتاح الموقع API قبل السماح بالتسجيل أو الخروج أو أي إجراء محمي.
قد يُسمى حقل النموذج المخفي checkify_token، لكن قيمته هي request_id Checkify.
في لوحة معلومات عملك، افتح مطور وقم بإنشاء مفتاح موقع API للموقع الذي تقوم بدمجه. قم بتخزينه في متغيرات بيئة الخادم فقط — لا تقم أبدًا بشحنه إلى المتصفح.
لستَ بحاجةٍ إلى استدعاء GET /v1/qr/pass/{PASS_ID}/start يدويًا. يقوم تضمين Checkify JavaScript ببدء الجلسة، واستلام request_id، وكتابته في النموذج الخاص بك تلقائيًا.
كل ما يحتاجه نظامك الخلفي هو:
يقوم برنامج SDK في واجهة المستخدم بكتابة مُعرّف الطلب Checkify في حقل نموذج مخفي بعد إتمام المستخدم لعملية التحقق. اسم الحقل الافتراضي هو checkify_token، وهو اسم الحقل وليس نوعًا منفصلاً من الرموز المميزة. يتم إرسال قيمة الحقل إلى نقطة نهاية التحقق كمعرّف الطلب.
قد تُعيد عملية تسليم تطبيق الهاتف المحمول قيمة checkify_request_id في عنوان URL للصفحة. يقرأها SDK عند التحميل؛ ويظل خادمك يتحقق من قيمة request_id نفسها.
إرسال النموذج من واجهة المستخدم الخاصة بك
{
"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 حتى لا يتم التعامل مع علامة الاستفهام (؟) كنمط عام.
لا يعمل خيار "Pass Start" إلا من نطاق موقع ويب مسجل. تُرسل المتصفحات عنوان Origin تلقائيًا، بينما لا يفعل cURL ذلك. أرسل Origin (أو X-Checkify-Site-Url) مع اسم مضيف مُدرج ضمن "المواقع" ← "النطاقات المسموح بها". يجب أن يتطابق اسم المضيف تمامًا - فـ 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"] |
استخدم هذا عندما يطلب تصريحك العمر فوق 13 عامًا. |
| محتوى لمن هم فوق 16 عامًا أو قواعد السن الإقليمية | ["age_over_16"] |
استخدم هذا عندما يطلب تصريحك العمر فوق 16 عامًا. |
| السجائر الإلكترونية، أو الكحول، أو من هم فوق سن 18 عامًا. | ["age_over_18"] |
قم بمطابقة الفئة العمرية مع منتجك وسوقك. |
| المنتجات المخصصة لمن هم فوق سن 21 عامًا (إن وجدت) | ["age_over_21"] |
استخدم هذا عندما يطلب تصريحك العمر فوق 21 عامًا. |
| تحدي سن 25 أو سياسة بيع بالتجزئة أكثر صرامة | ["age_over_25"] |
استخدم هذا عندما يطلب تصريحك العمر فوق 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.
تم نشر الإصدار 1.0.0 من @checkify/server على منصة npm. تأتي حزمة checkify-server الخاصة بلغة Python ضمن مستودع 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 مع قيمة النجاح: true والحالة: مكتمل. يُسمح بالوصول فقط عند وجود البيانات المطلوبة (على سبيل المثال، 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 وافق على المطالبة المطلوبة وقت التحقق. معظم التكاملات تحتاج فقط إلى approved_claims. قد تخزّن الشركات الخاضعة للتنظيم أو عالية المخاطر signed_result أيضًا. قد يتضمن proof_metadata المتداخل أدلة تشفيرية أو تشغيلية (مثل بيانات assurance وأنواع الأدلة أو تجزئات الموافقة) — وليس وثائق الهوية أو تاريخ الميلاد الخام. لا تعامل حقول assurance المتداخلة كشهادة أو ضمان ثقة؛ راجع certification_status وسياستك. لا تخزّن معلومات شخصية أكثر مما يلزم.
إذا لم يُنهِ العميل استخدام التطبيق بعد، فإنّ Checkify يُعيد رمز HTTP 200 مع رسالة النجاح: خطأ والحالة: معلق. امنع الإجراءات المحمية واطلب من المستخدم إكمال عملية التحقق.
{
"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 | المطالبات Checkify المعتمدة، على سبيل المثال. human_verified: true |
signed_result | الحمولة الموقعة الاختيارية لمسارات التدقيق |
عند تعذر إتمام عملية التحقق، يُعيد 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"]
}
}
}
| شفرة | HTTP | معنى | الإجراء الموصى به |
|---|---|---|---|
missing_authorization | 401 | لم يتم إرسال أي ترويسة تفويض. | إرسال التفويض: Bearer YOUR_SITE_API_KEY من كود جانب الخادم فقط. |
invalid_token | 401 | رمز الحامل مفقود أو مشوه أو ليس مفتاح موقع صالح API. | تحقق من المفتاح في لوحة معلومات أعمالك وقم بتخزينه في متغيرات البيئة. |
expired_token | 401 | تم إلغاء مفتاح الموقع API. | قم بإنشاء مفتاح موقع جديد API وقم بتدويره على خوادمك. |
missing_required_field | 400 / 422 | معرف الطلب أو الرمز المميز مفقود من نص JSON. | قم بتمرير request_id من حقل النموذج المخفي، أو رمز الاستطلاع إذا كان التكامل الخاص بك لا يزال يستخدمه. |
invalid_request_id | 400 | تعذر تحليل المرجع أو أنه فارغ بعد التطبيع. | تأكد من أن واجهة المستخدم الخاصة بك ترسل طلب Checkify request_id دون تغيير. |
result_not_found | 404 | لا يوجد طلب تحقق لهذا المرجع. | ارفض الإجراء. ربما يكون المستخدم قد عبث بالحقل المخفي أو أرسل جلسة قديمة. |
result_expired | 410 | لقد تم التحقق منذ فترة طويلة جدًا بحيث لا يمكن الوثوق به في هذا الإجراء. | اطلب من المستخدم إجراء المسح مرة أخرى واستدعاء التحقق باستخدام معرف الطلب الجديد. |
verification_failed | 403 / 409 | عدم تطابق الموقع/النشاط، أو نتيجة مستهلكة مسبقًا (HTTP 409)، أو فشل تحقق عام. | ارفض الوصول. افحص error.details. لفجوات المطالبات/الحقول راجع 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 | فشل التحقق من صحة مخطط JSON body (HTTP 422). | افحص ملف error.details.validation_errors بحثًا عن رسائل على مستوى الحقول. أصلح أنواع request_id و required_claims و required_fields قبل إعادة المحاولة. |
rate_limited | 429 | عدد كبير جدًا من طلبات التحقق في فترة زمنية قصيرة. | أعد المحاولة مع التراجع الأسي. تحقق فقط عند الإجراءات المحمية، وليس في كل عرض للصفحة. |
server_error | 500+ | لم يتمكن برنامج Checkify من إكمال عملية التحقق بسبب مشكلة مؤقتة في الخادم. | أعد المحاولة مرة أو مرتين، ثم أغلق العملية في حالة الفشل وقم بتسجيل الحادثة. |
اليوم، تتم عملية التحقق من الخادم بشكل متزامن: حيث يتحقق نظامك الخلفي من مُعرّف الطلب (request_id) عندما يُرسل المستخدم الإجراء المحمي. يُعد هذا النهج هو المُوصى به لعمليات الدفع والتسجيل والتحكم في الوصول. لا تتطلب عمليات التكامل القياسية استخدام روابط الويب العامة للتحقق. قد تستخدم GoHighLevel وعمليات التكامل مع الشركاء الآخرين إعدادات منفصلة لروابط الويب الصادرة في لوحة تحكم الأعمال.
تعامل مع الحقل المخفي كمرجع غير موثوق به، وليس كدليل. تحقق دائمًا باستخدام مفتاح موقعك API الموجود على الخادم قبل منح الوصول. استخدم
consume: true
لإجراءات لمرة واحدة مثل الاشتراك أو إعادة تعيين كلمة المرور.