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.

  1. Fetch metadata and catalog; display 77 selectable targets and the current price.
  2. Offer a searchable target selector with exact IDs; show selected target count, molecule count, planned requests and total estimated credits.
  3. Validate strings, duplicates, extra fields and request limits before submission.
  4. Persist one key per batch and submit batches sequentially.
  5. Display classification probability/class separately from regression values; retain target IDs and original input mapping when combining batches.
  6. Show invalid-input errors beside accepted predictions and update the wallet.
  7. 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.

77 of 77 targets
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.