ADMET API guide: all 77 prediction targets
Live base URL: https://gitlabnsclbio.jbnu.ac.kr
Model: C1 · 77 targets: 59 binary classification + 18 regression
Paid price: 5 credits per successful request, not per target or molecule.
There is one prediction HTTP route with 77 selectable model targets. The JSON
field endpoints contains target IDs such as BBB, BCF and logP; those names
are not separate URLs. Do not construct a URL such as /predict/BBB.
Full target catalog · Quick start · All 77 workflow · Responses · Errors and retries · Backend Swagger · Direct Swagger
Choose the correct route
All paths below are relative to the live base URL.
| Method and route | Authentication | Credits and saved history | Purpose |
|---|---|---|---|
GET /api/services/admet/metadata |
Bearer token | Free; no run created | Release target list, limits, revision and active flag |
POST /api/services/admet/predict |
Bearer token + Idempotency-Key | 5 credits; saved run | Frontend/platform prediction |
GET /api/services |
Bearer token | Free | Find ADMET_PREDICT, price and availability |
GET /api/runs?service_code=ADMET_PREDICT |
Bearer token | Free | Current user's ADMET history |
GET /api/runs/{run_id} |
Bearer token | Free | Saved inputs, status and result |
GET /admet/health |
None | No billing/history | Live model readiness: 200 or 503 |
GET /admet/metadata |
None | No billing/history | Model target list and limits |
POST /admet/predict |
None | Bypasses backend billing/history | Direct inference; same input limits |
GET /admet/docs |
None | No inference | Interactive direct API reference |
Direct access remains available by policy. Use the /api/services/ route when
accounts, billing, replay protection and user history are required. Metadata is
a release contract; its active flag does not replace a live GPU-health check.
Quick start
Set TOKEN to an existing active user's access token. These commands are Bash;
JSON examples contain real accepted target IDs. Do not literally send the token
placeholder. A paid prediction below spends five credits if successful.
BASE='https://gitlabnsclbio.jbnu.ac.kr'
TOKEN='YOUR_ACCESS_TOKEN'
# Free: available targets and current release limits.
curl --fail-with-body "$BASE/api/services/admet/metadata" \
-H "Authorization: Bearer $TOKEN"
# Generate ONCE for this logical batch. Keep it for retries of this exact batch.
KEY="$(python -c 'import uuid; print(uuid.uuid4())')"
curl --fail-with-body --max-time 330 "$BASE/api/services/admet/predict" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $KEY" \
-H 'Content-Type: application/json' \
--data '{"smiles":["CCO"],"endpoints":["BBB","BCF"]}'
For direct inference, use the same JSON with POST /admet/predict and omit the
bearer and idempotency headers. The direct response is the prediction object
itself; it has no run_id or billing wrapper and no gateway replay guarantee.
Request contract and limits
{"smiles":["CCO","CCN"],"endpoints":["BBB","BCF","logP"]}
This example requests six predictions (two molecules × three targets) and costs five credits through the backend. Choose targets from the exact catalog below.
| Field or limit | Rule |
|---|---|
smiles |
Required array of 1–4 nonempty strings; distinct after whitespace trimming |
endpoints |
Required array of 1–8 distinct, case-sensitive target IDs |
| SMILES length | At most 1,024 characters per string |
| Molecule size | At most 128 atoms per molecule |
| Model token length | At most 128 tokenizer tokens; not the same as characters or atoms |
| Request body | At most 65,536 bytes (64 KiB) |
| Work per request | At most 32 molecule/target pairs |
| Extra JSON fields | Rejected |
| Paid retry key | Required Idempotency-Key, 1–200 characters; use a UUID |
| Upstream deadline | 300 seconds; a client timeout does not cancel GPU inference reliably |
| Upstream result size | At most 10 MiB |
| Concurrency | One admitted inference request; concurrent requests may return 429 immediately |
Atom/token validation runs in the model service. Oversized molecules are
reported as invalid inputs, never silently truncated. The model consumes the
trimmed original SMILES; canonical_smiles is returned separately. Distinct
strings are checked for duplication; chemically equivalent alternative SMILES
are not deduplicated by the API.
Requesting all 77 targets
For one to four molecules, split the target list into 10 sequential requests: nine groups of eight and a final group of five. Ten successful paid requests cost 50 credits total, including when all four molecules are used. A complete four-molecule run produces 308 predictions across those ten requests. There is no single all-77 request, asynchronous job endpoint, or automatic server-side fan-out. Each batch creates its own saved run. Five to eight molecules require a second molecule group and therefore 20 successful requests / 100 credits.
A general estimate is 5 × ceil(molecule_count / 4) × ceil(target_count / 8)
credits when every batch succeeds. An invalid-only batch refunds; a mixed-validity
successful batch still costs five credits. Requests that finish with unknown
outcome retain their debit pending reconciliation.
The frontend should create and persist the batch plan before sending requests.
Keep each batch's JSON, idempotency key, status and returned run ID. Do not use
Promise.all: the GPU service admits one request at a time. Resume completed
batches from saved results and stop on an error to apply the retry rules below.
const apiBase = "https://gitlabnsclbio.jbnu.ac.kr/api";
async function createAllTargetsPlan(token, smiles) {
if (smiles.length < 1 || smiles.length > 4) {
throw new Error("This plan supports one to four molecules.");
}
const response = await fetch(`${apiBase}/services/admet/metadata`, {
headers: { Authorization: `Bearer ${token}` }
});
const metadata = await response.json();
if (!response.ok || !metadata.active) throw new Error("ADMET is unavailable.");
const targets = metadata.available_endpoints.map(item => item.name);
const batches = [];
for (let i = 0; i < targets.length; i += 8) {
batches.push({
key: crypto.randomUUID(),
request: { smiles: [...smiles], endpoints: targets.slice(i, i + 8) },
response: null
});
}
return { estimatedCredits: batches.length * 5, batches };
}
async function submitBatch(token, batch) {
const response = await fetch(`${apiBase}/services/admet/predict`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
"Idempotency-Key": batch.key
},
body: JSON.stringify(batch.request)
});
const data = await response.json();
if (!response.ok) {
const error = new Error(data.detail?.message || `HTTP ${response.status}`);
Object.assign(error, {
status: response.status, code: data.detail?.code,
retryAfter: response.headers.get("Retry-After"),
runId: response.headers.get("X-Run-ID")
});
throw error; // Stop; resolve the specific outcome before sending more work.
}
batch.response = data;
return data;
}
createAllTargetsPlan only reads metadata; it does not spend credits. Display the
estimated cost and obtain the user's submission action before calling
submitBatch. Persist the plan outside these functions, then call submitBatch
for each unfinished batch in sequence, saving each response before moving on.
Reuse an unfinished batch's existing key for an exact replay check. Only replace
that key after the API confirms the previous attempt was refunded.
Response contract
The paid response has three top-level fields: run_id, billing, and result.
The example below uses a live direct result captured on 2026-11-13; wrapper IDs
and billing fields illustrate a first successful request from a 100-credit wallet.
Do not use its numeric values as a scientific regression fixture.
{
"run_id": "00000000-0000-4000-8000-000000000001",
"billing": {
"user_id": 123,
"spent": 5,
"balance": 95,
"service_code": "ADMET_PREDICT",
"ref_id": "illustrative-billing-reference",
"idempotency_replayed": false
},
"result": {
"model_version": "C1",
"artifact_revision": "6c5e3da13596b4b4fb27094351c385655ddd2d72ee2d116445333f6c0e99f83d",
"predictions": [
{
"input_index": 0,
"smiles": "CCO",
"canonical_smiles": "CCO",
"endpoint": "BBB",
"task_type": "binary_classification",
"probability": 0.9521309733390808,
"predicted_class": 1,
"predicted_value": null
},
{
"input_index": 0,
"smiles": "CCO",
"canonical_smiles": "CCO",
"endpoint": "BCF",
"task_type": "regression",
"probability": null,
"predicted_class": null,
"predicted_value": 0.5704332590103149
}
],
"errors": []
}
}
| Field | Meaning |
|---|---|
run_id |
Identifier for GET /api/runs/{run_id}; store it immediately |
billing.spent |
Operation price; may still be 5 on a replay, which is not a second charge |
billing.balance |
Balance returned with billing; use /api/wallet/me to refresh current wallet state |
billing.idempotency_replayed |
true means the saved result was reused without another inference/debit |
billing.ref_id |
Billing reference; retain for support/reconciliation |
result.model_version |
C1 |
result.artifact_revision |
SHA-256 revision identifying the model artifact inventory; preserve with results |
predictions[].input_index |
Zero-based index into this request's smiles array, not a global batch-plan index |
smiles, canonical_smiles |
Submitted trimmed string and canonical representation |
endpoint, task_type |
Exact requested target ID; binary_classification or regression |
probability, predicted_class |
Classification: finite probability in [0,1] and class 0/1; predicted_value is null |
predicted_value |
Regression: finite de-normalized value; probability/class fields are null |
errors |
Invalid-input list; empty on a fully valid batch |
Join rows using (input_index, endpoint), not array position. Every accepted
molecule has exactly one row for every requested target. All outputs are fused
predictions; auxiliary graph/language-model heads are not returned.
Classification uses a target-specific threshold, not always 0.5. Use the
returned predicted_class. Label 1 means the model's positive class for that
particular target; it does not universally mean safe, favorable, or toxic.
The supplied deployment manifest does not define authoritative class semantics,
physical units or log transforms for every target. Regression values are already
de-normalized into the training target scale; do not apply the mean/std again,
convert units, or exponentiate a result based only on its name. Confirm those
scientific interpretations with the model owner.
Mixed valid and invalid molecules
For {"smiles":["CCO","invalid"],"endpoints":["BBB","BCF"]}, a successful
response includes two prediction rows for input_index: 0, plus this error:
{"input_index":1,"smiles":"invalid","error":"Invalid SMILES or atom limit exceeded"}
The errors array is inside result on the paid route and at the root on the
direct route. The mixed batch costs five credits, not a discounted amount.
If every molecule is invalid, there is no successful prediction result: the
paid route returns 400 and refunds its debit. Never convert an error into a
prediction of zero or drop input errors from the UI.
Errors and retries
Backend application errors normally have this shape; parse detail.code rather
than matching human-readable messages. Gateway/proxy body-size responses may
instead contain a simple string detail or a non-JSON body. A client must tolerate
those responses and should stop rather than retry on a JSON parsing error.
{"detail":{"code":"SERVICE_BUSY","message":"ADMET worker is busy; credits refunded","request_id":"example-request-id"}}
| HTTP / code | Billing state | Correct action |
|---|---|---|
| 401 / authentication error | No new debit | Obtain a valid active-user bearer token |
| 402 / insufficient balance | No inference/debit | Fund wallet; retry the same unchanged request/key |
| 413 / body too large | Rejected before model work | Reduce request size; do not retry unchanged |
422 / VALIDATION_ERROR, UNKNOWN_ADMET_ENDPOINT, INVALID_IDEMPOTENCY_KEY |
No debit | Fix payload/key, including case-sensitive target IDs |
400 / INVALID_ADMET_INPUT |
Known failure refunded | Correct SMILES/limits and use a new key |
429 / SERVICE_BUSY |
Known failure refunded | Wait at least Retry-After (currently 5 seconds); submit with a new key |
409 / IDEMPOTENCY_CONFLICT |
No additional debit | Same key was used for different input; use a new key for new work |
409 / IDEMPOTENCY_KEY_REQUIRES_NEW_KEY |
Earlier request refunded | Use a new key if intentionally submitting again |
409 / RUN_IN_PROGRESS |
Existing unresolved run; no additional debit | Check history; do not switch keys to force resubmission |
502 / SERVICE_UNAVAILABLE, UPSTREAM_REJECTED, INVALID_SERVICE_RESULT, SERVICE_REQUEST_FAILED, RESULT_TOO_LARGE |
Known failure automatically refunded unless refund itself fails | Inspect error/history; a new attempt after confirmed refund needs a new key |
503 / SERVICE_DISABLED |
No debit | Disable submission UI; wait for activation |
504 / UPSTREAM_OUTCOME_UNKNOWN |
Debit retained; outcome uncertain | Check run history and reconcile; never automatically submit a new key |
500 / REFUND_FAILED |
Refund not confirmed | Contact support with run/reference/request IDs; do not assume wallet was restored |
| Connection loss / client timeout | Unknown | Reuse the same key for an exact replay check; do not assume cancellation or refund |
A successful exact replay returns HTTP 200, the original run and stored result,
even after a future model update. Preserve the original request, including array
order. The idempotency key is scoped to the authenticated user and operation.
Network cancellation does not prove that model work stopped. Unknown outcomes
can appear as INTERRUPTED in history after their deadline; that status alone
is not proof of a refund. Send run/reference/request IDs to support for reconciliation.
History and frontend checklist
curl --fail-with-body "$BASE/api/runs?service_code=ADMET_PREDICT&limit=20&offset=0" \
-H "Authorization: Bearer $TOKEN"
# Replace RUN_ID with the successful response's run_id.
curl --fail-with-body "$BASE/api/runs/RUN_ID" \
-H "Authorization: Bearer $TOKEN"
History is user-scoped. Another user receives 404 for someone else's run.
List responses contain items, total, limit and offset; list limit is 1–100.
Supported status filters are RUNNING, SUCCEEDED, FAILED and INTERRUPTED.
Fetch the run detail to retrieve its saved result. Ten all-target batches are ten
runs; group them in the frontend's persisted plan.
- Fetch metadata and catalog; display 77 selectable targets and the current price.
- Offer a searchable target selector with exact IDs; show selected target count, molecule count, planned requests and total estimated credits.
- Validate strings, duplicates, extra fields and request limits before submission.
- Persist one key per batch and submit batches sequentially.
- Display classification probability/class separately from regression values; retain target IDs and original input mapping when combining batches.
- Show invalid-input errors beside accepted predictions and update the wallet.
- Save run IDs and support exact replay/history recovery; handle busy, refunded, disabled and unknown-outcome states differently.
Target catalog
These are all 77 exact target IDs from the deployed C1 manifest. Discovery
returns this same set in available_endpoints. Use exact spelling and case,
including punctuation (CL-plasma, logD7.4, NR-AR). Thresholds below are
rounded for display; the server's returned class is authoritative. A dash means
regression, for which no classification threshold applies.
| Target ID | Task type | Classification threshold |
|---|---|---|
A549_Cytotoxicity |
binary_classification |
0.05 |
AMES_Mutagenicity |
binary_classification |
0.69 |
BBB |
binary_classification |
0.94 |
BCF |
regression |
— |
BCRP_inhibitor |
binary_classification |
0.47 |
BSEP_inhibitor |
binary_classification |
0.295 |
CL-plasma |
regression |
— |
CYP1A2_inhibitor |
binary_classification |
0.05 |
CYP1A2_substrate |
binary_classification |
0.72 |
CYP2B6_inhibitor |
binary_classification |
0.4 |
CYP2B6_substrate |
binary_classification |
0.175 |
CYP2C19_inhibitor |
binary_classification |
0.11 |
CYP2C19_substrate |
binary_classification |
0.245 |
CYP2C8_inhibitor |
binary_classification |
0.405 |
CYP2C9_inhibitor |
binary_classification |
0.695 |
CYP2C9_substrate |
binary_classification |
0.595 |
CYP2D6_inhibitor |
binary_classification |
0.485 |
CYP2D6_substrate |
binary_classification |
0.315 |
CYP3A4_inhibitor |
binary_classification |
0.77 |
CYP3A4_substrate |
binary_classification |
0.74 |
Caco-2_Permeability |
regression |
— |
Carcinogenicity |
binary_classification |
0.435 |
DILI |
binary_classification |
0.385 |
Drug-induced_Nephrotoxicity |
binary_classification |
0.51 |
Drug-induced_Neurotoxicity |
binary_classification |
0.32 |
Eye_Corrosion |
binary_classification |
0.155 |
Eye_Irritation |
binary_classification |
0.595 |
F20percent |
binary_classification |
0.56 |
F30percent |
binary_classification |
0.56 |
F50percent |
binary_classification |
0.545 |
FDAMDD |
binary_classification |
0.46 |
Fu |
regression |
— |
Genotoxicity |
binary_classification |
0.365 |
HIA |
binary_classification |
0.05 |
HLM_Stability |
binary_classification |
0.425 |
Hek293_Cytotoxicity |
binary_classification |
0.545 |
Hematotoxicity |
binary_classification |
0.59 |
Human_Hepatotoxicity |
binary_classification |
0.705 |
IGC50 |
regression |
— |
LC50DM |
regression |
— |
LC50FM |
regression |
— |
MDCK_Permeability |
regression |
— |
MRP1_inhibitor |
binary_classification |
0.675 |
NR-AR |
binary_classification |
0.915 |
NR-AR-LBD |
binary_classification |
0.94 |
NR-AhR |
binary_classification |
0.24 |
NR-Aromatase |
binary_classification |
0.765 |
NR-ER |
binary_classification |
0.95 |
NR-ER-LBD |
binary_classification |
0.48 |
NR-PPAR-gamma |
binary_classification |
0.075 |
OATP1B1_Inhibitor |
binary_classification |
0.44 |
OATP1B3_inhibitor |
binary_classification |
0.575 |
Ototoxicity |
binary_classification |
0.855 |
PAMPA |
binary_classification |
0.05 |
PPB |
regression |
— |
Pgp_inhibitor |
binary_classification |
0.615 |
Pgp_substrate |
binary_classification |
0.31 |
ROA |
binary_classification |
0.825 |
RPMI-8226_Immunotoxicity |
binary_classification |
0.195 |
Respiratory |
binary_classification |
0.7 |
SR-ARE |
binary_classification |
0.74 |
SR-ATAD5 |
binary_classification |
0.915 |
SR-HSE |
binary_classification |
0.105 |
SR-MMP |
binary_classification |
0.835 |
SR-p53 |
binary_classification |
0.435 |
Skin_Sensitization |
binary_classification |
0.51 |
T1_2 |
regression |
— |
VDss |
regression |
— |
boiling_point |
regression |
— |
hERG_Blocker |
binary_classification |
0.215 |
hERG_Blocker_10um |
binary_classification |
0.47 |
logD7.4 |
regression |
— |
logP |
regression |
— |
logS |
regression |
— |
melting_point |
regression |
— |
pKa_acidic |
regression |
— |
pKa_basic |
regression |
— |
Catalog artifact revision: 6c5e3da13596b4b4fb27094351c385655ddd2d72ee2d116445333f6c0e99f83d.
Version and validation notes
Model artifacts and returned results carry a revision so clients can distinguish releases. Store that revision with exports; never rewrite an old run with new predictions. Deployment and public billing tests passed. Numerical differences against producer reference predictions are documented separately for the model owner; deployment does not establish scientific equivalence or experimental accuracy. No weights or production precision policy were changed to hide those findings. This guide documents the deployed API contract, not clinical cutoffs or target-specific scientific units.