Spaces:
Running
content = '''# 📡 AILIXIR API Reference
Version: 2.1 | Last Updated: May 29, 2026 | Status: Production Ready
Complete API specification for AILIXIR-Backend, including all endpoints, authentication, request/response schemas, error handling, and integration examples.
📋 Table of Contents
- Overview
- Authentication
- Base URLs
- Common Patterns
- Health & Status
- Authentication Endpoints
- AI Integration Endpoints
- AI Service Endpoints
- AI Agent Endpoints (Chemistry AI)
- Chemical Search Endpoints
- Docking API
- Drug Repurposing API
- Convert SMILES API
- User Management Endpoints
- Awards And Scientists API
- News API
- Admet Prediction API
- AI Generation API
- MD Simulation API
- Error Handling
- Rate Limiting
- Integration Examples
- Support
Overview
AILIXIR provides a RESTful API for accessing all drug discovery services. The API is built with:
- Framework: Laravel 11 with Sanctum authentication
- Response Format: JSON
- Authentication: JWT Bearer tokens
- Rate Limiting: In place (contact admin for limits)
- Versioning: URL-based (
/api/v1/...)
Key Features:
- Asynchronous job processing (long-running AI tasks)
- Real-time health monitoring
- User authentication and authorization
- Result caching and versioning
- File upload/download support
- AI-powered chemistry analysis agent with conversation memory
Authentication
Overview
AILIXIR uses Laravel Sanctum for API authentication. Most endpoints require a valid JWT bearer token.
Types of Tokens
| Token Type | Purpose | Duration |
|---|---|---|
| Access Token | Query user data, submit jobs | Session-based |
| API Token | Long-lived access (optional) | 365 days |
| Refresh Token | Renew access after expiry | 14 days |
Authentication Header
All authenticated requests must include:
Authorization: Bearer YOUR_ACCESS_TOKEN
Token Generation
Tokens are issued after successful login or registration. Store securely (never in localStorage for sensitive apps).
Base URLs
Production
https://ailixir.pharmaai.io/api
Development (Local)
http://localhost:8080/api
Service-Specific Discovery
Each microservice exposes its own API discovery endpoint:
http://localhost:8002/docs # ADMET Service (FastAPI)
http://localhost:8001/docs # Drug Repurposing (FastAPI)
http://localhost:5000/docs # Chemical RAG (FastAPI)
http://localhost:8080/docs # Laravel API (Swagger)
Common Patterns
Pagination
List endpoints support pagination:
?page=1&per_page=20
Response Field: meta.pagination
{
"data": [...],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 100,
"last_page": 5
}
}
}
Filtering
Endpoints support filtering (details per endpoint):
?filter[status]=completed&filter[created_after]=2026-05-01
Sorting
?sort=created_at&sort_order=desc
Asynchronous Jobs
Long-running operations return 202 Accepted with job tracking URL:
{
"success": true,
"job_id": "abc-123-def",
"status": "pending",
"check_url": "/api/ai/status/abc-123-def"
}
Check Status:
GET /api/ai/status/{job_id}
Health & Status
System Health
Check overall system status:
GET /health
Response (200 OK):
{
"status": "healthy",
"timestamp": "2026-05-29T12:30:45Z",
"version": "2.0.0",
"uptime_seconds": 876543
}
All Services Health
Check all AI microservices:
GET /ai-services/health
Response (200 OK):
{
"success": true,
"services": {
"admet": {
"status": "healthy",
"http_status": 200,
"body": {
"status": "ready",
"model_version": "MPNN_CNN_BindingDB"
}
},
"drug_repurposing": {
"status": "healthy",
"http_status": 200,
"body": {
"status": "ready",
"model": "DeepPurpose v0.1.5"
}
},
"chemical_rag": {
"status": "healthy",
"http_status": 200,
"body": {
"status": "ready",
"index_size": 1000000
}
}
}
}
Response (503 Service Unavailable): One or more services is down
Authentication Endpoints
Register User
POST /user/register
Content-Type: application/json
{
"name": "Yasmeen Ahmed",
"email": "yasmeen@test.com",
"password": "password123",
"password_confirmation": "password123"
}
Response (201 Created):
{
"success": true,
"message": "Registered successfully. Please check your email for OTP verification code.",
"data": {
"email": "yasmeen@test.com"
}
}
Login
POST /user/login
Content-Type: application/json
{
"email": "yasmeen@test.com",
"password": "password123"
}
Response (200 OK):
{
"success": true,
"message": "Login successful",
"data": {
"token": "55|F4V06Yis3FcP35oGoEE2cwmNv3yTiVCpMEx9vYjya891dcb2",
"user": {
"id": 80,
"name": "yasmeen564",
"email": "salehyasmeen080@gmail.com",
"email_verified_at": null,
"last_otp_sent_at": null,
"role": "normal",
"created_at": "2026-05-25T00:21:51.000000Z",
"updated_at": "2026-05-30T00:02:06.000000Z",
"email_verification_otp_expires_at": null,
"is_verified": true,
"password_reset_otp_expires_at": null
}
}
}
Verify Email
After account creation, verify email to activate account:
POST /user/verify-email
Content-Type: application/json
{
"email": "yasmeen@test.com",
"otp": "123456"
}
Response (200 OK):
{
"success": true,
"message": "Email verified successfully",
"data": {
"token": "54|dxcTq6KRZQfOESfbKcqEoXV4znbkU8IKCND1nX2H085c2309",
"user": {
"id": 80,
"name": "yasmeen564",
"email": "salehyasmeen080@gmail.com",
"email_verified_at": null,
"last_otp_sent_at": null,
"role": "normal",
"created_at": "2026-05-25T00:21:51.000000Z",
"updated_at": "2026-05-30T00:02:06.000000Z",
"email_verification_otp_expires_at": null,
"is_verified": true,
"password_reset_otp_expires_at": null
}
}
}
Resend Verification Email
POST /user/resend-verification
Content-Type: application/json
{
"email": "yasmeen@test.com"
}
Response (200 OK):
{
"success": true,
"message": "OTP resent successfully",
"data": {
"email": "yasmeen111@example.com"
}
}
Forgot Password
POST /user/forgot-password
Content-Type: application/json
{
"email": "yasmeen@test.com"
}
Response (200 OK):
{
"success": true,
"message": "OTP sent successfully",
"data": {
"email": "salehyasmeen080@gmail.com"
}
}
Reset Password
POST /user/reset-password
Content-Type: application/json
{
"email": "yasmeen@test.com",
"otp": "123456",
"password": "new_password123",
"password_confirmation": "new_password123"
}
Response (200 OK):
{
"success": true,
"message": "Password reset successfully"
}
Logout
POST /user/logout
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Logged out successfully"
}
'''
AI Integration Endpoints
These endpoints are for testing and monitoring AI microservices. Available only if AI_INTEGRATION_ROUTES_ENABLED=true.
Test ADMET Prediction
Quick test of ADMET service:
POST /ai-services/test/admet
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"batch_size": 32
}
Response (200 OK):
{
"success": true,
"service": "admet",
"upstream_status": 200,
"data": {
"status": "success",
"predictions": {
"absorption": 0.78,
"distribution": 0.65,
"metabolism": 0.45,
"excretion": 0.82,
"toxicity": 0.12
},
"processing_time_ms": 234
}
}
Test Chemical Search
Quick test of Chemical RAG service:
POST /ai-services/test/chemical-search
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"top_k": 5
}
Response (200 OK):
{
"success": true,
"service": "chemical_rag",
"upstream_status": 200,
"data": {
"query": {
"smiles": "CC(=O)Oc1ccccc1C(=O)O"
},
"results": [
{
"rank": 1,
"cid": 2244,
"name": "Aspirin",
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"similarity": 1.0,
"image_url": "https://..."
}
],
"processing_time_ms": 145
}
}
Test Drug Repurposing
Quick test of Drug Repurposing service:
GET /ai-services/test/drug-repurposing
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"service": "drug_repurposing",
"health": {
"status": 200,
"body": {
"status": "healthy",
"model": "DeepPurpose",
"version": "0.1.5"
}
},
"model_status": {
"status": 200,
"body": {
"available_models": ["MPNN_CNN_BindingDB"]
}
}
}
AI Service Endpoints
Submit AI Job
Submit a drug discovery analysis job:
POST /ai/run
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"job_type": "admet_prediction",
"parameters": {
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"batch_size": 32
},
"notification_email": "john@pharmaai.io"
}
Response (202 Accepted):
{
"success": true,
"job_id": "job-abc-123-def",
"status": "pending",
"created_at": "2026-05-29T12:30:45Z",
"check_url": "/api/ai/status/job-abc-123-def"
}
Get Job Status
GET /ai/status/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK - Pending):
{
"success": true,
"job_id": "job-abc-123-def",
"status": "processing",
"progress": 45,
"estimated_completion": "2026-05-29T12:35:00Z"
}
Response (200 OK - Completed):
{
"success": true,
"job_id": "job-abc-123-def",
"status": "completed",
"results": {
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"predictions": {
"absorption": 0.78,
"distribution": 0.65,
"metabolism": 0.45,
"excretion": 0.82,
"toxicity": 0.12
}
},
"completed_at": "2026-05-29T12:32:15Z"
}
Response (200 OK - Failed):
{
"success": false,
"job_id": "job-abc-123-def",
"status": "failed",
"error": "Invalid SMILES string",
"failed_at": "2026-05-29T12:30:50Z"
}
Preview Results
Get a preview of results while job is processing:
GET /ai/preview/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"job_id": "job-abc-123-def",
"status": "processing",
"preview": {
"processed_compounds": 50,
"total_compounds": 100,
"average_prediction_time_ms": 234
}
}
Download Results (Top)
Download first N results (useful for large datasets):
GET /ai/download/top/{job_id}?limit=100
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
Content-Type: text/csv
Content-Disposition: attachment; filename="results-top-100.csv"
smiles,absorption,distribution,metabolism,excretion,toxicity
CC(=O)Oc1ccccc1C(=O)O,0.78,0.65,0.45,0.82,0.12
...
Download Full Results
Download complete results as CSV:
GET /ai/download/full/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
Content-Type: application/zip
Content-Disposition: attachment; filename="results-full.zip"
# Contains: predictions.csv, metadata.json, summary.txt
Job History
Get all jobs submitted by user:
GET /ai/history?page=1&per_page=20&filter[status]=completed&sort=created_at&sort_order=desc
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"data": [
{
"id": "job-abc-123-def",
"job_type": "admet_prediction",
"status": "completed",
"created_at": "2026-05-29T12:00:00Z",
"completed_at": "2026-05-29T12:30:00Z",
"result_summary": {
"total_compounds": 100,
"average_absorption": 0.72
}
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 42,
"last_page": 3
}
}
}
AI Agent Endpoints (Chemistry AI)
AI-powered chemistry analysis agent with conversation memory. All endpoints require authentication.
Base Path: /api/chemistry
Capabilities:
- SMILES validation and property calculation
- Drug-likeness classification (Lipinski Ro5, Veber, Lead-likeness)
- ADMET profiling with structural toxicity alerts
- Molecular docking result ranking and recommendation
- Multi-molecule side-by-side comparison
- Async CSV batch processing
- Conversation context via thread_id
Create Conversation Thread
Start a new isolated chemistry conversation thread.
POST /api/chemistry/thread
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"data": {
"thread_id": "3a148307-b97f-4910-88db-03eca6477419",
"id": 2,
"created_at": "2026-05-25T18:34:15.000000Z"
}
}
Notes:
- One thread_id per user session
- Do not share thread IDs across different users
- Pass the same thread_id across multiple calls to maintain conversation history
List User Threads
Get all active threads for the authenticated user.
GET /api/chemistry/threads
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"data": [
{
"id": 2,
"thread_id": "3a148307-b97f-4910-88db-03eca6477419",
"title": "New Conversation",
"last_used_at": "2026-05-25T18:34:15.000000Z",
"created_at": "2026-05-25T18:34:15.000000Z"
},
{
"id": 1,
"thread_id": "0455ef45-faa0-4e82-b808-db1c574ad175",
"title": "New Conversation",
"last_used_at": "2026-05-25T18:21:23.000000Z",
"created_at": "2026-05-24T14:54:10.000000Z"
}
]
}
Send Chat Message
Send a natural language chemistry question to the AI agent.
POST /api/chemistry/chat
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"message": "Is CC(=O)Oc1ccccc1C(=O)O a good drug candidate?",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede"
}
Response (200 OK):
{
"success": true,
"data": {
"reply": "Based on the analysis of CC(=O)Oc1ccccc1C(=O)O (Aspirin)...",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede",
"processing_time_ms": 11888
}
}
Example Messages:
"Is CC(=O)Oc1ccccc1C(=O)O a good drug candidate?""Compare aspirin and ibuprofen CC(C)Cc1ccc(cc1)C(C)C(=O)O""What are the toxicity concerns for this molecule?"(follow-up)"Which molecule we discussed has the best CNS penetration?"(follow-up)
Notes:
thread_idis optional. Omit to start a fresh conversation automatically.- The agent remembers all prior messages on the same thread.
- The agent automatically handles: SMILES validation, molecular property calculation, drug-likeness rules, ADMET profiling, docking ranking, and multi-molecule comparison.
Analyze Single SMILES
Full molecular analysis pipeline in one call.
POST /api/chemistry/analyze/smiles
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede"
}
Response (200 OK):
{
"success": true,
"data": {
"reply": "Complete analysis text...",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede",
"processing_time_ms": 5234
}
}
Pipeline Steps:
- Validate SMILES
- Compute molecular properties (MW, LogP, HBD, HBA, TPSA, QED, Fsp3)
- Drug-likeness classification (Lipinski Ro5, Veber, Lead-likeness)
- ADMET profile with structural toxicity alerts
Notes:
smilesfield is required in JSON body- URL-encode special characters if sending via query string:
CC%28%3DO%29Oc1ccccc1C%28%3DO%29O
Compare Multiple Molecules
Side-by-side comparison of 2 or more molecules with recommendation.
POST /api/chemistry/analyze/compare
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"smiles": [
"CC(=O)Oc1ccccc1C(=O)O",
"CC(C)Cc1ccc(cc1)C(C)C(=O)O",
"Cn1cnc2c1c(=O)n(c(=O)n2C)C"
],
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede"
}
Response (200 OK):
{
"success": true,
"data": {
"reply": "Side-by-side property table and recommendation...",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede",
"processing_time_ms": 23543
}
}
Agent Returns:
- Side-by-side property table (MW, LogP, HBD, HBA, TPSA, QED, Fsp3)
- Drug-likeness pass/fail for each molecule
- Named recommendation with justification
Analyze Docking Results
Rank and recommend best docking candidates.
POST /api/chemistry/analyze/docking
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"docking_data": "CC(=O)Oc1ccccc1C(=O)O | -7.2 | 1.1 | H-bond to Ser195\\nCC(C)Cc1ccc(cc1)C(C)C(=O)O | -8.9 | 0.8 | deep pocket binding\\nCn1cnc2c1c(=O)n(c(=O)n2C)C | -6.1 | 1.9 |",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede"
}
Docking Data Format:
SMILES | binding_affinity_kcal_mol | rmsd_angstrom | optional_notes
Response (200 OK):
{
"success": true,
"data": {
"reply": "Top Pick: CC(C)Cc1ccc(cc1)C(C)C(=O)O...",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede",
"processing_time_ms": 5392
}
}
Interpretation Rules:
- ΔG more negative = stronger binding
- RMSD < 2 Å = reliable pose; > 2 Å = uncertain binding mode
- Best candidate = strongest binder that also passes Lipinski Ro5
Upload CSV for Batch Analysis
Process multiple molecules asynchronously.
POST /api/chemistry/csv/upload
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: multipart/form-data
file: [Choose File] molecules.csv
analysis_type: full
Analysis Types:
| Type | What It Runs | Speed |
|---|---|---|
full |
Properties + drug-likeness + ADMET | Slow |
quick |
Lipinski pass/fail + QED only | Fast |
admet |
ADMET profile only | Medium |
classify |
Drug-likeness classification only | Fast |
Required CSV Columns:
smiles— SMILES string (required)name— compound name or ID (optional, auto-generated if missing)
Example CSV:
name,smiles
Aspirin,CC(=O)Oc1ccccc1C(=O)O
Ibuprofen,CC(C)Cc1ccc(cc1)C(C)C(=O)O
Caffeine,Cn1cnc2c1c(=O)n(c(=O)n2C)C
Response (200 OK):
{
"success": true,
"data": {
"job_id": "0ec86cee-6ce8-4e91-95f4-ad807f7ee283",
"id": 1,
"status": "queued",
"total_rows": 4
}
}
Limits: Maximum 100 rows per upload. Split larger datasets into batches.
Check CSV Job Status
Poll for processing progress.
GET /api/chemistry/csv/status/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK - Running):
{
"success": true,
"data": {
"job_id": "0ec86cee-6ce8-4e91-95f4-ad807f7ee283",
"status": "running",
"total": 4,
"completed": 3,
"failed_rows": 2,
"progress_percent": 75
}
}
Status Values:
| Value | Meaning |
|---|---|
queued |
Job is waiting to start |
running |
Actively processing rows |
done |
All rows finished — results are ready |
failed |
Job-level error (row errors are inside results) |
Polling: Poll every 5–10 seconds. Once status == "done", call GET /csv/results/{job_id}.
Download CSV Results
Get completed analysis as CSV file download.
GET /api/chemistry/csv/results/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
Content-Type: text/csv
Content-Disposition: attachment; filename="results_{job_id}.csv"
row,name,smiles,status,error,analysis
1,Aspirin,CC(=O)Oc1ccccc1C(=O)O,success,,"Full analysis text..."
2,Ibuprofen,CC(C)Cc1ccc(cc1)C(C)C(=O)O,failed,"Quota exceeded",...
Output CSV Columns:
row— original row number in the uploaded filename— compound namesmiles— input SMILES stringstatus— success or failedanalysis— full agent analysis texterror— error message (empty if status is success)
List User CSV Jobs
GET /api/chemistry/csv/jobs
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"data": [
{
"id": 1,
"job_id": "0ec86cee-6ce8-4e91-95f4-ad807f7ee283",
"filename": "molecules.csv",
"analysis_type": "full",
"status": "done",
"total_rows": 4,
"completed_rows": 4,
"failed_rows": 3,
"progress_percent": 100,
"created_at": "2026-05-29T12:00:00Z"
}
]
}
Delete CSV Job
Remove completed job and free storage.
DELETE /api/chemistry/csv/jobs/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Job deleted successfully"
}
Notes:
- Call this after successfully downloading results to keep memory usage low
- Trying to delete a non-existent job returns 404
Get User Analysis History
Retrieve all past analyses with pagination.
GET /api/chemistry/history?type=smiles
Authorization: Bearer YOUR_ACCESS_TOKEN
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
type |
string | Filter: smiles, compare, docking, chat |
page |
integer | Page number |
Response (200 OK):
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"id": 1,
"type": "smiles",
"input_data": "CC(=O)Oc1ccccc1C(=O)O",
"response": "Analysis text...",
"status": "success",
"created_at": "2026-05-29T12:00:00Z",
"thread": {
"id": 1,
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede",
"title": "New Conversation"
}
}
],
"per_page": 20,
"total": 42
}
}
Chemical Search Endpoints
Retrieval-Only Search
Query the chemical database for similar compounds (no explanations):
POST /chemical-search
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"top_k": 10
}
Response (202 Accepted):
{
"success": true,
"query": {
"smiles": "CN1C=NC2=C1C(=O)N(C(=O)N2C)",
"top_k": 3
},
"compounds": [
{
"rank": 1,
"smiles": "CN1C=NC2=C1C(=O)NC(=O)N2C",
"name": "Compound_5429",
"cid": "5429",
"similarity": 1,
"explanation": null,
"image_url": "https://unsteady-chlorine-imaginary.ngrok-free.dev/static/images/6096554304416497818.png"
},
{
"rank": 2,
"smiles": "CN1C=NC2=C1C(=O)N(C(=O)N2C)C",
"name": "Compound_2519",
"cid": "2519",
"similarity": 0.9922,
"explanation": null,
"image_url": "https://unsteady-chlorine-imaginary.ngrok-free.dev/static/images/3925926930136341582.png"
},
{
"rank": 3,
"smiles": "CN1C=NC2=C1C(=O)N(C(=O)N2)C",
"name": "Compound_4687",
"cid": "4687",
"similarity": 0.9922,
"explanation": null,
"image_url": "https://unsteady-chlorine-imaginary.ngrok-free.dev/static/images/5189886293630140187.png"
}
],
"metadata": {
"total_results": 3,
"search_time_ms": 443.08,
"similarity_metric": "Tanimoto",
"fingerprint": "Morgan (2048, radius=2)",
"source": "retrieval"
}
}
Full RAG Search
Query with LLM-generated explanations:
POST /chemical-search/full-rag
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"top_k": 5
}
Response (202 Accepted):
{
"success": true,
"query": {
"smiles": "C1=CC=C(C(=C1)C(=O)O)",
"top_k": 2
},
"compounds": [
{
"rank": 1,
"smiles": "C1=CC=C(C=C1)C(=O)O",
"name": "Compound_243",
"cid": "243",
"similarity": 1,
"explanation": "These compounds are structurally identical, as indicated by the similarity score of 1.000. Both share the same core scaffold of a benzene ring (C1=CC=C(C=C1)) with a carboxylic acid group (C(=O)O) attached to it. The molecular formulas (C7H6O2) and heavy atom counts (9) are identical, confirming no atom substitutions or differences in structure. The only apparent difference is the SMILES representation, which is",
"image_url": "https://unsteady-chlorine-imaginary.ngrok-free.dev/static/images/2500971538592982398.png"
},
{
"rank": 2,
"smiles": "C1=CC=C(C=C1)[13C](=O)O",
"name": "Compound_19759",
"cid": "19759",
"similarity": 1,
"explanation": "These compounds are structurally identical, as indicated by the similarity score of 1.000. Both share the same core scaffold of a benzene ring (C1=CC=C(C=C1)) with a carboxylic acid group (C(=O)O) attached. The only difference is that the match compound has a ^13C isotope substitution at the carboxylic acid carbon, which does not alter the molecular structure or connectivity. Both compounds have the same molecular formula (C7H6O",
"image_url": "https://unsteady-chlorine-imaginary.ngrok-free.dev/static/images/8561718417946188610.png"
}
],
"metadata": {
"total_results": 2,
"search_time_ms": 7975.89,
"similarity_metric": "Tanimoto",
"fingerprint": "Morgan (2048, radius=2)",
"source": "full_rag"
}
}
Docking API
POST /api/docking/submit
- Auth required
- Content type:
multipart/form-data - Required fields:
protein_name(string)protein_file(file)center_x(numeric)center_y(numeric)center_z(numeric)box_size_x(numeric)box_size_y(numeric)box_size_z(numeric)
VERY IMPORTANT
Optional fields:
ligand_name(string)exhaustiveness(integer)n_poses(integer)
Must include exactly one of:
ligand_file(file)ligand_smiles(string)
Example curl request
curl -X POST "{base_url}/api/docking/submit" \\
-H "Authorization: Bearer {token}" \\
-F "protein_name=EGFR" \\
-F "protein_file=@protein.pdbqt" \\
-F "ligand_name=Erlotinib" \\
-F "ligand_smiles=CC1=CC(=O)NC2=C1C=CC=C2" \\
-F "center_x=10.0" \\
-F "center_y=15.0" \\
-F "center_z=20.0" \\
-F "box_size_x=25.0" \\
-F "box_size_y=25.0" \\
-F "box_size_z=25.0" \\
-F "exhaustiveness=8" \\
-F "n_poses=5"
Success response
{
"success": true,
"message": "Docking Job Successfully Queued",
"data": {
"job_id": 123,
"status": "pending"
}
}
GET /api/docking/{id}
- Auth required
- Path parameter:
id(integer)
Response (completed)
{
"success": true,
"message": "Job details retrieved successfully",
"data": {
"id": 5,
"status": "completed",
"protein": "EGFR",
"ligand": "Erlotinib",
"created_at": "2026-06-17T05:45:31+00:00",
"download_url": "{base_url}/api/docking/download/5",
"scores": [
{
"affinity": 0,
"inter": 0,
"intra": -2.031,
"torsions": 0,
"unbound": -2.031
},
{
"affinity": 0,
"inter": 0,
"intra": -2.031,
"torsions": 0,
"unbound": -2.031
},
{
"affinity": 0.001,
"inter": 0,
"intra": -2.031,
"torsions": 0,
"unbound": -2.031
}
],
"error": null
}
}
If the job is not completed, scores will be an empty array.
Response (failed)
{
"success": true,
"message": "Job details retrieved successfully",
"data": {
"id": 7,
"status": "failed",
"protein": "EGFR",
"ligand": "Erlotinib",
"created_at": "2026-06-17T05:45:31+00:00",
"download_url": "{base_url}/api/docking/download/7",
"scores": [],
"error": "\n\nPDBQT parsing error: Unknown or inappropriate tag found in flex residue or ligand.\n > ATOM 1 N UNL 1 8.304 191.693 26.328 0.00 0.00 +0.000 N \n"
}
}
Error response (not found)
{
"success": false,
"message": "Docking job not found or unauthorized",
"data": null
}
GET /api/docking/history
- Auth required
- Query parameters:
per_page(integer, optional, default 15)
Response
{
"success": true,
"message": "Docking history retrieved successfully",
"data": {
"results": [
{
"id": 5,
"status": "completed",
"protein": "EGFR",
"ligand": "Erlotinib",
"created_at": "2026-06-17T05:45:31+00:00",
"download_url": "{base_url}/api/docking/download/5",
"scores": [
{
"affinity": 0,
"inter": 0,
"intra": -2.031,
"torsions": 0,
"unbound": -2.031
},
{
"affinity": 0,
"inter": 0,
"intra": -2.031,
"torsions": 0,
"unbound": -2.031
},
{
"affinity": 0.001,
"inter": 0,
"intra": -2.031,
"torsions": 0,
"unbound": -2.031
}
],
"error": null
}
],
"pagination": {
"currentPage": 1,
"totalPages": 2,
"totalResults": 3,
"perPage": 2,
"hasNextPage": true,
"hasPrevPage": false
}
}
}
GET /api/docking/download/{id}
- Path parameter:
id(integer)
- Query parameter (instead of Bearer header for browser link clicks):
token(string, required) — Sanctum token
- Accepts
Authorization: Bearerheader or?token=query parameter. - Returns a file download for the completed docking result (multi-model PDBQT with all poses).
- Content disposition filename:
docking_result_{id}.pdbqt
Drug Repurposing API
POST /api/drug-repurposing/targets
- Auth required
- Content type:
application/json - Request body:
disease_name(string, required)top_n(integer, optional, default 10, range 1–100)
Example curl request
curl -X POST "{base_url}/api/drug-repurposing/targets" \\
-H "Authorization: Bearer {token}" \\
-H "Content-Type: application/json" \\
-d '{"disease_name": "Type 2 Diabetes", "top_n": 10}'
Success response
{
"success": true,
"message": "Target lookup queued successfully",
"data": {
"job_id": 15,
"status": "pending"
}
}
GET /api/drug-repurposing/targets/{id}
- Auth required
- Path parameter:
id(integer)
Success response (completed)
{
"success": true,
"message": "Target lookup history retrieved successfully",
"data": {
"id": 4,
"input": {
"disease_name": "Type 2 Diabetes",
"top_n": 10
},
"output": {
"disease": "Type 2 Diabetes",
"disease_id": "EFO_0001360",
"total_targets": 10,
"targets": [
{
"symbol": "KCNJ11",
"name": "potassium inwardly rectifying channel subfamily J member 11",
"score": 0.8651,
"sequence": null,
"uniprot_id": "Q14654",
"pdb_ids": ["2UKM", "2UGY", "2UUG"]
},
{
"symbol": "ABCC8",
"name": "ATP binding cassette subfamily C member 8",
"score": 0.8648,
"sequence": null,
"uniprot_id": "Q09428",
"pdb_ids": []
},
{
"symbol": "GCK",
"name": "glucokinase",
"score": 0.8612,
"sequence": null,
"uniprot_id": "P35557",
"pdb_ids": ["1V4S", "3F9M", "4ISE"]
},
{
"symbol": "PPARG",
"name": "peroxisome proliferator activated receptor gamma",
"score": 0.8486,
"sequence": null,
"uniprot_id": "P37231",
"pdb_ids": ["7AEX", "7AEW", "7AEV"]
},
{
"symbol": "INSR",
"name": "insulin receptor",
"score": 0.7887,
"sequence": null,
"uniprot_id": "P06213",
"pdb_ids": ["2HR7", "3EKN", "4IBM"]
},
{
"symbol": "HNF1B",
"name": "HNF1 homeobox B",
"score": 0.7846,
"sequence": null,
"uniprot_id": "P35680",
"pdb_ids": []
},
{
"symbol": "HNF1A",
"name": "HNF1 homeobox A",
"score": 0.7796,
"sequence": null,
"uniprot_id": "P20823",
"pdb_ids": []
},
{
"symbol": "HNF4A",
"name": "hepatocyte nuclear factor 4 alpha",
"score": 0.7763,
"sequence": null,
"uniprot_id": "P41235",
"pdb_ids": ["7D1C", "7D1D"]
},
{
"symbol": "WFS1",
"name": "wolframin ER transmembrane glycoprotein",
"score": 0.7695,
"sequence": null,
"uniprot_id": "O76024",
"pdb_ids": []
},
{
"symbol": "GLP1R",
"name": "glucagon like peptide 1 receptor",
"score": 0.7667,
"sequence": null,
"uniprot_id": "P43220",
"pdb_ids": []
}
]
},
"status": "completed"
}
}
If the job is not completed, the output field will be null.
GET /api/drug-repurposing/targets/history
- Auth required
- Query parameters:
per_page(integer, optional, default 15)
Response
{
"success": true,
"message": "Target lookup history retrieved successfully",
"data": {
"data": [
{
"id": 4,
"input": {
"disease_name": "Type 2 Diabetes",
"top_n": 10
},
"output": {
"disease": "Type 2 Diabetes",
"disease_id": "EFO_0001360",
"total_targets": 10,
"targets": [
{
"symbol": "KCNJ11",
"name": "potassium inwardly rectifying channel subfamily J member 11",
"score": 0.8651,
"sequence": null,
"uniprot_id": "Q14654",
"pdb_ids": ["2UKM", "2UGY", "2UUG"]
},
{
"symbol": "GCK",
"name": "glucokinase",
"score": 0.8612,
"sequence": null,
"uniprot_id": "P35557",
"pdb_ids": ["1V4S", "3F9M", "4ISE"]
}
]
},
"status": "completed",
"created_at": "2026-06-03T07:31:42.000000Z"
}
],
"pagination": {
"current_page": 1,
"per_page": 15,
"total": 3,
"last_page": 1,
"has_more": false
}
}
}
POST /api/drug-repurposing/screen
- Auth required
- Content type:
application/json - Request body:
disease_name(string, required)known_drugs(array of strings, optional)min_score(numeric, optional, range 0–1)top_n_targets(integer, optional, range 1–100)
Example curl request
curl -X POST "{base_url}/api/drug-repurposing/screen" \\
-H "Authorization: Bearer {token}" \\
-H "Content-Type: application/json" \\
-d '{
"disease_name": "Type 2 Diabetes",
"known_drugs": ["Metformin", "Insulin"],
"min_score": 0.5,
"top_n_targets": 10
}'
Success response
{
"success": true,
"message": "Screening queued successfully",
"data": {
"job_id": 22,
"status": "pending"
}
}
GET /api/drug-repurposing/screen/{id}
- Auth required
- Path parameter:
id(integer)
Success response (completed)
{
"success": true,
"message": "Screening history retrieved successfully",
"data": {
"id": 22,
"input": {
"disease_name": "Type 2 Diabetes",
"min_score": 0.5,
"top_n_targets": 10,
"known_drugs": ["Metformin", "Insulin"]
},
"output": {
"disease_name": "Type 2 Diabetes",
"total_targets_found": 10,
"total_drugs_screened": 200,
"total_pairs_evaluated": 2000,
"top_candidates": [
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "KCNJ11",
"uniprot_id": "Q14654",
"binding_score": 0.9821,
"rank": 1,
"status": "Potential Discovery"
},
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "ABCC8",
"uniprot_id": "Q09428",
"binding_score": 0.9765,
"rank": 2,
"status": "Potential Discovery"
},
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "GCK",
"uniprot_id": "P35557",
"binding_score": 0.9712,
"rank": 3,
"status": "Potential Discovery"
},
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "PPARG",
"uniprot_id": "P37231",
"binding_score": 0.9689,
"rank": 4,
"status": "Potential Discovery"
},
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "INSR",
"uniprot_id": "P06213",
"binding_score": 0.9634,
"rank": 5,
"status": "Potential Discovery"
}
],
"warnings": []
},
"status": "completed"
}
}
If the job is not completed, the output field will be null.
GET /api/drug-repurposing/screen/history
- Auth required
- Query parameters:
per_page(integer, optional, default 15)
Response
{
"success": true,
"message": "Screening history retrieved successfully",
"data": {
"data": [
{
"id": 22,
"input": {
"disease_name": "Type 2 Diabetes",
"min_score": 0.5,
"top_n_targets": 10,
"known_drugs": ["Metformin", "Insulin"]
},
"output": {
"disease_name": "Type 2 Diabetes",
"total_targets_found": 10,
"total_drugs_screened": 200,
"total_pairs_evaluated": 2000,
"top_candidates": [
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "KCNJ11",
"uniprot_id": "Q14654",
"binding_score": 0.9821,
"rank": 1,
"status": "Potential Discovery"
},
{
"drug_name": "Drug_CHEMBL1754",
"smiles": "CC1=C(C=C(C=C1)NC(=O)C2=CC=C(C=C2)Cl)Cl",
"target_symbol": "ABCC8",
"uniprot_id": "Q09428",
"binding_score": 0.9765,
"rank": 2,
"status": "Potential Discovery"
}
],
"warnings": []
},
"status": "completed",
"created_at": "2026-06-02T21:35:24.000000Z"
}
],
"pagination": {
"current_page": 1,
"per_page": 15,
"total": 5,
"last_page": 1,
"has_more": false
}
}
}
Convert SMILES API
GET /api/convert-smiles/history
- Auth required
- Query parameters:
per_page(integer, optional, default 15)
Response
{
"success": true,
"message": "Conversion history retrieved successfully",
"data": {
"items": [
{
"job_id": 16,
"status": "completed",
"smiles": "CCN1CC(CCN2CCOCC2)C(c2ccccc2)(c2ccccc2)Cl=0",
"created_at": "2026-04-21T18:43:58+00:00",
"results": {
"download_url": "{base_url}/api/convert-smiles/download/{job_id}"
}
}
],
"pagination": {
"current_page": 1,
"per_page": 3,
"total": 13,
"last_page": 5,
"has_more": true
}
}
}
POST /api/convert-smiles/convert
- Auth required
- Content type:
application/json - Request body:
ligand_smiles(string, required)
Example curl request
curl -X POST "{base_url}/api/convert-smiles/convert" \\
-H "Authorization: Bearer {token}" \\
-H "Content-Type: application/json" \\
-d '{"ligand_smiles":"CCN1CC(CCN2CCOCC2)C(c2ccccc2)(c2ccccc2)Cl=0"}'
Success response
{
"success": true,
"message": "SMILES converted to PDBQT successfully",
"data": {
"job_id": 16,
"download_url": "{base_url}/api/convert-smiles/download/{job_id}",
"smiles": "CCN1CC(CCN2CCOCC2)C(c2ccccc2)(c2ccccc2)Cl=0"
}
}
GET /api/convert-smiles/download/{id}
- Auth required
- Path parameter:
id(integer)
- Returns a file download for the converted PDBQT.
- Content disposition filename:
converted_ligand_{id}.pdbqt
User Management Endpoints
Get Profile
GET /user/profile
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"user": {
"id": 1,
"name": "John Researcher",
"email": "john@pharmaai.io",
"email_verified_at": "2026-05-29T10:00:00Z",
"profile": {
"institution": "MIT",
"research_focus": "drug_discovery",
"bio": "Computational chemist..."
},
"created_at": "2026-05-01T00:00:00Z"
}
}
Update Profile
POST /user/update-profile
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"name": "John Researcher, PhD",
"profile": {
"institution": "Stanford",
"research_focus": "drug_discovery",
"bio": "Senior researcher..."
}
}
Response (200 OK):
{
"success": true,
"message": "Profile updated successfully",
"user": {...}
}
Awards And Scientists API
List Awards
GET /awards?page=1&per_page=10
Response (200 OK):
{
"success": true,
"message": "Awards retrieved successfully",
"data": {
"results": [
{
"id": 1,
"name": "Nobel Prize in Physiology or Medicine",
"category": "Medicine",
"images": ["https://..."],
"short_description": "The Nobel Prize in Physiology or Medicine is the world's most prestigious award...",
"scientists_count": 9,
"scientists": [
{
"id": 14,
"name": "Alexander Fleming",
"nationality": "British",
"birth_year": null,
"death_year": null,
"field": "Microbiology",
"images": ["https://..."],
"bio": null,
"short_bio": null,
"impact": null
}
]
}
],
"pagination": {
"currentPage": 1,
"totalPages": 1,
"totalResults": 10,
"perPage": 10,
"hasNextPage": false,
"hasPrevPage": false
}
}
}
Get Award Details
GET /awards/{award_id}
Example: GET /awards/2
Response (200 OK):
{
"success": true,
"message": "Award retrieved successfully",
"data": {
"id": 2,
"name": "Lasker Award",
"category": "Medical Research",
"images": ["https://..."],
"short_description": "The Lasker Award is often called the 'American Nobel Prize'...",
"scientists": [
{
"id": 17,
"name": "Tu Youyou",
"nationality": "Chinese",
"birth_year": null,
"death_year": null,
"field": "Pharmaceutical Chemistry",
"images": ["https://..."],
"bio": null,
"short_bio": null,
"impact": null
}
]
}
}
Get Award Scientists
GET /awards/{award_id}/scientists
Example: GET /awards/2/scientists
Response (200 OK):
{
"success": true,
"message": "Scientists retrieved successfully",
"data": [
{
"id": 17,
"name": "Tu Youyou",
"nationality": "Chinese",
"birth_year": null,
"death_year": null,
"field": "Pharmaceutical Chemistry",
"images": ["https://..."],
"bio": null,
"short_bio": null,
"impact": null
}
]
}
List Scientists
GET /scientists?page=1&per_page=50
Response (200 OK):
{
"success": true,
"message": "Scientists retrieved successfully",
"data": {
"results": [
{
"id": 14,
"name": "Alexander Fleming",
"nationality": "British",
"birth_year": null,
"death_year": null,
"field": "Microbiology",
"images": ["https://..."],
"bio": null,
"short_bio": null,
"impact": null
}
],
"pagination": {
"currentPage": 1,
"totalPages": 1,
"totalResults": 24,
"perPage": 50,
"hasNextPage": false,
"hasPrevPage": false
}
}
}
Get Scientist Details
GET /scientists/{scientist_id}
Response (200 OK):
{
"success": true,
"message": "Scientist retrieved successfully",
"data": {
"id": 14,
"name": "Alexander Fleming",
"nationality": "British",
"birth_year": null,
"death_year": null,
"field": "Microbiology",
"images": ["https://..."],
"bio": "Full biography text...",
"short_bio": "Short biography...",
"impact": "Scientific impact description...",
"awards": [
{
"id": 1,
"name": "Nobel Prize in Physiology or Medicine",
"year": 1945
}
]
}
}
Get Scientist Awards
GET /scientists/{scientist_id}/awards
Response (200 OK):
{
"success": true,
"message": "Awards retrieved successfully",
"data": [
{
"id": 1,
"name": "Nobel Prize in Physiology or Medicine",
"category": "Medicine",
"year": 1945,
"images": ["https://..."]
}
]
}
News API
Get News Feed
GET /news?page=1&per_page=10
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Articles retrieved successfully",
"data": {
"results": [
{
"id": 13,
"title": "AAPS National Biotechnology Conference",
"summary": "11 May 2026 - 14 May 2026 - All Day Sheraton San Diego...",
"source": "European Pharmaceutical Review",
"url": "https://...",
"published_at": "2026-05-11T07:00:00+00:00"
}
],
"pagination": {
"currentPage": 1,
"totalPages": 44,
"totalResults": 434,
"perPage": 10,
"hasNextPage": true,
"hasPrevPage": false
}
}
}
Get News with Pagination
GET /news?page=24&per_page=10
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Articles retrieved successfully",
"data": {
"results": [
{
"id": 21,
"title": "EU kicks off one-year pilot to expedite multinational trials",
"summary": "The European Union unveiled details of a pilot project...",
"source": "Endpoints News",
"url": "https://...",
"published_at": "2026-01-23T19:24:15+00:00"
}
],
"pagination": {
"currentPage": 24,
"totalPages": 44,
"totalResults": 434,
"perPage": 10,
"hasNextPage": true,
"hasPrevPage": true
}
}
}
Refresh News
GET /news/refresh
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "News refreshed successfully",
"data": {
"new_articles": 5,
"total_articles": 439
}
}
Get News Categories
GET /news/categories
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Categories retrieved successfully",
"data": [
"chemistry",
"pharma",
"biotech",
"medicine",
"research",
"clinical_trials"
]
}
Save Article
POST /news/{article_id}/save
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Article saved successfully",
"data": {
"saved_article_id": 123,
"article_id": 13,
"title": "AAPS National Biotechnology Conference",
"saved_at": "2026-05-29T12:00:00Z"
}
}
Share Article
POST /news/{article_id}/share
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"share_with": "colleague@pharmaai.io",
"message": "Check out this interesting article!"
}
Response (200 OK):
{
"success": true,
"message": "Article shared successfully",
"data": {
"share_id": 456,
"article_id": 13,
"shared_with": "colleague@pharmaai.io",
"shared_at": "2026-05-29T12:00:00Z"
}
}
Get Saved Articles
GET /news/saved
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Saved articles retrieved successfully",
"data": {
"results": [
{
"id": 123,
"article_id": 13,
"title": "AAPS National Biotechnology Conference",
"summary": "11 May 2026 - 14 May 2026...",
"source": "European Pharmaceutical Review",
"saved_at": "2026-05-29T12:00:00Z"
}
],
"pagination": {
"currentPage": 1,
"totalPages": 1,
"totalResults": 5,
"perPage": 10,
"hasNextPage": false,
"hasPrevPage": false
}
}
}
Unsave Article
DELETE /news/saved/{saved_article_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
Response (200 OK):
{
"success": true,
"message": "Article unsaved successfully"
}
'''
Admet Prediction API
POST /api/admet/predict
Predict ADMET properties for chemical compounds from SMILES strings or file uploads.
Authentication: Bearer token required
Input Options:
| Option | Type | Description |
|---|---|---|
smiles |
string | Comma-separated SMILES strings (max 6) |
file |
file | CSV or TXT file with SMILES (max 100 rows) |
Example 1: JSON Input
curl -X POST /api/admet/predict \\
-H "Authorization: Bearer {token}" \\
-H "Content-Type: application/json" \\
-d '{"smiles": "c1ccccc1, CCO, CCC"}'
Example 2: File Upload Input (CSV or TXT)
curl -X POST /api/admet/predict \\
-H "Authorization: Bearer {token}" \\
-F "file=@/path/to/file.csv"
Response (200 OK):
{
"success": true,
"message": "ADMET predictions generated successfully",
"data": [
{
"smiles": "c1ccccc1",
"absorption": -2.9907076358795166,
"distribution": 0.8750113248825073,
"metabolism": -0.11453431844711304,
"excretion": 7.360866546630859,
"toxicity": 0.8492187261581421
},
{
"smiles": "CCO",
"absorption": -3.7663559913635254,
"distribution": 0.8921501040458679,
"metabolism": -0.2787337601184845,
"excretion": 20.92142677307129,
"toxicity": -0.6471661329269409
},
{
"smiles": "CCC",
"absorption": -3.09336519241333,
"distribution": 1.2096238136291504,
"metabolism": -0.17122718691825867,
"excretion": 20.524127960205078,
"toxicity": -0.25303196907043457
}
]
}
'''
AI Generation API
POST /api/ai/generation/run
Authentication: Bearer token required
Input Options:
| Option | Type | Description |
|---|---|---|
num_molecules |
integer | Number of molecules to generate |
return_top_k |
integer | Number of top molecules to return |
docking_mode |
string | Docking mode: "all" or "off" or "top_k" |
dock_top_k |
integer | Number of top molecules to dock is only required when docking mode is top_k |
Example:
curl -X POST /api/ai/generation/run \\
-H "Authorization: Bearer {token}" \\
-H "Content-Type: application/json" \\
-d '{"num_molecules": 5, "return_top_k": 5, "docking_mode": "all", "dock_top_k": 5}'
Response (200 OK):
{
"success": true,
"message": "Generation job started successfully",
"data": {
"job_id": "gen_20260627_192907_58c7f5",
"status": "running",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "off",
"dock_top_k": 0,
"created_at": "2026-06-27 19:29:05"
}
}
GET /api/ai/generation/status/{job_id}
Authentication: Bearer token required
Example:
curl -X GET /api/ai/generation/status/gen_20260602_174612_90c1b1 \\
-H "Authorization: Bearer {token}"
Response (200 OK):
{
"success": true,
"message": "Generation job status",
"data": {
"job_id": "gen_20260627_192907_58c7f5",
"status": "completed",
"stage": "completed",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "off",
"dock_top_k": 0,
"summary": {
"num_requested": 5,
"num_generated": 4,
"num_valid": 4,
"num_returned": 4,
"num_docked": 0
},
"files": {
"csv": {
"filename": "generated_results.csv",
"download_url": "https://shdwrow-ailixir-generation.hf.space/files/jobs/gen_20260627_192907_58c7f5/generated_results.csv"
},
"json": {
"filename": "generated_results.json",
"download_url": "https://shdwrow-ailixir-generation.hf.space/files/jobs/gen_20260627_192907_58c7f5/generated_results.json"
}
},
"ligands": [
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 4.57,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"mw": 427.5120000000002,
"logp": 3.1636000000000006,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5234216428527144,
"sa_score": 2.7645745083533857,
"pred_pAff_mean": 10.726751327514648,
"docking_score": null,
"docking_status": "not_run",
"rank": 1
},
{
"SMILES": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)CC1",
"SMILES_state": 1,
"NLL": 5.39,
"valid": true,
"canonical_smiles": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)CC1",
"mw": 427.5120000000002,
"logp": 2.8160000000000007,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5240018720180243,
"sa_score": 2.567665997715085,
"pred_pAff_mean": 10.247249603271484,
"docking_score": null,
"docking_status": "not_run",
"rank": 2
},
{
"SMILES": "O=C(CCc1ccncc1)Nc1ccc2nncc(-c3ccc4nncn4c3)c2c1",
"SMILES_state": 1,
"NLL": 12.24,
"valid": true,
"canonical_smiles": "O=C(CCc1ccncc1)Nc1ccc2nncc(-c3ccc4nncn4c3)c2c1",
"mw": 395.4260000000001,
"logp": 3.3058000000000014,
"tpsa": 97.96,
"hbd": 1,
"hba": 6,
"rot_bonds": 5,
"qed": 0.4902723648859505,
"sa_score": 2.652044473533349,
"pred_pAff_mean": 8.516275405883789,
"docking_score": null,
"docking_status": "not_run",
"rank": 3
},
{
"SMILES": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCN4CCOCC4)cc23)c1",
"SMILES_state": 1,
"NLL": 6.54,
"valid": true,
"canonical_smiles": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCN4CCOCC4)cc23)c1",
"mw": 433.51200000000034,
"logp": 3.3061000000000016,
"tpsa": 96.45,
"hbd": 2,
"hba": 6,
"rot_bonds": 7,
"qed": 0.593505953472874,
"sa_score": 2.37134883917013,
"pred_pAff_mean": 7.571469783782959,
"docking_score": null,
"docking_status": "not_run",
"rank": 4
}
],
"created_at": "2026-06-27 19:29:05"
}
}
GET /api/ai/generation/jobs/{job_id}/results
Authentication: Bearer token required
Example:
curl -X GET /api/ai/generation/jobs/gen_20260602_174612_90c1b1/results \\
-H "Authorization: Bearer {token}"
Response (200 OK):
{
"success": true,
"message": "Generation job results",
"data": {
"job_id": "gen_20260627_192907_58c7f5",
"status": "completed",
"stage": "completed",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "off",
"dock_top_k": 0,
"summary": {
"num_requested": 5,
"num_generated": 4,
"num_valid": 4,
"num_returned": 4,
"num_docked": 0
},
"files": {
"csv": {
"filename": "generated_results.csv",
"download_url": "https://shdwrow-ailixir-generation.hf.space/files/jobs/gen_20260627_192907_58c7f5/generated_results.csv"
},
"json": {
"filename": "generated_results.json",
"download_url": "https://shdwrow-ailixir-generation.hf.space/files/jobs/gen_20260627_192907_58c7f5/generated_results.json"
}
},
"ligands": [
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 4.57,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"mw": 427.5120000000002,
"logp": 3.1636000000000006,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5234216428527144,
"sa_score": 2.7645745083533857,
"pred_pAff_mean": 10.726751327514648,
"docking_score": null,
"docking_status": "not_run",
"rank": 1
},
{
"SMILES": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)CC1",
"SMILES_state": 1,
"NLL": 5.39,
"valid": true,
"canonical_smiles": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)CC1",
"mw": 427.5120000000002,
"logp": 2.8160000000000007,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5240018720180243,
"sa_score": 2.567665997715085,
"pred_pAff_mean": 10.247249603271484,
"docking_score": null,
"docking_status": "not_run",
"rank": 2
},
{
"SMILES": "O=C(CCc1ccncc1)Nc1ccc2nncc(-c3ccc4nncn4c3)c2c1",
"SMILES_state": 1,
"NLL": 12.24,
"valid": true,
"canonical_smiles": "O=C(CCc1ccncc1)Nc1ccc2nncc(-c3ccc4nncn4c3)c2c1",
"mw": 395.4260000000001,
"logp": 3.3058000000000014,
"tpsa": 97.96,
"hbd": 1,
"hba": 6,
"rot_bonds": 5,
"qed": 0.4902723648859505,
"sa_score": 2.652044473533349,
"pred_pAff_mean": 8.516275405883789,
"docking_score": null,
"docking_status": "not_run",
"rank": 3
},
{
"SMILES": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCN4CCOCC4)cc23)c1",
"SMILES_state": 1,
"NLL": 6.54,
"valid": true,
"canonical_smiles": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCN4CCOCC4)cc23)c1",
"mw": 433.51200000000034,
"logp": 3.3061000000000016,
"tpsa": 96.45,
"hbd": 2,
"hba": 6,
"rot_bonds": 7,
"qed": 0.593505953472874,
"sa_score": 2.37134883917013,
"pred_pAff_mean": 7.571469783782959,
"docking_score": null,
"docking_status": "not_run",
"rank": 4
}
],
"created_at": "2026-06-27 19:29:05"
}
}
POST /api/ai/generation/jobs/{job_id}/cancel
Authentication: Bearer token required
Example:
curl -X POST http://localhost:8080/api/ai/generation/jobs/{job_id}/cancel \
-H "Authorization: Bearer {token}"
Response: Status:Completed
{
"success": false,
"message": "Cannot cancel a completed job",
"data": null
}
Response: Status:No Completed
{
"success": true,
"message": "Job cancelled successfully",
"data": {
"job_id": "gen_20260627_193543_01b810",
"status": "cancelled"
}
}
GET /api/ai/generation/history
Authentication: Bearer token required
Example:
curl -X GET http://localhost:8080/api/ai/generation/history \
-H "Authorization: Bearer {token}"
Response:
{
"success": true,
"message": "Generation job history retrieved successfully",
"data": {
"results": [
{
"id": 5,
"user_id": 1,
"job_id": "gen_20260602_185419_15fc7b",
"status": "completed",
"preset": "egfr_generator",
"num_molecules": 3,
"return_top_k": 3,
"docking_mode": "all",
"dock_top_k": 3,
"summary": {
"num_requested": 3,
"num_generated": 3,
"num_valid": 3,
"num_returned": 3,
"num_docked": 3
},
"files": {
"csv": {
"filename": "generated_results.csv",
"relative_url": "/files/jobs/gen_20260602_185419_15fc7b/generated_results.csv",
"download_url": "https://superplausibly-nonflowering-keiko.ngrok-free.dev/files/jobs/gen_20260602_185419_15fc7b/generated_results.csv"
},
"json": {
"filename": "generated_results.json",
"relative_url": "/files/jobs/gen_20260602_185419_15fc7b/generated_results.json",
"download_url": "https://superplausibly-nonflowering-keiko.ngrok-free.dev/files/jobs/gen_20260602_185419_15fc7b/generated_results.json"
}
},
"created_at": "2026-06-02T18:54:16.000000Z",
"updated_at": "2026-06-02T18:56:01.000000Z",
"ligands": [
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 4.14,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"mw": 427.5120000000002,
"logp": 3.1636000000000006,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5234216428527144,
"sa_score": 2.7645745083533857,
"pred_pAff_mean": 10.726750373840332,
"docking_score": -9.16,
"docking_status": "completed",
"rank": 1
},
{
"SMILES": "O=C(CCN1CCCC1)Nc1ccc2c(Nc3cccc(Cl)c3)ncnc2c1",
"SMILES_state": 1,
"NLL": 6.06,
"valid": true,
"canonical_smiles": "O=C(CCN1CCCC1)Nc1ccc2c(Nc3cccc(Cl)c3)ncnc2c1",
"mw": 395.89400000000006,
"logp": 4.451200000000003,
"tpsa": 70.15,
"hbd": 2,
"hba": 5,
"rot_bonds": 6,
"qed": 0.6447750051881624,
"sa_score": 2.11252799494409,
"pred_pAff_mean": 8.844084739685059,
"docking_score": -8.23,
"docking_status": "completed",
"rank": 2
},
{
"SMILES": "CN1CCC2C1CCN2CCC(=O)Nc1ccc2ncnc(Nc3ccc4ncncc4c3)c2c1",
"SMILES_state": 1,
"NLL": 22.74,
"valid": true,
"canonical_smiles": "CN1CCC2C1CCN2CCC(=O)Nc1ccc2ncnc(Nc3ccc4ncncc4c3)c2c1",
"mw": 468.5650000000001,
"logp": 3.4236000000000013,
"tpsa": 99.17,
"hbd": 2,
"hba": 8,
"rot_bonds": 6,
"qed": 0.4441562846144389,
"sa_score": 3.462932738106919,
"pred_pAff_mean": 8.693540573120117,
"docking_score": -9.2,
"docking_status": "completed",
"rank": 3
}
]
},
{
"id": 4,
"user_id": 1,
"job_id": "gen_20260602_185402_e9b887",
"status": "running",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "all",
"dock_top_k": 5,
"summary": null,
"files": null,
"created_at": "2026-06-02T18:54:00.000000Z",
"updated_at": "2026-06-02T18:54:00.000000Z",
"ligands": null
},
{
"id": 3,
"user_id": 1,
"job_id": "gen_20260602_174612_90c1b1",
"status": "completed",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "all",
"dock_top_k": 5,
"summary": {
"num_requested": 5,
"num_generated": 5,
"num_valid": 5,
"num_returned": 5,
"num_docked": 5
},
"files": {
"csv": {
"filename": "generated_results.csv",
"relative_url": "/files/jobs/gen_20260602_174612_90c1b1/generated_results.csv",
"download_url": "https://superplausibly-nonflowering-keiko.ngrok-free.dev/files/jobs/gen_20260602_174612_90c1b1/generated_results.csv"
},
"json": {
"filename": "generated_results.json",
"relative_url": "/files/jobs/gen_20260602_174612_90c1b1/generated_results.json",
"download_url": "https://superplausibly-nonflowering-keiko.ngrok-free.dev/files/jobs/gen_20260602_174612_90c1b1/generated_results.json"
}
},
"created_at": "2026-06-02T17:46:10.000000Z",
"updated_at": "2026-06-02T17:51:19.000000Z",
"ligands": [
{
"SMILES": "CCN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5ncncc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 8.24,
"valid": true,
"canonical_smiles": "CCN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5ncncc5c4)c3c2)C1",
"mw": 427.5120000000002,
"logp": 3.1636000000000006,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 6,
"qed": 0.505688822717197,
"sa_score": 2.715858141741272,
"pred_pAff_mean": 10.734132766723633,
"docking_score": -8.91,
"docking_status": "completed",
"rank": 1
},
{
"SMILES": "Cn1cnc2ccc(Nc3ncnc4ccc(NC(=O)CCN5CCC5)cc34)cc21",
"SMILES_state": 1,
"NLL": 5.32,
"valid": true,
"canonical_smiles": "Cn1cnc2ccc(Nc3ncnc4ccc(NC(=O)CCN5CCC5)cc34)cc21",
"mw": 401.4740000000003,
"logp": 3.2944000000000013,
"tpsa": 87.96999999999998,
"hbd": 2,
"hba": 6,
"rot_bonds": 6,
"qed": 0.5154635202823702,
"sa_score": 2.404394987645352,
"pred_pAff_mean": 9.775605201721191,
"docking_score": -8.27,
"docking_status": "completed",
"rank": 2
},
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnccc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 5.95,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnccc5c4)c3c2)C1",
"mw": 426.5240000000002,
"logp": 3.768600000000002,
"tpsa": 74.25,
"hbd": 1,
"hba": 6,
"rot_bonds": 5,
"qed": 0.523710400747619,
"sa_score": 2.669701840595609,
"pred_pAff_mean": 9.587095260620115,
"docking_score": -10.25,
"docking_status": "completed",
"rank": 3
},
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnnnc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 8.32,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnnnc5c4)c3c2)C1",
"mw": 428.5000000000002,
"logp": 2.5586,
"tpsa": 100.03,
"hbd": 1,
"hba": 8,
"rot_bonds": 5,
"qed": 0.5177099598248629,
"sa_score": 2.917413951888572,
"pred_pAff_mean": 8.804740905761719,
"docking_score": -10.15,
"docking_status": "completed",
"rank": 4
},
{
"SMILES": "O=C(CN1CCNCC1)Nc1ccc2nncc(-c3ccc4cnncc4c3)c2c1",
"SMILES_state": 1,
"NLL": 8.41,
"valid": true,
"canonical_smiles": "O=C(CN1CCNCC1)Nc1ccc2nncc(-c3ccc4cnncc4c3)c2c1",
"mw": 399.45800000000014,
"logp": 2.0836999999999994,
"tpsa": 95.93,
"hbd": 2,
"hba": 7,
"rot_bonds": 4,
"qed": 0.5423758682727866,
"sa_score": 2.665545251407164,
"pred_pAff_mean": 7.531160354614258,
"docking_score": -9.5,
"docking_status": "completed",
"rank": 5
}
]
},
{
"id": 2,
"user_id": 1,
"job_id": "gen_20260602_162928_00f1a6",
"status": "completed",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "all",
"dock_top_k": 5,
"summary": {
"num_requested": 5,
"num_generated": 5,
"num_valid": 5,
"num_returned": 5,
"num_docked": 5
},
"files": {
"csv": {
"filename": "generated_results.csv",
"relative_url": "/files/jobs/gen_20260602_162928_00f1a6/generated_results.csv",
"download_url": "https://abcd-1234.ngrok-free.app/files/jobs/gen_20260602_162928_00f1a6/generated_results.csv"
},
"json": {
"filename": "generated_results.json",
"relative_url": "/files/jobs/gen_20260602_162928_00f1a6/generated_results.json",
"download_url": "https://abcd-1234.ngrok-free.app/files/jobs/gen_20260602_162928_00f1a6/generated_results.json"
}
},
"created_at": "2026-06-02T16:29:26.000000Z",
"updated_at": "2026-06-02T16:45:06.000000Z",
"ligands": [
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 5.95,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"mw": 427.5120000000002,
"logp": 3.1636000000000006,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5234216428527144,
"sa_score": 2.7645745083533857,
"pred_pAff_mean": 10.726750373840332,
"docking_score": -9.17,
"docking_status": "completed",
"rank": 1
},
{
"SMILES": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)CC1",
"SMILES_state": 1,
"NLL": 5.14,
"valid": true,
"canonical_smiles": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)CC1",
"mw": 427.5120000000002,
"logp": 2.8160000000000007,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5240018720180243,
"sa_score": 2.567665997715085,
"pred_pAff_mean": 10.2472505569458,
"docking_score": -9.04,
"docking_status": "completed",
"rank": 2
},
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnccc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 5.85,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnccc5c4)c3c2)C1",
"mw": 426.5240000000002,
"logp": 3.768600000000002,
"tpsa": 74.25,
"hbd": 1,
"hba": 6,
"rot_bonds": 5,
"qed": 0.523710400747619,
"sa_score": 2.669701840595609,
"pred_pAff_mean": 9.5870943069458,
"docking_score": -9.18,
"docking_status": "completed",
"rank": 3
},
{
"SMILES": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnccc5c4)c3c2)CC1",
"SMILES_state": 1,
"NLL": 7.45,
"valid": true,
"canonical_smiles": "CN1CCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cnccc5c4)c3c2)CC1",
"mw": 426.5240000000002,
"logp": 3.421000000000002,
"tpsa": 74.25,
"hbd": 1,
"hba": 6,
"rot_bonds": 5,
"qed": 0.5271519273668187,
"sa_score": 2.4727933299573124,
"pred_pAff_mean": 9.139262199401855,
"docking_score": -9.59,
"docking_status": "completed",
"rank": 4
},
{
"SMILES": "CCN1CCN(CCC(=O)Nc2ccc3nncc(-c4cccc(F)c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 7.31,
"valid": true,
"canonical_smiles": "CCN1CCN(CCC(=O)Nc2ccc3nncc(-c4cccc(F)c4)c3c2)C1",
"mw": 393.4660000000002,
"logp": 3.359500000000001,
"tpsa": 61.36,
"hbd": 1,
"hba": 5,
"rot_bonds": 6,
"qed": 0.6958924258182049,
"sa_score": 2.483388547894851,
"pred_pAff_mean": 8.095303535461426,
"docking_score": -8.79,
"docking_status": "completed",
"rank": 5
}
]
},
{
"id": 1,
"user_id": 1,
"job_id": "gen_20260602_161105_95a4f3",
"status": "completed",
"preset": "egfr_generator",
"num_molecules": 5,
"return_top_k": 5,
"docking_mode": "off",
"dock_top_k": 0,
"summary": {
"num_requested": 5,
"num_generated": 5,
"num_valid": 5,
"num_returned": 5,
"num_docked": 0
},
"files": {
"csv": {
"filename": "generated_results.csv",
"relative_url": "/files/jobs/gen_20260602_161105_95a4f3/generated_results.csv",
"download_url": "https://abcd-1234.ngrok-free.app/files/jobs/gen_20260602_161105_95a4f3/generated_results.csv"
},
"json": {
"filename": "generated_results.json",
"relative_url": "/files/jobs/gen_20260602_161105_95a4f3/generated_results.json",
"download_url": "https://abcd-1234.ngrok-free.app/files/jobs/gen_20260602_161105_95a4f3/generated_results.json"
}
},
"created_at": "2026-06-02T16:11:02.000000Z",
"updated_at": "2026-06-02T16:45:52.000000Z",
"ligands": [
{
"SMILES": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"SMILES_state": 1,
"NLL": 5.97,
"valid": true,
"canonical_smiles": "CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1",
"mw": 427.5120000000002,
"logp": 3.1636000000000006,
"tpsa": 87.14,
"hbd": 1,
"hba": 7,
"rot_bonds": 5,
"qed": 0.5234216428527144,
"sa_score": 2.7645745083533857,
"pred_pAff_mean": 10.726750373840332,
"docking_score": null,
"docking_status": "not_run",
"rank": 1
},
{
"SMILES": "O=C(CCN1CCCCC1)Nc1ccc2nncc(-c3ccc4cncnc4c3)c2c1",
"SMILES_state": 1,
"NLL": 8.21,
"valid": true,
"canonical_smiles": "O=C(CCN1CCCCC1)Nc1ccc2nncc(-c3ccc4cncnc4c3)c2c1",
"mw": 412.4970000000002,
"logp": 4.054500000000003,
"tpsa": 83.9,
"hbd": 1,
"hba": 6,
"rot_bonds": 5,
"qed": 0.532283447216262,
"sa_score": 2.5088336367127653,
"pred_pAff_mean": 9.917120933532717,
"docking_score": null,
"docking_status": "not_run",
"rank": 2
},
{
"SMILES": "CNCCCC(=O)Nc1ccc2nncc(-c3cccc4cncnc34)c2c1",
"SMILES_state": 1,
"NLL": 8.3,
"valid": true,
"canonical_smiles": "CNCCCC(=O)Nc1ccc2nncc(-c3cccc4cncnc34)c2c1",
"mw": 372.4320000000001,
"logp": 3.178100000000001,
"tpsa": 92.69,
"hbd": 2,
"hba": 6,
"rot_bonds": 6,
"qed": 0.5051251070006001,
"sa_score": 2.5602974133305807,
"pred_pAff_mean": 9.24955940246582,
"docking_score": null,
"docking_status": "not_run",
"rank": 3
},
{
"SMILES": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCN4CCCN(C)C4)cc23)c1",
"SMILES_state": 1,
"NLL": 6.61,
"valid": true,
"canonical_smiles": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCN4CCCN(C)C4)cc23)c1",
"mw": 446.5550000000004,
"logp": 3.568900000000003,
"tpsa": 90.45999999999998,
"hbd": 2,
"hba": 6,
"rot_bonds": 7,
"qed": 0.5767061490837626,
"sa_score": 2.580768170904193,
"pred_pAff_mean": 8.717927932739258,
"docking_score": null,
"docking_status": "not_run",
"rank": 4
},
{
"SMILES": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCCN)cc23)c1",
"SMILES_state": 1,
"NLL": 7.34,
"valid": true,
"canonical_smiles": "CCC(=O)Nc1cccc(-c2cnnc3ccc(NC(=O)CCCN)cc23)c1",
"mw": 377.4480000000002,
"logp": 3.322700000000001,
"tpsa": 110,
"hbd": 3,
"hba": 5,
"rot_bonds": 7,
"qed": 0.5849389128589325,
"sa_score": 2.2821504292780475,
"pred_pAff_mean": 7.681546688079834,
"docking_score": null,
"docking_status": "not_run",
"rank": 5
}
]
}
],
"pagination": {
"currentPage": 1,
"totalPages": 1,
"totalResults": 5,
"perPage": 10,
"hasNextPage": false,
"hasPrevPage": false
}
}
}
ligands export
POST /api/ai/ligands/export
Authentication: Bearer token required
Input Options:
| Name | Type | Description |
|---|---|---|
smiles |
string | SMILES strings |
format |
string | Supported formats: pdbqt or pdb or sdf |
Example:
curl -X POST http://localhost:8080/api/ai/ligands/export \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"smiles": "CCO", "format": "pdbqt"}'
Response:
{
"success": true,
"message": "Ligands exported successfully",
"data": {
"job_id": "lig_20260627_193222_e57b0b",
"status": "completed",
"format": "pdb",
"filename": "ligand_3d.pdb",
"smiles": "CCC",
"download_url": "https://shdwrow-ailixir-generation.hf.space/files/jobs/lig_20260627_193222_e57b0b/ligand_3d.pdb"
}
}
ligands download files or Generation files
GET /api/ai/files/{job_id}/{filename}
Authentication: Bearer token required
Example ligands download:
curl -X GET http://localhost:8080/api/ai/files/lig_20260602_181751_0227c4/ligand_3d.pdbqt \
-H "Authorization: Bearer {token}"
Response:
REMARK SMILES CCC
REMARK SMILES IDX 1 1 2 2 3 3
REMARK H PARENT
ROOT
ATOM 1 C UNL 1 1.223 -0.144 -0.355 1.00 0.00 0.003 C
ATOM 2 C UNL 1 0.031 -0.177 0.596 1.00 0.00 -0.007 C
ATOM 3 C UNL 1 -1.247 0.279 -0.101 1.00 0.00 0.003 C
ENDROOT
TORSDOF 0
Example Generation files download:
curl -X GET http://127.0.0.1:8000/api/ai/files/gen_20260602_185419_15fc7b/generated_results.csv \
-H "Authorization: Bearer {token}"
Response:
SMILES,SMILES_state,NLL,valid,canonical_smiles,mw,logp,tpsa,hbd,hba,rot_bonds,qed,sa_score,pred_pAff_mean,docking_score,docking_status
CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1,1,4.14,True,CN1CCCN(CCC(=O)Nc2ccc3nncc(-c4ccc5cncnc5c4)c3c2)C1,427.5120000000002,3.1636000000000006,87.14,1,7,5,0.5234216428527144,2.7645745083533857,10.726750373840332,-9.16,completed
O=C(CCN1CCCC1)Nc1ccc2c(Nc3cccc(Cl)c3)ncnc2c1,1,6.06,True,O=C(CCN1CCCC1)Nc1ccc2c(Nc3cccc(Cl)c3)ncnc2c1,395.89400000000006,4.451200000000003,70.15,2,5,6,0.6447750051881624,2.11252799494409,8.844084739685059,-8.23,completed
CN1CCC2C1CCN2CCC(=O)Nc1ccc2ncnc(Nc3ccc4ncncc4c3)c2c1,1,22.74,True,CN1CCC2C1CCN2CCC(=O)Nc1ccc2ncnc(Nc3ccc4ncncc4c3)c2c1,468.5650000000001,3.4236000000000013,99.17,2,8,6,0.4441562846144389,3.462932738106919,8.693540573120117,-9.2,completed
MD Simulation API
Molecular Dynamics simulation of protein-ligand complexes via an external OpenMM service. All endpoints require authentication.
POST /api/md-simulation/process
Submit a new MD simulation job.
Authentication: Bearer token required
Content-Type: multipart/form-data
Required fields:
| Field | Type | Description |
|---|---|---|
protein |
file | Protein PDB file |
ligand |
file | Ligand PDB file |
Optional fields:
| Field | Type | Default | Description |
|---|---|---|---|
force_field |
string | ff19SB |
ff19SB or ff14SB |
net_charge |
integer | 0 |
Ligand net formal charge |
box_size |
float | 12.0 |
Solvation box size (Å) |
ion_type |
string | NaCl |
NaCl or KCl |
salt_conc |
float | 0.15 |
Salt concentration (M) |
remove_waters |
boolean | True |
Strip crystal waters |
add_hydrogens |
boolean | True |
Add H to ligand |
equil_time_ns |
float | 5.0 |
Equilibration time (ns) |
sim_time_ns |
float | 0.1 |
Production time per stride (ns) |
n_strides |
integer | 1 |
Number of production strides |
temperature_k |
float | 298.0 |
Temperature (K) |
pressure_bar |
float | 1.0 |
Pressure (bar) |
dt_fs |
integer | 2 |
Integration timestep (fs) |
Note: when you send boolean values(True or False) multipart/form-data cast it to string unless you use json, in this case you should use: 1 as True 0 as False
Example:
curl -X POST /api/md-simulation/process \
-H "Authorization: Bearer {token}" \
-F "protein=@protein.pdb" \
-F "ligand=@ligand.pdb" \
-F "sim_time_ns=1.0" \
-F "temperature_k=310"
Response (202 Accepted):
{
"success": true,
"message": "MD Simulation job submitted successfully",
"data": {
"remote_job_id": "a1b2c3d4",
"status": "processing",
"created_at": "2026-06-22 12:00:00"
}
}
GET /api/md-simulation/status/{remoteJobId}
Poll job status. Syncs the local status from the remote service on each call.
Authentication: Bearer token required
Response (200 OK — processing):
{
"success": true,
"message": "Status retrieved",
"data": {
"remote_job_id": "a1b2c3d4",
"status": "processing",
"remote_status": "Step 2/7 — Building GAFF2 topology and solvated system",
"protein": "4w52.pdb",
"ligand": "ligand.pdb",
"result_meta": null,
"analysis_meta": null,
"error_message": null,
"created_at": "2026-06-22 12:00:00"
}
}
Response (200 OK — completed):
{
"success": true,
"message": "Status retrieved",
"data": {
"remote_job_id": "a1b2c3d4",
"status": "completed",
"remote_status": "Success: MD Pipeline Completed",
"protein": "4w52.pdb",
"ligand": "ligand.pdb",
"result_meta": {
"download_url": "/download/a1b2c3d4",
"download_analysis_url": "/download_analysis/a1b2c3d4"
},
"analysis_meta": null,
"error_message": null,
"created_at": "2026-06-22 12:00:00"
}
}
Response (200 OK — failed):
{
"success": true,
"message": "Status retrieved",
"data": {
"remote_job_id": "a1b2c3d4",
"status": "failed",
"remote_status": "Failed: antechamber failed...",
"error_message": "antechamber failed: unable to assign parameters",
...
}
}
GET /api/md-simulation/download/{remoteJobId}
Download the simulation results ZIP (streamed from the remote service).
Authentication: Bearer token required
Response (200 OK): Binary ZIP attachment — {job_id}_Results.zip
POST /api/md-simulation/analyze/{remoteJobId}
Run post-simulation analysis (RMSD, RMSF, RoG, PCA, etc.) on a completed job.
Authentication: Bearer token required
Content-Type: application/json
Optional body fields:
| Field | Type | Default | Description |
|---|---|---|---|
rmsd_mask |
string | @CA |
Atom selection mask for RMSD |
cc_mask |
string | @CA |
Atom selection mask for cross-correlation |
skip |
integer | 1 |
Frame stride for analysis |
dpi |
integer | 300 |
DPI for output plots |
threshold |
float | 0.3 |
ProLIF interaction threshold |
Example:
curl -X POST /api/md-simulation/analyze/a1b2c3d4 \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"rmsd_mask": "@CA", "dpi": 150}'
Response (200 OK):
{
"success": true,
"message": "Analysis triggered successfully",
"data": {
"download_url": "/download_analysis/a1b2c3d4",
"outputs": [
"rmsd",
"rmsf",
"radgyr",
"2d_rmsd",
"pca",
"cross_corr",
"interaction_e",
"prolif"
]
}
}
GET /api/md-simulation/download-analysis/{remoteJobId}
Download the analysis results ZIP (streamed from the remote service).
Authentication: Bearer token required
Response (200 OK): Binary ZIP attachment — {job_id}_Analysis.zip
GET /api/md-simulation/history
List all MD simulation jobs for the authenticated user.
Authentication: Bearer token required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
per_page |
integer | 15 |
Results per page |
Response (200 OK):
{
"success": true,
"message": "MD Simulation history retrieved",
"data": {
"results": [
{
"remote_job_id": "x9y8z7w6",
"status": "completed",
"input_params": {
"sim_time_ns": "5.0",
"temperature_k": "310"
},
"protein_original_name": "1ake.pdb",
"ligand_original_name": "stl.pdb",
"result_meta": {
"download_url": "/download/x9y8z7w6",
"download_analysis_url": "/download_analysis/x9y8z7w6"
},
"analysis_meta": {
"download_url": "/download_analysis/x9y8z7w6",
"outputs": ["rmsd", "rmsf", "radgyr"]
},
"error_message": null,
"created_at": "2026-06-22 14:30:00",
"updated_at": "2026-06-22 18:45:00"
}
],
"pagination": {
"currentPage": 1,
"totalPages": 1,
"totalResults": 3,
"perPage": 15,
"hasNextPage": false,
"hasPrevPage": false
}
}
}
'''
Error Handling
Error Response Format
All errors follow this standard format:
{
"success": false,
"message": "Human-readable error message",
"error_code": "SPECIFIC_ERROR_CODE",
"details": {
"field_errors": {...}
},
"timestamp": "2026-05-29T12:30:45Z"
}
HTTP Status Codes
| Code | Meaning | Example |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created |
| 202 | Accepted | Async job queued |
| 400 | Bad Request | Invalid parameters |
| 401 | Unauthorized | Missing/invalid token |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource not found |
| 422 | Unprocessable | Validation failed |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Server Error | Internal error |
| 502 | Bad Gateway | Upstream service down |
| 503 | Service Unavailable | System maintenance |
Common Error Codes
| Code | Description |
|---|---|
INVALID_SMILES |
Given SMILES string is invalid |
JOB_NOT_FOUND |
Job ID doesn't exist |
SERVICE_UNAVAILABLE |
AI service not responding |
AUTHENTICATION_FAILED |
Invalid credentials |
INSUFFICIENT_QUOTA |
User quota exceeded |
UNSUPPORTED_OPERATION |
Feature not available |
QUOTA_EXCEEDED |
LLM API daily quota reached |
THREAD_NOT_FOUND |
Thread ID doesn't exist or unauthorized |
JOB_NOT_COMPLETE |
Results requested before job completion |
CSV_TOO_LARGE |
Exceeds 100 row limit |
MISSING_SMILES |
smiles field not provided |
Example Error Response
POST /ai/run
Authorization: Bearer invalid_token
HTTP 401 Unauthorized
Content-Type: application/json
{
"success": false,
"message": "Unauthenticated",
"error_code": "AUTHENTICATION_FAILED",
"timestamp": "2026-05-29T12:30:45Z"
}
Rate Limiting
Rate Limit Headers
All responses include rate limit information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1716954645
Limits by Endpoint Category
| Category | Limit | Window |
|---|---|---|
| Auth | 10 requests | 15 minutes |
| AI Jobs | 100 requests | 1 hour |
| Search | 500 requests | 1 hour |
| General | 1000 requests | 1 hour |
AI Agent Rate Limits
| Endpoint | Limit | Window |
|---|---|---|
/chat |
20 requests | Per day (upstream quota) |
/analyze/smiles |
20 requests | Per day (upstream quota) |
/analyze/compare |
20 requests | Per day (upstream quota) |
/analyze/docking |
20 requests | Per day (upstream quota) |
/csv/upload |
10 uploads | Per day |
| All others | 1000 requests | 1 hour |
Note: AI-powered endpoints are limited by upstream Google Gemini free tier (20 requests/day). Use analysis_type: quick to reduce consumption.
Handling Rate Limits
When rate limited (HTTP 429):
{
"success": false,
"message": "Rate limit exceeded",
"retry_after": 120,
"error_code": "RATE_LIMIT_EXCEEDED"
}
Retry-After Header: Seconds to wait before retry
Integration Examples
Example 1: Complete ADMET Prediction Workflow
#!/bin/bash
BASE_URL="http://localhost:8080/api"
TOKEN="your_access_token_here"
SMILES="CC(=O)Oc1ccccc1C(=O)O"
# Step 1: Submit job
echo "1. Submitting ADMET job..."
JOB_RESPONSE=$(curl -s -X POST "$BASE_URL/ai/run" \\
-H "Authorization: Bearer $TOKEN" \\
-H "Content-Type: application/json" \\
-d "{\\"job_type\\": \\"admet_prediction\\", \\"parameters\\": {\\"smiles\\": \\"$SMILES\\"}}")
JOB_ID=$(echo $JOB_RESPONSE | jq -r '.job_id')
echo "Job ID: $JOB_ID"
# Step 2: Poll for completion
echo "2. Waiting for results..."
while true; do
STATUS_RESPONSE=$(curl -s -X GET "$BASE_URL/ai/status/$JOB_ID" \\
-H "Authorization: Bearer $TOKEN")
STATUS=$(echo $STATUS_RESPONSE | jq -r '.status')
if [ "$STATUS" == "completed" ]; then
echo "Job completed!"
echo $STATUS_RESPONSE | jq '.results'
break
elif [ "$STATUS" == "failed" ]; then
echo "Job failed!"
echo $STATUS_RESPONSE | jq '.error'
exit 1
else
echo "Status: $STATUS, waiting..."
sleep 5
fi
done
# Step 3: Download results
echo "3. Downloading full results..."
curl -X GET "$BASE_URL/ai/download/full/$JOB_ID" \\
-H "Authorization: Bearer $TOKEN" \\
-o results.zip
echo "✓ Results saved to results.zip"
Example 2: Chemical Similarity Search
import requests
import json
import time
class AILIXIRClient:
def __init__(self, base_url, token):
self.base_url = base_url
self.token = token
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
def search_similar_compounds(self, smiles, top_k=10, use_rag=True):
"""Search for compounds similar to query SMILES"""
endpoint = "full-rag" if use_rag else "retrieval-only"
url = f"{self.base_url}/chemical-search/{endpoint}"
response = requests.post(url, headers=self.headers, json={
"smiles": smiles,
"top_k": top_k
})
if response.status_code != 202:
raise Exception(f"Failed to submit search: {response.text}")
job_id = response.json()["job_id"]
print(f"Search submitted: {job_id}")
# Poll for results
while True:
status_url = f"{self.base_url}/chemical-search/{job_id}/status"
status_response = requests.get(status_url, headers=self.headers)
status_data = status_response.json()
if status_data["status"] == "completed":
return status_data["compounds"]
elif status_data["status"] == "failed":
raise Exception(f"Search failed: {status_data.get('error')}")
print(f"Status: {status_data['status']}, waiting...")
time.sleep(2)
# Usage
client = AILIXIRClient("http://localhost:8080/api", "your_token_here")
results = client.search_similar_compounds("CC(=O)Oc1ccccc1C(=O)O", top_k=5)
for compound in results:
print(f"Rank {compound['rank']}: {compound['name']} (similarity: {compound['similarity']:.2f})")
if 'explanation' in compound:
print(f" Explanation: {compound['explanation'][:100]}...")
Example 3: Health Monitoring
// Node.js / JavaScript example
const axios = require("axios");
async function checkSystemHealth() {
const baseURL = "http://localhost:8080/api";
try {
// Check overall system
const healthResponse = await axios.get(`${baseURL}/health`);
console.log("System Health:", healthResponse.data);
// Check all AI services
const servicesResponse = await axios.get(
`${baseURL}/ai-services/health`,
);
const allHealthy = servicesResponse.data.success;
const services = servicesResponse.data.services;
console.log("\\nAI Services Status:");
Object.entries(services).forEach(([name, status]) => {
const indicator = status.status === "healthy" ? "✓" : "✗";
console.log(`${indicator} ${name}: ${status.status}`);
});
return {
healthy: allHealthy,
timestamp: new Date(),
};
} catch (error) {
console.error("Health check failed:", error.message);
}
}
// Run every 60 seconds
setInterval(checkSystemHealth, 60000);
Example 4: AI Agent Drug Discovery Workflow
#!/bin/bash
BASE_URL="http://localhost:8080/api"
TOKEN="your_access_token_here"
# Step 1: Create thread
echo "1. Creating thread..."
THREAD_RESPONSE=$(curl -s -X POST "$BASE_URL/chemistry/thread" \\
-H "Authorization: Bearer $TOKEN")
THREAD_ID=$(echo $THREAD_RESPONSE | jq -r '.data.thread_id')
echo "Thread ID: $THREAD_ID"
# Step 2: Analyze SMILES
echo "2. Analyzing Aspirin..."
curl -s -X POST "$BASE_URL/chemistry/analyze/smiles" \\
-H "Authorization: Bearer $TOKEN" \\
-H "Content-Type: application/json" \\
-d "{\\"smiles\\": \\"CC(=O)Oc1ccccc1C(=O)O\\", \\"thread_id\\": \\"$THREAD_ID\\"}" | jq '.data.reply'
# Step 3: Compare with Ibuprofen
echo "3. Comparing molecules..."
curl -s -X POST "$BASE_URL/chemistry/analyze/compare" \\
-H "Authorization: Bearer $TOKEN" \\
-H "Content-Type: application/json" \\
-d "{\\"smiles\\": [\\"CC(=O)Oc1ccccc1C(=O)O\\", \\"CC(C)Cc1ccc(cc1)C(C)C(=O)O\\"], \\"thread_id\\": \\"$THREAD_ID\\"}" | jq '.data.reply'
# Step 4: Chat follow-up
echo "4. Follow-up question..."
curl -s -X POST "$BASE_URL/chemistry/chat" \\
-H "Authorization: Bearer $TOKEN" \\
-H "Content-Type: application/json" \\
-d "{\\"message\\": \\"Which molecule has better CNS penetration?\\", \\"thread_id\\": \\"$THREAD_ID\\"}" | jq '.data.reply'
echo "✓ Workflow complete!"
Example 5: Flutter Integration
class ChemistryApiService {
final String baseUrl = 'http://your-domain.com/api/chemistry';
String? token;
Future<Map<String, dynamic>> analyzeSmiles(String smiles, {String? threadId}) async {
final response = await http.post(
Uri.parse('$baseUrl/analyze/smiles'),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: jsonEncode({
'smiles': smiles,
'thread_id': threadId,
}),
);
return jsonDecode(response.body);
}
Future<Map<String, dynamic>> chat(String message, {String? threadId}) async {
final response = await http.post(
Uri.parse('$baseUrl/chat'),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: jsonEncode({
'message': message,
'thread_id': threadId,
}),
);
return jsonDecode(response.body);
}
Future<Map<String, dynamic>> createThread() async {
final response = await http.post(
Uri.parse('$baseUrl/thread'),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
);
return jsonDecode(response.body);
}
}
Support
For API issues or questions:
- Check Logs:
docker compose logs -f laravel - Test Endpoint: Use provided curl examples
- Version: Confirm you're using latest API version
- Rate Limits: Check
X-RateLimit-*headers - Contact: pharma-support@ailixir.io
Created: May 29, 2026 | Version: 2.1.0 | Last Updated: May 29, 2026 '''
with open('/mnt/agents/output/AILIXIR_API_Reference_v2.1.md', 'w', encoding='utf-8') as f: f.write(content)
print("File saved successfully!") print(f"Total lines: {len(content.splitlines())}") print(f"Total characters: {len(content)}")