Una volta completato l'incorporamento nel browser, il tuo server deve verificare il risultato con una chiave API del sito prima di consentire la registrazione, il pagamento o qualsiasi azione protetta.
Il campo nascosto del modulo può essere denominato checkify_token, ma il suo valore è Checkify request_id.
Nella dashboard aziendale, apri Sviluppatore e crea una chiave API del sito per il sito che stai integrando. Memorizzalo solo nelle variabili di ambiente del server: non inviarlo mai al browser.
Non è necessario chiamare manualmente GET /v1/qr/pass/{PASS_ID}/start. L'embed Checkify JavaScript avvia la sessione, riceve il request_id e lo scrive automaticamente nel modulo.
Il tuo backend deve solo:
Il frontend SDK scrive il request_id Checkify in un campo modulo nascosto dopo che l'utente ha completato la verifica. Il nome del campo predefinito è checkify_token, ovvero il nome del campo, non un tipo di token separato. Invia il valore del campo all'endpoint di verifica come request_id.
Il passaggio di consegne tramite app mobile potrebbe restituire checkify_request_id nell'URL della pagina. Il componente SDK lo legge al caricamento; il server verifica comunque lo stesso valore di request_id.
Invia il modulo POST dal tuo frontend
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
Verifica la richiesta dal tuo backend
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
Integrazione manuale del frontend
Gli sviluppatori backend normalmente non chiamano /start. Utilizzare questa sezione solo quando si crea un frontend personalizzato o si esegue il test senza l'embed. Gli URL in zsh/bash sono racchiusi tra virgolette in modo che ? non venga trattato come un carattere jolly.
L'avvio del passaggio funziona solo da un dominio web registrato. I browser inviano automaticamente l'origine; cURL no. Invia l'origine (o X-Checkify-Site-Url) con un nome host elencato in Siti → domini consentiti. Il nome host deve corrispondere esattamente: checkify.me e www.checkify.me sono diversi.
Il problema più comune durante i test
Se la richiesta /start restituisce un errore HTTP 403, il tuo Pass ID potrebbe comunque essere valido. La causa più comune è che il dominio della richiesta non è presente nell'elenco dei domini consentiti, oppure che è stato registrato www.example.com ma è stato utilizzato example.com (o viceversa).
Utilizza un sito di test dedicato e Pass nella tua dashboard Checkify per i test di integrazione. Le chiavi del sito API utilizzano il prefisso csk_; non esiste un formato di chiave di test separato. Non eseguire test sul checkout di produzione finché non hai confermato sia i flussi di successo che quelli di rifiuto.
# 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
}'
Utilizza la chiave del tuo sito API solo durante la chiamata di verifica. Completa la verifica nell'app prima di chiamare per la verifica, altrimenti lo stato sarà in sospeso.
Imposta required_claims in modo che corrisponda alla prova necessaria per la tua azione protetta. I nomi delle attestazioni devono corrispondere a quelli approvati da Checkify per quella sessione di verifica. I controlli dell'età utilizzano age_over_{N} (ad esempio age_over_18). Sono supportate soglie dinamiche da 10 a 110 quando l'embed richiede il tipo di richiesta corrispondente.
| Caso d'uso | Richieste di informazioni richieste suggerite | Note |
|---|---|---|
| Sostituzione del bot / CAPTCHA | ["human_verified"] |
Conferma che un utente reale ha completato il flusso Checkify. |
| Contenuti adatti a un pubblico di età superiore ai 13 anni o prodotti destinati ai giovani. | ["age_over_13"] |
Da utilizzare quando il tuo Pass richiede un'età superiore ai 13 anni. |
| Contenuti per maggiori di 16 anni o norme regionali sull'età | ["age_over_16"] |
Da utilizzare quando il tuo Pass richiede età superiore a 16 anni. |
| Vietato l'acquisto di sigarette elettroniche, alcolici o prodotti per maggiori di 18 anni. | ["age_over_18"] |
Adatta la soglia di età al tuo prodotto e al tuo mercato. |
| Prodotti soggetti a restrizioni di età pari o superiore a 21 anni (ove applicabile) | ["age_over_21"] |
Da utilizzare quando il tuo Pass richiede un'età superiore ai 21 anni. |
| Sfida dei 25 anni o una politica di vendita al dettaglio più rigorosa | ["age_over_25"] |
Da utilizzare quando il tuo Pass richiede un'età superiore ai 25 anni. |
| Soglia di età personalizzata | ["age_over_N"] |
Utilizza age_over_N dove N è compreso tra 10 e 110, in linea con il tipo di richiesta di incorporamento. |
Il tipo di richiesta del browser deve corrispondere all'asserzione che verifichi lato server.
| Tipo di richiesta di incorporamento | richieste_richieste |
|---|---|
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) |
Oltre a required_claims, puoi richiedere campi di identità approvati specifici (ad es. paese o fascia di età) se la tua integrazione li ha raccolti. Passa i nomi in required_fields — se mancano nel risultato approvato, verify restituisce missing_required_fields con missing_fields in error.details.
Effettua una chiamata POST a /v1/qr/results/verify con la chiave API del tuo sito prima di concedere l'accesso. Considera il riferimento del browser (request_id o token di polling legacy) come non attendibile finché Checkify non conferma il risultato.
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
}
Puoi anche inviare
token
invece di
request_id.
La chiave API è associata al tuo sito Checkify: non devi inviare site_id nel corpo della richiesta.
# 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;
}
}
}
Utilizzare consume: true per le azioni protette finali — Pagamento, registrazione, reimpostazione password, acquisto con restrizioni di età, accesso a contenuti protetti
Utilizzare consume: false solo per — test, debug o verifiche non definitive in cui il risultato deve essere verificato nuovamente in seguito
Per le azioni regolamentate o ad alto rischio, è preferibile utilizzare `consume: true` in modo che lo stesso risultato della verifica non possa essere riutilizzato per più decisioni protette.
Se il tuo backend non riesce a raggiungere Checkify, non consentire il checkout con restrizioni di età, l'accesso al gioco d'azzardo, l'accesso a contenuti per adulti, l'acquisto di sigarette elettroniche o alcolici o altre azioni protette senza una conferma lato server.
Utilizzare timeout HTTP brevi (ad esempio 10 secondi). Riprovare una o due volte in caso di errori 5xx o di rete temporanei, quindi negare l'accesso. Registrare gli incidenti lato server e mostrare messaggi sicuri per l'utente. Non divulgare ai clienti i dettagli interni degli errori Checkify.
try {
const verdict = await verifyCheckifyResult(requestId);
if (!verdict.allow) {
return res.status(403).json({ error: "Verification required" });
}
// Continue protected action
} catch (err) {
console.error("Checkify verification unavailable", err);
return res.status(403).json({
error: "Verification is temporarily unavailable. Please try again.",
});
}
The Checkify monorepo includes @checkify/server (Node.js) and checkify-server (Python) packages for server-side verify calls. There is no published OpenAPI spec or Postman collection yet — use the examples on this page and POST /v1/qr/results/verify directly.
@checkify/server v1.0.0 è pubblicato su npm. Il pacchetto Python checkify-server è incluso nel monorepo Checkify SDK.
Le verifiche completate scadono dopo QR_RESULT_MAX_AGE_SECONDS (valore predefinito 900 secondi / 15 minuti). Dopo la scadenza, la verifica restituisce result_expired: chiedi all'utente di verificare nuovamente.
I parametri JavaScript e SDK gestiscono lo stato della sessione per gli embed standard. Utilizzali solo quando crei un frontend personalizzato che chiama manualmente 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}In caso di successo, Checkify restituisce HTTP 200 con success: true e status: completed. Consenti l'accesso solo quando sono presenti le attestazioni richieste (ad esempio 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’oggetto signed_result consente al backend di conservare un record di audit a prova di manomissione che Checkify ha approvato il claim richiesto al momento della verifica. La maggior parte delle integrazioni necessita solo di approved_claims. Aziende regolamentate o ad alto rischio possono anche memorizzare signed_result. proof_metadata annidato può includere evidenza crittografica od operativa (metadati di assurance, tipi di evidence o hash di consenso) — non documenti di identità né data di nascita grezza. Non trattare i campi di assurance annidati come certificazione o garanzia di fiducia; controlla certification_status e la tua policy. Non memorizzare più dati personali del necessario.
Se il cliente non ha ancora terminato nell'app, Checkify restituisce HTTP 200 con success: false e status: pending. Nega le azioni protette e chiedi all'utente di completare la verifica.
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| Campo | Significato |
|---|---|
success | true quando la verifica è completata e requisiti Rivendicazioni corrispondenti |
status | completed o pending |
approved_claims | Checkify approvate, ad es. human_verified: true |
signed_result | Payload firmato opzionale per audit trail |
Quando la verifica non può procedere, Checkify restituisce HTTP 4xx/5xx con un corpo JSON strutturato. Controlla error.code e registra error.details lato server. Restituisci messaggi generici agli utenti finali.
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| Codice | AMD | Senso | Azione consigliata |
|---|---|---|---|
missing_authorization | 401 | Non è stata inviata alcuna intestazione di autorizzazione. | Invia autorizzazione: Bearer YOUR_SITE_API_KEY solo dal codice lato server. |
invalid_token | 401 | Token di appartenenza mancante, malformato o non valido per il sito API. | Verifica la chiave nella dashboard aziendale e memorizzala nelle variabili d'ambiente. |
expired_token | 401 | La chiave del sito API è stata revocata. | Crea una nuova chiave per il sito API e ruotala sui tuoi server. |
missing_required_field | 400 / 422 | Il campo request_id o token non è presente nel corpo della richiesta JSON. | Passa l'ID della richiesta (request_id) dal campo nascosto del modulo, oppure il token di sondaggio se la tua integrazione lo utilizza ancora. |
invalid_request_id | 400 | Impossibile analizzare il riferimento oppure il riferimento risulta vuoto dopo la normalizzazione. | Assicurati che il tuo frontend invii il request_id Checkify senza modifiche. |
result_not_found | 404 | Non esiste alcuna richiesta di verifica per quel riferimento. | Rifiuta l'azione. L'utente potrebbe aver manomesso il campo nascosto o aver inviato una sessione precedente. |
result_expired | 410 | La verifica è stata completata troppo tempo fa per potersi fidare di questa azione. | Chiedi all'utente di eseguire nuovamente la scansione e di chiamare la funzione di verifica con il nuovo request_id. |
verification_failed | 403 / 409 | Mismatch di sito/business, risultato già consumato (HTTP 409) o errore generico di verifica. | Nega l’accesso. Ispeziona error.details. Per lacune di claim/campi vedi missing_required_claims e 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 | L'account aziendale è bloccato, archiviato o non operativo. | Contatta il titolare dell'attività o l'assistenza di Checkify. Non consentire azioni protette finché l'account non è attivo. |
validation_errors | 422 | Il corpo JSON non ha superato la convalida dello schema (HTTP 422). | Esamina error.details.validation_errors per individuare messaggi a livello di campo. Correggi i tipi request_id, required_claims o required_fields prima di riprovare. |
rate_limited | 429 | Troppe chiamate di verifica in un breve lasso di tempo. | Riprova con un intervallo di tempo esponenziale. Verifica solo in corrispondenza delle azioni protette, non a ogni visualizzazione di pagina. |
server_error | 500+ | Checkify non è riuscito a completare la verifica a causa di un problema temporaneo del server. | Riprova una o due volte, poi chiudi la segnalazione di errore e registra l'incidente. |
Attualmente, la verifica del server è sincrona: il backend verifica il request_id quando l'utente invia l'azione protetta. Questo è l'approccio consigliato per i flussi di checkout, registrazione e controllo degli accessi. I webhook di verifica generici non sono necessari per le integrazioni standard. GoHighLevel e le integrazioni di altri partner possono utilizzare una configurazione separata per i webhook in uscita nella dashboard aziendale.
Tratta il campo nascosto come un riferimento non attendibile, non come una prova. Verifica sempre la chiave API del tuo sito sul server prima di concedere l'accesso. Utilizzo
consume: true
per azioni una tantum come la registrazione o la reimpostazione della password.