Une fois l'intégration du navigateur terminée, votre serveur doit vérifier le résultat avec une clé de site API avant d'autoriser l'inscription, le paiement ou toute action protégée.
Le champ de formulaire caché peut être nommé checkify_token, mais sa valeur est le request_id Checkify.
Dans le tableau de bord de votre entreprise, ouvrez Développeur et créez une clé de site API pour le site que vous intégrez. Stockez-le uniquement dans les variables d'environnement du serveur - ne l'envoyez jamais au navigateur.
Il n'est pas nécessaire d'appeler manuellement la requête GET /v1/qr/pass/{PASS_ID}/start. Le module intégré Checkify JavaScript démarre la session, reçoit l'identifiant de requête et l'inscrit automatiquement dans votre formulaire.
Votre serveur dorsal n'a besoin que de :
L'interface utilisateur (SDK) enregistre l'identifiant de requête (Checkify) dans un champ caché du formulaire une fois la vérification effectuée par l'utilisateur. Le nom par défaut de ce champ est « checkify_token » ; il s'agit du nom du champ et non d'un type de jeton distinct. Envoyez la valeur de ce champ au point de terminaison de vérification en tant qu'identifiant de requête.
Le transfert depuis une application mobile peut renvoyer checkify_request_id dans l'URL de la page. Le SDK le lit au chargement ; votre serveur vérifie toujours la même valeur de request_id.
Formulaire POST depuis votre interface utilisateur
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
Vérifiez la requête provenant de votre serveur.
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
Intégration manuelle du frontend uniquement
Les développeurs backend n'utilisent généralement pas la commande `/start`. Utilisez cette section uniquement lors de la création d'une interface personnalisée ou lors de tests sans intégration. Dans zsh/bash, placez les URL entre guillemets afin que le caractère `?` ne soit pas interprété comme un glob.
La commande « Pass start » ne fonctionne qu'à partir d'un nom de domaine enregistré. Les navigateurs envoient automatiquement l'origine ; cURL, non. Envoyez l'origine (ou X-Checkify-URL-du-site) avec un nom d'hôte figurant dans la section « Sites » → « Domaines autorisés ». Le nom d'hôte doit correspondre exactement : « checkify.me » et « www.checkify.me » sont différents.
Problème de test le plus courant
Si la commande /start renvoie une erreur HTTP 403, votre identifiant de mot de passe peut néanmoins être valide. Cela est généralement dû au fait que le domaine demandé ne figure pas dans la liste des domaines autorisés, ou que www.example.com a été enregistré mais que example.com a été utilisé (ou inversement).
Utilisez un site de test dédié et transmettez votre tableau de bord Checkify pour les tests d'intégration. Les clés du site API utilisent le préfixe csk_ ; il n'existe pas de format de clé de test spécifique. Ne réalisez pas de tests sur l'environnement de production tant que vous n'avez pas validé les scénarios de succès et d'échec.
# 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
}'
Utilisez votre clé API uniquement lors de l'appel de vérification. Finalisez la vérification dans l'application avant d'appeler pour vérifier votre demande ; sinon, le statut restera « en attente ».
Configurez les revendications requises pour qu'elles correspondent aux preuves nécessaires à votre action protégée. Les noms des revendications doivent correspondre à ceux approuvés par Checkify pour cette session de vérification. Les contrôles d'âge utilisent age_over_{N} (par exemple, age_over_18). Les seuils dynamiques de 10 à 110 sont pris en charge lorsque l'intégration demande le type de requête correspondant.
| Cas d'utilisation | revendications_requises suggérées | Notes |
|---|---|---|
| Remplacement du robot / CAPTCHA | ["human_verified"] |
Confirme qu'un utilisateur réel a terminé le flux Checkify. |
| Contenu destiné aux 13 ans et plus ou produits destinés aux jeunes | ["age_over_13"] |
À utiliser lorsque votre Pass requiert l'âge de plus de 13 ans. |
| Contenu réservé aux adultes (16+) ou soumis à des règles d'âge régionales | ["age_over_16"] |
À utiliser lorsque votre Pass requiert l'âge de plus de 16 ans. |
| Vape, alcool ou caisse réservée aux personnes de plus de 18 ans | ["age_over_18"] |
Adaptez le seuil d'âge à votre produit et à votre marché. |
| Produits réservés aux personnes de 21 ans et plus (le cas échéant) | ["age_over_21"] |
À utiliser lorsque votre Pass requiert l'âge de plus de 21 ans. |
| Défiez 25 ou une politique de vente au détail plus stricte | ["age_over_25"] |
À utiliser lorsque votre Pass requiert l'âge de plus de 25 ans. |
| Seuil d'âge personnalisé | ["age_over_N"] |
Utilisez age_over_N où N est compris entre 10 et 110, en accord avec votre type de requête d'intégration. |
Le type de requête du navigateur doit correspondre à l'affirmation que vous vérifiez côté serveur.
| Type de requête d'intégration | revendications_obligatoires |
|---|---|
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) |
Outre required_claims, vous pouvez exiger des champs d’identité approuvés spécifiques (par ex. pays ou tranche d’âge) lorsque votre intégration les a collectés. Passez les noms dans required_fields — s’ils manquent dans le résultat approuvé, verify renvoie missing_required_fields avec missing_fields dans error.details.
Effectuez une requête POST /v1/qr/results/verify avec votre clé API avant d'accorder l'accès. Considérez la référence du navigateur (request_id ou jeton d'interrogation hérité) comme non fiable jusqu'à ce que Checkify confirme le résultat.
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
}
Vous pouvez également envoyer
token
au lieu de
request_id.
La clé API est limitée à votre site Checkify — vous n'envoyez pas site_id dans le corps de la requête.
# 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;
}
}
}
Utilisez consume: true pour les actions protégées finales — Paiement, inscription, réinitialisation du mot de passe, achat soumis à une restriction d'âge, accès au contenu protégé
Utilisez consume: false uniquement pour — tests, débogage ou vérifications non finales où le résultat doit être vérifié ultérieurement
Pour les actions réglementées ou à haut risque, privilégiez consumer: true afin que le même résultat de vérification ne puisse pas être réutilisé pour plusieurs décisions protégées.
Si votre serveur ne peut pas atteindre Checkify, n'autorisez pas les paiements réservés aux personnes majeures, l'accès aux jeux d'argent, l'accès au contenu pour adultes, l'achat de cigarettes électroniques ou d'alcool, ni d'autres actions protégées sans un résultat confirmé côté serveur.
Utilisez des délais d'attente HTTP courts (par exemple, 10 secondes). En cas d'erreur 5xx ou d'erreur réseau transitoire, réessayez une ou deux fois, puis refusez l'accès. Consignez les incidents côté serveur et affichez des messages sécurisés pour l'utilisateur. Ne divulguez pas les détails des erreurs internes Checkify aux clients.
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 est disponible sur npm. Le package Python checkify-server est inclus dans le monorepo Checkify SDK.
Les vérifications effectuées expirent après QR_RESULT_MAX_AGE_SECONDS (par défaut 900 secondes / 15 minutes). Après expiration, la vérification renvoie result_expired ; l’utilisateur est alors invité à vérifier à nouveau.
Les classes JavaScript et SDK gèrent l'état de session pour les applications intégrées standard. Utilisez-les uniquement lorsque vous créez une interface personnalisée qui appelle manuellement la fonction 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}En cas de succès, Checkify renvoie HTTP 200 avec success: true et status: completed. L'accès n'est autorisé que si les revendications requises sont présentes (par exemple, 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"
}
}
L’objet signed_result permet à votre backend de conserver une trace d’audit inviolable indiquant que Checkify a approuvé le claim requis au moment de la vérification. La plupart des intégrations n’ont besoin que de approved_claims. Les entreprises réglementées ou à haut risque peuvent aussi stocker signed_result. proof_metadata imbriqué peut contenir des preuves cryptographiques ou opérationnelles (métadonnées d’assurance, types de preuves ou hachages de consentement) — pas de documents d’identité ni de date de naissance brute. Ne traitez pas les champs d’assurance imbriqués comme une certification ou une garantie de confiance ; vérifiez certification_status et votre propre politique. Ne stockez pas plus de données personnelles que nécessaire.
Si le client n'a pas encore terminé dans l'application, Checkify renvoie HTTP 200 avec success: false et status: pending. Refusez les actions protégées et demandez à l'utilisateur de terminer la vérification.
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| Champ | Signification |
|---|---|
success | true lorsque la vérification est terminée et que les exigences correspondent |
status | completed ou pending |
approved_claims | Réclamations Checkify approuvées, par ex. human_verified: true |
signed_result | Charge utile signée en option pour les pistes d'audit |
En cas d'échec de la vérification, Checkify renvoie une réponse HTTP 4xx/5xx avec un corps structuré JSON. Vérifiez le code d'erreur et consignez les détails de l'erreur côté serveur. Affichez des messages génériques aux utilisateurs.
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| Code | HTTP | Signification | Action recommandée |
|---|---|---|---|
missing_authorization | 401 | Aucun en-tête d'autorisation n'a été envoyé. | Envoyer l'autorisation : Bearer VOTRE_SITE_API_KEY uniquement depuis le code côté serveur. |
invalid_token | 401 | Jeton porteur manquant, mal formé ou clé de site API non valide. | Vérifiez la clé dans votre tableau de bord d'entreprise et stockez-la dans les variables d'environnement. |
expired_token | 401 | La clé du site API a été révoquée. | Créez une nouvelle clé de site API et faites-la tourner sur vos serveurs. |
missing_required_field | 400 / 422 | L'identifiant de requête ou le jeton est manquant dans le corps JSON. | Transmettez l'identifiant de requête (request_id) depuis votre champ de formulaire caché, ou le jeton d'interrogation si votre intégration l'utilise encore. |
invalid_request_id | 400 | La référence n'a pas pu être analysée ou est vide après normalisation. | Assurez-vous que votre interface soumette l'identifiant de requête Checkify sans modification. |
result_not_found | 404 | Aucune demande de vérification n'existe pour cette référence. | Rejetez l'action. L'utilisateur a peut-être modifié le champ caché ou soumis une ancienne session. |
result_expired | 410 | La vérification date de trop longtemps pour qu'on puisse se fier à cette action. | Demandez à l'utilisateur de scanner à nouveau et appelez la fonction de vérification avec le nouvel identifiant de requête (request_id). |
verification_failed | 403 / 409 | Incohérence site/entreprise, résultat déjà consommé (HTTP 409), ou échec générique de vérification. | Refusez l’accès. Inspectez error.details. Pour les manques de claims/champs, voir missing_required_claims et 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 | Le compte professionnel est verrouillé, archivé ou non opérationnel. | Contactez le propriétaire de l'entreprise ou le support Checkify. N'autorisez aucune action protégée tant que le compte n'est pas actif. |
validation_errors | 422 | Le corps JSON n'a pas pu être validé selon le schéma (HTTP 422). | Examinez les erreurs de validation (error.details.validation_errors) pour identifier les messages d'erreur au niveau des champs. Corrigez les types request_id, required_claims ou required_fields avant de réessayer. |
rate_limited | 429 | Trop d'appels de vérification en peu de temps. | Réessayer avec un délai exponentiel. Vérifier uniquement lors d'actions protégées, et non à chaque affichage de page. |
server_error | 500+ | Checkify n'a pas pu terminer la vérification en raison d'un problème temporaire de serveur. | Réessayez une ou deux fois, puis fermez le ticket en cas d'échec et consignez l'incident. |
Aujourd'hui, la vérification côté serveur est synchrone : votre système vérifie l'identifiant de requête (request_id) lorsque l'utilisateur effectue l'action protégée. Cette approche est recommandée pour les processus de paiement, d'inscription et de contrôle d'accès. Les webhooks de vérification génériques ne sont pas nécessaires pour les intégrations standard. GoHighLevel et d'autres partenaires peuvent utiliser une configuration de webhook sortant distincte dans le tableau de bord métier.
Traitez le champ caché comme une référence non fiable, et non comme une preuve. Vérifiez toujours avec la clé API de votre site sur le serveur avant d'accorder l'accès. Utilisez
consume: true
pour des actions ponctuelles telles que l'inscription ou la réinitialisation du mot de passe.