API Reference
All endpoints require the X-IdentifyOrg-Key header. Base URL: https://api.identifyorg.com. This reference is generated from our OpenAPI 3.0 specification — the same source of truth our SDKs are built from.
Verify a BVN
/v1/verify/bvnVerify an 11-digit Bank Verification Number. phone_number is required on live keys (the upstream provider rejects requests without it) — test keys ignore it. Optionally pass first_name, last_name and date_of_birth for cross-match scoring against what's on file. Synchronous — responds in under 3 seconds.
{
"bvn": "12345678901",
"phone_number": "08012345678", // required on live keys
"first_name": "Adaeze", // optional, for cross-match
"last_name": "Okafor", // optional, for cross-match
"date_of_birth": "1992-04-15" // optional, for cross-match
}{
"id": "ver_01hxyz...",
"type": "bvn",
"status": "success",
"match": true,
"confidence_score": 98,
"data": {
"bvn": "12345678901",
"date_of_birth": "1992-04-15",
"phone_number": "+2348012345678",
"gender": "female"
}
}Verify a NIN
/v1/verify/ninVerify an 11-digit National Identification Number issued by NIMC. Optionally pass first_name and last_name to cross-match against what's on file (the upstream lookup itself doesn't do matching, so we do it for you). Synchronous — responds in under 4 seconds.
{
"nin": "12345678901",
"first_name": "Adaeze", // optional, for cross-match
"last_name": "Okafor" // optional, for cross-match
}{
"id": "ver_01hxyz...",
"type": "nin",
"status": "success",
"match": true,
"data": {
"nin": "12345678901",
"first_name": "Adaeze",
"last_name": "Okafor",
"date_of_birth": "1992-04-15",
"phone_number": "+2348012345678",
"gender": "female"
}
}Verify a driver's licence
/v1/verify/frscVerify a Nigerian driver's licence via licensed FRSC data partners. Returns licence status, class, expiry date and state of issue.
{
"licence_number": "ABC12345DE67",
"first_name": "Adaeze", // optional
"last_name": "Okafor" // optional
}{
"id": "ver_01hxyz...",
"type": "frsc",
"status": "success",
"data": {
"licence_status": "valid",
"expiry_date": "2028-11-30",
"licence_class": "B",
"state_of_issue": "Lagos"
}
}Verify a document
/v1/verify/documentUpload an ID document photo (multipart/form-data, field `file`) for OCR extraction and validity checks. Synchronous — responds directly, no polling.
curl -X POST https://api.identifyorg.com/v1/verify/document \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@passport.jpg"{
"id": "ver_01hxyz...",
"type": "document",
"status": "success",
"match": null,
"confidence_score": 91,
"data": {
"full_name": "OKAFOR ADAEZE N",
"document_number": "A12345678",
"expiry_date": "2030-05-01"
},
"cost": 30.0,
"currency": "NGN",
"is_test": false,
"created_at": "2026-07-02T10:24:00Z"
}Check liveness
/v1/verify/livenessUpload a selfie photo (multipart/form-data, field `file`) for passive anti-spoofing analysis. Synchronous. `confidence_score` of 75+ is considered live.
curl -X POST https://api.identifyorg.com/v1/verify/liveness \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@selfie.jpg"{
"id": "ver_01hxyz...",
"type": "liveness",
"status": "success",
"match": null,
"confidence_score": 91,
"data": null,
"cost": 25.0,
"currency": "NGN",
"is_test": false,
"created_at": "2026-07-02T10:24:00Z"
}Compare two faces
/v1/verify/face-matchUpload two images (multipart/form-data, fields `selfie` and `id_photo`) to biometrically compare them. Synchronous.
curl -X POST https://api.identifyorg.com/v1/verify/face-match \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "selfie=@selfie.jpg" \
-F "id_photo=@id_card_photo.jpg"{
"id": "ver_01hxyz...",
"type": "face_match",
"status": "success",
"match": true,
"confidence_score": 94,
"data": null,
"cost": 35.0,
"currency": "NGN",
"is_test": false,
"created_at": "2026-07-02T10:24:00Z"
}Issue a video/voice/stream token
/v1/streaming/{session_type}/tokenMint a short-lived LiveKit token for a participant. `session_type` in the path is one of `video`, `voice` or `stream`. Omit `room_name` to start a new room. Room creation is implicit — the first token issued for a room name creates it. Billed per participant-minute; see the pricing page for rates by session type.
{
"room_name": "kyc-session-4821", // optional, omit to create a new room
"identity": "user-8821",
"display_name": "Adaeze Okafor", // optional
"role": "publisher" // publisher (send+receive) or viewer
}{
"session_id": "cs_01hxyz...",
"room_name": "kyc-session-4821",
"token": "eyJhbGciOi...",
"url": "wss://livekit.identifyorg.com",
"type": "video",
"expires_in_minutes": 180,
"price_per_minute": 2.5,
"currency": "NGN",
"is_test": false
}List call/stream sessions
/v1/streaming/sessionsReturns your most recent call/streaming sessions and their billed cost.
[
{
"id": "cs_01hxyz...",
"type": "video",
"room_name": "kyc-session-4821",
"status": "completed",
"duration_seconds": 342,
"cost": 14.25,
"currency": "NGN",
"created_at": "2026-07-02T10:24:00Z"
}
]Balance & usage
/v1/balanceGET /v1/balance returns your current credit balance and free-tier calls remaining this month. GET /v1/usage returns usage history with date filters (?from=2026-06-01&to=2026-06-30). GET /v1/pricing returns current per-verification-type pricing.
{
"balance": 48250.00,
"currency": "NGN",
"low_balance": false,
"free_tier_remaining": 2
}PDF to DOCX
/v1/tools/pdf-to-docxConvert a PDF into an editable Word document. multipart/form-data upload, field name `file`. Returns the .docx binary directly (Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document). Max file size 20MB.
curl -X POST https://api.identifyorg.com/v1/tools/pdf-to-docx \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@document.pdf" \
-o converted.docxDOCX to PDF
/v1/tools/docx-to-pdfConvert a Word document to PDF. multipart/form-data upload, field name `file`. Returns the .pdf binary directly. Max file size 20MB.
curl -X POST https://api.identifyorg.com/v1/tools/docx-to-pdf \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@document.docx" \
-o converted.pdfAudio format conversion
/v1/tools/audio-convertConvert audio between mp3, wav, aac, flac, ogg and m4a. multipart/form-data upload with fields `file` and `target_format`. Returns the converted audio binary. Max file size 50MB.
curl -X POST https://api.identifyorg.com/v1/tools/audio-convert \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@voice-note.wav" \
-F "target_format=mp3" \
-o converted.mp3Background remover
/v1/tools/remove-backgroundRemove the background from an image, returning a transparent PNG. multipart/form-data upload, field name `file`. Max file size 15MB.
curl -X POST https://api.identifyorg.com/v1/tools/remove-background \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@photo.jpg" \
-o no-background.pngWebsite Audit
/v1/auditsRun a self-hosted security, performance, and AI-generation-detection scan against any URL — security headers, TLS, exposed paths, CORS misconfiguration, Lighthouse performance/accessibility/SEO scoring, and more. Synchronous — takes 15-70 seconds since a real Lighthouse run is the long pole. First audit is free per account, then billed at the API rate (separate from the website's own rate). Note: the free anonymous/claim flow used on the homepage is web-only, not part of this API.
{
"url": "https://example.com"
}{
"id": "aud_01hxyz...",
"url": "https://example.com/",
"status": "ready",
"score": 78,
"grade": "C",
"findings": [
{
"category": "headers",
"severity": "warning",
"title": "Content-Security-Policy header is missing",
"detail": "",
"fix": "Add a Content-Security-Policy response header to reduce this class of attack surface."
}
],
"lighthouse": {
"performance": { "score": 92, "title": "Performance" },
"accessibility": { "score": 96, "title": "Accessibility" },
"best_practices": { "score": 96, "title": "Best Practices" },
"seo": { "score": 100, "title": "SEO" }
},
"ai_signals": { "signals": [], "count": 0 },
"cost": 300.0,
"created_at": "2026-07-02T10:24:00Z"
}List your website audits
/v1/auditsReturns your audit history, most recent first.
[
{
"id": "aud_01hxyz...",
"url": "https://example.com/",
"status": "ready",
"score": 78,
"grade": "C",
"cost": 300.0,
"created_at": "2026-07-02T10:24:00Z"
}
]Run a Deep Audit
/v1/auditsPass tier="deep" for the expanded audit — multi-page crawl, responsiveness, data-exposure checks, AI-generated-design-pattern detection, an optional GitHub code review, and (only for domains you've verified via /v1/domains) ownership-gated active security tests (login-throttling probe, CSRF header verification). Runs in the background — this call returns immediately with status="pending"; poll GET /v1/audits/{id} until status is "ready" or "failed", or just wait for the completion email. Always billed, no free trial.
{
"url": "https://example.com",
"tier": "deep",
"github_repo_url": "https://github.com/owner/repo"
}{
"id": "aud_01hxyz...",
"url": "https://example.com/",
"status": "pending",
"score": null,
"grade": null,
"tier": "deep",
"active_tests_run": false,
"cost": 5000.0,
"created_at": "2026-07-02T10:24:00Z"
}Start domain ownership verification
/v1/domains/verify/startProves you control a domain, to unlock the deep audit tier's active security tests for it. Returns both verification options — add either the DNS TXT record or the .well-known file, then call the check endpoint below. Free; dashboard-only (JWT auth).
{
"domain": "example.com"
}{
"id": "dom_01hxyz...",
"domain": "example.com",
"token": "3a810d5fe095e8f16555177ab14b8c29",
"dns_txt": {
"record": "_identifyorg-verify.example.com",
"type": "TXT",
"value": "3a810d5fe095e8f16555177ab14b8c29"
},
"well_known_file": {
"path": "/.well-known/identifyorg-verify.txt",
"url": "https://example.com/.well-known/identifyorg-verify.txt",
"content": "3a810d5fe095e8f16555177ab14b8c29"
}
}Check domain verification status
/v1/domains/verify/{domain_id}/checkRe-checks whether the DNS TXT record or well-known file is now in place. Retry-able — no error if not found yet.
{
"verified": true,
"method": "dns_txt"
}Check an image for AI generation / doctoring
/v1/media-scan/imageSelf-hosted detection — metadata/provenance, JPEG forensics, frequency/noise analysis, face-splice signals, plus a local ONNX classifier. multipart/form-data upload, field name `file`. Reports which signals fired, not a manufactured confidence percentage. First image check is free per account, then billed at the API rate (separate from the website's own rate). Note: the free anonymous/claim flow used on the homepage is web-only, not part of this API.
curl -X POST https://api.identifyorg.com/v1/media-scan/image \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@photo.jpg"{
"id": "scn_01hxyz...",
"media_type": "image",
"status": "ready",
"verdict": "likely_authentic",
"signals": [
{
"category": "provenance",
"severity": "weak",
"title": "No camera metadata present",
"detail": "No Make/Model/DateTimeOriginal EXIF fields.",
"measured": null
}
],
"signal_count": 1,
"classifier_model": "ateeqq-ai-vs-human-siglip@1",
"cost": 200.0,
"is_test": false,
"created_at": "2026-07-02T10:24:00Z"
}Check text for AI generation
/v1/media-scan/textSelf-hosted detection — stylometric heuristics (sentence/paragraph uniformity, vocabulary diversity, repeated phrasing, AI-phrasing lexicon) plus perplexity/burstiness scoring from a local language model. Requires at least 800 characters (shorter text is statistically meaningless for these checks). First text check is free per account, then billed at the API rate.
{
"text": "Paste at least 800 characters of text to check..."
}{
"id": "scn_01hxyz...",
"media_type": "text",
"status": "ready",
"verdict": "likely_ai",
"signals": [
{
"category": "language_model",
"severity": "moderate",
"title": "Text is unusually predictable to a language model",
"detail": "Mean perplexity (20.2) is low.",
"measured": { "mean_perplexity": 20.25 }
}
],
"signal_count": 1,
"classifier_model": "gpt2-base@1",
"text_char_count": 942,
"cost": 150.0,
"is_test": false,
"created_at": "2026-07-02T10:24:00Z"
}Check a video for AI generation / doctoring
/v1/media-scan/videoffprobe container/metadata analysis plus ffmpeg frame-sampling through the same image-detection pipeline, aggregated across frames. multipart/form-data upload, field name `file`, optional `frames` query param (4-30, default 12). Always billed — there is no free tier and no anonymous trial for video, since a scan is real, multi-frame compute cost. Max file size 200MB, max duration 5 minutes.
curl -X POST "https://api.identifyorg.com/v1/media-scan/video?frames=12" \
-H "X-IdentifyOrg-Key: io_live_xxxx" \
-F "file=@clip.mp4"{
"id": "scn_01hxyz...",
"media_type": "video",
"status": "ready",
"verdict": "inconclusive",
"signals": [
{
"category": "container",
"severity": "weak",
"title": "No audio stream present",
"detail": "",
"measured": null
}
],
"signal_count": 1,
"duration_seconds": 8.4,
"frames_sampled": 12,
"cost": 800.0,
"is_test": false,
"created_at": "2026-07-02T10:24:00Z"
}List your media checks
/v1/media-scanReturns your image/video/text check history, most recent first. Optional `?media_type=image|video|text` filter.
[
{
"id": "scn_01hxyz...",
"media_type": "image",
"status": "ready",
"verdict": "likely_authentic",
"signal_count": 1,
"cost": 200.0,
"created_at": "2026-07-02T10:24:00Z"
}
]Logo generator
/v1/tools/generate-logoGenerate a procedural SVG logo — monogram, badge, abstract mark, or wordmark — from a company name and two brand colors. Instant, no queue.
{
"company_name": "Acme Fintech",
"style": "monogram", // monogram | badge | abstract | wordmark
"primary_color": "#10b981",
"secondary_color": "#0a0f1a",
"size": 256
}<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<rect width="256" height="256" rx="56" fill="#10b981" />
<text ...>AF</text>
</svg>