Nadat het insluiten van de browser is voltooid, moet uw server het resultaat verifiëren met een site-API-sleutel voordat u zich kunt aanmelden, afrekenen of een beschermde actie kunt uitvoeren.
Het verborgen formulierveld mag checkify_token heten, maar de waarde ervan is de Checkify request_id.
Open in uw bedrijfsdashboard Ontwikkelaar en maak een site-API-sleutel voor de site die u integreert. Bewaar het alleen in serveromgevingsvariabelen; stuur het nooit naar de browser.
U hoeft GET /v1/qr/pass/{PASS_ID}/start niet handmatig aan te roepen. De Checkify JavaScript-embed start de sessie, ontvangt de request_id en schrijft deze automatisch in uw formulier.
Uw backend hoeft alleen maar:
De frontend-SDK schrijft de Checkify request_id naar een verborgen formulierveld nadat de gebruiker de verificatie heeft voltooid. De standaardveldnaam is checkify_token, dat is de veldnaam en geen afzonderlijk tokentype. Stuur de veldwaarde naar het verificatie-eindpunt als request_id.
Handoff van mobiele app kan checkify_request_id retourneren in de pagina-URL. De SDK leest het tijdens het laden; uw server verifieert nog steeds dezelfde request_id-waarde.
Formulier POST vanaf uw frontend
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
Verifieer het verzoek van uw backend
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
Alleen handmatige frontend-integratie
Backend-ontwikkelaars bellen normaal gesproken niet /start. Gebruik deze sectie alleen als u een aangepaste frontend bouwt of test zonder de insluiting. Citeer URL's in zsh/bash dus? wordt niet als een klodder behandeld.
Pass start werkt alleen vanaf een geregistreerd websitedomein. Browsers verzenden Origin automatisch; krul niet. Stuur Origin (of X-Checkify-Site-Url) met een hostnaam vermeld onder Sites → toegestane domeinen. De hostnaam moet exact overeenkomen: checkify.me en www.checkify.me zijn verschillend.
Meest voorkomende testprobleem
Als /start HTTP 403 retourneert, is uw Pass-ID mogelijk nog steeds geldig. De gebruikelijke oorzaak is dat het aanvraagdomein niet in de toegestane domeinen staat, of dat www.example.com geregistreerd was maar example.com werd gebruikt (of omgekeerd).
Gebruik een speciale testsite en slaag in uw Checkify-dashboard voor integratietesten. Site-API-sleutels gebruiken het voorvoegsel csk_; er is geen afzonderlijk testsleutelformaat. Voer geen tests uit aan de hand van de productieafrekening totdat u zowel de succes- als de weigeringsstromen hebt bevestigd.
# 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
}'
Gebruik de API-sleutel van uw site alleen tijdens de verificatieaanroep. Voltooi de verificatie in de app voordat u verificatie aanroept. Anders krijgt u de status In behandeling.
Stel require_claims in zodat deze overeenkomen met het bewijs dat uw beschermde actie nodig heeft. Claimnamen moeten overeenkomen met wat Checkify heeft goedgekeurd voor die verificatiesessie. Leeftijdscontroles gebruiken age_over_{N} (bijvoorbeeld age_over_18). Dynamische drempelwaarden van 10 tot en met 110 worden ondersteund wanneer de insluiting het overeenkomende verzoektype aanvraagt.
| Gebruiksgeval | Voorgestelde vereiste_claims | Opmerkingen |
|---|---|---|
| Bot / CAPTCHA-vervanging | ["human_verified"] |
Bevestigt dat een echte gebruiker de Checkify-stroom heeft voltooid. |
| 13+ inhoud of op jongeren gerichte producten | ["age_over_13"] |
Gebruik deze als je Pas een leeftijd van 13 jaar of ouder aanvraagt. |
| 16+ inhoud of regionale leeftijdsregels | ["age_over_16"] |
Gebruik deze als je Pas een leeftijd van 16 jaar of ouder aanvraagt. |
| Vapen, alcohol of 18+ afrekenen | ["age_over_18"] |
Stem de leeftijdsgrens af op uw product en markt. |
| 21+ beperkte producten (waar van toepassing) | ["age_over_21"] |
Gebruik deze als je Pas een leeftijd van 21 jaar of ouder aanvraagt. |
| Challenge 25 of strenger retailbeleid | ["age_over_25"] |
Gebruik deze als je Pas een leeftijd van 25 jaar of ouder aanvraagt. |
| Aangepaste leeftijdsdrempel | ["age_over_N"] |
Gebruik age_over_N waarbij N 10–110 is, afgestemd op uw type insluitingsverzoek. |
Het browserverzoektype moet overeenkomen met de claim die u aan de serverzijde verifieert.
| Verzoektype insluiten | vereiste_claims |
|---|---|
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) |
Naast verplichte_claims heeft u mogelijk specifieke goedgekeurde identiteitsvelden nodig (bijvoorbeeld land of leeftijdscategorie) toen uw integratie deze verzamelde. Geef veldnamen door in verplichte_velden. Als er ontbreken in het goedgekeurde resultaat, verifieer dan de retourzendingen verificatie_failed met ontbrekende_velden in error.details.
Roep POST /v1/qr/results/verify aan met de API-sleutel van uw site voordat u toegang verleent. Behandel de browserreferentie (request_id of verouderd poll-token) als niet-vertrouwd totdat Checkify het resultaat bevestigt.
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
}
Je kunt ook verzenden
token
in plaats van
request_id.
De API-sleutel is gericht op uw Checkify-site; u verzendt geen site_id in de hoofdtekst van het verzoek.
# 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;
}
}
}
Gebruik consumeren: waar voor definitieve beschermde acties — afrekenen, aanmelden, wachtwoord opnieuw instellen, aankoop met leeftijdsbeperking, beveiligde toegang tot inhoud
Gebruik consumer: false alleen voor — testen, debuggen of niet-eindcontroles waarbij het resultaat later opnieuw moet worden geverifieerd
Voor gereguleerde of risicovolle acties geeft u de voorkeur aan consumer: true, zodat hetzelfde verificatieresultaat niet kan worden hergebruikt voor meerdere beschermde beslissingen.
Als uw backend Checkify niet kan bereiken, sta dan geen leeftijdsgebonden afrekenen, goktoegang, toegang tot inhoud voor volwassenen, aankoop van vape of alcohol of andere beschermde acties toe zonder een bevestigd server-side resultaat.
Gebruik korte HTTP-time-outs (bijvoorbeeld 10 seconden). Probeer het een of twee keer opnieuw voor tijdelijke 5xx- of netwerkfouten en weiger vervolgens de toegang. Registreer incidenten op de server en toon gebruikersveilige berichten. Stel interne Checkify-foutdetails niet bloot aan klanten.
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.",
});
}
Gebruik @checkify/server (npm) of checkify-server (Python) voor getypte verificatiehelpers, of roep POST /v1/qr/results/verify rechtstreeks aan. Er is nog geen OpenAPI-specificatie gepubliceerd. Gebruik de voorbeelden op deze pagina.
@checkify/server v1.0.0 is gepubliceerd op npm. Het Python checkify-server-pakket wordt geleverd in de Checkify SDK-monorepo.
Voltooide verificaties verlopen na QR_RESULT_MAX_AGE_SECONDS (standaard 900 seconden / 15 minuten). Na de vervaldatum verifieert u het resultaat result_expired: vraag de gebruiker om opnieuw te verifiëren.
De JavaScript SDK verwerkt de sessiestatus voor standaard insluitingen. Gebruik deze alleen wanneer u een aangepaste frontend bouwt die GET /v1/qr/pass/{pass_id}/start handmatig aanroept.
KRIJG /v1/qr/status?token={poll_token}GET /v1/qr/status/request/{request_id}?status_token={status_token}Bij succes retourneert Checkify HTTP 200 met succes: waar en status: voltooid. Sta alleen toegang toe als er vereiste claims aanwezig zijn (bijvoorbeeld 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"
}
}
Met het object Signed_result kan uw backend een fraudebestendige auditregistratie bijhouden waaruit blijkt dat Checkify de vereiste claim op het verificatietijdstip heeft goedgekeurd. Voor de meeste integraties zijn alleen goedgekeurde_claims nodig. Gereguleerde bedrijven of bedrijven met een hoog risico kunnen ook ondertekende resultaten opslaan voor controle. Bewaar niet meer persoonlijke informatie dan nodig is.
Als de klant nog niet klaar is in de app, retourneert Checkify HTTP 200 met succes: false en status: in behandeling. Weiger beschermde acties en vraag de gebruiker om de verificatie te voltooien.
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| Veld | Betekenis |
|---|---|
success | true wanneer de verificatie is voltooid en de vereisten overeenkomen |
status | completed of pending |
approved_claims | Claims Checkify goedgekeurd, b.v. human_verified: true |
signed_result | Optionele ondertekende payload voor audittrails |
Wanneer de verificatie niet kan doorgaan, retourneert Checkify HTTP 4xx/5xx met een gestructureerde JSON-body. Controleer error.code en log error.details op de server. Retourneer generieke berichten naar eindgebruikers.
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| Code | HTTP | Betekenis | Aanbevolen actie |
|---|---|---|---|
missing_authorization | 401 | Er is geen autorisatieheader verzonden. | Autorisatie verzenden: Bearer YOUR_SITE_API_KEY alleen vanaf code aan de serverzijde. |
invalid_token | 401 | Bearer-token ontbreekt, heeft een onjuiste indeling of heeft geen geldige site-API-sleutel. | Verifieer de sleutel in uw bedrijfsdashboard en sla deze op in omgevingsvariabelen. |
expired_token | 401 | De API-sleutel van de site is ingetrokken. | Maak een nieuwe site-API-sleutel en roteer deze op uw servers. |
missing_required_field | 400 / 422 | request_id of token ontbreekt in de JSON-hoofdtekst. | Geef de request_id uit uw verborgen formulierveld door, of de poll-token als uw integratie deze nog steeds gebruikt. |
invalid_request_id | 400 | De verwijzing kon niet worden geparseerd of is leeg na normalisatie. | Zorg ervoor dat uw frontend de Checkify request_id ongewijzigd indient. |
result_not_found | 404 | Er bestaat geen verificatieverzoek voor die referentie. | De actie afwijzen. Mogelijk heeft de gebruiker met het verborgen veld geknoeid of een oude sessie ingediend. |
result_expired | 410 | De verificatie is te lang geleden voltooid om deze actie te kunnen vertrouwen. | Vraag de gebruiker om opnieuw te scannen en bel verificatie aan met de nieuwe request_id. |
verification_failed | 403 / 409 | De verificatie is voltooid, maar voldoet niet aan de vereiste claims/velden, behoort tot een andere site of is al gebruikt. | Toegang weigeren. Inspecteer error.details op ontbrekende_claims, ontbrekende_velden of reden. |
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 | Het zakelijke account is vergrendeld, gearchiveerd of niet operationeel. | Neem contact op met de bedrijfseigenaar of met Checkify-ondersteuning. Sta geen beschermde acties toe totdat het account actief is. |
validation_errors | 422 | De JSON-hoofdtekst is niet in staat om het schema te valideren (HTTP 422). | Inspecteer error.details.validation_errors voor berichten op veldniveau. Corrigeer de typen request_id, require_claims of require_fields voordat u het opnieuw probeert. |
rate_limited | 429 | Te veel verificatieoproepen in een kort tijdsbestek. | Probeer het opnieuw met exponentieel uitstel. Verifieer alleen bij beveiligde acties, niet bij elke paginaweergave. |
server_error | 500+ | Checkify kon de verificatie niet voltooien vanwege een tijdelijk serverprobleem. | Probeer het een of twee keer opnieuw, sluit vervolgens de fout en registreer het incident. |
Tegenwoordig is serververificatie synchroon: uw backend verifieert de request_id wanneer de gebruiker de beschermde actie indient. Voor betaal-, aanmeldings- en toegangscontrolestromen is dit de aanbevolen aanpak. Algemene verificatiewebhooks zijn niet vereist voor standaardintegraties. GoHighLevel en andere partnerintegraties kunnen een afzonderlijke uitgaande webhookconfiguratie gebruiken in het bedrijfsdashboard.
Behandel het verborgen veld als een niet-vertrouwde referentie, niet als bewijs. Verifieer altijd met de API-sleutel van uw site op de server voordat u toegang verleent. Gebruik
consume: true
voor eenmalige acties zoals aanmelden of wachtwoord opnieuw instellen.