Developer Help
AstraCaph supports an open mode without mandatory frontend keys. You can embed the widget immediately, then verify tokens by your site origin or by a secret key in stricter deployments.
Example: https://example.com Your backend will send this origin to AstraCaph as the expected binding for the token.
<script src="https://caph.astracat.ru/api/v1/widget.js" async defer></script> <div id="astracaph-container"></div>
<input type="hidden" name="astracaph-response" value="eyJ..." />
POST https://caph.astracat.ru/api/v1/verify
Content-Type: application/json
{
"token": "user_generated_token",
"origin": "https://example.com"
}POST https://caph.astracat.ru/api/v1/sites
Content-Type: application/json
{
"domain": "example.com",
"name": "Example store"
}DELETE https://caph.astracat.ru/api/v1/sites
Content-Type: application/json
{
"domain": "example.com",
"secret": "sk_live_..."
}AstraCaph's default mode does not require a frontend site key: embedding `/api/v1/widget.js` with `#astracaph-container` is enough.
POST /api/v1/verify can validate a token against `origin` or `domain`, which keeps Vercel deployments working even without a persistent site database.
POST /api/v1/sites creates a free site registration and returns a fresh siteKey plus secret when you need a dedicated isolated profile.
DELETE /api/v1/sites removes a registered domain only when the matching sk_live server secret is provided.
Challenge logic also queries multiple free IP databases to estimate whether the IP looks like hosting, proxy, VPN, Tor, mobile carrier, or residential ISP.
POST /api/v1/challenge accepts telemetry, computes a risk score and either returns a token or asks for a visual follow-up step.
POST /api/v1/verify validates the signed token, checks origin binding or a secret key, and consumes the token once.
POST /public/api/v1/verify supports the same verification flow and also accepts `origin`, `domain`, and `secretKey` for server-to-server integrations.
GET /api/v1/widget.js serves a framework-free loader designed to initialize inside any page with a matching container.
GET /captcha/widget serves an iframe-ready widget page with `theme=dark|light`, while `siteKey` remains optional for compatibility.
The `/sandbox` page lets you test custom HTML, widget behavior, and challenge / verify logs in one live debugging surface.
ASTRACAPH_TOKEN_SECRET=replace_with_long_random_secret
# Optional if you want strict secret-based verification for a custom site:
ASTRACAPH_OPEN_SECRET=replace_with_private_open_verify_secret
# Optional seeded sites for internal or enterprise bindings:
ASTRACAPH_SITE_CONFIG=[{"name":"Seed Site","siteKey":"pk_live_example","secret":"sk_live_example","origins":["https://example.com"],"createdAt":0}]
UPSTASH_REDIS_REST_URL=...
UPSTASH_REDIS_REST_TOKEN=...
VERIFY_TRUSTED_IPS=203.0.113.10,203.0.113.11Iframe Integration API
Below is a compatible integration flow using the iframe widget, postMessage, and server-to-server verification without mandatory frontend keys.
<iframe
src={\`https://caph.astracat.ru/captcha/widget?theme=dark\`}
width="350"
height="500"
frameBorder="0"
scrolling="no"
></iframe>window.addEventListener("message", (event) => {
if (event.origin !== (process.env.NEXT_PUBLIC_APP_URL || "https://caph.astracat.ru")) {
return;
}
if (event.data.type === "astracaph-verified") {
const { token, success } = event.data.detail;
if (success) {
fetch("/your-backend-endpoint", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ token }),
});
}
}
});app.post("/your-backend-endpoint", async (req, res) => {
const { token } = req.body;
const expectedOrigin = process.env.CAPTCHA_EXPECTED_ORIGIN || "https://example.com";
try {
const response = await fetch(
\`https://caph.astracat.ru/public/api/v1/verify\`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ token, origin: expectedOrigin }),
}
);
const data = await response.json();
if (data.success) {
res.status(200).json({ message: "CAPTCHA verified successfully." });
} else {
res.status(400).json({ message: "CAPTCHA verification failed." });
}
} catch (error) {
res.status(500).json({ message: "Internal server error." });
}
});import os
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/your-backend-endpoint", methods=["POST"])
def verify_captcha():
token = request.json.get("token")
expected_origin = os.environ.get("CAPTCHA_EXPECTED_ORIGIN", "https://example.com")
captcha_verify_url = f"{os.environ.get('NEXT_PUBLIC_APP_URL', 'https://caph.astracat.ru')}/public/api/v1/verify"
try:
response = requests.post(
captcha_verify_url,
json={"token": token, "origin": expected_origin}
)
response.raise_for_status()
data = response.json()
if data.get("success"):
return jsonify({"message": "CAPTCHA verified successfully."}), 200
return jsonify({"message": "CAPTCHA verification failed."}), 400
except requests.exceptions.RequestException:
return jsonify({"message": "Internal server error."}), 500{
"success": true,
"message": "Verification successful"
}