Zero data retention · Zero data collection · Zero patient data

SHOMA AI Health API — Important Notice

This API is an administrative support tool intended exclusively for authorised staff of hospitals and clinics. It helps structure and organise clinical documents to reduce administrative workload.

  • It does not provide medical advice, diagnoses or treatment recommendations.
  • It is not clinical decision support and is not intended as a medical device.
  • All clinical decisions remain the sole responsibility of the licensed healthcare professional.
  • The platform operates under a strict zero-retention policy: clinical data is permanently deleted immediately after the temporary report is generated and is never stored or used for training.

By using this API you confirm that you understand and accept these limitations.

01 · Getting started

Overview

The SHOMA Health API securely processes clinical documents for authorised hospital and clinic staff. Files are envelope-encrypted in transit, PII/PHI is redacted before model processing, and results come back as a temporary, structured administrative report. Nothing is retained afterwards.

AES-256 + RSA envelope encryptionPII / PHI redactionAPI-key authentication

What you can do

POST/api/v1/analysisStructure 1–3 encrypted clinical documents into an administrative report
GET/api/v1/auth/public-keyFetch the RSA public key used to wrap your AES session key

Limits at a glance

1–3files per request
10 MBmaximum size per file
5accepted file formats
1credit per analysis, flat rate
2response modes: JSON or SSE
1 / 24hanalyses on free trial
0bytes of clinical data retained
RSA-2048key wrapping (OAEP, SHA-256)

Base URL & response modes

ItemValueNotes
Base URLhttps://api.health.shoma-ai.comAll paths are prefixed with /api/v1.
Payload formatmultipart/form-dataRequired for /analysis. Binary file parts plus form string fields.
Default responseapplication/jsonOne complete JSON envelope when isStreamingResponse=false.
Streaming responsetext/event-streamServer-Sent Events when isStreamingResponse=true.
Output languageautoThe engine detects the document language and replies in it; falls back to English. Reported as responseLanguage.

02 · Getting started

Quickstart

Four steps from a fresh account to a structured report.

  1. 1

    Get your API key

    Create a key on the API Keys page and send it as the X-API-Key header on every request.

  2. 2

    Point at the base URL

    https://api.health.shoma-ai.com/api/v1

  3. 3

    Encrypt your document

    Documents must be envelope-encrypted before upload — see Encryption for the full flow.

  4. 4

    Make your first request

    Call POST /api/v1/analysis — a complete, runnable example is in Code examples.

Create your key on the API Keys page.

03 · Getting started

Authentication

The analysis endpoint accepts three authentication schemes. Server-to-server integrations should use the API key.

SchemeHeader / carrierIntended use
API keyX-API-Key: sk-shoma-…Server-to-server integrations. The primary scheme for this API.
Bearer tokenAuthorization: Bearer …OAuth2 session token issued to a signed-in user.
Session cookieaccess_token (HttpOnly)Browser sessions inside the SHOMA dashboard and playground.
Public key endpointGET /api/v1/auth/public-key requires no authentication.
# Fetch the RSA public key
curl https://api.health.shoma-ai.com/api/v1/auth/public-key
# Authenticate an analysis request
curl -X POST https://api.health.shoma-ai.com/api/v1/analysis \
-H "X-API-Key: YOUR_API_KEY" \
-F "encryptedAesKey=<base64-rsa-wrapped-aes-key>" \
-F "files=@document.enc"

Key lifecycle

TopicBehaviour
RotationRotating a key immediately invalidates the old credential and generates a new one. Update the key in your integrations before rotating — there is no grace period.
Enable / disableDisabling a key temporarily blocks all API traffic for that key and returns AKEY004. Enabling restores access instantly using the same key value.
Multiple keysBasic: 1 key. Pro: up to 10 keys. Enterprise: unlimited — use separate keys to isolate testing and production workloads.
Test vs productionThere is no separate sandbox environment. Isolation is key-based only — issue a distinct key per workload and track usage per key.
ExpirationKeys never expire on a timer. They remain valid indefinitely until you rotate or delete them — so treat a leaked key as live until you act on it.
Never expose a key client-side. API keys carry full account privileges and consume credits. Call the API from your backend only.

04 · Getting started

Versioning

The API is versioned in the URL path. The version segment is mandatory — there is no unversioned route.

https://api.health.shoma-ai.com/api/v1/analysis
└── version segment
RulePolicy
Selecting a versionSet it in the path (/api/v1/…). No header or query parameter is used.
Breaking changesShip only in a new major version (/api/v2). v1 keeps its contract.
Additive changesNew optional fields and new response keys may appear within v1. Clients must ignore unknown keys.
Status labelsEach version carries a status in the changelog. v1 is Current and nothing is deprecated today.

05 · Uploads

Supported file formats & limits

Each request carries between one and three documents. Every file is encrypted client-side before it leaves your machine.

FormatExtensionTypical use
PDF.pdfLab reports, discharge letters, referrals
Word.docxClinical notes and dictated summaries
JPEG.jpg · .jpegPhotographed or scanned paper documents
PNG.pngScreenshots and exported images
WebP.webpCompressed images exported from web tools
10 MBmaximum size per file
3maximum files per analysis request
1minimum files — an empty request is rejected
Size is checked per file, not per request. Each of the 1–3 files must be at or under 10 MB. Measure the encrypted payload you upload — AES-GCM adds a 12-byte IV and a 16-byte authentication tag on top of the original bytes.
DICOM is not accepted. The backend decrypts only the five formats listed above. Sending a .dcm file will fail server-side after upload, so screen uploads in your own client before encrypting.
Filename privacy.The filename travels in plaintext in the multipart headers. Don't include personal or sensitive information in it — avoid john_doe_report.pdf; use a generic name like document.enc.

06 · Uploads

Encrypting your documents

RSA can't encrypt a file directly (~200-byte limit), so you encrypt the document with a one-time AES key and wrap that key with our RSA public key. This is envelope encryption.

01Your documentPlaintext, on your machine
02AES-256-GCMOne-time key, 12-byte IV prepended
03RSA-OAEPAES key wrapped with our public key
04ServerDecrypts in memory, processes, clears
  1. 1

    Fetch the RSA public key

    Call GET /api/v1/auth/public-key to get the server's public key (PEM).

  2. 2

    Generate a random AES-256 key

    Create a random 32-byte key, used for this upload only.

  3. 3

    Encrypt the document with AES-256-GCM

    Encrypt the file bytes and prepend the 12-byte IV to the ciphertext.

  4. 4

    Wrap the AES key with RSA

    Encrypt the AES key using RSA-OAEP (SHA-256), then base64-encode it.

  5. 5

    Upload

    POST to /api/v1/analysis as multipart form data: the encrypted files, the encryptedAesKey field, and an optional message if you want to add context.

  6. 6

    Server decrypts & discards

    The backend unwraps the AES key with its private key, decrypts the document in memory, processes it, then clears it.

One AES key covers the whole request. All files in a single request must be encrypted with the same session key — you send exactly one encryptedAesKey.

07 · Reference

API reference

Full parameters, headers, request and response schemas for both endpoints.

GET/api/v1/auth/public-key

Retrieve the RSA-2048 public key in PEM format to encrypt session keys client-side before sending medical files to the analysis pipeline. Authentication: none (public).

Request

GET /api/v1/auth/public-key HTTP/1.1
Host: api.health.shoma-ai.com

Response schema — 200 OK

FieldTypeDescription
statusintegerMirrors the HTTP status code.
messagestringHuman-readable outcome.
errorCodestringSUC000 on success; an ERR*/AUTH* code otherwise.
data.publicKeystringRSA-2048 public key, PEM encoded, newlines escaped as \n.

Example response

{
"status": 200,
"message": "Public key retrieved successfully.",
"errorCode": "SUC000",
"data": {
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----"
}
}
POST/api/v1/analysis

Core document analysis pipeline. Accepts 1–3 envelope-encrypted documents and returns a temporary structured administrative report, as one JSON body or as a Server-Sent Events stream.

Headers

HeaderRequiredDescription
X-API-Keyone of threeYour API key. Preferred for server-to-server calls.
Authorizationone of threeBearer <token> — OAuth2 session token.
Cookieone of threeHttpOnly access_token session cookie.
Content-Typeyesmultipart/form-data (set automatically by most HTTP clients)

Body parameters

FieldTypeRequiredDescription
encryptedAesKeystringrequiredBase64 of the AES-256 session key wrapped with RSA-OAEP (SHA-256).
filesfile[]1–3 requiredEach file AES-256-GCM encrypted, 12-byte IV prepended. Repeat the field for multiple files.
messagestringoptionalFree-text clinical context or a specific question sent along with the documents.
isStreamingResponsebooleanoptional · default false"true" streams pipeline progress as Server-Sent Events instead of one JSON response.

Request payload

POST /api/v1/analysis HTTP/1.1
Host: api.health.shoma-ai.com
X-API-Key: YOUR_API_KEY
Content-Type: multipart/form-data
encryptedAesKey: <base64 RSA-OAEP-wrapped AES key>
files: document.enc # binary, repeat for up to 3
message: Patient presents with acute chest pain...
isStreamingResponse: true # optional

Response schema — 200 OK

FieldTypeDescription
data.medicalInsightsstringNarrative administrative summary of the submitted documents.
data.extractedEntitiesobjectStructured extraction: symptoms, medicalHistory, statedConditions, medications[], labValues[].
data.completenessScorenumberHow complete the source documentation appeared, 0–100.
data.conflictFlagsstring[]Documentation inconsistencies noted between records.
data.suggestionsstring[]Administrative follow-up items extracted from the documents.
data.visitTrendsobject[]Parameter values over time: date, parameter, value.
data.highlightsstring[]Short headline points from the report.
data.disclaimerstringMandatory AI-output notice. Must be surfaced to the end user verbatim.
data.analysisScorenumberOverall confidence in the structuring pass.
data.scoreComputationStatusstringsuccess when scoring completed.
data.creditsUsedintegerCredits deducted for this request. Always 1 — a flat rate regardless of file count.
data.inputTokens · outputTokensintegerToken counts consumed by the model pass. Recorded for auditing only; they do not affect billing.
data.effortScoringobjectrawReadingTimeMinutes, assistedReviewTimeMinutes, effortReductionPercentage, basis.
data.responseLanguagestringLanguage the report was written in, detected from the documents.

A complete example body is in Success responses.

08 · Reference

Code examples

End-to-end: fetch the public key, encrypt, upload, handle the response. No SDK required — this is a plain REST API.

# End-to-end: fetch key -> encrypt -> upload -> read response
import os, base64, requests
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
BASE = "https://api.health.shoma-ai.com/api/v1"
HEADERS = {"X-API-Key": os.environ["SHOMA_API_KEY"]}
# 1. Fetch the RSA public key (no auth required)
pem = requests.get(f"{BASE}/auth/public-key").json()["data"]["publicKey"]
public_key = serialization.load_pem_public_key(pem.encode())
# 2. Generate a one-time AES-256 key
aes_key = AESGCM.generate_key(bit_length=256)
# 3. Encrypt the document: 12-byte IV prepended to the ciphertext
iv = os.urandom(12)
plaintext = open("report.pdf", "rb").read()
encrypted_payload = iv + AESGCM(aes_key).encrypt(iv, plaintext, None)
# 4. Wrap the AES key with RSA-OAEP (SHA-256), then base64
wrapped = public_key.encrypt(
aes_key,
padding.OAEP(padding.MGF1(hashes.SHA256()), hashes.SHA256(), None),
)
encrypted_aes_key_b64 = base64.b64encode(wrapped).decode()
# 5. Upload (1-3 files, all sharing this one AES key)
resp = requests.post(
f"{BASE}/analysis",
headers=HEADERS,
data={
"encryptedAesKey": encrypted_aes_key_b64,
"message": "Patient presents with acute chest pain radiating to left arm...",
"isStreamingResponse": "false",
},
files={"files": ("document.enc", encrypted_payload, "application/octet-stream")},
)
# 6. Handle the response
body = resp.json()
if resp.status_code != 200:
raise RuntimeError(f"{body['errorCode']}: {body['message']}")
report = body["data"]
print(report["medicalInsights"])
print("credits used:", report["creditsUsed"])
print(report["disclaimer"]) # must be shown to the end user verbatim

09 · Reference

Streaming responses (SSE)

Send isStreamingResponse=true to receive Server-Sent Events as the pipeline runs. Read the fetch body stream directly — the native EventSource only supports GET.

Event types

typeWhen it firesPayload
pipeline_startOnce, when processing begins.Run metadata.
stepOnce per phase: decryption, extraction, redaction, llm_analysis, billing, audit_log.Step name and state.
analysis_completeOnce, on success.The full report in data, identical to the JSON body.
errorOn failure, at any point. The stream then closes.status, message, errorCode.

Consuming the stream

// Set isStreamingResponse=true to receive Server-Sent Events.
// Read the fetch body directly — the browser EventSource is GET-only.
const res = await fetch("https://api.health.shoma-ai.com/api/v1/analysis", {
method: "POST", headers, body: form
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
for (const block of buffer.split("\n\n")) {
const line = block.split("\n").find(l => l.startsWith("data:"));
if (!line) continue;
const event = JSON.parse(line.slice(5).trim());
switch (event.type) {
case "pipeline_start": console.log("started"); break;
case "step": console.log("step:", event.data.step); break;
case "analysis_complete": console.log(event.data); break;
case "error": throw new Error(`${event.errorCode}: ${event.message}`);
}
}
}

Example event sequence

data: {"type":"pipeline_start","data":{"files":2}}
data: {"type":"step","data":{"step":"decryption","status":"completed"}}
data: {"type":"step","data":{"step":"extraction","status":"completed"}}
data: {"type":"step","data":{"step":"redaction","status":"completed"}}
data: {"type":"step","data":{"step":"llm_analysis","status":"completed"}}
data: {"type":"analysis_complete","data":{ /* full report — see Success responses */ }}

Streaming error event

Errors raised after the stream has opened arrive as an error event, not as an HTTP status — the response is already 200 with text/event-stream. Always branch on event.type.

data: {"type":"step","data":{"step":"decryption","status":"completed"}}
data: {
"type": "error",
"status": 400,
"message": "LLM returned an invalid JSON response schema. Please try again.",
"errorCode": "ERR400",
"data": null
}

10 · Reference

Success responses

Every response — success or failure — uses the same envelope: status, message, errorCode, data. A success always carries errorCode: "SUC000".

Success message for /analysis:
"AI administrative processing complete. Temporary report ready for professional review. Data will be permanently deleted immediately."

Complete example — POST /api/v1/analysis

{
"status": 200,
"message": "AI administrative processing complete. Temporary report ready for professional review. Data will be permanently deleted immediately.",
"errorCode": "SUC000",
"data": {
"medicalInsights": "The patient exhibits chronic stable blood pressure with mild fluctuations. The general indicators suggest high adherence to the primary therapeutic routine with no critical safety alerts flagged.",
"extractedEntities": {
"symptoms": ["Mild headache", "occasional dizziness"],
"medicalHistory": ["Essential hypertension diagnosed in 2021", "Hyperlipidemia"],
"statedConditions": ["Chronic stable hypertension"],
"medications": [
{
"name": "Lisinopril",
"dose": "10mg",
"frequency": "Once daily in the morning"
},
{
"name": "Atorvastatin",
"dose": "20mg",
"frequency": "Once daily at night"
}
],
"labValues": [
{
"parameter": "Blood Pressure",
"value": "135/85",
"unit": "mmHg",
"referenceRange": "120/80"
},
{
"parameter": "Total Cholesterol",
"value": "195",
"unit": "mg/dL",
"referenceRange": "< 200"
}
]
},
"completenessScore": 92,
"conflictFlags": ["No significant clinical conflicts identified between documentation records."],
"suggestions": [
"Maintain active low-sodium dietary regimen.",
"Monitor blood pressure twice daily (morning and evening).",
"Follow up in 4 weeks for laboratory reassessment."
],
"visitTrends": [
{
"date": "2026-08-01",
"parameter": "Systolic BP",
"value": "138"
},
{
"date": "2026-08-10",
"parameter": "Systolic BP",
"value": "135"
}
],
"highlights": [
"Target blood pressure goals are being approached.",
"Lipid levels are controlled within references."
],
"disclaimer": "IMPORTANT NOTICE — This is an AI-generated administrative output only. It does not constitute medical advice, a diagnosis or clinical decision support. You must review and validate all content before any clinical use. No patient data is stored by SHOMA AI after this report is generated.",
"analysisScore": 90.0,
"scoreComputationStatus": "success",
"creditsUsed": 1,
"inputTokens": 1420,
"outputTokens": 320,
"effortScoring": {
"rawReadingTimeMinutes": 15.0,
"assistedReviewTimeMinutes": 3.0,
"effortReductionPercentage": 80,
"basis": "Quantified duration comparison between typical manual reading/extraction of multiple documents and reviewing structural AI outputs."
},
"responseLanguage": "English"
}
}
The disclaimer field is mandatory. It must be displayed verbatim to any end user who sees the report. Do not truncate, paraphrase or hide it.

11 · Reference

Errors & status codes

Errors return the same envelope as successes, with data: null (or a validation detail array) and a machine-readable errorCode. Branch on errorCode, not on the message text — messages may be reworded.

HTTP status codes

StatusMeaningTypical causes
200OKProcessing complete, or an SSE stream opened.
400Bad RequestAUTH002 · ANA001 · ERR400 · ERR500
401UnauthorizedAKEY003 · AKEY004 · AUTH003
403ForbiddenAUTH008 · ERR403 · ANA003
422Unprocessable EntityAUTH002 — form-field validation failure.
500Internal Server ErrorERR500 · ANA002
502Bad GatewayUpstream AI provider failure.
503Service UnavailableProvider temporarily unreachable — retry with backoff.

Error code index

CodeHTTPMeaningWhat to do
SUC000200Success
AUTH002400 · 422Invalid file count, file over 10 MB, or form validation failureFix the request. Do not retry unchanged.
AUTH003401Session logged out or revokedRe-authenticate the user.
AUTH008403Account not permitted: email unverified, org pending approval, or subscription expiredSurface the message to the account owner.
AKEY003401Missing or invalid API keyCheck the X-API-Key header.
AKEY004401API key deactivatedRe-enable or rotate the key.
ANA001400Patient name does not match the registered userIndividual accounts only. Verify the document.
ANA002500 · 502 · 503AI service provider errorRetry with exponential backoff.
ANA003403Free trial rate limit exceededWait for the window stated in the message, or upgrade.
ERR400400Model returned an invalid JSON schemaRetry once; no credits are deducted on a schema failure.
ERR403403Credit limit reachedPurchase add-on credits or upgrade the plan.
ERR500400 · 500Server misconfiguration or unhandled internal errorRetry; if persistent, contact support.

Error catalogue — GET /api/v1/auth/public-key

400ERR500Public key not configured+

The server is missing the RSA public key configuration settings.

Public key is not configured on the server.

{
"status": 400,
"message": "Public key is not configured on the server.",
"errorCode": "ERR500",
"data": null
}

Error catalogue — POST /api/v1/analysis

400AUTH002Invalid file count+

Fewer than 1 or more than 3 files were uploaded.

You must upload between 1 and 3 files.

{
"status": 400,
"message": "You must upload between 1 and 3 files.",
"errorCode": "AUTH002",
"data": null
}
400AUTH002File too large+

One of the uploaded files exceeds the 10 MB per-file limit. The check runs per file, so a request of three files fails if any single one is over the limit.

File size exceeds the limit of 10 MB.

{
"status": 400,
"message": "File size exceeds the limit of 10 MB.",
"errorCode": "AUTH002",
"data": null
}

Raised as BadRequestException(ErrorMessage.FILE_TOO_LARGE) with no explicit code, so it falls back to that exception's default of AUTH002.

400ANA001Patient name mismatch+

The patient's name does not match the registered user name. Enforced strictly on individual account types.

Patient name in the document does not match the registered user's name.

{
"status": 400,
"message": "Patient name in the document does not match the registered user's name.",
"errorCode": "ANA001",
"data": null
}
400ERR400Invalid LLM response format+

The AI engine failed to return a valid structured JSON output matching the required schema.

LLM returned an invalid JSON response schema. Please try again.

{
"status": 400,
"message": "LLM returned an invalid JSON response schema. Please try again.",
"errorCode": "ERR400",
"data": null
}
401AKEY003 / AUTH003Missing or invalid API key / auth token+

The API key header (X-API-Key) or OAuth2 session token is missing or invalid. The code returned depends on the authorization scheme used.

Invalid or missing API key. Provide a valid key in the X-API-Key header.

Missing authentication token.

{
"status": 401,
"message": "Invalid or missing API key. Provide a valid key in the X-API-Key header.",
"errorCode": "AKEY003",
"data": null
}
401AKEY004API key deactivated+

The API key passed in X-API-Key has been deactivated or deleted by the user.

This API key has been deactivated. Please generate or rotate your key.

{
"status": 401,
"message": "This API key has been deactivated. Please generate or rotate your key.",
"errorCode": "AKEY004",
"data": null
}
401AUTH003Session revoked+

The browser cookie or bearer token session was logged out or revoked.

Session has been logged out or revoked.

{
"status": 401,
"message": "Session has been logged out or revoked.",
"errorCode": "AUTH003",
"data": null
}
403AUTH008Email not verified+

The user's account has not completed the email verification step.

Email is not verified. Access denied.

{
"status": 403,
"message": "Email is not verified. Access denied.",
"errorCode": "AUTH008",
"data": null
}
403AUTH008Organization access pending approval+

The organization profile or legal agreements are pending administrator approval.

Access pending. Organization profile and agreements must be approved by admin.

{
"status": 403,
"message": "Access pending. Organization profile and agreements must be approved by admin.",
"errorCode": "AUTH008",
"data": null
}
403AUTH008Subscription expired / no active plan+

The subscription has expired or the user does not have an active plan.

Subscription or Free Trial has expired. Please upgrade to a paid plan to restore access.

No active plan. Please subscribe to a plan to access the API.

{
"status": 403,
"message": "Subscription or Free Trial has expired. Please upgrade to a paid plan to restore access.",
"errorCode": "AUTH008",
"data": null
}
403ERR403Credit limit reached+

The remaining balance in the user's active credit ledger buckets is zero.

Processing limit reached. No data has been retained. Please contact your administrator or purchase additional credits.

{
"status": 403,
"message": "Processing limit reached. No data has been retained. Please contact your administrator or purchase additional credits.",
"errorCode": "ERR403",
"data": null
}
403ANA003Free trial rate limit exceeded+

Free trial accounts are limited to a maximum of 1 successful analysis per 24 hours. The message interpolates the remaining wait.

Free trial limits to 1 successful analysis per 24 hours. You can perform your next analysis in {hours}h {minutes}m.

{
"status": 403,
"message": "Free trial limits to 1 successful analysis per 24 hours. You can perform your next analysis in 23h 45m.",
"errorCode": "ANA003",
"data": null
}
422AUTH002Request validation failure+

Form data fields do not match the expected structural requirements — for example encryptedAesKey is missing. Unlike other errors, data carries an array of per-field details.

Validation failed: body.encryptedAesKey: field required

{
"status": 422,
"message": "Validation failed: body.encryptedAesKey: field required",
"errorCode": "AUTH002",
"data": [
{
"type": "missing",
"loc": ["body", "encryptedAesKey"],
"msg": "Field required",
"input": null
}
]
}
500 · 502 · 503ERR500 / ANA002LLM provider or server error+

General fallback when the LLM service fails or an unhandled traceback is logged. Safe to retry with exponential backoff.

An internal server error occurred.

An error occurred with the AI service provider while processing your request. Please try again later.

{
"status": 500,
"message": "An internal server error occurred.",
"errorCode": "ERR500",
"data": null
}

12 · Operations

Rate limits & credits

Access is governed by two independent mechanisms: a rate limit on how often you may call, and a credit balance for how much you may process.

Rate limits

Account typeLimitOn exceed
Free trial1 successful analysis per 24 hours, and 3 credits in total403 · ANA003 with the remaining wait in the message.
Paid plansNo rate limitAccess is governed solely by a positive, active credit balance. There is no per-second, per-minute or per-day request cap.
Only successful analyses count toward the free-trial window. A request that fails validation or authentication does not start the 24-hour clock.

How credits are consumed

One analysis costs exactly 1 credit. The cost is a flat rate per request. It does not scale with the number of files you upload or with token usage — sending three documents costs the same single credit as sending one.
  • Every successful call to a SHOMA AI processing endpoint deducts 1 credit. The amount is echoed back in data.creditsUsed.
  • inputTokens and outputTokens are recorded for metadata and auditing only. They do not affect what you are charged.
  • The free trial grants 3 credits in total, spendable at no more than one analysis per 24 hours.
  • Plan credits reset to the plan limit at the start of each billing cycle and do not roll over.
  • Add-on credit packs never expire and are consumed only after the monthly plan credits are fully exhausted.
  • A request that fails before the model runs — validation, authentication, decryption — does not deduct credits.

When credits run out

The API returns 403 · ERR403 with the message "Processing limit reached. No data has been retained. Please contact your administrator or purchase additional credits." No document is processed and nothing is retained. Access is restored immediately once an add-on credit pack is purchased or the plan is upgraded.

API key quotas by plan

1key — Basic
10keys — Pro
keys — Enterprise

13 · Operations

Changelog & release notes

What changed in each API version — expand a version to see additions, changes and deprecations, and plan your migration.

Ready to integrate?

Create an API key and make your first call.

Get Your API Key
Transparency

AI Transparency & Professional Use Only

This solution uses artificial intelligence solely to assist hospital and clinic staff with administrative document processing.

  • Outputs are temporary reports generated exclusively for review by qualified doctors and authorised clinical staff.
  • All data is cancelled and permanently deleted immediately after the report is produced.
  • No patient data is stored, retained, logged or accessible to patients or any third parties.
  • Patients have no access to the system or any information it processes.
  • The AI does not provide medical advice, diagnoses, treatment recommendations or clinical decision support.
  • All final clinical decisions remain the sole responsibility of the licensed doctor or qualified healthcare professional.

The system is intended only to reduce administrative and documentation burden.