After a user completes the CAPTCHA challenge, you must validate the token on your server before processing the form submission.
Validation Endpoint#
Send a POST request to validate the token:
POST https://challenge.captchacat.com/validate_token
Content-Type: application/jsonRequest Body
{
"api_key": "YOUR_API_KEY",
"token": "TOKEN_FROM_FORM"
}| Field | Type | Description |
|---|---|---|
api_key | string | Your secret API key from the dashboard |
token | string | The captchacat-token value from the form submission |
Response
| Status Code | Description |
|---|---|
200 OK | Token is valid |
400 Bad Request | Token is invalid, expired, or already used |
Code Examples#
Node.js / Express
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.post('/submit', async (req, res) => {
const token = req.body['captchacat-token'];
if (!token) {
return res.status(400).json({ error: 'CAPTCHA token missing' });
}
const response = await fetch('https://challenge.captchacat.com/validate_token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: process.env.CAPTCHA_CAT_API_KEY,
token: token
})
});
if (!response.ok) {
return res.status(400).json({ error: 'CAPTCHA validation failed' });
}
// Token is valid - process the form
// ...
res.json({ success: true });
});Python / Flask
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/submit', methods=['POST'])
def submit():
token = request.form.get('captchacat-token')
if not token:
return jsonify({'error': 'CAPTCHA token missing'}), 400
response = requests.post(
'https://challenge.captchacat.com/validate_token',
json={
'api_key': CAPTCHA_CAT_API_KEY,
'token': token
}
)
if response.status_code != 200:
return jsonify({'error': 'CAPTCHA validation failed'}), 400
# Token is valid - process the form
# ...
return jsonify({'success': True})Python / Django
import requests
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.conf import settings
@require_POST
def submit(request):
token = request.POST.get('captchacat-token')
if not token:
return JsonResponse({'error': 'CAPTCHA token missing'}, status=400)
response = requests.post(
'https://challenge.captchacat.com/validate_token',
json={
'api_key': settings.CAPTCHA_CAT_API_KEY,
'token': token
}
)
if response.status_code != 200:
return JsonResponse({'error': 'CAPTCHA validation failed'}, status=400)
# Token is valid - process the form
# ...
return JsonResponse({'success': True})PHP
<?php
$token = $_POST['captchacat-token'] ?? null;
if (!$token) {
http_response_code(400);
echo json_encode(['error' => 'CAPTCHA token missing']);
exit;
}
$response = file_get_contents('https://challenge.captchacat.com/validate_token', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode([
'api_key' => getenv('CAPTCHA_CAT_API_KEY'),
'token' => $token
])
]
]));
$httpCode = $http_response_header[0];
if (strpos($httpCode, '200') === false) {
http_response_code(400);
echo json_encode(['error' => 'CAPTCHA validation failed']);
exit;
}
// Token is valid - process the form
// ...
echo json_encode(['success' => true]);Go
package main
import (
"bytes"
"encoding/json"
"net/http"
"os"
)
func submitHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
token := r.FormValue("captchacat-token")
if token == "" {
http.Error(w, "CAPTCHA token missing", http.StatusBadRequest)
return
}
payload, _ := json.Marshal(map[string]string{
"api_key": os.Getenv("CAPTCHA_CAT_API_KEY"),
"token": token,
})
resp, err := http.Post(
"https://challenge.captchacat.com/validate_token",
"application/json",
bytes.NewBuffer(payload),
)
if err != nil || resp.StatusCode != http.StatusOK {
http.Error(w, "CAPTCHA validation failed", http.StatusBadRequest)
return
}
// Token is valid - process the form
// ...
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success": true}`))
}Ruby / Rails
class FormsController < ApplicationController
def submit
token = params['captchacat-token']
if token.blank?
return render json: { error: 'CAPTCHA token missing' }, status: :bad_request
end
response = HTTParty.post(
'https://challenge.captchacat.com/validate_token',
headers: { 'Content-Type' => 'application/json' },
body: {
api_key: ENV['CAPTCHA_CAT_API_KEY'],
token: token
}.to_json
)
unless response.success?
return render json: { error: 'CAPTCHA validation failed' }, status: :bad_request
end
# Token is valid - process the form
# ...
render json: { success: true }
end
endBest Practices#
Always Validate Server-Side
Never trust client-side validation alone. Always validate the token on your server before processing any form submission.
Keep Your API Key Secret
- Never expose your API key in client-side code
- Use environment variables to store the key
- Rotate keys if they are accidentally exposed
Handle Validation Failures Gracefully
- Display a user-friendly error message
- Allow users to retry the CAPTCHA
- Log failures for monitoring
Validate Before Processing
Always validate the CAPTCHA token before performing any database operations or sending emails. This prevents bots from triggering expensive operations.
// Good: Validate first
const isValid = await validateCaptcha(token);
if (!isValid) {
return res.status(400).json({ error: 'Invalid CAPTCHA' });
}
await saveToDatabase(formData);
// Bad: Don't do this
await saveToDatabase(formData);
const isValid = await validateCaptcha(token);Token Properties
- Tokens are single-use and expire after validation
- Tokens have a limited lifetime (typically a few minutes)
- Each token is bound to a specific site key
Troubleshooting#
Token Always Invalid
- Verify your API key is correct
- Check that you're using the production API key, not a test key
- Ensure the token hasn't expired (validate promptly after form submission)
Missing Token
- Verify the widget is properly initialized
- Check that the form contains a
captchacat-tokenhidden field after verification - Ensure the widget's sitekey matches your site
Network Errors
- Ensure your server can reach the CAPTCHA Cat validation endpoint
- Check for firewall rules blocking outbound requests
- Implement retry logic for transient failures