Skip to content

API Endpoints

Base URL: https://biomapi.com

Interactive docs (Swagger UI): /apidocs


Process a biometry file and return structured measurements.

The engine is selected automatically based on the file extension — no manual selection needed:

ExtensionEngineWhat happens
PDF, JPG, PNG, GIF, BMPBiomAIBytes sent to Gemini LLM for structured extraction
JSONBiomJSONSchema validation + metadata preservation

Unsupported extensions are rejected with 400 before any processing occurs.

Multipart form data:

FieldTypeRequiredDefaultDescription
filefileYesBiometry report file
biompinboolNofalseGenerate a BiomPIN for secure sharing

Headers:

HeaderDescription
Authorization: Bearer <key>Optional BiomAPI key — unlocks higher per-user rate limits
X-Gemini-API-Key: <key>Optional BYOK Gemini key — uses your own Google quota

BiomPIN is off by default (biompin=false). Set biompin=true to receive a secure sharing link in the response. If generation fails (e.g., DB unavailable), processing still succeeds and the biompin field is null.

When X-Gemini-API-Key is provided, extraction uses your personal Gemini quota instead of the shared server quota. The request is tracked under the biomai_byok rate limit bucket (separate from biomai). BYOK has no effect on JSON uploads — BiomJSON doesn’t call the LLM.

BiomAI and BYOK rate limits are consumed after local file validation and before the Gemini call, so attempts that reach the external API path count even if extraction fails or times out. Non-BYOK BiomAI is also protected by internal shared daily capacity limits. BiomJSON is local and only consumes quota after successful JSON validation/processing.

ScenarioBucketPublic default
PDF/image, no BYOKbiomai15/day
PDF/image, BYOKbiomai_byok1,000/day
JSON uploadbiomjson300/day

When you re-upload an unedited JSON that originally came from a BiomAI extraction, BiomJSON preserves the original LLM metadata (token counts, model name, timing). The input_schema_version field is populated with the schema version of the uploaded JSON, so you can detect if it was produced by an older BiomAPI version. Manual web edits are submitted as new latest-state BiomDIRECT payloads with source_app: "BiomAPI Webapp". If the JSON has no recognizable BiomAI provenance, it’s attributed as BiomDIRECT.

Integrations can identify direct/manual JSON sources with metadata.extraction.source_app and source_version:

{
"metadata": {
"schema_version": "1.0.0",
"app_version": "2.0.22",
"extraction": {
"method": "BiomDIRECT",
"timestamp": "2026-05-24T12:00:00Z",
"input_schema_version": "1.0.0",
"source_app": "BiomLINK",
"source_version": "0.1.0"
}
}
}

The extra_data.posterior_keratometry field is populated only for devices that support PK extraction (Anterion, EyestarES900, IOLMaster700, MS39, PentacamAXL). For other devices, extra_data is null.

{
"data": {
"biometer": {
"device_name": "IOLMaster700",
"manufacturer": "Zeiss"
},
"patient": {
"name": "JD",
"id": "12345",
"date_of_birth": "1965-03-15",
"gender": "Male"
},
"right_eye": {
"AL": 23.45,
"ACD": 3.12,
"K1_magnitude": 43.25,
"K1_axis": 5,
"K2_magnitude": 44.50,
"K2_axis": 95,
"WTW": 11.8,
"LT": 4.52,
"CCT": 545,
"lens_status": "Phakic",
"post_refractive": "None",
"keratometric_index": 1.3375
},
"left_eye": { "...": "..." }
},
"extra_data": {
"notes": null,
"posterior_keratometry": {
"pk_device_name": "IOLMaster700",
"right_eye": { "PK1_magnitude": 6.12, "PK1_axis": 8, "PK2_magnitude": 6.45, "PK2_axis": 98 },
"left_eye": { "PK1_magnitude": 6.08, "PK1_axis": 172, "PK2_magnitude": 6.38, "PK2_axis": 82 }
}
},
"metadata": {
"schema_version": "1.0.0",
"app_version": "2.0.22",
"extraction": {
"method": "BiomAI",
"timestamp": "2025-01-15T10:30:00Z",
"byok": false,
"llm": "gemini-3.5-flash",
"llm_api_metrics": {
"prompt_token_count": 1500,
"cached_content_token_count": null,
"candidates_token_count": 200,
"thoughts_token_count": null,
"total_token_count": 1700,
"cache_hit_ratio": null
},
"llm_performance": {
"llm_response_time_seconds": 2.5,
"retry_attempts": 0,
"total_retry_delay_seconds": 0.0
}
}
},
"biompin": {
"pin": "lunar-rocket-731904",
"expires_at": "2025-02-15T10:30:00Z",
"db_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}

See Response Schema for the complete field reference.

CodeCondition
400Empty file, unsupported extension, or invalid file content
422JSON schema mismatch (major version) or Pydantic validation failure
429Rate limit exceeded for the applicable engine bucket
504BiomAI extraction exceeded BIOMAI_TIMEOUT_SECONDS (default 30 s)

Retrieve encrypted biometry data using a BiomPIN code.

BiomPIN codes have two parts: word-word (the share ID, stored in the database) and -123456 (the 6-digit numeric PIN, the encryption key, never stored). The server derives the AES-256-GCM decryption key from the numeric PIN using Argon2id. Without the full PIN including the numeric suffix, the data cannot be decrypted.

Rate limiting for this endpoint is applied before retrieval (unlike /process). This prevents quota exhaustion via wrong PIN attempts, though the primary brute-force protection is the auto-destroy mechanism.

GET /api/v1/biom/retrieve?biom_pin=lunar-rocket-731904
ParameterRequiredDescription
biom_pinYesFull PIN including numeric suffix: word-word-123456

Each wrong numeric PIN increments a counter. After 3 failed attempts, the database record is permanently deleted — the data is gone, and all subsequent requests for that share ID return 404. This is intentional: it prevents offline brute-forcing by destroying the ciphertext.

Note that rate limiting is also applied per-IP/per-user, but the 3-attempt destruction is tracked in the database independently of rate limit state.

Same StandardAPIResponse shape as /process. The biompin field reflects the original PIN info (pin, expiry, db_id).

CodeCondition
400PIN doesn’t match the word-word-123456 format
404PIN not found, already expired, or destroyed after too many wrong attempts
429Rate limit exceeded

Generate a by-eye CSV from an array of StandardAPIResponse objects.

No authentication required. No rate limiting. Pure data transformation — no LLM calls.

Export requests are bounded to keep public transformation endpoints lightweight:

LimitDefaultEnvironment variable
JSON request body size5 MBEXPORT_MAX_BODY_SIZE
Responses per request1000EXPORT_MAX_RESPONSES

The Content-Length header is required. The body-size limit is checked from Content-Length before JSON parsing, and the response-count limit is checked after parsing.

The CSV produces two rows per report: one for the right eye (right_eye=1) and one for the left eye (right_eye=0). Each row includes patient info, device info, and all 12 biometric fields as flat columns.

{
"responses": [
{ "json_data": { "...": "StandardAPIResponse object" }, "filename": "report1.pdf" },
{ "json_data": { "...": "StandardAPIResponse object" }, "filename": "report2.json" }
]
}

text/csv file download (Content-Disposition: attachment; filename=biometry_export.csv).

CodeCondition
400Invalid Content-Length header or empty response list
411Missing Content-Length header
413Request body exceeds EXPORT_MAX_BODY_SIZE or response count exceeds EXPORT_MAX_RESPONSES
500CSV generation failed

Generate a ZIP archive containing a by-eye CSV and individual JSON files per report.

No authentication required. No rate limiting.

The same export limits as /csv apply: EXPORT_MAX_BODY_SIZE caps the incoming JSON request body, and EXPORT_MAX_RESPONSES caps the number of response objects per archive.

FileDescription
biomapi-export-YYYYMMDD-HHMMSS.csvBy-eye CSV of all results (same format as /csv)
biomapi-{patientId}-{device}.jsonOne JSON file per report

Smart filenames: JSON filenames are derived from data.patient.id (slugified) and data.biometer.device_name. If no patient ID is present, the current date is used instead. Duplicate filenames within the same archive are disambiguated with a numeric suffix.

Same structure as /csv: { "responses": [...] }.

application/zip file download.


Returns current rate limit usage and API key validity for the caller.

No rate limiting applied to this endpoint — it’s a read-only in-memory query.

Public callers see per-IP usage. Authenticated callers see per-user usage. The engines section shows used/limit/resets for all four engine buckets regardless of which ones have been used.

The keys section reports validity of the BiomAPI key (instant, in-memory check) and optionally the Gemini BYOK key.

Pass ?validate=true to test the X-Gemini-API-Key header against the live Gemini API. This adds ~1–2 seconds of latency. Without validate=true, the gemini key entry only reports "provided": true — no validity check is performed.

GET /api/v1/biom/usage
GET /api/v1/biom/usage?validate=true
Query parameterDefaultDescription
validatefalseAlso validate X-Gemini-API-Key against Gemini API (~1–2 s)
{
"auth_type": "authenticated",
"user_id": "user1",
"engines": {
"biomai": { "used": 5, "limit": 300, "resets_in_seconds": 72400 },
"biomai_byok": { "used": 0, "limit": 3000, "resets_in_seconds": 72400 },
"biomjson": { "used": 2, "limit": 3000, "resets_in_seconds": 72400 },
"retrieve": { "used": 12, "limit": 10000, "resets_in_seconds": 72400 }
},
"keys": {
"biomapi": { "provided": true, "valid": true, "user_id": "user1" },
"gemini": { "provided": true, "valid": true }
}
}

keys field details:

Scenariobiomapi valuegemini value
No keys provided{"provided": false}{"provided": false}
BiomAPI key provided, valid{"provided": true, "valid": true, "user_id": "..."}
BiomAPI key provided, invalid{"provided": true, "valid": false}
Gemini key provided, validate=false{"provided": true}
Gemini key provided, validate=true, valid{"provided": true, "valid": true}
Gemini key provided, validate=true, invalid{"provided": true, "valid": false}

resets_in_seconds is the time until the oldest tracked request in the sliding window rolls off — i.e., the earliest your limit could recover by one slot.


Lightweight API status and deployment metadata. Public, no authentication required.

Use this endpoint for frequent polling when integrations need the BiomPIN database instance identifier. It does not call Gemini, open a database session, count BiomPIN records, or emit analytics.

{
"status": "ok",
"gemini_llm": "gemini-3.5-flash",
"environment": "production",
"app_version": "2.0.22",
"schema_version": "1.0.0",
"db_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
FieldDescription
statusAlways "ok" if the API process can serve the request
gemini_llmThe Gemini model configured on the server
environmentDeployment environment
app_versionRunning BiomAPI package version
schema_versionCurrent response schema version
db_idBiomPIN database instance identifier
FieldCost
db_idIn-memory value initialized at startup; no per-request DB lookup
environment, app_version, schema_version, gemini_llmConfiguration/package metadata reads

Active health check. Public, no authentication required.

Use this endpoint for monitoring when you need live Gemini and database readiness. Avoid high-frequency polling because it may perform external API and database work.

{
"status": "operational",
"gemini_api_connected": true,
"db_connected": true,
"db_records": 42,
"gemini_llm": "gemini-3.5-flash",
"environment": "production",
"app_version": "2.0.22",
"schema_version": "1.0.0",
"db_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
FieldDescription
status"operational" (all healthy), "degraded" (one of Gemini/DB unavailable), "error" (both unavailable)
gemini_api_connectedWhether the server’s Gemini API key is valid and reachable; this may call Gemini and is cached for 60 seconds
db_connectedWhether the BiomPIN SQLite database manager is initialized
db_recordsTotal BiomPIN records from SELECT COUNT(*) FROM share
gemini_llmThe Gemini model configured on the server
environmentDeployment environment
app_versionRunning BiomAPI package version
schema_versionCurrent response schema version
db_idBiomPIN database instance identifier

RouteDescription
GET /Main web application (SPA)
GET /pin/{biompin}Direct BiomPIN access — pre-fills the BiomPIN tab and auto-retrieves
GET /docs/This documentation site
GET /apidocsSwagger UI (interactive API explorer)
GET /openapi.jsonOpenAPI 3.0 spec (machine-readable, powers Swagger UI)
GET /llms.txtLLM-readable site index (also /llms-full.txt, /llms-small.txt)