> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kallima.bio/llms.txt
> Use this file to discover all available pages before exploring further.

# Structure prediction

> Predict a 3D antibody structure from sequence and download the PDB.

Kallima runs [ImmuneBuilder](https://github.com/oxpig/ImmuneBuilder) on the variable region of your variant. mAbs use **ABodyBuilder2**; nanobodies (no VL chain) use **NanoBodyBuilder2**. The job takes 1–3 minutes and costs 5 credits.

## Submit a job

```python theme={null}
from kallima import KallimaClient

client = KallimaClient(api_key)

job = client.structure_predictions.submit(variant_id=variant_id)
job.wait(timeout=300)
```

## Read the result

```python theme={null}
result = job.results  # dict, populated when status == "completed"

print(result["model_used"])        # ABodyBuilder2 | NanoBodyBuilder2
print(result["confidence_score"])  # mean per-residue pLDDT, e.g. 0.87
```

`confidence_score` is the mean per-residue pLDDT across the full predicted structure. Values above \~0.85 are well-predicted; values below \~0.60 in a loop indicate structural uncertainty.

### CDR loop analysis

```python theme={null}
for loop in result["cdr_analysis"] or []:
    print(loop["name"], loop["loop_length"], loop["mean_plddt"])
```

`cdr_analysis` is a list of dicts — one per CDR loop — containing the loop label (`name`, e.g. `H3`), residue count (`loop_length`), geometry, and mean pLDDT.

## Download the PDB

`pdb_url` is a signed URL that expires **1 hour** after the job completes. It is only populated on `GET /v1/structure-predictions/{id}` — list responses omit it.

```python theme={null}
import httpx

# job.results["pdb_url"] is already present when fetched via get() or wait()
pdb_url = job.results["pdb_url"]
pdb_bytes = httpx.get(pdb_url).content

with open("structure.pdb", "wb") as f:
    f.write(pdb_bytes)
```

If the URL has expired, re-fetch the job to rotate it:

```python theme={null}
job = client.structure_predictions.get(job.id)
pdb_url = job.results["pdb_url"]
```

## Cancel a pending job

```python theme={null}
client.structure_predictions.cancel(job.id)
```

Only works while the job is `pending`. Returns `409` if it has already started running.

## List prior predictions for a variant

```python theme={null}
for job in client.structure_predictions.list(variant_id=variant_id):
    print(job.id, job.status, job["created_at"])
```

List responses do not include `pdb_url`. Fetch by ID to get the signed download URL.
