API documentation
Verify content programmatically: images (AI/deepfake), text (fake news, manipulation) and social media videos (with automatic transcription). Analyses use credits from your account — the same as on the website. Generate a key in your account, API tab.
Base URL: https://czytofejk.pl/api/public/v1
Authorization
Every request requires an Authorization header with a key in the czf_… format:
Authorization: Bearer czf_TWOJ_KLUCZ
Costs in credits
| Analysis | Cost |
|---|---|
| Text (up to 1000 characters — the excess is truncated) | 10–150 credits |
| Image from a URL (AI / deepfake) | 10–60 credits |
| Video from a URL (TikTok, YouTube…) — transcription + analysis | 10–600 credits |
| Duplicate (content previously analysed by anyone) | 0 credits |
At the start we hold a deposit (the top of the range) and refund the difference after the analysis — you pay exactly the real cost of the operation. If an analysis fails on our side, the full amount is refunded. The API bills credits only (top-ups and subscriptions: pricing).
Rate limits
60 requests/min per key (Redakcja plan: 300/min) for POST /checks; status and balance reads: 300/min. When exceeded: 429 with a Retry-After header.
POST /checks — start an analysis
JSON body with exactly one of the fields: text (text to verify or a link to a social media video) or image_url (a direct link to an image). Optionally "wait": true — synchronous mode (below).
The optional language field (pl — default, en, uk) sets the language of the verdict body (summary, reasoning, signals). Enum values (PRAWDA | MANIPULACJA | FAŁSZ) stay unchanged regardless of language. Note: dedup is content-based — re-checking identical content returns the existing verdict in the language it was generated in.
Synchronous mode — result in a single response
With "wait": true we hold the request open until the analysis finishes (max ~90 s) and return 200 with the final result — no polling. If the analysis takes longer (typically videos with transcription), you get a regular 202 running and fetch the result with a GET — ideally also with ?wait=true (long-poll). Images and text almost always finish within the budget.
curl — synchronous (the simplest)
curl -X POST https://czytofejk.pl/api/public/v1/checks \
-H "Authorization: Bearer czf_TWOJ_KLUCZ" \
-H "Content-Type: application/json" \
-d '{"text": "Rząd potwierdził, że od sierpnia ceny prądu wzrosną o 45%.", "wait": true}'
# → 200 { "id": "…", "status": "done", "result": { "verdict": "FAŁSZ", … } }curl — asynchronous
curl -X POST https://czytofejk.pl/api/public/v1/checks \
-H "Authorization: Bearer czf_TWOJ_KLUCZ" \
-H "Content-Type: application/json" \
-d '{"text": "Rząd potwierdził, że od sierpnia ceny prądu wzrosną o 45%."}'
# → 202 { "id": "a1b2c3d4e5", "status": "running", … }
# potem (long-poll do wyniku):
curl "https://czytofejk.pl/api/public/v1/checks/a1b2c3d4e5?wait=true" \
-H "Authorization: Bearer czf_TWOJ_KLUCZ"JavaScript (Node) — synchronous
const res = await fetch("https://czytofejk.pl/api/public/v1/checks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CZYTOFEJK_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
image_url: "https://example.com/zdjecie.jpg",
wait: true,
}),
});
const check = await res.json();
if (check.status === "done") console.log(check.result); // gotowy werdyktPython — async with long-polling (e.g. videos)
import os, requests
API = "https://czytofejk.pl/api/public/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['CZYTOFEJK_API_KEY']}"}
check = requests.post(f"{API}/checks", headers=HEADERS, json={
"text": "https://www.tiktok.com/@uzytkownik/video/724..." # film → transkrypcja
}).json()
# long-poll: każde wywołanie czeka do wyniku albo ~90 s
while check.get("status") == "running":
check = requests.get(
f"{API}/checks/{check['id']}", params={"wait": "true"},
headers=HEADERS, timeout=120,
).json()
print(check["result"]["verdict"])202 response (analysis started)
{
"id": "a1b2c3d4e5",
"status": "running",
"cost_tokens": 1,
"result_url": "https://czytofejk.pl/w/a1b2c3d4e5"
}A duplicate returns 200 with "deduped": true and "cost_tokens": 0 (existing result, zero cost). For a new check, cost_tokens is the deposit — the real cost appears in the result (chargedCredits).
GET /checks/{id} — status and result
With ?wait=true (recommended) the request waits for the result — max ~90 s per call; repeat until the status is done. Without wait it returns the current state immediately (then poll every ~2 s). Analysis times: images 5–20 s, text 10–30 s, videos with transcription up to a few minutes. Status error = credits refunded automatically.
{
"id": "a1b2c3d4e5",
"status": "done",
"result_url": "https://czytofejk.pl/w/a1b2c3d4e5",
"result": {
"kind": "tresc", // albo "plik" (obraz)
"verdict": "MANIPULACJA", // PRAWDA | MANIPULACJA | FAŁSZ
"verdictSub": "…", // 1–2 zdania oceny
"summary": "…", // uzasadnienie
"signals": [{ "strong": true, "text": "…" }],
"sources": [{ "domain": "…", "title": "…", "url": "…" }]
// dla kind="plik": "percent" 0–100 (prawdopodobieństwo AI/fałszerstwa),
// "verdict" np. "AI" / "AUTENTYCZNE" oraz lista sygnałów technicznych
}
}GET /balance — credit balance
{
"plan": "pro",
"tokens": { "subscription": 184, "topup": 40, "total": 224 }
}Error codes
| Status | error | Meaning |
|---|---|---|
| 401 | invalid_api_key | Missing/invalid/revoked key |
| 402 | insufficient_tokens | Not enough credits (fields required, balance) |
| 400 | invalid_input | Provide exactly one field: text or image_url |
| 422 | text_too_short / not_an_image | The content is not suitable for analysis |
| 429 | rate_limited | Per-minute rate limit — wait for Retry-After |
| 404 | not_found | No check with this id |
| 500 | analysis_failed | Error on our side — try again |
Best practices
- Keep the key in a server-side environment variable; use a separate key per integration (easier rotation and auditing — see the "last used" column in your account).
- Every result has a stable, public permalink
result_url— you can link it for your readers as evidence. - Sending the same content multiple times? You lose nothing — dedup responds instantly and for free.
- The verdict is an evidence-based probability assessment, not a ruling — for editorial decisions, look into
signalsandsources.
Questions, higher limits, webhooks? Get in touch. We version under /v1 — breaking changes will land under a new path.