Automation

API quickstart

Discover a service, submit one job, and monitor it without duplicate submissions.

On this pageDiscover the contract firstSubmit once and preserve the IDMonitor the existing jobInspect the file listing

This example submits one DiffDock-L job, records its ID, polls for a bounded period, and lists available outputs. It requires a receptor PDB and a ligand CSV matching the service’s current form.

Discover the contract first

Read Authentication, install Python’s requests package, and make NEUROSNAP_API_KEY available in your environment. Open DiffDock-L and inspect its generated API example and current limits.

GET /api/services provides service metadata, including form sections. Each field wrapper describes its type, field, and optional status. Use exact field titles; names from another model are not interchangeable.

Prepare receptor.pdb and a valid molecules.csv. A molecule CSV uses the columns shown below; replace the example row with the ligand you intend to dock.

name,type,value
Ligand,smiles,CCO

Ethanol is a simple encoding example, not a proposed active ligand. Use a scientifically appropriate compound for a meaningful docking experiment. See Docking and screening.

Submit once and preserve the ID

The following code creates a billable job. Inspect your inputs and estimate before running it. It deliberately has no automatic submission retry.

import os
from pathlib import Path
from urllib.parse import quote
import requests

base = "https://neurosnap.ai"
headers = {"X-API-KEY": os.environ["NEUROSNAP_API_KEY"]}
service = quote("DiffDock-L", safe="")

with open("receptor.pdb", "rb") as receptor, open("molecules.csv", "rb") as ligand:
    response = requests.post(
        f"{base}/api/job/submit/{service}",
        headers=headers,
        params={"note": "API docking pilot"},
        data={"Number Samples": "50"},
        files=[
            ("Input Receptor", ("receptor.pdb", receptor, "chemical/x-pdb")),
            ("Input Ligand", ("molecules.csv", ligand, "text/csv")),
        ],
        timeout=120,
    )
response.raise_for_status()
job_id = response.json()  # A JSON string, not an object containing an ID field.
Path("job_id.txt").write_text(job_id + "\n")
print("Created job:", job_id)

Let requests generate the multipart Content-Type and boundary. A list of upload tuples preserves repeated field names. For a multipart field accepting multiple files, repeat that exact title for each file.

If the request times out before you receive an ID, inspect your job history and note before trying again. Do not rerun the submission block just to check progress.

Monitor the existing job

Run this separately using the saved ID. The loop stops after ten minutes; a still-running job remains available for later monitoring.

import time

job_id = Path("job_id.txt").read_text().strip()
for attempt in range(60):
    response = requests.get(
        f"{base}/api/job/status/{job_id}", headers=headers, timeout=30
    )
    response.raise_for_status()
    status = response.json()  # "pending", "running", "completed", etc.
    print(status)
    if status in {"completed", "failed", "cancelled", "deleted"}:
        break
    time.sleep(10)
else:
    print("Monitoring window ended; keep this job ID and check again later.")

Inspect the file listing

After completion, request the configuration and file listing:

response = requests.get(
    f"{base}/api/job/data/{job_id}", headers=headers, timeout=30
)
response.raise_for_status()
result = response.json()
print(result["out"])  # Rows of [filename, human-readable size].

Download files using the file endpoint, then inspect poses and native metrics. Completion and an attractive pose score do not establish binding or efficacy.

Search documentation