Skip to content
Developers

The Veriscore API.

Check creators from your own tools: a shortlist spreadsheet, a CRM, an internal vetting script. The API runs the same analysis as the website, charges the same credits, and returns the same verdict. If you can send an HTTP request, you can use it.

Quick start

Three steps to your first verdict

  1. Create an account (new accounts get free credits) and open Dashboard, API keys.
  2. Create a key and copy it. It starts with vs_live_ and is shown only once.
  3. Start a check, poll its status, then read the result:
curl
# 1. Start a check
curl -X POST https://veriscore-production.up.railway.app/api/v1/analyses \
  -H "X-Api-Key: $VERISCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"platform": "instagram", "username": "natgeo"}'

# 2. Poll until status is "completed"
curl https://veriscore-production.up.railway.app/api/v1/analyses/ANALYSIS_ID/status \
  -H "X-Api-Key: $VERISCORE_API_KEY"

# 3. Read the verdict
curl https://veriscore-production.up.railway.app/api/v1/analyses/ANALYSIS_ID \
  -H "X-Api-Key: $VERISCORE_API_KEY"

Base URL: https://veriscore-production.up.railway.app/api/v1

Authentication

API keys

Send your key in the X-Api-Key header on every request. If your tool only supports bearer tokens, Authorization: Bearer vs_live_... works too.

  • A key acts as you. Checks are charged to your credit balance, count toward your rate limits, and appear in your dashboard alongside checks made on the website.
  • Keys are scoped. They can start and read analyses and read your credit balance and history. They cannot change account settings, buy credits, or create other keys. Those calls return 403.
  • Keys are stored hashed. We cannot show a key again after it is created. Lost a key? Revoke it and create a new one.
  • Revoke any time. A revoked key stops working on the next request. You can hold up to 10 active keys, so give each tool or teammate its own.

Keep keys on the server side. Never put one in a public web page, a mobile app, or a shared document.

Reference

Endpoints

POST/analyses
Start an analysis. Returns an analysis_id straight away.
GET/analyses/{id}/status
Poll progress: pending, processing, completed, or failed.
GET/analyses/{id}
The full result: verdict, scores, and the detailed report.
GET/analyses
Your analyses, newest first. Supports limit and offset.
GET/analyses/{id}/pdf
The branded PDF report.
GET/credits/balance
Your current credit balance.
GET/credits/transactions
Your credit history.

Start an analysis

POST /analyses with a JSON body:

  • platform (required): instagram, youtube, tiktok, or twitter
  • username (required): the handle without the @, up to 50 characters
  • force_refresh (optional, default false): skip the cache and fetch fresh data
Response
{
  "analysis_id": "3f1c0b9e-6a1d-4d7e-9a43-0f8b2c1e7a55",
  "status": "pending",
  "message": "Analysis started for @natgeo on instagram",
  "cached": false,
  "cache_age_hours": null,
  "cache_tier": null,
  "refresh_analysis_id": null
}

When a recent result already exists, status comes back as completed with cached: true and you can read the result immediately. Otherwise poll the status endpoint every 10 seconds or so. Most checks finish within a minute or two.

Read the result

GET /analyses/{id} returns the verdict once the status is completed. risk_score runs from 0 to 100, where lower is better, and maps to four tiers: Legit (0 to 25), Monitor (26 to 50), Sketchy (51 to 75), and Run (76 to 100). See the methodology for what goes into the score.

Response (abridged)
{
  "analysis_id": "3f1c0b9e-6a1d-4d7e-9a43-0f8b2c1e7a55",
  "status": "completed",
  "platform": "instagram",
  "username": "natgeo",
  "risk_tier": "Legit",
  "risk_score": 18,
  "authenticity_score": 82,
  "confidence_level": 0.86,
  "report_data": { "...": "signal breakdown, flags, and recommendations" },
  "created_at": "2026-10-01T09:12:44Z",
  "completed_at": "2026-10-01T09:13:31Z",
  "processing_time_seconds": 47.2
}

The same report is viewable at https://veriscore.regnor.systems/report/{id} when you are signed in, and as a PDF from GET /analyses/{id}/pdf.

Pricing

Credits

API checks cost exactly what they cost on the website, from the same balance.

Instagram instagram50 credits
YouTube youtube35 credits
TikTok tiktok50 credits
X / Twitter twitter50 credits
  • Re-checking an account you already checked in the last 4 days is free.
  • If an analysis fails, its credits are refunded automatically.
  • Short on credits? The API returns 402 and charges nothing. Top up here.
Limits

Rate limits

New analyses are limited to 20 per minute, 30 per hour, and 200 per day per account. Keys share your account's limits, so two keys do not double them. Reading results and polling status are limited separately and generously (200 requests per minute). Over the limit, you get a 429; wait and retry.

Need more volume for a campaign? Talk to us.

Errors

Status codes

Errors return JSON with a detail field that explains what went wrong.

401Missing, invalid, or revoked key.
402Not enough credits for this check. Top up and retry.
403The endpoint is not available to API keys (account settings, purchases, key management).
404No analysis with that ID on your account.
422Invalid request, for example an unknown platform or a malformed handle.
429Rate limit reached. Wait a little and retry.
Examples

Python and JavaScript

Python (requests)
import os, time, requests

BASE = "https://veriscore-production.up.railway.app/api/v1"
HEADERS = {"X-Api-Key": os.environ["VERISCORE_API_KEY"]}

def check(platform: str, username: str) -> dict:
    r = requests.post(f"{BASE}/analyses", headers=HEADERS,
                      json={"platform": platform, "username": username})
    r.raise_for_status()
    analysis_id = r.json()["analysis_id"]

    while True:
        status = requests.get(f"{BASE}/analyses/{analysis_id}/status",
                              headers=HEADERS).json()["status"]
        if status in ("completed", "failed"):
            break
        time.sleep(10)

    return requests.get(f"{BASE}/analyses/{analysis_id}", headers=HEADERS).json()

result = check("instagram", "natgeo")
print(result["risk_tier"], result["risk_score"])
JavaScript (Node 18+)
const BASE = "https://veriscore-production.up.railway.app/api/v1";
const headers = { "X-Api-Key": process.env.VERISCORE_API_KEY, "Content-Type": "application/json" };

async function check(platform, username) {
  const start = await fetch(`${BASE}/analyses`, {
    method: "POST", headers, body: JSON.stringify({ platform, username }),
  });
  if (!start.ok) throw new Error(`Veriscore ${start.status}`);
  const { analysis_id } = await start.json();

  for (;;) {
    const { status } = await (await fetch(`${BASE}/analyses/${analysis_id}/status`, { headers })).json();
    if (status === "completed" || status === "failed") break;
    await new Promise((r) => setTimeout(r, 10_000));
  }
  return (await fetch(`${BASE}/analyses/${analysis_id}`, { headers })).json();
}

const result = await check("instagram", "natgeo");
console.log(result.risk_tier, result.risk_score);
No code

Google Sheets template

Built for agencies vetting a shortlist. Paste handles into a sheet, choose Veriscore, Check handles, and the verdict, risk score, and a report link fill in next to each creator. Nothing runs until you choose it from the menu, and you see the maximum credit cost before anything is charged.

  1. Click Make a copy in Google Sheets and confirm. The copy lands in your own Google Drive with the Veriscore script already inside.
  2. In your copy, open the Veriscore menu next to Help (reload the sheet if you don't see it). The first time, Google asks you to authorize the script: choose your account, then Advanced, then Go to Veriscore, then Allow.
  3. Choose Set API key and paste a key from your dashboard. It is stored privately for your Google account only.
  4. On the Creators tab, put handles in column A (an @handle or a full profile link both work) and pick a platform in column B.
  5. Choose Check handles. You see the maximum credit cost and your balance first; results appear as checks finish. For long lists, use Refresh pending results or turn on auto-refresh.

Prefer your own spreadsheet?

Add the script to any sheet: open Extensions, Apps Script, delete the placeholder code, paste the script, click Save, and reload the sheet. Then use Veriscore, Set up this sheet to add the columns.

View the script

The script talks only to the Veriscore API, and you can read every line before you run it. Large lists pause at the hourly limit; run Check handles again later and it picks up where it stopped.

Questions or a use case we should support? romil@regnor.systems