Documentation

Base URL: https://api.shernova.com · Errors: { error, message, error_code, doc_url, request_id } · OpenAPI Swagger UI is disabled on production (/docs returns 404); use this reference or your local dev server.

Authentication

HeaderUsed for
Authorization: Bearer {jwt}Dashboard & org routes
Authorization: Bearer sk_live_…Production server verification API
Authorization: Bearer sk_test_…Test server verification API
Authorization: Bearer {sdk_jwt}Mobile SDK verification calls
Authorization: Bearer pk_live_… / pk_test_…POST /v1/sdk/token only
X-Shernova-Organization-IdOrg-scoped dashboard routes
X-Shernova-Gateway-TokenGateway device routes only

Health

GET /health/live

Purpose: Liveness probe. Auth: None.

GET /health/ready

Purpose: Readiness (DB + Redis). Auth: None.

Auth

POST /v1/auth/register

Purpose: Create developer account. Auth: None.

json
{ "email": "dev@company.com", "password": "secure-password" }

POST /v1/auth/login

json
{ "email": "dev@company.com", "password": "secure-password" }

POST /v1/auth/refresh

json
{ "refresh_token": "…" }

GET /v1/auth/me

Purpose: Current user profile. Auth: JWT.

Applications

GET /v1/apps

Purpose: List organization apps. Auth: JWT + APPS_READ.

POST /v1/apps

json
{ "name": "My App", "webhook_url": "https://example.com/webhooks/shernova" }

PATCH /v1/apps/:id

json
{ "name": "Updated name", "webhook_url": "https://…", "is_active": true }

POST /v1/apps/:id/test-webhook

json
{ "webhook_url": "https://example.com/webhooks/shernova" }

POST /v1/apps/:id/rotate-api-key · rotate-webhook-secret

json
{ "reason": "Scheduled rotation" }

Verifications

Never call this from the browser

sk_live_… and sk_test_… are server secrets. Proxy create/status/cancel through your backend. See Website Integration for complete Node.js, PHP, and Python flows.

POST /v1/verifications

Purpose: Start verification session. Auth: API key (sk_live_ or SDK JWT).

bash
curl -X POST https://api.shernova.com/v1/verifications \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"+201012345678","client_request_id":"my-idempotency-key-12345678"}'
Response 201
{
  "session_id": "uuid",
  "status": "waiting",
  "gateway_phone_number": "+201140774187",
  "qr_code_data": "tel:+201140774187",
  "environment": "live",
  "method": "missed_call",
  "expires_at": "2026-07-21T12:00:00.000Z"
}

Optional header: Idempotency-Key (8-128 chars). Test-key sessions use real gateways and consume credits - same flow as live.

If no gateway line is free, the session is created as queued: gateway_phone_number is null and queue_reason is one of none_online, country_unavailable, all_busy. Keep polling GET /v1/verifications/:id until status becomes waiting (a gateway line was assigned) - only then place the call. Treat gateway_phone_number as nullable and read it again on every poll.

qr_code_data is the same gateway number as a tel: URI. Render it as a QR code while waiting so desktop users can scan it with the phone that will place the call instead of typing the number. It is null while queued and after the session leaves waiting.

GET /v1/verifications/:id

Purpose: Poll session status (created → queued → waiting → terminal). Auth: API key.

DELETE /v1/verifications/:id

Purpose: Cancel a waiting or queued session (releases credit hold). Auth: API key.

GET /v1/dashboard/sessions

Purpose: List org verification sessions in dashboard. Auth: JWT + SESSIONS_READ.

SDK Token

POST /v1/sdk/token

Purpose: Exchange publishable key for short-lived JWT. Auth: Bearer pk_live_…

json
{
  "package_name": "com.yourcompany.app",
  "sha256": "64-char-hex",
  "nonce": "random-min-8-chars"
}
Response 201
{
  "access_token": "eyJ…",
  "token_type": "Bearer",
  "expires_in": 180,
  "app_id": "uuid",
  "available_credits": 100,
  "ui": { "waiting_title": "…", "waiting_body": "…" }
}

Test keys (pk_test_ / sk_test_)

Test keys create sessions against real online gateways. Complete by placing a missed call to gateway_phone_number (once status is waiting; it is null while queued) from the user's phone. Credits are held and captured like live sessions.

Receipts

POST /v1/verifications/:id/receipt

Purpose: Issue signed JWT receipt for a verified session. Auth: API key (sk_* or SDK JWT).

POST /v1/receipts/verify

Purpose: Verify receipt JWT server-side. Auth: API key. Replay returns 409 receipt_already_used (SH_014).

json
{ "receipt": "eyJ…" }

Billing (Developer)

GET /v1/apps/:id/billing

Purpose: Credit balance and plan info. Auth: JWT + APPS_READ.

GET /v1/apps/:id/billing/ledger

Purpose: Credit ledger entries. Auth: JWT + APPS_READ.

POST /v1/apps/:id/android-signatures

json
{ "package_name": "com.app", "sha256": "…", "label": "Release" }

Organizations

Routes: POST/GET /v1/organizations, GET/PATCH /v1/organizations/current, members, invitations, analytics. Auth: JWT + org permissions.

Admin (Platform)

Routes under /v1/admin/* for platform operators: users, organizations, gateways, sessions, webhooks, audit, billing management. Auth: JWT + platform permissions.

Gateway (Internal)

POST /v1/gateway/ring, /v1/gateway/heartbeat, GET /v1/gateway/health. Used by Shernova gateway Android app - not for integrators.

Session Status Values

created, queued, waiting, verified, rejected, expired, failed, cancelled, completed