Após a conclusão da incorporação no navegador, seu servidor deve verificar o resultado com uma chave API do site antes de permitir o cadastro, a finalização da compra ou qualquer ação protegida.
O campo oculto do formulário pode ser nomeado checkify_token, mas seu valor é o request_id Checkify.
No painel de controle da sua empresa, abra Desenvolvedor Crie uma chave de site API para o site que você está integrando. Armazene-a apenas em variáveis de ambiente do servidor — nunca a envie para o navegador.
Você não precisa chamar manualmente o método GET /v1/qr/pass/{PASS_ID}/start. O componente Checkify JavaScript inicia a sessão, recebe o request_id e o insere automaticamente no seu formulário.
Seu backend só precisa:
O frontend SDK insere o request_id Checkify em um campo oculto do formulário após o usuário concluir a verificação. O nome padrão do campo é checkify_token — esse é o nome do campo, não um tipo de token separado. Envie o valor do campo para o endpoint de verificação como request_id.
A transferência de aplicativos móveis pode retornar o `checkify_request_id` na URL da página. O SDK lê esse valor ao carregar a página; seu servidor ainda verifica o mesmo valor de `request_id`.
Formulário POST do seu frontend
{
"email": "user@example.com",
"checkify_token": "56a57761-ff5b-42f0-9c97-6c13e223e017"
}
Verifique a solicitação do seu backend.
{
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"required_claims": ["human_verified"],
"required_fields": [],
"consume": true
}
Somente integração manual de frontend
Desenvolvedores de backend normalmente não chamam `/start`. Use esta seção apenas ao criar um frontend personalizado ou ao realizar testes sem o recurso incorporado. Coloque URLs entre aspas no zsh/bash para que `?` não seja interpretado como um padrão glob.
O comando `pass start` só funciona a partir de um domínio de website registrado. Os navegadores enviam o `Origin` automaticamente; o cURL não. Envie `Origin` (ou `X-Checkify-Site-Url`) com um nome de host listado em Sites → domínios permitidos. O nome de host deve ser exatamente o mesmo — `checkify.me` e `www.checkify.me` são diferentes.
Problema de teste mais comum
Se /start retornar HTTP 403, seu ID de acesso ainda pode ser válido. A causa mais comum é que o domínio da solicitação não esteja listado nos domínios permitidos, ou que www.example.com esteja registrado, mas example.com tenha sido usado (ou vice-versa).
Utilize um site de teste dedicado e passe seu painel Checkify para testes de integração. As chaves do site API usam o prefixo csk_; não há um formato de chave de teste separado. Não teste com o checkout de produção até que você tenha confirmado os fluxos de sucesso e de recusa.
# 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
}'
Use sua chave de site API somente na chamada de verificação. Conclua a verificação no aplicativo antes de ligar para verificar — caso contrário, você receberá o status pendente.
Defina `required_claims` para corresponder à comprovação necessária para sua ação protegida. Os nomes das declarações devem corresponder ao que o Checkify aprovou para essa sessão de verificação. As verificações de idade usam `age_over_{N}` (por exemplo, `age_over_18`). Limiares dinâmicos de 10 a 110 são suportados quando o componente incorporado solicita o tipo de requisição correspondente.
| Caso de uso | Sugestões de reivindicações obrigatórias | Notas |
|---|---|---|
| Substituição de bot/CAPTCHA | ["human_verified"] |
Confirma que um usuário real concluiu o fluxo Checkify. |
| Conteúdo para maiores de 13 anos ou produtos voltados para o público jovem. | ["age_over_13"] |
Use quando o seu Passe solicitar idade_acima_de_13_anos. |
| Conteúdo para maiores de 16 anos ou regras regionais de idade | ["age_over_16"] |
Use quando o seu Passe solicitar idade_acima_de_16_anos. |
| Vape, álcool ou caixa para maiores de 18 anos | ["age_over_18"] |
Ajuste a faixa etária ao seu produto e mercado. |
| Produtos com restrição de idade para maiores de 21 anos (quando aplicável) | ["age_over_21"] |
Use quando o seu Passe solicitar idade_acima_de_21_anos. |
| Política de varejo do Desafio 25 ou mais rigorosa | ["age_over_25"] |
Use quando o seu Passe solicitar idade_acima_de_25_anos. |
| Limite de idade personalizado | ["age_over_N"] |
Use age_over_N onde N é de 10 a 110, de acordo com o tipo da sua solicitação de incorporação. |
O tipo de solicitação do navegador deve corresponder à declaração que você verifica no servidor.
| Tipo de solicitação de incorporação | reivindicações_obrigatórias |
|---|---|
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) |
Além de `required_claims`, você pode exigir campos de identidade específicos aprovados (por exemplo, país ou faixa etária) quando sua integração os coletar. Passe os nomes dos campos em `required_fields` — se algum estiver faltando no resultado aprovado, a verificação retornará `verification_failed` com `missing_fields` em `error.details`.
Faça a requisição POST para /v1/qr/results/verify com a chave API do seu site antes de conceder acesso. Considere a referência do navegador (request_id ou token de pesquisa legado) como não confiável até que Checkify confirme o resultado.
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
}
Você também pode enviar
token
em vez de
request_id.
A chave API tem escopo no seu site Checkify — você não envia o site_id no corpo da solicitação.
# 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;
}
}
}
Use consume: true para ações protegidas finais — finalização da compra, cadastro, redefinição de senha, compra com restrição de idade, acesso a conteúdo protegido
Use consume: false somente para — testes, depuração ou verificações não definitivas em que o resultado precisa ser verificado novamente mais tarde
Para ações regulamentadas ou de alto risco, prefira `consumer: true` para que o mesmo resultado de verificação não possa ser reutilizado para múltiplas decisões protegidas.
Se o seu servidor não conseguir acessar Checkify, não permita o pagamento com restrição de idade, acesso a jogos de azar, acesso a conteúdo adulto, compra de cigarros eletrônicos ou bebidas alcoólicas, ou outras ações protegidas sem uma confirmação do servidor.
Use tempos limite HTTP curtos (por exemplo, 10 segundos). Tente novamente uma ou duas vezes em caso de erros transitórios 5xx ou de rede e, em seguida, negue o acesso. Registre os incidentes no servidor e exiba mensagens seguras para o usuário. Não exponha detalhes internos de erros do Checkify aos clientes.
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.",
});
}
Use @checkify/server (npm) ou checkify-server (Python) para auxiliares de verificação tipada, ou chame POST /v1/qr/results/verify diretamente. Ainda não há uma especificação OpenAPI publicada — use os exemplos nesta página.
O pacote @checkify/server v1.0.0 foi publicado no npm. O pacote Python checkify-server é distribuído no monorepo Checkify SDK.
As verificações concluídas expiram após QR_RESULT_MAX_AGE_SECONDS (padrão de 900 segundos / 15 minutos). Após a expiração, a verificação retorna result_expired — solicitando ao usuário que verifique novamente.
O JavaScript SDK gerencia o estado da sessão para incorporações padrão. Use-os somente quando você criar um frontend personalizado que chame GET /v1/qr/pass/{pass_id}/start manualmente.
GET /v1/qr/status?token={poll_token}GET /v1/qr/status/request/{request_id}?status_token={status_token}Em caso de sucesso, Checkify retorna HTTP 200 com success: true e status: completed. Permita o acesso somente quando as declarações necessárias estiverem presentes (por exemplo, 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"
}
}
O objeto `signed_result` permite que seu backend mantenha um registro de auditoria inviolável de que a Checkify aprovou a solicitação necessária no momento da verificação. A maioria das integrações precisa apenas do objeto `approved_claims`. Empresas regulamentadas ou de alto risco também podem armazenar o `signed_result` para fins de auditoria. Não armazene mais informações pessoais do que o necessário.
Se o cliente ainda não tiver finalizado a ação no aplicativo, Checkify retorna HTTP 200 com sucesso: falso e status: pendente. Negue as ações protegidas e solicite ao usuário que conclua a verificação.
{
"success": false,
"status": "pending",
"message": "Verification is not completed yet",
"request_id": "56a57761-ff5b-42f0-9c97-6c13e223e017",
"approved_claims": {},
"signed_result": null
}
| Campo | Significado |
|---|---|
success | true quando a verificação for concluída e os requisitos forem atendidos |
status | completed ou pending |
approved_claims | Alegações Checkify aprovadas, por exemplo. human_verified: true |
signed_result | Carga útil assinada opcional para trilhas de auditoria |
Quando a verificação não puder prosseguir, Checkify retorna HTTP 4xx/5xx com um corpo estruturado JSON. Verifique o error.code e registre os detalhes do erro no servidor. Retorne mensagens genéricas aos usuários finais.
{
"success": false,
"error": {
"code": "verification_failed",
"message": "The verification did not include all required claims.",
"details": {
"missing_claims": ["age_over_18"]
}
}
}
| Código | HTTP | Significado | Ação recomendada |
|---|---|---|---|
missing_authorization | 401 | Nenhum cabeçalho de autorização foi enviado. | Enviar autorização: Bearer YOUR_SITE_API_KEY somente a partir do código do lado do servidor. |
invalid_token | 401 | Token de portador ausente, malformado ou não é uma chave de site válida API. | Verifique a chave no painel de controle da sua empresa e armazene-a nas variáveis de ambiente. |
expired_token | 401 | A chave do site API foi revogada. | Crie uma nova chave de site API e alterne-a em seus servidores. |
missing_required_field | 400 / 422 | O request_id ou token está faltando no corpo do JSON. | Passe o request_id do campo oculto do seu formulário ou o token de pesquisa, caso sua integração ainda o utilize. |
invalid_request_id | 400 | A referência não pôde ser analisada ou está vazia após a normalização. | Certifique-se de que seu frontend envie o request_id Checkify sem alterações. |
result_not_found | 404 | Não existe nenhuma solicitação de verificação para essa referência. | Rejeitar a ação. O usuário pode ter adulterado o campo oculto ou enviado uma sessão antiga. |
result_expired | 410 | A verificação foi concluída há muito tempo para que se possa confiar nessa ação. | Peça ao usuário para escanear novamente e chamar o método de verificação com o novo request_id. |
verification_failed | 403 / 409 | A verificação foi concluída, mas não atendeu às suas solicitações/campos obrigatórios, pertence a outro site ou já foi utilizada. | Negar acesso. Inspecionar error.details para obter informações sobre missing_claims, missing_fields ou reason. |
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 | A conta comercial está bloqueada, arquivada ou inativa. | Contate o proprietário da empresa ou o suporte da Checkify. Não permita ações protegidas até que a conta esteja ativa. |
validation_errors | 422 | O corpo da requisição JSON falhou na validação do esquema (HTTP 422). | Inspecione o arquivo error.details.validation_errors em busca de mensagens de erro em nível de campo. Corrija os tipos request_id, required_claims ou required_fields antes de tentar novamente. |
rate_limited | 429 | Muitas chamadas de verificação em um curto período de tempo. | Tente novamente com recuo exponencial. Verifique apenas em ações protegidas, não em cada visualização de página. |
server_error | 500+ | Checkify não pôde concluir a verificação devido a um problema temporário no servidor. | Tente novamente uma ou duas vezes, depois encerre a sessão e registre o incidente. |
Atualmente, a verificação do servidor é síncrona: seu backend verifica o `request_id` quando o usuário envia a ação protegida. Para fluxos de finalização de compra, cadastro e controle de acesso, essa é a abordagem recomendada. Webhooks de verificação de uso geral não são necessários para integrações padrão. O GoHighLevel e outras integrações de parceiros podem usar configurações de webhook de saída separadas no painel de controle da empresa.
Trate o campo oculto como uma referência não confiável, não como uma prova. Sempre verifique com a chave API do seu site no servidor antes de conceder acesso. Use
consume: true
Para ações pontuais, como cadastro ou redefinição de senha.