The VectaBind REST API lets you score compound libraries against 473 disease targets programmatically. Integrate binding affinity predictions directly into your drug discovery pipeline — or use the interactive app for Hit Triage Workbench (CSV upload, indication panels, multi-target selectivity heatmaps) with no code.
https://api.vectabind.com ·
Model: Stage6 SE(3)-EGNN + ESM2-3B ·
MAE: 0.20 pKd
Get your first prediction in under a minute. Get a free API key (instant email), then:
# Score a compound against EGFR
curl -X POST https://api.vectabind.com/score \
-H "Content-Type: application/json" \
-H "X-API-Key: vb_your_key_here" \
-d '{"smiles": ["CC(=O)Nc1ccc(O)cc1"], "protein_id": "egfr"}'
{
"protein_id": "egfr",
"results": [
{
"rank": 1,
"smiles": "CC(=O)Nc1ccc(O)cc1",
"affinity": 6.84,
"bind_prob": 0.73,
"mw": 151.2,
"logp": 1.35,
"qed": 0.72,
"lipinski_ok": true,
"drug_like": true
}
],
"n_valid": 1,
"n_total": 1
}
affinity is the predicted pKd value (higher = tighter binding). bind_prob is the probability the compound is an active binder (0–1). Batch responses also include mw, logp, qed, lipinski_ok, and drug_like for med-chem triage.
All requests require an API key passed in the X-API-Key header:
-H "X-API-Key: vb_your_key_here"
# Or as a Bearer token
-H "Authorization: Bearer vb_your_key_here"
API keys are prefixed with vb_. Keep your key secret — it controls your monthly quota. Email us to rotate a compromised key.
| Tier | Monthly limit | Targets | Docking | Batch size |
|---|---|---|---|---|
| Free | 500 scores | 70+ targets | ✗ | 10 |
| Pro | 50,000 scores | All 473 | ✓ | 1,000 |
| Enterprise | Unlimited | All 473 + custom | ✓ | 10,000 |
When you exceed your limit you'll receive a 429 response with your current usage and limit. Usage resets on the 1st of each month.
Score one or more compounds against a protein target. Returns predicted pKd and binding probability for each valid SMILES.
| Parameter | Type | Required | Description |
|---|---|---|---|
| smiles | string[] | required | Array of SMILES strings to score |
| protein_id | string | optional | Target protein ID (default: 10gs). Use GET /proteins for full list. |
import requests
response = requests.post(
"https://api.vectabind.com/score",
headers={"X-API-Key": "vb_your_key"},
json={
"smiles": [
"CCCOc1cc(N2CCC(Oc3ccc(C(C)NC(=O)c4cnn(C)c4)cc3)C2)ccn1",
"COC1=CC=C(CC2=CN=C(NC3=NC=C(F)C=C3)S2)C=C1",
],
"protein_id": "egfr"
}
)
for result in response.json()["results"]:
print(f"pKd: {result['affinity']:.2f} Bind: {result['bind_prob']:.0%} {result['smiles'][:40]}")
Get full drug-like properties, VectaBind scoring, and ChEMBL similarity for a single compound.
| Parameter | Type | Required | Description |
|---|---|---|---|
| smiles | string | required | Single SMILES string |
| protein_id | string | optional | Target protein ID |
| chembl_lookup | boolean | optional | Include ChEMBL similarity search (default: true) |
Returns the full list of available protein targets with their IDs.
curl https://api.vectabind.com/proteins \
-H "X-API-Key: vb_your_key"
# Response
{"proteins": ["10gs", "11gs", "egfr", ...], "count": 19509}
Returns scoreable targets with gene symbols, PDB IDs, and disease-indication groupings. pdb_id is the production scoring pocket (e.g. EGFR → 2ITK). Powers the app's indication filter and multi-target selectivity panel.
curl https://api.vectabind.com/targets \
-H "X-API-Key: vb_your_key"
# Response (abbreviated)
{
"targets": [
{"name": "egfr", "gene": "EGFR", "pdb_id": "2itk", "disease": "oncology_lung"}
],
"disease_groups": [
{"id": "hematology", "label": "AML / Leukemia / Lymphoma", "targets": ["flt3", "jak2", "btk", ...]}
]
}
Returns your API tier, monthly usage, and batch size limit. The app displays this as the usage meter (42 / 500 scores · batch 10). The Hit Triage Workbench uses this batch size to chunk library runs — up to 1,000 compounds per score in the browser.
curl https://api.vectabind.com/me \
-H "X-API-Key: vb_your_key"
# Response
{"tier": "free", "usage_this_month": 42, "monthly_limit": 500, "batch_size": 10}
Run GNINA docking to get a 3D binding pose and CNN-scored affinity. Pro/Enterprise only.
| Parameter | Type | Required | Description |
|---|---|---|---|
| smiles | string | required | SMILES of compound to dock |
| protein_id | string | required | Target protein ID |
Launch a REINVENT4 generative chemistry job to design novel molecules optimized for a target. Returns a job ID for polling.
| Parameter | Type | Required | Description |
|---|---|---|---|
| protein_id | string | required | Target to optimize for |
| n_steps | integer | optional | RL steps (default: 100, max: 500) |
import requests
import pandas as pd
API_KEY = "vb_your_key"
BASE_URL = "https://api.vectabind.com"
# Load your compound library
df = pd.read_csv("compounds.csv")
smiles_list = df["smiles"].tolist()
# Score in batches of 100
results = []
for i in range(0, len(smiles_list), 100):
batch = smiles_list[i:i+100]
r = requests.post(
f"{BASE_URL}/score",
headers={"X-API-Key": API_KEY},
json={"smiles": batch, "protein_id": "egfr"}
)
results.extend(r.json()["results"])
print(f"Scored {i+len(batch)}/{len(smiles_list)}")
# Sort by affinity and save top hits
results_df = pd.DataFrame(results)
top_hits = results_df.sort_values("affinity", ascending=False).head(50)
top_hits.to_csv("top_hits.csv", index=False)
print(f"Top hit: pKd {top_hits.iloc[0]['affinity']:.2f}")
import requests
import pandas as pd
API_KEY = "vb_your_key"
BASE = "https://api.vectabind.com"
H = {"X-API-Key": API_KEY}
# Load panel from disease group (matches app indication filter)
catalog = requests.get(f"{BASE}/targets", headers=H).json()
hem = next(g for g in catalog["disease_groups"] if g["id"] == "hematology")
targets = hem["targets"]
df = pd.read_csv("library.csv")
smiles = df["smiles"].tolist()
rows = []
for target in targets:
for i in range(0, len(smiles), 10):
batch = smiles[i:i+10]
r = requests.post(f"{BASE}/score", headers=H,
json={"smiles": batch, "protein_id": target})
for hit in r.json()["results"]:
rows.append({"target": target, **hit})
panel = pd.DataFrame(rows)
panel.to_csv("selectivity_panel.csv", index=False)
import requests
API_KEY = "vb_your_key"
TARGETS = ["egfr", "bace1", "jak2", "kras"]
SMILES = "CCCOc1cc(N2CCC(Oc3ccc(C(C)NC(=O)c4cnn(C)c4)cc3)C2)ccn1"
for target in TARGETS:
r = requests.post(
"https://api.vectabind.com/score",
headers={"X-API-Key": API_KEY},
json={"smiles": [SMILES], "protein_id": target}
)
result = r.json()["results"][0]
print(f"{target.upper():8s} pKd: {result['affinity']:.2f} Bind: {result['bind_prob']:.0%}")
# Score a single compound
curl -X POST https://api.vectabind.com/score \
-H "Content-Type: application/json" \
-H "X-API-Key: vb_your_key" \
-d '{"smiles":["CCO"],"protein_id":"egfr"}'
# Get all available proteins
curl https://api.vectabind.com/proteins \
-H "X-API-Key: vb_your_key"
# Full compound details + ChEMBL lookup
curl -X POST https://api.vectabind.com/details \
-H "Content-Type: application/json" \
-H "X-API-Key: vb_your_key" \
-d '{"smiles":"CCO","protein_id":"egfr","chembl_lookup":true}'
library(httr)
library(jsonlite)
api_key <- "vb_your_key"
response <- POST(
"https://api.vectabind.com/score",
add_headers("X-API-Key" = api_key),
content_type_json(),
body = toJSON(list(
smiles = c("CC(=O)Nc1ccc(O)cc1", "CCO"),
protein_id = "egfr"
), auto_unbox = TRUE)
)
results <- fromJSON(content(response, "text"))$results
print(results[, c("smiles", "affinity", "bind_prob", "confidence")])
catalog <- fromJSON(content(GET(
"https://api.vectabind.com/targets",
add_headers("X-API-Key" = api_key)
), "text"))
targets <- catalog$disease_groups[[which(sapply(catalog$disease_groups, function(g) g$id) == "hematology")]]$targets
smiles <- read.csv("library.csv")$smiles
for (target in targets) {
r <- POST("https://api.vectabind.com/score",
add_headers("X-API-Key" = api_key),
content_type_json(),
body = toJSON(list(smiles = smiles, protein_id = target), auto_unbox = TRUE))
print(target, nrow(fromJSON(content(r, "text"))$results))
}
# pip install requests pandas matplotlib
import requests, pandas as pd, matplotlib.pyplot as plt
API_KEY = "vb_your_key"
df = pd.read_csv("library.csv")
r = requests.post("https://api.vectabind.com/score",
headers={"X-API-Key": API_KEY},
json={"smiles": df.smiles.tolist(), "protein_id": "egfr"})
res = pd.DataFrame(r.json()["results"])
res = res.merge(df, on="smiles", how="left")
plt.scatter(res.logp, res.affinity, c=res.confidence.map({"high":"C0","medium":"C1","low":"C2"}))
plt.xlabel("LogP"); plt.ylabel("pKd"); plt.title("SAR view — EGFR"); plt.show()
VectaBind works best as a fast filter early in your pipeline — before expensive docking or synthesis:
import requests
def vectabind_filter(smiles_list, target, min_pkd=6.0, min_bind=0.6, api_key=""):
"""Filter compounds by predicted binding affinity."""
r = requests.post(
"https://api.vectabind.com/score",
headers={"X-API-Key": api_key},
json={"smiles": smiles_list, "protein_id": target}
)
results = r.json()["results"]
# Keep only predicted binders above threshold
hits = [
res for res in results
if res["affinity"] >= min_pkd
and res["bind_prob"] >= min_bind
]
print(f"Filtered {len(smiles_list)} → {len(hits)} compounds")
return [h["smiles"] for h in hits]
# Example: filter 10k compounds to top predicted binders
# before sending to expensive docking
library = load_your_library() # 10,000 compounds
hits = vectabind_filter( # → ~200-500 hits
library, "egfr",
min_pkd=7.0, min_bind=0.75,
api_key="vb_your_key"
)
# Now dock only the top hits
run_gnina_docking(hits)
Get a free API key and score your first 500 compounds today. No credit card required.