REST API
Base URL: https://biomapi.com
Interactive docs (Swagger UI): /apidocs
The seven REST endpoints below are the operations exposed in the OpenAPI 3.1 schema. Web pages and documentation resources are listed separately at the end of this page; they are not OpenAPI operations.
POST /api/v1/biom/process
Section titled “POST /api/v1/biom/process”Process a biometry file and return structured measurements.
File routing
Section titled “File routing”The engine is selected automatically based on the file extension — no manual selection needed:
| Extension | Engine | What happens |
|---|---|---|
| PDF, JPG, PNG, GIF, BMP | BiomAI | Bytes sent to Gemini LLM for structured extraction |
| JSON | BiomJSON | Schema validation + metadata preservation |
Unsupported extensions are rejected with 400 before any processing occurs.
Request
Section titled “Request”Multipart form data:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
file |
file | Yes | — | Biometry report file |
biompin |
bool | No | false |
Generate a BiomPIN for secure sharing |
service_tier |
string | No | standard |
BiomAPI tier for PDF/images: standard or slow; ignored for JSON |
Headers:
| Header | Description |
|---|---|
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 |
X-BiomAPI-Integrator-ID: <id> |
Optional lowercase integration identifier used for operational attribution |
X-BiomAPI-Integrator-Origin: <origin> |
Optional integration origin; only its hostname is retained for operational attribution |
The integration headers are soft attribution. Invalid or missing values never change processing behavior. With a valid integrator ID, BiomAPI uses a valid declared integration origin and falls back to the standard HTTP Origin. Without a valid ID, it ignores the declared integration origin but can still retain the host from the standard Origin. If the ID is absent or invalid, integrator_id remains absent rather than becoming unknown. BiomAPI retains only the origin’s host component. The biomapi.* ID namespace is reserved by convention for official BiomAPI clients, but it is not an authentication boundary. BiomAPI’s Web Widget sets both integration headers automatically.
BiomPIN generation
Section titled “BiomPIN generation”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.
BYOK behavior
Section titled “BYOK behavior”When X-Gemini-API-Key is provided, extraction uses your personal Gemini quota for that request. BYOK takes precedence over deployment-managed routing, is tracked under the biomai_byok rate limit bucket, and never falls back to a server-managed credential if the supplied key fails. BYOK has no effect on JSON uploads — BiomJSON doesn’t call the LLM.
Standard and Slow processing
Section titled “Standard and Slow processing”service_tier=standard uses normal-priority processing and costs 1 BiomAI credit. service_tier=slow costs 0.5 credit and is intended for non-urgent workloads. Latency is variable and the request may take substantially longer, so clients should keep the request open for the deployment’s configured Slow timeout. There is no automatic fallback to Standard.
The selected tier is operational request data and is not added to extraction metadata or the StandardAPIResponse payload.
Rate limiting
Section titled “Rate limiting”BiomAI and BYOK rate limits are consumed after local file validation and credential resolution, and before the Gemini call, so attempts that reach the external API path count even if extraction fails or times out. Deployment-managed BiomAI is also protected by internal capacity limits. BiomJSON is local and only consumes quota after successful JSON validation/processing.
| Scenario | Bucket |
|---|---|
| PDF/image, no BYOK | biomai |
| PDF/image, BYOK | biomai_byok |
| JSON upload | biomjson |
Standard PDF/image processing consumes 1 credit and Slow consumes 0.5. JSON uploads and retrievals consume 1 credit each.
Use GET /api/v1/biom/usage to obtain the limits that apply to the caller.
Round-trip re-upload (JSON)
Section titled “Round-trip re-upload (JSON)”When you re-upload an unedited JSON that originally came from a BiomAI extraction, BiomJSON preserves the public BiomAI provenance fields (timestamp, byok, llm) and populates input_schema_version with the schema version of the uploaded JSON, so you can detect if it was produced by an older BiomAPI version. Operational diagnostics such as token counts, retry timing, and preprocessing details are internal and are not returned in public API payloads. 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.1.66", "extraction": { "method": "BiomDIRECT", "timestamp": "2026-05-24T12:00:00Z", "input_schema_version": "1.0.0", "source_app": "BiomLINK", "source_version": "0.1.0" } }}Posterior keratometry
Section titled “Posterior keratometry”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.
Response
Section titled “Response”{ "data": { "biometer": { "device_name": "IOLMaster700", "manufacturer": "Zeiss" }, "exam_date": "2026-05-24", "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": { "request_id": "3f5e3c51-d0b9-45fd-a7f4-6d7a3b592f42", "schema_version": "1.0.0", "app_version": "2.1.66", "extraction": { "method": "BiomAI", "timestamp": "2025-01-15T10:30:00Z", "byok": false, "llm": "gemini-3.7-flash", "input_schema_version": null } }, "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.
When analytics is enabled, every successful BiomAI PDF/image extraction (including
BYOK) can be rated through POST /api/v1/biom/feedback.
Keep the original metadata.request_id for this purpose. No opt-in header or
additional processing parameter is needed. JSON processing is not eligible,
even if it preserves BiomAI extraction metadata.
Errors
Section titled “Errors”| Code | Condition |
|---|---|
400 |
Empty file, unsupported extension, or invalid file content |
422 |
JSON schema mismatch (major version) or Pydantic validation failure |
429 |
Rate limit exceeded for the applicable engine bucket |
500 |
Processing failed, including LLM extraction errors |
504 |
BiomAI extraction exceeded the configured tier timeout: BIOMAI_TIMEOUT_SECONDS for Standard or BIOMAI_SLOW_TIMEOUT_SECONDS for Slow |
POST /api/v1/biom/feedback
Section titled “POST /api/v1/biom/feedback”Submit an optional accuracy rating for a successful BiomAI extraction. Available to web-app and API clients when analytics is enabled. No API key is required and ratings do not consume extraction quotas.
Request
Section titled “Request”Send Content-Type: application/json and only these two fields (maximum body
size: 256 bytes):
{ "request_id": "3f5e3c51-d0b9-45fd-a7f4-6d7a3b592f42", "rating": "accurate"}The optional X-BiomAPI-Integrator-ID and X-BiomAPI-Integrator-Origin
headers are accepted for soft operational attribution. They do not change the
two-field JSON contract, feedback eligibility, or processing behavior.
request_id must be the original metadata.request_id returned by
POST /api/v1/biom/process for a PDF/image extraction. Do not use a retrieval
request ID. rating must be accurate or inaccurate.
Do not include files, extracted values, patient information, or contact text.
The biomai_feedback analytics event contains the submitted rating as
outcome (accurate or inaccurate), the feedback HTTP
request_id (matching its X-Request-ID response header), and the original
extraction_request_id, plus deployment environment and app version.
Availability and retries
Section titled “Availability and retries”References are eligible for up to 24 hours after processing, subject to a 10,000-entry process-local limit. Eviction or a server restart expires the reference. JSON validation, manual edits, and retrieval do not create eligible references.
The first rating is final. Resubmitting the same rating returns success without
emitting another event; submitting a different rating returns 409.
Response
Section titled “Response”{"success": true}Success means the rating was handed to the analytics SDK, not confirmation of
delivery to PostHog. A 503 leaves the reference unrated, so retrying is safe.
Errors
Section titled “Errors”| Code | Condition |
|---|---|
404 |
Unknown, ineligible, expired, or evicted extraction reference |
409 |
The extraction already has a different rating |
413 |
Request body exceeds 256 bytes |
415 |
Content-Type is not application/json |
422 |
Invalid JSON, request ID, rating, or extra fields |
503 |
Feedback analytics is temporarily unavailable |
GET /api/v1/biom/retrieve
Section titled “GET /api/v1/biom/retrieve”Retrieve encrypted biometry data using a BiomPIN code.
How it works
Section titled “How it works”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, so unsuccessful retrieval attempts also consume quota. The primary brute-force protection is the auto-destroy mechanism.
Request
Section titled “Request”GET /api/v1/biom/retrieve?biom_pin=lunar-rocket-731904| Parameter | Required | Description |
|---|---|---|
biom_pin |
Yes | Full PIN including numeric suffix: word-word-123456 |
The optional Authorization, X-BiomAPI-Integrator-ID, and X-BiomAPI-Integrator-Origin headers are also accepted. The integration headers have the same soft-attribution behavior as on /process.
Browser integrations can use the Browser SDK for fragment consumption, sharing, browser-local history, and patient identifier context. Its helpers do not make process or retrieve requests; your application owns those REST calls.
Wrong PIN attempts
Section titled “Wrong PIN attempts”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.
Response
Section titled “Response”Same StandardAPIResponse shape as /process. The biompin field reflects the original PIN info (pin, expiry, db_id).
Errors
Section titled “Errors”| Code | Condition |
|---|---|
400 |
PIN doesn’t match the word-word-123456 format |
404 |
PIN not found, already expired, or destroyed after too many wrong attempts |
422 |
Missing required biom_pin query parameter |
429 |
Rate limit exceeded |
POST /api/v1/biom/export
Section titled “POST /api/v1/biom/export”Generate a ZIP archive in any combination of CSV, XLSX, and JSON formats.
No authentication required. No rate limiting. Pure data transformation with no LLM calls.
Export requests are bounded to keep this public transformation endpoint lightweight:
| Limit | Environment variable |
|---|---|
| JSON request body size | EXPORT_MAX_BODY_SIZE |
| Responses per request | EXPORT_MAX_RESPONSES |
The Content-Length header is required. The body-size limit is checked before JSON parsing, and the response-count limit is checked after parsing.
Archive contents
Section titled “Archive contents”| File | Description |
|---|---|
biomapi-export-YYYYMMDD-HHMMSS.csv |
Combined by-eye CSV of all results |
biomapi-export-YYYYMMDD-HHMMSS.xlsx |
Formatted workbook containing the same by-eye data |
biomapi-{patientId}-{device}.json |
One JSON file per report |
The CSV and XLSX produce two rows per report: one for the right eye (right_eye=1) and one for the left eye (right_eye=0). Each row includes exam, patient, device, anterior biometry, and posterior keratometry fields.
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.
Request body
Section titled “Request body”formats accepts any non-empty combination of csv, xlsx, and json. It defaults to all three when omitted.
{ "responses": [ { "json_data": { "...": "StandardAPIResponse object" }, "filename": "report1.pdf" }, { "json_data": { "...": "StandardAPIResponse object" }, "filename": "report2.json" } ], "formats": ["csv", "xlsx", "json"]}The optional X-BiomAPI-Integrator-ID and X-BiomAPI-Integrator-Origin
headers are accepted for the same soft operational attribution used by process
and retrieve requests.
Response
Section titled “Response”application/zip file download.
Errors
Section titled “Errors”| Code | Condition |
|---|---|
400 |
Invalid Content-Length, empty response list, or empty formats array |
411 |
Missing Content-Length header |
413 |
Request body exceeds EXPORT_MAX_BODY_SIZE or response count exceeds EXPORT_MAX_RESPONSES |
422 |
Invalid request body, including missing fields or unsupported export formats |
500 |
Export generation failed |
GET /api/v1/biom/usage
Section titled “GET /api/v1/biom/usage”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.
What it returns
Section titled “What it returns”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.
Validating your Gemini key
Section titled “Validating your Gemini 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.
Request
Section titled “Request”GET /api/v1/biom/usageGET /api/v1/biom/usage?validate=true| Query parameter | Default | Description |
|---|---|---|
validate |
false |
Also validate X-Gemini-API-Key against Gemini API (~1–2 s) |
Response
Section titled “Response”The response reports used, limit, and resets_in_seconds for biomai, biomai_byok, biomjson, and retrieve. Public callers receive the deployment’s per-IP limits. Authenticated callers receive the quotas configured for their API key.
keys field details:
| Scenario | biomapi value |
gemini 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.
Errors
Section titled “Errors”| Code | Condition |
|---|---|
422 |
Invalid validate query parameter; a boolean value is required |
GET /api/v1/status
Section titled “GET /api/v1/status”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.
Response
Section titled “Response”{ "status": "ok", "gemini_llm": "gemini-3.7-flash", "environment": "production", "app_version": "2.1.66", "schema_version": "1.0.0", "db_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}| Field | Description |
|---|---|
status |
Always "ok" if the API process can serve the request |
gemini_llm |
The Gemini model configured on the server |
environment |
Deployment environment |
app_version |
Running BiomAPI package version |
schema_version |
Current response schema version |
db_id |
BiomPIN database instance identifier |
Performance
Section titled “Performance”| Field | Cost |
|---|---|
db_id |
In-memory value initialized at startup; no per-request DB lookup |
environment, app_version, schema_version, gemini_llm |
Configuration/package metadata reads |
GET /api/v1/health
Section titled “GET /api/v1/health”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.
Response
Section titled “Response”{ "status": "operational", "gemini_api_connected": true, "db_connected": true, "db_records": 42, "gemini_llm": "gemini-3.7-flash", "environment": "production", "app_version": "2.1.66", "schema_version": "1.0.0", "db_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}| Field | Description |
|---|---|
status |
"operational" (all healthy), "degraded" (one of Gemini/DB unavailable), "error" (both unavailable) |
gemini_api_connected |
Whether the server’s Gemini API key is valid and reachable; this may call Gemini and is cached for 60 seconds |
db_connected |
Whether the BiomPIN SQLite database manager is initialized |
db_records |
Total BiomPIN records from SELECT COUNT(*) FROM share |
gemini_llm |
The Gemini model configured on the server |
environment |
Deployment environment |
app_version |
Running BiomAPI package version |
schema_version |
Current response schema version |
db_id |
BiomPIN database instance identifier |
Web pages and documentation resources
Section titled “Web pages and documentation resources”These URLs remain accessible but are excluded from the OpenAPI schema and Swagger’s operation list. For browser workflows, see the Web App guide and Web Widget guide.
| Route | Description |
|---|---|
GET / |
Main web application (SPA) |
GET /pin/{biompin} |
Direct BiomPIN access — pre-fills the BiomPIN tab and auto-retrieves |
GET /widget |
Web app with the integrator handoff interface |
GET /browser-sdk-demo |
Browser SDK demo: widget, sharing, and fragment imports |
GET /docs/ |
This documentation site |
GET /apidocs |
Swagger UI (interactive API explorer) |
GET /openapi.json |
OpenAPI 3.1 schema for the public REST endpoints (powers Swagger UI) |
GET /llms.txt |
LLM-readable site index (also /llms-full.txt, /llms-small.txt) |