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.byebot.de/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 byebot-token value from the form submission |
Response
| Status Code | Description |
|---|---|
200 OK | Token is valid — returns JSON body with challenge metadata |
400 Bad Request | Token is invalid, expired, or already used — no body |
Success Response Body
On 200 OK, the response includes a JSON body with metadata about the solved challenge:
{
"success": true,
"sitekey": "abc123def456ghij7890",
"challenged_at": 1742140800,
"solve_time_ms": 2340,
"interactive_solved": false
}| Field | Type | Description |
|---|---|---|
success | boolean | Always true on 200 |
sitekey | string | The site key the challenge was solved for |
challenged_at | integer | Unix timestamp (seconds) when the challenge was created |
solve_time_ms | integer | Milliseconds from challenge creation to solution |
interactive_solved | boolean | Whether an interactive challenge was completed |
Checking the HTTP status code is sufficient for basic validation. The response body is optional and provides additional metadata for logging or analytics.
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['byebot-token'];
if (!token) {
return res.status(400).json({ error: 'CAPTCHA token missing' });
}
const response = await fetch('https://challenge.byebot.de/validate_token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: process.env.BYEBOT_API_KEY,
token: token
})
});
if (!response.ok) {
return res.status(400).json({ error: 'CAPTCHA validation failed' });
}
// Token is valid - process the form
// Optionally parse response for challenge metadata:
// const { sitekey, challenged_at, solve_time_ms, interactive_solved } = await response.json();
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('byebot-token')
if not token:
return jsonify({'error': 'CAPTCHA token missing'}), 400
response = requests.post(
'https://challenge.byebot.de/validate_token',
json={
'api_key': BYEBOT_API_KEY,
'token': token
}
)
if response.status_code != 200:
return jsonify({'error': 'CAPTCHA validation failed'}), 400
# Token is valid - process the form
# Optionally parse response for challenge metadata:
# metadata = response.json() # {'sitekey': ..., 'challenged_at': ..., 'solve_time_ms': ..., 'interactive_solved': ...}
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('byebot-token')
if not token:
return JsonResponse({'error': 'CAPTCHA token missing'}, status=400)
response = requests.post(
'https://challenge.byebot.de/validate_token',
json={
'api_key': settings.BYEBOT_API_KEY,
'token': token
}
)
if response.status_code != 200:
return JsonResponse({'error': 'CAPTCHA validation failed'}, status=400)
# Token is valid - process the form
# Optionally parse response for challenge metadata:
# metadata = response.json()
return JsonResponse({'success': True})PHP
<?php
$token = $_POST['byebot-token'] ?? null;
if (!$token) {
http_response_code(400);
echo json_encode(['error' => 'CAPTCHA token missing']);
exit;
}
$response = file_get_contents('https://challenge.byebot.de/validate_token', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode([
'api_key' => getenv('BYEBOT_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
// Optionally parse response for challenge metadata:
// $metadata = json_decode($response, true);
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("byebot-token")
if token == "" {
http.Error(w, "CAPTCHA token missing", http.StatusBadRequest)
return
}
payload, _ := json.Marshal(map[string]string{
"api_key": os.Getenv("BYEBOT_API_KEY"),
"token": token,
})
resp, err := http.Post(
"https://challenge.byebot.de/validate_token",
"application/json",
bytes.NewBuffer(payload),
)
if err != nil || resp.StatusCode != http.StatusOK {
http.Error(w, "CAPTCHA validation failed", http.StatusBadRequest)
return
}
defer resp.Body.Close()
// Token is valid - process the form
// Optionally decode response for challenge metadata:
// var metadata map[string]interface{}
// json.NewDecoder(resp.Body).Decode(&metadata)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"success": true}`))
}Ruby / Rails
class FormsController < ApplicationController
def submit
token = params['byebot-token']
if token.blank?
return render json: { error: 'CAPTCHA token missing' }, status: :bad_request
end
response = HTTParty.post(
'https://challenge.byebot.de/validate_token',
headers: { 'Content-Type' => 'application/json' },
body: {
api_key: ENV['BYEBOT_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
# Optionally parse response for challenge metadata:
# metadata = JSON.parse(response.body)
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
byebot-tokenhidden field after verification - Ensure the widget's sitekey matches your site
Network Errors
- Ensure your server can reach the ByeBot validation endpoint
- Check for firewall rules blocking outbound requests
- Implement retry logic for transient failures