ailixir-api / API.md
RottenShadow's picture
Rename API.mpd to API.md
d6b835a verified
|
Raw
History Blame Contribute Delete
115 kB
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](#overview)
- [Authentication](#authentication)
- [Base URLs](#base-urls)
- [Common Patterns](#common-patterns)
- [Health & Status](#health--status)
- [Authentication Endpoints](#authentication-endpoints)
- [AI Integration Endpoints](#ai-integration-endpoints)
- [AI Service Endpoints](#ai-service-endpoints)
- [AI Agent Endpoints (Chemistry AI)](#ai-agent-endpoints-chemistry-ai)
- [Chemical Search Endpoints](#chemical-search-endpoints)
- [Docking API](#docking-api)
- [Drug Repurposing API](#drug-repurposing-api)
- [Convert SMILES API](#convert-smiles-api)
- [User Management Endpoints](#user-management-endpoints)
- [Awards And Scientists API](#awards-and-scientists-api)
- [News API](#news-api)
- [Admet Prediction API](#admet-prediction-api)
- [AI Generation API](#ai-generation-api)
- [MD Simulation API](#md-simulation-api)
- [Error Handling](#error-handling)
- [Rate Limiting](#rate-limiting)
- [Integration Examples](#integration-examples)
- [Support](#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:
```http
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:
```query
?page=1&per_page=20
```
**Response Field:** `meta.pagination`
```json
{
"data": [...],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 100,
"last_page": 5
}
}
}
```
### Filtering
Endpoints support filtering (details per endpoint):
```query
?filter[status]=completed&filter[created_after]=2026-05-01
```
### Sorting
```query
?sort=created_at&sort_order=desc
```
### Asynchronous Jobs
Long-running operations return `202 Accepted` with job tracking URL:
```json
{
"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:
```http
GET /health
```
**Response (200 OK):**
```json
{
"status": "healthy",
"timestamp": "2026-05-29T12:30:45Z",
"version": "2.0.0",
"uptime_seconds": 876543
}
```
### All Services Health
Check all AI microservices:
```http
GET /ai-services/health
```
**Response (200 OK):**
```json
{
"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
```http
POST /user/register
Content-Type: application/json
{
"name": "Yasmeen Ahmed",
"email": "yasmeen@test.com",
"password": "password123",
"password_confirmation": "password123"
}
```
**Response (201 Created):**
```json
{
"success": true,
"message": "Registered successfully. Please check your email for OTP verification code.",
"data": {
"email": "yasmeen@test.com"
}
}
```
---
### Login
```http
POST /user/login
Content-Type: application/json
{
"email": "yasmeen@test.com",
"password": "password123"
}
```
**Response (200 OK):**
```json
{
"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:
```http
POST /user/verify-email
Content-Type: application/json
{
"email": "yasmeen@test.com",
"otp": "123456"
}
```
**Response (200 OK):**
```json
{
"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
```http
POST /user/resend-verification
Content-Type: application/json
{
"email": "yasmeen@test.com"
}
```
**Response (200 OK):**
```json
{
"success": true,
"message": "OTP resent successfully",
"data": {
"email": "yasmeen111@example.com"
}
}
```
---
### Forgot Password
```http
POST /user/forgot-password
Content-Type: application/json
{
"email": "yasmeen@test.com"
}
```
**Response (200 OK):**
```json
{
"success": true,
"message": "OTP sent successfully",
"data": {
"email": "salehyasmeen080@gmail.com"
}
}
```
---
### Reset Password
```http
POST /user/reset-password
Content-Type: application/json
{
"email": "yasmeen@test.com",
"otp": "123456",
"password": "new_password123",
"password_confirmation": "new_password123"
}
```
**Response (200 OK):**
```json
{
"success": true,
"message": "Password reset successfully"
}
```
---
### Logout
```http
POST /user/logout
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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:
```http
POST /ai-services/test/admet
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"batch_size": 32
}
```
**Response (200 OK):**
```json
{
"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:
```http
POST /ai-services/test/chemical-search
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"top_k": 5
}
```
**Response (200 OK):**
```json
{
"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:
```http
GET /ai-services/test/drug-repurposing
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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:
```http
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):**
```json
{
"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
```http
GET /ai/status/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK - Pending):**
```json
{
"success": true,
"job_id": "job-abc-123-def",
"status": "processing",
"progress": 45,
"estimated_completion": "2026-05-29T12:35:00Z"
}
```
**Response (200 OK - Completed):**
```json
{
"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):**
```json
{
"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:
```http
GET /ai/preview/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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):
```http
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:
```http
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:
```http
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):**
```json
{
"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.
```http
POST /api/chemistry/thread
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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.
```http
GET /api/chemistry/threads
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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.
```http
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):**
```json
{
"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_id` is 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.
```http
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):**
```json
{
"success": true,
"data": {
"reply": "Complete analysis text...",
"thread_id": "aa761d2c-ecbc-4da0-abe4-189c2d77eede",
"processing_time_ms": 5234
}
}
```
**Pipeline Steps:**
1. Validate SMILES
2. Compute molecular properties (MW, LogP, HBD, HBA, TPSA, QED, Fsp3)
3. Drug-likeness classification (Lipinski Ro5, Veber, Lead-likeness)
4. ADMET profile with structural toxicity alerts
**Notes:**
- `smiles` field 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.
```http
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):**
```json
{
"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.
```http
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):**
```json
{
"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.
```http
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:**
```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):**
```json
{
"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.
```http
GET /api/chemistry/csv/status/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK - Running):**
```json
{
"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.
```http
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 file
- `name` — compound name
- `smiles` — input SMILES string
- `status` — success or failed
- `analysis` — full agent analysis text
- `error` — error message (empty if status is success)
---
### List User CSV Jobs
```http
GET /api/chemistry/csv/jobs
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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.
```http
DELETE /api/chemistry/csv/jobs/{job_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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.
```http
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):**
```json
{
"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):
```http
POST /chemical-search
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"smiles": "CC(=O)Oc1ccccc1C(=O)O",
"top_k": 10
}
```
**Response (202 Accepted):**
```json
{
"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:
```http
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):**
```json
{
"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
```bash
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
```json
{
"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)
```json
{
"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)
```json
{
"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)
```json
{
"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
```json
{
"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: Bearer` header 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
```bash
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
```json
{
"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)
```json
{
"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
```json
{
"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
```bash
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
```json
{
"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)
```json
{
"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
```json
{
"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
```json
{
"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
```bash
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
```json
{
"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
```http
GET /user/profile
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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
```http
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):**
```json
{
"success": true,
"message": "Profile updated successfully",
"user": {...}
}
```
---
## Awards And Scientists API
### List Awards
```http
GET /awards?page=1&per_page=10
```
**Response (200 OK):**
```json
{
"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
```http
GET /awards/{award_id}
```
**Example:** `GET /awards/2`
**Response (200 OK):**
```json
{
"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
```http
GET /awards/{award_id}/scientists
```
**Example:** `GET /awards/2/scientists`
**Response (200 OK):**
```json
{
"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
```http
GET /scientists?page=1&per_page=50
```
**Response (200 OK):**
```json
{
"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
```http
GET /scientists/{scientist_id}
```
**Response (200 OK):**
```json
{
"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
```http
GET /scientists/{scientist_id}/awards
```
**Response (200 OK):**
```json
{
"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
```http
GET /news?page=1&per_page=10
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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
```http
GET /news?page=24&per_page=10
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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
```http
GET /news/refresh
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"success": true,
"message": "News refreshed successfully",
"data": {
"new_articles": 5,
"total_articles": 439
}
}
```
---
### Get News Categories
```http
GET /news/categories
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"success": true,
"message": "Categories retrieved successfully",
"data": [
"chemistry",
"pharma",
"biotech",
"medicine",
"research",
"clinical_trials"
]
}
```
---
### Save Article
```http
POST /news/{article_id}/save
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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
```http
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):**
```json
{
"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
```http
GET /news/saved
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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
```http
DELETE /news/saved/{saved_article_id}
Authorization: Bearer YOUR_ACCESS_TOKEN
```
**Response (200 OK):**
```json
{
"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**
```bash
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)**
```bash
curl -X POST /api/admet/predict \\
-H "Authorization: Bearer {token}" \\
-F "file=@/path/to/file.csv"
```
**Response (200 OK):**
```json
{
"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:**
```bash
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):**
```json
{
"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:**
```bash
curl -X GET /api/ai/generation/status/gen_20260602_174612_90c1b1 \\
-H "Authorization: Bearer {token}"
```
**Response (200 OK):**
```json
{
"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:**
```bash
curl -X GET /api/ai/generation/jobs/gen_20260602_174612_90c1b1/results \\
-H "Authorization: Bearer {token}"
```
**Response (200 OK):**
```json
{
"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:**
```bash
curl -X POST http://localhost:8080/api/ai/generation/jobs/{job_id}/cancel \
-H "Authorization: Bearer {token}"
```
**Response: Status:Completed**
```json
{
"success": false,
"message": "Cannot cancel a completed job",
"data": null
}
```
**Response: Status:No Completed**
```json
{
"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:**
```bash
curl -X GET http://localhost:8080/api/ai/generation/history \
-H "Authorization: Bearer {token}"
```
**Response:**
```json
{
"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:**
```bash
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:**
```json
{
"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:**
```bash
curl -X GET http://localhost:8080/api/ai/files/lig_20260602_181751_0227c4/ligand_3d.pdbqt \
-H "Authorization: Bearer {token}"
```
**Response:**
```pdbqt
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:**
```bash
curl -X GET http://127.0.0.1:8000/api/ai/files/gen_20260602_185419_15fc7b/generated_results.csv \
-H "Authorization: Bearer {token}"
```
**Response:**
```csv
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:**
```bash
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):**
```json
{
"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):**
```json
{
"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):**
```json
{
"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):**
```json
{
"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:**
```bash
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):**
```json
{
"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):**
```json
{
"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:
```json
{
"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
```http
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:
```http
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):
```json
{
"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
```bash
#!/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
```python
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
```javascript
// 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
```bash
#!/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
```dart
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:
1. **Check Logs:** `docker compose logs -f laravel`
2. **Test Endpoint:** Use provided curl examples
3. **Version:** Confirm you're using latest API version
4. **Rate Limits:** Check `X-RateLimit-*` headers
5. **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)}")