Nachdem die Browser-Einbettung abgeschlossen ist, muss Ihr Server das Ergebnis mit einem Site-API-Schlüssel überprüfen, bevor er die Anmeldung, den Checkout oder eine geschützte Aktion zulässt.
Das versteckte Formularfeld kann zwar den Namen checkify_token tragen, sein Wert ist jedoch die Checkify request_id.
Öffnen Sie in Ihrem Unternehmens-Dashboard Entwickler und erstellen Sie einen Site-API-Schlüssel für die Site, die Sie integrieren. Speichern Sie es nur in Serverumgebungsvariablen – senden Sie es niemals an den Browser.
Sie müssen GET /v1/qr/pass/{PASS_ID}/start nicht manuell aufrufen. Die Checkify JavaScript-Einbettung startet die Sitzung, empfängt die request_id und schreibt sie automatisch in Ihr Formular.
Ihr Backend muss lediglich Folgendes leisten:
Das Frontend SDK schreibt die Checkify-Anfrage-ID nach Abschluss der Benutzerverifizierung in ein verstecktes Formularfeld. Der Standardfeldname lautet checkify_token – dies ist der Feldname, kein separater Token-Typ. Senden Sie den Feldwert als Anfrage-ID an den Verifizierungsendpunkt.
Bei der Übergabe einer mobilen App kann die URL `checkify_request_id` enthalten. SDK liest diese beim Laden der Seite aus; Ihr Server überprüft weiterhin denselben Wert für `request_id`.
Formular POST von Ihrem Frontend
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
Überprüfen Sie die Anfrage von Ihrem Backend.
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
Nur manuelle Frontend-Integration
Backend-Entwickler rufen `/start` normalerweise nicht auf. Verwenden Sie diesen Abschnitt nur beim Erstellen eines benutzerdefinierten Frontends oder beim Testen ohne Einbettung. Setzen Sie URLs in zsh/bash in Anführungszeichen, damit das Fragezeichen nicht als Glob interpretiert wird.
Der Befehl „Pass start“ funktioniert nur von einer registrierten Website-Domain. Browser senden den Ursprung automatisch; cURL hingegen nicht. Senden Sie den Ursprung (oder die X-Checkify-Site-Url) mit einem Hostnamen, der unter „Websites → Zulässige Domains“ aufgeführt ist. Der Hostname muss exakt übereinstimmen – checkify.me und www.checkify.me sind unterschiedlich.
Häufigstes Testproblem
Wenn /start den HTTP-Statuscode 403 zurückgibt, ist Ihre Pass-ID möglicherweise trotzdem gültig. Die übliche Ursache ist, dass die angeforderte Domain nicht in der Liste der zulässigen Domains aufgeführt ist oder dass www.example.com zwar registriert, aber example.com verwendet wurde (oder umgekehrt).
Verwenden Sie eine dedizierte Testumgebung und geben Sie „Pass“ in Ihrem Checkify-Dashboard für Integrationstests ein. Site-API-Schlüssel verwenden das Präfix „csk_“; es gibt kein separates Testschlüsselformat. Testen Sie erst dann mit der Produktionsumgebung, wenn Sie sowohl erfolgreiche als auch fehlerhafte Abläufe bestätigt haben.
# 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
}'
Verwenden Sie Ihren API-Schlüssel ausschließlich beim Verifizierungsanruf. Schließen Sie die Verifizierung in der App ab, bevor Sie den Verifizierungsanruf tätigen – andernfalls erhalten Sie den Status „Ausstehend“.
Legen Sie die erforderlichen Ansprüche so fest, dass sie dem Nachweis entsprechen, den Ihre geschützte Aktion benötigt. Die Anspruchsnamen müssen mit den von Checkify für diese Verifizierungssitzung genehmigten Namen übereinstimmen. Altersprüfungen verwenden age_over_{N} (z. B. age_over_18). Dynamische Schwellenwerte von 10 bis 110 werden unterstützt, wenn die Einbettung den entsprechenden Anfragetyp anfordert.
| Anwendungsfall | Vorgeschlagene erforderliche Ansprüche | Anmerkungen |
|---|---|---|
| Bot / CAPTCHA Ersatz | ["human_verified"] |
Bestätigt, dass ein echter Benutzer den Checkify-Workflow abgeschlossen hat. |
| Inhalte ab 13 Jahren oder Produkte für Jugendliche | ["age_over_13"] |
Verwenden Sie diese Option, wenn Ihr Pass ein Alter über 13 Jahren erfordert. |
| Inhalte ab 16 Jahren oder regionale Altersbestimmungen | ["age_over_16"] |
Verwenden Sie diese Option, wenn Ihr Pass eine Altersangabe über 16 Jahren erfordert. |
| Vape, Alkohol oder Kasse für Artikel ab 18 Jahren | ["age_over_18"] |
Passen Sie die Altersgrenze an Ihr Produkt und Ihren Markt an. |
| Produkte, die nur für Personen ab 21 Jahren geeignet sind (sofern zutreffend). | ["age_over_21"] |
Verwenden Sie diese Option, wenn Ihr Pass ein Alter über 21 Jahren erfordert. |
| Herausforderung 25 oder strengere Einzelhandelspolitik | ["age_over_25"] |
Verwenden Sie diese Option, wenn Ihr Pass eine Altersangabe über 25 Jahren erfordert. |
| Benutzerdefinierte Altersgrenze | ["age_over_N"] |
Verwenden Sie age_over_N, wobei N zwischen 10 und 110 liegt, entsprechend Ihrem Einbettungsanforderungstyp. |
Der Browser-Anfragetyp muss mit der serverseitig überprüften Behauptung übereinstimmen.
| Einbettungsanfragetyp | erforderliche Ansprüche |
|---|---|
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) |
Neben required_claims können Sie bestimmte genehmigte Identitätsfelder verlangen (z. B. Land oder Altersband), wenn Ihre Integration sie erfasst hat. Übergeben Sie Feldnamen in required_fields — fehlen sie im genehmigten Ergebnis, liefert verify missing_required_fields mit missing_fields in error.details.
Rufen Sie POST /v1/qr/results/verify mit Ihrem API-Schlüssel auf, bevor Sie Zugriff gewähren. Behandeln Sie die Browserreferenz (request_id oder Legacy-Poll-Token) als nicht vertrauenswürdig, bis Checkify das Ergebnis bestätigt hat.
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
}
Sie können auch senden
token
anstatt
request_id.
Der Schlüssel API ist auf Ihre Checkify-Site beschränkt – Sie senden die site_id nicht im Anfragetext.
# 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;
}
}
}
Verwenden Sie consume: true für endgültige geschützte Aktionen — Bezahlvorgang, Registrierung, Passwort zurücksetzen, Kauf mit Altersbeschränkung, Zugriff auf geschützte Inhalte
Verwenden Sie consume: false nur für — Testen, Debuggen oder nicht finale Prüfungen, bei denen das Ergebnis später erneut überprüft werden muss.
Bei regulierten oder risikoreichen Aktionen sollte „consume: true“ bevorzugt werden, damit dasselbe Verifizierungsergebnis nicht für mehrere geschützte Entscheidungen wiederverwendet werden kann.
Falls Ihr Backend Checkify nicht erreichen kann, erlauben Sie keine altersbeschränkten Bezahlvorgänge, keinen Zugriff auf Glücksspiele, keinen Zugriff auf Inhalte für Erwachsene, keinen Kauf von E-Zigaretten oder Alkohol oder andere geschützte Aktionen ohne ein bestätigtes serverseitiges Ergebnis.
Verwenden Sie kurze HTTP-Timeouts (z. B. 10 Sekunden). Versuchen Sie bei vorübergehenden 5xx-Fehlern oder Netzwerkfehlern ein- bis zweimal, den Zugriff zu verweigern und protokollieren Sie Vorfälle serverseitig mit benutzerfreundlichen Meldungen. Geben Sie interne GLO_6-Fehlerdetails nicht an Kunden weiter.
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 ist auf npm veröffentlicht. Das Python-Paket checkify-server ist im Checkify SDK Monorepo enthalten.
Abgeschlossene Verifizierungen verfallen nach QR_RESULT_MAX_AGE_SECONDS (standardmäßig 900 Sekunden / 15 Minuten). Nach Ablauf dieser Frist gibt die Überprüfung „result_expired“ zurück und fordert den Benutzer zur erneuten Verifizierung auf.
Die Klassen JavaScript und SDK verwalten den Sitzungsstatus für Standard-Einbettungen. Verwenden Sie diese nur, wenn Sie ein benutzerdefiniertes Frontend erstellen, das manuell GET /v1/qr/pass/{pass_id}/start aufruft.
GET /v1/qr/status?token={poll_token}GET /v1/qr/status/request/{request_id}?status_token={status_token}Bei Erfolg gibt Checkify den HTTP-Statuscode 200 mit success: true und status: completed zurück. Der Zugriff wird nur gewährt, wenn die erforderlichen Angaben vorhanden sind (z. B. 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"
}
}
Das Objekt signed_result ermöglicht Ihrem Backend einen manipulationssicheren Audit-Eintrag, dass Checkify den erforderlichen Claim zum Verifizierungszeitpunkt genehmigt hat. Die meisten Integrationen benötigen nur approved_claims. Regulierte oder risikoreiche Unternehmen können signed_result zusätzlich speichern. Verschachteltes proof_metadata kann kryptografische oder operative Nachweise enthalten (z. B. Assurance-Metadaten, Evidence-Typen oder Consent-Hashes) — keine Ausweisdokumente und kein rohes Geburtsdatum. Behandeln Sie verschachtelte Assurance-Felder nicht als Zertifizierung oder Vertrauensgarantie; prüfen Sie certification_status und Ihre eigene Richtlinie. Speichern Sie nicht mehr personenbezogene Daten als nötig.
Wenn der Kunde die Anwendung noch nicht abgeschlossen hat, gibt Checkify den HTTP-Statuscode 200 mit „success: false“ und „status: pending“ zurück. Geschützte Aktionen werden verweigert und der Benutzer zur Verifizierung aufgefordert.
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| Feld | Bedeutung |
|---|---|
success | true wenn die Verifizierung abgeschlossen ist und Anforderungen senden übereinstimmend |
status | completed oder pending |
approved_claims | Ansprüche Checkify genehmigt, z.B. human_verified: true |
signed_result | Optional signierte Nutzlast für Audit-Trails |
Wenn die Verifizierung fehlschlägt, gibt Checkify einen HTTP-4xx/5xx-Fehler mit einem strukturierten JSON-Body zurück. Prüfen Sie den Fehlercode und protokollieren Sie die Fehlerdetails serverseitig. Geben Sie allgemeine Fehlermeldungen an die Endbenutzer zurück.
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| Code | HTTP | Bedeutung | Empfohlene Maßnahmen |
|---|---|---|---|
missing_authorization | 401 | Es wurde kein Autorisierungsheader gesendet. | Send Authorization: Bearer YOUR_SITE_API_KEY ausschließlich vom serverseitigen Code. |
invalid_token | 401 | Bearer-Token fehlt, ist fehlerhaft oder kein gültiger Site-API-Schlüssel. | Überprüfen Sie den Schlüssel in Ihrem Business-Dashboard und speichern Sie ihn in den Umgebungsvariablen. |
expired_token | 401 | Der Website-Schlüssel API wurde widerrufen. | Erstellen Sie einen neuen Site-Schlüssel API und wechseln Sie ihn regelmäßig auf Ihren Servern. |
missing_required_field | 400 / 422 | Im JSON-Body fehlt die request_id oder das Token. | Übergeben Sie die request_id aus Ihrem versteckten Formularfeld oder das Poll-Token, falls Ihre Integration dieses noch verwendet. |
invalid_request_id | 400 | Die Referenz konnte nicht analysiert werden oder ist nach der Normalisierung leer. | Stellen Sie sicher, dass Ihr Frontend die Checkify request_id unverändert übermittelt. |
result_not_found | 404 | Für diese Referenz existiert keine Verifizierungsanfrage. | Die Aktion wird abgelehnt. Der Benutzer hat möglicherweise das versteckte Feld manipuliert oder eine alte Sitzung übermittelt. |
result_expired | 410 | Die Überprüfung ist zu lange her, um dieser Maßnahme noch vertrauen zu können. | Bitten Sie den Benutzer, erneut zu scannen und die Überprüfung mit der neuen request_id aufzurufen. |
verification_failed | 403 / 409 | Site-/Business-Mismatch, bereits verbrauchtes Ergebnis (HTTP 409) oder ein allgemeiner Verifizierungsfehler. | Zugriff verweigern. error.details prüfen. Bei Claim-/Feldlücken siehe missing_required_claims und 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 | Das Geschäftskonto ist gesperrt, archiviert oder nicht betriebsbereit. | Wenden Sie sich an den Geschäftsinhaber oder den GLO_6-Support. Geschützte Aktionen sind erst nach der Aktivierung des Kontos zulässig. |
validation_errors | 422 | Der JSON-Body konnte das Schema nicht validieren (HTTP 422). | Prüfen Sie error.details.validation_errors auf Meldungen auf Feldebene. Korrigieren Sie die Datentypen request_id, required_claims oder required_fields, bevor Sie es erneut versuchen. |
rate_limited | 429 | Zu viele Verifizierungsanrufe in einem kurzen Zeitraum. | Wiederholen mit exponentiellem Backoff. Überprüfung nur bei geschützten Aktionen, nicht bei jedem Seitenaufruf. |
server_error | 500+ | Die Überprüfung durch Checkify konnte aufgrund eines vorübergehenden Serverproblems nicht abgeschlossen werden. | Versuchen Sie es ein- oder zweimal erneut, schließen Sie dann den Fehler und protokollieren Sie den Vorfall. |
Die Serververifizierung erfolgt heute synchron: Ihr Backend überprüft die request_id, sobald der Nutzer die geschützte Aktion absendet. Dies ist die empfohlene Vorgehensweise für Checkout-, Registrierungs- und Zugriffskontrollprozesse. Allgemeine Verifizierungs-Webhooks sind für Standardintegrationen nicht erforderlich. GoHighLevel und andere Partnerintegrationen können separate ausgehende Webhook-Konfigurationen im Business-Dashboard verwenden.
Behandeln Sie das ausgeblendete Feld als nicht vertrauenswürdige Referenz, nicht als Beweis. Überprüfen Sie immer den API-Schlüssel Ihrer Website auf dem Server, bevor Sie Zugriff gewähren. Verwenden
consume: true
für einmalige Aktionen wie Anmeldung oder Passwort-Zurücksetzung.