๐Ÿงช PFAS Analysis Tools

๐Ÿ“Š PFAS Analyzer

Analyze molecules for 73 PFAS structural groups

Open Analyzer

๐Ÿ”ฌ Definition Checker

Check molecules against regulatory PFAS definitions (OECD, EU, OPPT, UK, PFASTRUCTv5)

Open Checker

๐Ÿ“„ MS Non-target Screening

Upload CSV/XLSX of masses; compare to PFAS dataset under data/

Open Screening

๐Ÿ”„ PFAS Alternatives Database

Explore ZeroPM database: 6,513 PFAS uses, 966 functions, and 3,389 alternatives

Open Explorer

โž• Submit New Alternative

Contribute to the database by submitting new PFAS uses, functions, or alternatives

Submit Data

๐Ÿงฌ SMARTS Tester

Test custom PFAS groups SMARTS patterns on molecule datasets with validation and review interface

Open SMARTS Tester

โœ… PFAS Group Validator

Run built-in example and counter-example tests for all PFAS groups and inspect detailed diagnostics.

Open Group Validator

๐Ÿ“ก API Endpoints

GET /health POST /analyze POST /analyze-batch POST /check-definitions GET /groups GET /groups/:id GET /definitions POST /ms-screening - Screen uploaded masses/files GET /alternatives-db/pfas - PFAS uses (6,513 entries) GET /alternatives-db/functions - PFAS functions (966 entries) GET /alternatives-db/alternatives - Alternatives (3,389 entries) GET /alternatives-db/all - All sheets combined POST /alternatives-db/submit - Submit new entries for review POST /manager/login - Manager authentication

๐Ÿ›ก๏ธ API Rate Limits

To ensure fair usage and server stability, the following rate limits apply per IP address:

  • General API endpoints 100/15min
    Applies to: GET /groups, /definitions, /alternatives-db/*
  • Analysis endpoints 20/15min
    Applies to: POST /analyze, /check-definitions, /ms-screening
  • Batch processing 5/15min
    Applies to: POST /analyze-batch

๐Ÿ’ก Rate limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) are included in all API responses.

๐Ÿ“– API Usage Examples

Analyze a Molecule (Python)

Python
import requests
import json

# Analyze a single PFAS molecule
url = "http://localhost:3000/analyze"
payload = {
    "input": "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)O",
    "inputType": "smiles"
}

response = requests.post(url, json=payload)
result = response.json()

print(f"Matches found: {len(result['matches'])}")
for match in result['matches']:
    print(f"  - {match['name']} ({match['alias']})")

Batch Analysis (Python)

Python
# Analyze multiple molecules at once
url = "http://localhost:3000/analyze-batch"
payload = {
    "molecules": [
        {"smiles": "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)O"},
        {"smiles": "FC(F)(F)S(=O)(=O)O"}
    ]
}

response = requests.post(url, json=payload)
results = response.json()

for i, result in enumerate(results['results']):
    print(f"Molecule {i+1}: {len(result['matches'])} matches")

Get PFAS Groups (Python)

Python
# Fetch all PFAS groups
response = requests.get("http://localhost:3000/groups")
groups = response.json()
print(f"Total groups: {len(groups)}")

# Get alternatives database
response = requests.get("http://localhost:3000/alternatives-db/all")
db = response.json()
print(f"PFAS uses: {len(db['pfas'])}")
print(f"Functions: {len(db['functions'])}")
print(f"Alternatives: {len(db['alternatives'])}")

Analyze a Molecule (R)

R
library(httr)
library(jsonlite)

# Analyze a single PFAS molecule
url <- "http://localhost:3000/analyze"
payload <- list(
  input = "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)O",
  inputType = "smiles"
)

response <- POST(url, 
                 body = payload, 
                 encode = "json",
                 content_type_json())

result <- content(response, "parsed")
cat("Matches found:", length(result$matches), "\n")

for (match in result$matches) {
  cat("  -", match$name, "(", match$alias, ")\n")
}

Get Data and Convert to DataFrame (R)

R
# Get PFAS groups as data frame
groups_response <- GET("http://localhost:3000/groups")
groups_df <- fromJSON(content(groups_response, "text"))
print(head(groups_df))

# Get alternatives database
alt_response <- GET("http://localhost:3000/alternatives-db/pfas")
pfas_df <- fromJSON(content(alt_response, "text"))
cat("PFAS uses loaded:", nrow(pfas_df), "\n")

# Filter and analyze
pharma_pfas <- pfas_df[grep("pharmaceutical", 
                            pfas_df$'Use categories', 
                            ignore.case = TRUE), ]
print(nrow(pharma_pfas))

Batch Processing with Data Frame (R)

R
# Prepare batch of SMILES
smiles_list <- list(
  list(smiles = "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)O"),
  list(smiles = "FC(F)(F)S(=O)(=O)O")
)

response <- POST("http://localhost:3000/analyze-batch",
                 body = list(molecules = smiles_list),
                 encode = "json")

results <- content(response, "parsed")
for (i in seq_along(results$results)) {
  cat("Molecule", i, ":", 
      length(results$results[[i]]$matches), 
      "matches\n")
}

Analyze a Molecule (cURL - Linux/Mac)

Bash
curl -X POST http://localhost:3000/analyze \
  -H "Content-Type: application/json" \
  -d '{
    "input": "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)O",
    "inputType": "smiles"
  }'

Get PFAS Groups (cURL)

Bash
# Get all groups
curl http://localhost:3000/groups

# Get specific group by ID
curl http://localhost:3000/groups/1

# Save to file
curl http://localhost:3000/groups -o pfas_groups.json

# Pretty print with jq
curl -s http://localhost:3000/groups | jq '.[0]'

Get Alternatives Database (cURL)

Bash
# Get PFAS uses
curl http://localhost:3000/alternatives-db/pfas -o pfas_uses.json

# Get functions
curl http://localhost:3000/alternatives-db/functions -o functions.json

# Get alternatives
curl http://localhost:3000/alternatives-db/alternatives -o alternatives.json

# Get all data combined
curl http://localhost:3000/alternatives-db/all -o full_database.json

Batch Analysis (cURL)

Bash
curl -X POST http://localhost:3000/analyze-batch \
  -H "Content-Type: application/json" \
  -d '{
    "molecules": [
      {"smiles": "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)O"},
      {"smiles": "FC(F)(F)S(=O)(=O)O"}
    ]
  }' | jq '.'

Analyze a Molecule (PowerShell)

PowerShell
# Analyze a single PFAS molecule
$url = "http://localhost:3000/analyze"
$body = @{
    input = "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)C(F)(F)O"
    inputType = "smiles"
} | ConvertTo-Json

$response = Invoke-RestMethod -Uri $url `
    -Method Post `
    -Body $body `
    -ContentType "application/json"

Write-Host "Matches found: $($response.matches.Count)"
$response.matches | ForEach-Object {
    Write-Host "  - $($_.name) ($($_.alias))"
}

Get and Save Data (PowerShell)

PowerShell
# Get PFAS groups
$groups = Invoke-RestMethod -Uri "http://localhost:3000/groups"
Write-Host "Total groups: $($groups.Count)"

# Save to file
$groups | ConvertTo-Json -Depth 10 | Out-File "pfas_groups.json"

# Get alternatives database
$db = Invoke-RestMethod -Uri "http://localhost:3000/alternatives-db/all"
Write-Host "PFAS uses: $($db.pfas.Count)"
Write-Host "Functions: $($db.functions.Count)"
Write-Host "Alternatives: $($db.alternatives.Count)"

# Save each sheet
$db.pfas | ConvertTo-Json | Out-File "pfas_uses.json"
$db.alternatives | ConvertTo-Json | Out-File "alternatives.json"

Batch Processing (PowerShell)

PowerShell
# Prepare batch payload
$molecules = @(
    @{ smiles = "FC(F)(F)C(F)(F)C(F)(F)C(F)(F)O" }
    @{ smiles = "FC(F)(F)S(=O)(=O)O" }
)

$body = @{
    molecules = $molecules
} | ConvertTo-Json -Depth 5

$response = Invoke-RestMethod `
    -Uri "http://localhost:3000/analyze-batch" `
    -Method Post `
    -Body $body `
    -ContentType "application/json"

$response.results | ForEach-Object {
    Write-Host "Matches: $($_.matches.Count)"
}

Filter and Export (PowerShell)

PowerShell
# Get PFAS uses and filter
$pfasUses = Invoke-RestMethod -Uri "http://localhost:3000/alternatives-db/pfas"

# Filter pharmaceutical uses
$pharma = $pfasUses | Where-Object { 
    $_.'Use categories' -like "*pharmaceutical*" 
}
Write-Host "Pharmaceutical PFAS: $($pharma.Count)"

# Export to CSV
$pharma | Export-Csv "pharmaceutical_pfas.csv" -NoTypeInformation

๐Ÿ“š Common Use Cases

๐Ÿ” Screen a list of SMILES for PFAS classification

Use the /analyze-batch endpoint with a list of SMILES strings to identify which structures match PFAS groups.

Typical workflow:

  1. Prepare your SMILES in a JSON array
  2. POST to /analyze-batch
  3. Parse results to extract matched PFAS groups
  4. Export to CSV/Excel for further analysis
๐Ÿญ Find alternatives for specific PFAS applications

Use the /alternatives-db/ endpoints to explore PFAS uses and their alternatives.

Example query:

  1. GET /alternatives-db/pfas to get all PFAS uses
  2. Filter by "Use categories" or "applications"
  3. GET /alternatives-db/alternatives with same filters
  4. Compare PFAS substances with their alternatives
โš—๏ธ Mass spectrometry non-target screening

Use the /ms-screening endpoint or web interface to match experimental masses against a PFAS database.

Features:

  • Exact mass matching with PPM tolerance
  • Homologue series detection (CFโ‚‚/CFH variations)
  • Multiple adduct modes ([M-H]โป, [M+H]โบ, etc.)
  • Optional PFAS group computation for matches
๐Ÿ“Š Integrate with data analysis pipelines

All endpoints return JSON data that can be easily integrated into Python/R/etc. workflows.

Integration tips:

  • Use batch endpoints for processing large datasets efficiently
  • Cache PFAS groups data locally to reduce API calls
  • Combine with other cheminformatics tools (RDKit, OpenBabel)
  • Export results to databases or visualization tools

โš ๏ธ Notes

  • Server runs on http://localhost:3000 by default
  • All POST endpoints expect Content-Type: application/json
  • SMILES, InChI, and Molblock formats supported for molecule input
  • Batch processing recommended for >10 molecules (use /analyze-batch)
  • Alternatives database is cached in memory for fast access
  • Custom PFAS groups can be provided via request body
Climate Responsible Hosting: This web application is hosted on Infomaniak servers powered by 100% local renewable energy (60% hydrolic power and 40% solar and other green power). The data center recovers and redistributs its waste heat to neighboring households.
๐Ÿ” Manager Login