Po zakończeniu osadzania w przeglądarce serwer musi zweryfikować wynik za pomocą klucza witryny API przed umożliwieniem rejestracji, realizacji transakcji lub wykonania jakiejkolwiek chronionej czynności.
Ukryte pole formularza może nazywać się checkify_token, ale jego wartością jest Checkify request_id.
W panelu swojej firmy otwórz Wywoływacz i utwórz klucz API dla witryny, którą integrujesz. Przechowuj go tylko w zmiennych środowiskowych serwera — nigdy nie wysyłaj go do przeglądarki.
Nie musisz ręcznie wywoływać polecenia GET /v1/qr/pass/{PASS_ID}/start. Funkcja osadzania Checkify JavaScript uruchamia sesję, odbiera request_id i automatycznie zapisuje go w formularzu.
Twoje zaplecze musi tylko:
Interfejs użytkownika SDK zapisuje request_id Checkify w ukrytym polu formularza po zakończeniu weryfikacji. Domyślna nazwa pola to checkify_token — jest to nazwa pola, a nie oddzielny typ tokena. Wartość pola należy wysłać do punktu końcowego weryfikacji jako request_id.
Przekazanie aplikacji mobilnej może zwrócić checkify_request_id w adresie URL strony. SDK odczytuje go podczas ładowania; serwer nadal weryfikuje tę samą wartość request_id.
Formularz POST z Twojego front-endu
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
Zweryfikuj żądanie z zaplecza
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
Tylko ręczna integracja front-endu
Programiści back-endu zazwyczaj nie wywołują /start. Używaj tej sekcji tylko podczas tworzenia niestandardowego front-endu lub testowania bez wbudowanego modułu. W zsh/bash podawaj adresy URL w cudzysłowie, więc znak ? nie jest traktowany jako glob.
Pass start działa tylko z zarejestrowanej domeny witryny. Przeglądarki wysyłają Origin automatycznie; cURL nie. Wyślij Origin (lub X-Checkify-Site-Url) z nazwą hosta z listy w sekcji Witryny → dozwolone domeny. Nazwa hosta musi być identyczna — checkify.me i www.checkify.me to różne domeny.
Najczęstszy problem testowy
Jeśli polecenie /start zwróci błąd HTTP 403, Twój identyfikator hasła może być nadal prawidłowy. Zazwyczaj przyczyną jest to, że domena żądania nie znajduje się na liście dozwolonych domen lub że zarejestrowano domenę www.example.com, ale użyto example.com (lub odwrotnie).
Użyj dedykowanej witryny testowej i przekaż ją w panelu Checkify do testów integracyjnych. Klucze witryny API używają prefiksu csk_; nie ma oddzielnego formatu klucza testowego. Nie testuj w środowisku produkcyjnym, dopóki nie potwierdzisz zarówno przepływu pomyślnego, jak i odrzuconego.
# 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
}'
Używaj klucza API tylko podczas połączenia weryfikacyjnego. Przed połączeniem weryfikacyjnym zakończ weryfikację w aplikacji — w przeciwnym razie otrzymasz status oczekujący.
Ustaw wymagane_roszczenia tak, aby odpowiadały dowodowi wymaganemu przez Twoje działanie chronione. Nazwy roszczeń muszą być zgodne z tym, co Checkify zatwierdził dla danej sesji weryfikacji. Weryfikacja wieku używa age_over_{N} (na przykład age_over_18). Dynamiczne progi od 10 do 110 są obsługiwane, gdy osadzanie żąda pasującego typu żądania.
| Przypadek użycia | Sugerowane wymagane_roszczenia | Notatki |
|---|---|---|
| Zamiennik bota / CAPTCHA | ["human_verified"] |
Potwierdza, że prawdziwy użytkownik ukończył przepływ Checkify. |
| Treści 13+ lub produkty skierowane do młodzieży | ["age_over_13"] |
Użyj, gdy Twój Karnet wymaga podania wieku powyżej 13 lat. |
| Treści dla osób powyżej 16 roku życia lub regionalne zasady dotyczące wieku | ["age_over_16"] |
Użyj, gdy Twój Karnet wymaga podania wieku powyżej 16 lat. |
| Vape, alkohol lub kasa dla osób powyżej 18 roku życia | ["age_over_18"] |
Dopasuj próg wiekowy do swojego produktu i rynku. |
| 21+ produktów objętych ograniczeniami (jeśli dotyczy) | ["age_over_21"] |
Użyj, gdy Twój Karnet wymaga podania wieku powyżej 21 lat. |
| Wyzwanie 25 lub bardziej rygorystyczna polityka detaliczna | ["age_over_25"] |
Użyj, gdy Twój Karnet wymaga podania wieku powyżej 25 lat. |
| Niestandardowy próg wiekowy | ["age_over_N"] |
Użyj age_over_N, gdzie N wynosi 10–110, zgodnie z typem żądania osadzenia. |
Typ żądania przeglądarki musi odpowiadać żądaniu weryfikowanemu po stronie serwera.
| Osadź typ żądania | wymagane_roszczenia |
|---|---|
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) |
Oprócz wymaganych_roszczeń, możesz wymagać określonych zatwierdzonych pól tożsamości (na przykład kraju lub przedziału wiekowego) podczas ich gromadzenia przez integrację. Przekaż nazwy pól w wymaganych_polach — jeśli w zatwierdzonym wyniku brakuje jakichkolwiek pól, weryfikacja zwróci verification_failed z missing_fields w error.details.
Wywołaj polecenie POST /v1/qr/results/verify z kluczem API swojej witryny przed udzieleniem dostępu. Traktuj odwołanie do przeglądarki (request_id lub starszy token sondy) jako niezaufane, dopóki Checkify nie potwierdzi wyniku.
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
}
Możesz również wysłać
token
zamiast
request_id.
Klucz API ma zakres ograniczony do witryny Checkify — w treści żądania nie wysyłasz parametru 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;
}
}
}
Użyj „consume: true” dla ostatecznych chronionych akcji — kasa, rejestracja, resetowanie hasła, zakup z ograniczeniem wiekowym, dostęp do treści chronionych
Użyj „consume: false” tylko dla — testowanie, debugowanie lub kontrole nieostateczne, w których wynik musi zostać później ponownie zweryfikowany
W przypadku działań regulowanych lub wysokiego ryzyka należy ustawić wartość consume: true, aby ten sam wynik weryfikacji nie mógł zostać wykorzystany ponownie do wielu chronionych decyzji.
Jeśli Twoje zaplecze nie może osiągnąć poziomu Checkify, nie zezwalaj na dokonywanie płatności z ograniczeniami wiekowymi, dostęp do gier hazardowych, dostęp do treści dla dorosłych, zakup e-papierosów lub alkoholu ani na inne chronione działania bez potwierdzonego wyniku po stronie serwera.
Stosuj krótkie limity czasu HTTP (na przykład 10 sekund). Ponów próbę raz lub dwa razy w przypadku przejściowych błędów 5xx lub sieciowych, a następnie odmów dostępu. Rejestruj incydenty po stronie serwera i wyświetlaj komunikaty bezpieczne dla użytkownika. Nie ujawniaj klientom wewnętrznych szczegółów błędu 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.",
});
}
Użyj @checkify/server (npm) lub checkify-server (Python) dla typowych funkcji pomocniczych do weryfikacji lub wywołaj bezpośrednio polecenie POST /v1/qr/results/verify. Nie opublikowano jeszcze specyfikacji OpenAPI — skorzystaj z przykładów na tej stronie.
Pakiet @checkify/server w wersji 1.0.0 został opublikowany na platformie npm. Pakiet Python checkify-server znajduje się w monorepozytorium Checkify SDK.
Zakończone weryfikacje tracą ważność po upływie QR_RESULT_MAX_AGE_SECONDS (domyślnie 900 sekund / 15 minut). Po upływie tego czasu funkcja weryfikacyjna zwraca wartość result_expired — prosząc użytkownika o ponowną weryfikację.
JavaScript SDK obsługuje stan sesji dla standardowych osadzeń. Używaj ich tylko wtedy, gdy tworzysz niestandardowy front-end, który ręcznie wywołuje GET /v1/qr/pass/{pass_id}/start.
POBIERZ /v1/qr/status?token={poll_token}POBIERZ /v1/qr/status/request/{request_id}?status_token={status_token}W przypadku powodzenia Checkify zwraca HTTP 200 z wartością success: true i statusem: completed. Zezwalaj na dostęp tylko wtedy, gdy występują wymagane oświadczenia (na przykład 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"
}
}
Obiekt signed_result pozwala Twojemu zapleczu przechowywać zabezpieczony przed manipulacją rekord audytu, który potwierdza, że Checkify zatwierdził wymagane roszczenie w momencie weryfikacji. Większość integracji wymaga jedynie approved_claims. Firmy regulowane lub wysokiego ryzyka mogą również przechowywać signed_result na potrzeby audytu. Nie przechowuj więcej danych osobowych niż to konieczne.
Jeśli klient nie zakończył jeszcze działania w aplikacji, Checkify zwraca HTTP 200 z komunikatem „sukces: fałsz” i statusem „oczekujący”. Odrzuca chronione akcje i prosi użytkownika o dokończenie weryfikacji.
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| Pole | Oznaczający |
|---|---|
success | true po zakończeniu weryfikacji i spełnieniu wymagań |
status | completed Lub pending |
approved_claims | Zatwierdzono roszczenia Checkify, np. human_verified: true |
signed_result | Opcjonalny podpisany ładunek dla śladów audytu |
Gdy weryfikacja nie może być kontynuowana, Checkify zwraca HTTP 4xx/5xx ze strukturą JSON. Sprawdź kod błędu i zaloguj szczegóły błędu po stronie serwera. Zwróć użytkownikom końcowym ogólne komunikaty.
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| Kod | HTTP | Oznaczający | Zalecane działanie |
|---|---|---|---|
missing_authorization | 401 | Nagłówek autoryzacyjny nie został wysłany. | Wyślij autoryzację: Nośnik YOUR_SITE_API_KEY tylko z kodu po stronie serwera. |
invalid_token | 401 | Brak tokenu nośnika, jest on źle sformatowany lub nie jest prawidłowym kluczem witryny API. | Zweryfikuj klucz w panelu biznesowym i zapisz go w zmiennych środowiskowych. |
expired_token | 401 | Klucz witryny API został unieważniony. | Utwórz nowy klucz witryny API i rotacyjnie go stosuj na swoich serwerach. |
missing_required_field | 400 / 422 | Brak identyfikatora żądania lub tokenu w treści JSON. | Przekaż request_id z ukrytego pola formularza lub token ankiety, jeśli Twoja integracja nadal go używa. |
invalid_request_id | 400 | Nie można przeanalizować odniesienia lub jest ono puste po normalizacji. | Upewnij się, że Twój interfejs użytkownika przesyła żądanie Checkify bez zmian. |
result_not_found | 404 | Dla tego odniesienia nie istnieje prośba o weryfikację. | Odrzuć akcję. Użytkownik mógł zmodyfikować ukryte pole lub przesłać starą sesję. |
result_expired | 410 | Weryfikacja została ukończona zbyt dawno temu, aby można było zaufać tej akcji. | Poproś użytkownika o ponowne skanowanie i wywołanie verify z nowym request_id. |
verification_failed | 403 / 409 | Weryfikacja została zakończona, ale nie spełniła wymagań/pól, należy do innej witryny lub została już wykorzystana. | Odmów dostępu. Sprawdź szczegóły błędu pod kątem brakujących roszczeń, brakujących pól lub przyczyny. |
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 | Konto firmowe jest zablokowane, zarchiwizowane lub nie działa. | Skontaktuj się z właścicielem firmy lub działem pomocy technicznej Checkify. Nie zezwalaj na akcje chronione, dopóki konto nie będzie aktywne. |
validation_errors | 422 | Treść JSON nie przeszła walidacji schematu (HTTP 422). | Sprawdź error.details.validation_errors pod kątem komunikatów na poziomie pola. Przed ponowieniem próby popraw typy request_id, required_claims lub required_fields. |
rate_limited | 429 | Zbyt wiele połączeń weryfikacyjnych w krótkim czasie. | Spróbuj ponownie z wycofywaniem wykładniczym. Weryfikuj tylko w przypadku akcji chronionych, a nie przy każdym wyświetleniu strony. |
server_error | 500+ | Checkify nie mógł dokończyć weryfikacji z powodu tymczasowego problemu z serwerem. | Spróbuj ponownie raz lub dwa razy, następnie zakończ akcję niepowodzeniem i zarejestruj incydent. |
Obecnie weryfikacja serwera jest synchroniczna: system zaplecza weryfikuje request_id, gdy użytkownik wysyła chronioną akcję. Jest to zalecane podejście w przypadku procesów płatności, rejestracji i kontroli dostępu. Standardowe integracje nie wymagają webhooków weryfikacyjnych ogólnego przeznaczenia. Integracje GoHighLevel i innych partnerów mogą korzystać z oddzielnej konfiguracji webhooków wychodzących w panelu biznesowym.
Traktuj ukryte pole jako niezaufane odniesienie, a nie dowód. Zawsze weryfikuj klucz API swojej witryny na serwerze przed udzieleniem dostępu.
consume: true
do jednorazowych czynności, np. rejestracji lub resetowania hasła.