Check molecules against regulatory PFAS definitions (OECD, EU, OPPT, UK, PFASTRUCTv5)
Open CheckerUpload CSV/XLSX of masses; compare to PFAS dataset under data/
Explore ZeroPM database: 6,513 PFAS uses, 966 functions, and 3,389 alternatives
Open ExplorerContribute to the database by submitting new PFAS uses, functions, or alternatives
Submit DataTest custom PFAS groups SMARTS patterns on molecule datasets with validation and review interface
Open SMARTS TesterRun built-in example and counter-example tests for all PFAS groups and inspect detailed diagnostics.
Open Group ValidatorGET /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
To ensure fair usage and server stability, the following rate limits apply per IP address:
๐ก Rate limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) are included in all API responses.
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']})")
# 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")
# 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'])}")
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 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))
# 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") }
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 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 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
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 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 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"
# 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)" }
# 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
Use the /analyze-batch endpoint with a list of SMILES strings to identify which structures match PFAS groups.
Typical workflow:
/analyze-batchUse the /alternatives-db/ endpoints to explore PFAS uses and their alternatives.
Example query:
/alternatives-db/pfas to get all PFAS uses/alternatives-db/alternatives with same filtersUse the /ms-screening endpoint or web interface to match experimental masses against a PFAS database.
Features:
All endpoints return JSON data that can be easily integrated into Python/R/etc. workflows.
Integration tips:
Content-Type: application/json/analyze-batch)