> This page is for Boltz-2, version 1.8.0.
> For other versions, use one of these documentation indexes:
> - 1.10.0 (Latest) (default): https://docs.nvidia.com/nim/bionemo/boltz2/1.10.0/llms.txt
> - 1.9.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.9.0/llms.txt
> - 1.8.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.8.0/llms.txt
> - 1.7.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.7.0/llms.txt
> - 1.6.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.6.0/llms.txt
> - 1.5.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.5.0/llms.txt
> - 1.4.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.4.0/llms.txt
> - 1.3.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.3.0/llms.txt
> - 1.2.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.2.0/llms.txt
> - 1.1.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.1.0/llms.txt
> - 1.0.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.0.0/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nim/bionemo/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nim/bionemo/_mcp/server.

# Inferencing with the NIM

This documentation provides a comprehensive guide for using the Boltz-2 NIM for protein structure prediction and related tasks.

## Before You Start

Deploy and start the Boltz-2 NIM container before using the API. For prerequisites, NGC authentication, `docker run`, and readiness checks, refer to [Getting Started](/nim/bionemo/boltz2/1.8.0/getting-started).

## NIM API Reference

This documentation contains the API reference for the Boltz-2 NIM.

### OpenAPI Specification

You can download the [complete OpenAPI Specification for the Boltz-2 NIM here](https://docs.api.nvidia.com/nim/reference/mit-boltz2).

### Example Notebooks

Below, we provide example notebooks that demonstrate how to use the Boltz-2 NIM API in various scenarios:

- **Protein-Ligand Covalent Complex Visualization with Mol*Star** - Use Boltz-2 NIM to predict and visualize a protein-ligand covalent complex structure using Mol*Star viewer

    Protein-Ligand Covalent Complex [View](https://nbviewer.org/github/NVIDIA-BioNeMo-blueprints/generative-protein-binder-design/blob/main/examples/boltz2-nim/notebooks/boltz2_nim_protein_ligand_covalent_complex_molstar_visualization.ipynb)

    <Download src="/nim/bionemo/_fern-files/bionemo-nim.docs.buildwithfern.com/42a4068e47a80d3b783f4565b3965100443f829ed80d32c591fcc57cd62aeda7/pages/boltz2/v1.8.0/notebooks/boltz2_nim_protein_ligand_covalent_complex_molstar_visualization.ipynb">Download boltz2_nim_protein_ligand_covalent_complex_molstar_visualization.ipynb</Download>

- **DNA-Protein Complex Visualization with py3Dmol** - Use Boltz-2 NIM to predict and visualize a DNA-Protein complex structure using py3Dmol viewer

    DNA-Protein Complex [View](https://nbviewer.org/github/NVIDIA-BioNeMo-blueprints/generative-protein-binder-design/blob/main/examples/boltz2-nim/notebooks/boltz2_nim_DNA_Protein_Complex_example_py3Dmol.ipynb)

    <Download src="/nim/bionemo/_fern-files/bionemo-nim.docs.buildwithfern.com/770adcd140c484d5df3ab362e6fc8d3c7969543bd0277a72b0b6914481f096fe/pages/boltz2/v1.8.0/notebooks/boltz2_nim_DNA_Protein_Complex_example_py3Dmol.ipynb">Download boltz2_nim_DNA_Protein_Complex_example_py3Dmol.ipynb</Download>

These notebooks provide hands-on examples of:
- Setting up the NIM environment
- Making API calls to the NIM
- Processing and visualizing the results
- Working with different types of molecular structures
- Using various visualization tools

### Predict a Protein Structure

Endpoint path: `/biology/mit/boltz2/predict`

Request type: `post`

#### Input Parameters

- `polymers (list[Polymer])`: Required. A list of polymers (DNA, RNA, or Protein). Minimum 1, maximum 12 polymers allowed. Each polymer contains:
  - `id (string)`: Optional. Unique identifier for the polymer chain. Must contain 1-4 alphanumeric characters. If omitted, the NIM assigns an ID automatically.
  - `molecule_type (string)`: Required. Type of molecule - "dna", "rna", or "protein".
  - `sequence (string)`: Required. The sequence of the polymer. Must be 1-4,096 characters and contain only valid characters for the molecule type. For proteins, valid characters are standard one-letter amino acid codes plus `X` for ambiguous residues. For DNA, use `A`, `T`, `C`, and `G`. For RNA, use `A`, `U`, `C`, and `G`.
  - `cyclic (boolean)`: Optional (default: false). Whether the polymer forms a cyclic structure.
  - `msa (dictionary)`: Optional. Multiple Sequence Alignments for protein molecules only, with a maximum of three database entries. This nested dictionary contains a mapping of database names to alignment formats and records (for example `{"database_1" : {"a3m" : {"format" : "a3m", "alignment" : ">1\nMVNIDIAIAMAI", "rank" : 0}}}`). The alignment format key and the `format` field must use lowercase values from `csv`, `fasta`, `a3m`, or `sto` (case-sensitive). Only `a3m` and `csv` alignments are consumed during inference; `fasta` and `sto` are accepted by the schema but removed during input preparation. The first sequence in each alignment must match the polymer `sequence`. Each alignment record may include an optional `rank` field (default: `-1`).
  - `modifications (list[Modification])`: Optional. Chemical modifications to specific residues in the sequence. Each modification contains:
    - `ccd (string)`: Required. Chemical Component Dictionary (CCD) ID of the modification (1-5 uppercase alphanumeric characters).
    - `position (int)`: Required. The 1-based index of the residue to modify.
  - `structural_templates (list[StructuralTemplate])`: Optional. Up to four structural templates to guide prediction. Structural templates are supported for protein polymers only. Each template contains:
    - `structure (string)`: Required. The structural template content in the specified format.
    - `format (string)`: Optional (default: `cif`). The format of the template structure. Supported formats: `cif` or `pdb`.
    - `name (string)`: Optional. Identifier or name for the template (for example, a PDB ID). Maximum 64 characters; only alphanumeric characters, underscores, and hyphens are supported.
    - `chain_id (string)`: Optional. Chain ID from the template structure, containing 1-4 alphanumeric characters. If omitted, the NIM selects the best-matching chain based on sequence similarity.

- `ligands (list[Ligand])`: Optional (default: empty list). A list of ligands. Maximum 20 ligands allowed. Each ligand contains:
  - `id (string)`: Optional. A chain ID for the ligand. If omitted, the NIM assigns IDs such as `B1`, `B2`, and so on.
  - `ccd (string)`: Optional. Chemical Component Dictionary (CCD) code for the ligand (1-5 uppercase alphanumeric characters). Must be uppercase.
  - `smiles (string)`: Optional. SMILES string representation of the ligand. Either CCD or SMILES must be provided, but not both.
  - `predict_affinity (boolean)`: Optional (default: false). Enable affinity prediction for this ligand. When enabled, the model predicts binding affinity between the protein and this ligand. Only one ligand per request can have `predict_affinity=True`. Duplicate CCD or SMILES values across ligands are not allowed when affinity prediction is enabled.
  - `output_affinity_embedding (boolean)`: Optional (default: false). When enabled together with `predict_affinity` on the same ligand, include 384-dimensional affinity embedding vectors under the ligand's entry in the `affinities` response field.

- `constraints (list[Union[Pocket, Bond]])`: Optional (default: empty list). Optional constraints for the prediction. Can be either:
  - **Bond Constraint**: Specifies atomic bonds between molecules
    - `constraint_type`: "bond"
    - `atoms (list[Atom])`: List of exactly two atoms involved in the bond. Each atom contains:
      - `id (string)`: Required. Chain identifier for the atom.
      - `residue_index (int)`: Required. 1-based index of the residue containing the atom.
      - `atom_name (string)`: Required. Name of the specific atom.
  - **Pocket Constraint**: Defines binding site interactions
    - `constraint_type`: "pocket"
    - `binder (string)`: Required. The ID of the binding ligand. Only one pocket binder is allowed per request.
    - `contacts (list[Contact])`: Required. List of contacts defining the pocket. Each contact contains:
      - `id (string)`: Required. Chain identifier for the polymer contact residue.
      - `residue_index (int)`: Required. 1-based index of the residue in the binding site.

- `recycling_steps (int)`: Optional (default: 3). The number of recycling steps to use for prediction. Range: 1-10.

- `sampling_steps (int)`: Optional (default: 50). The number of sampling steps to use for prediction. Range: 10-1,000.

- `diffusion_samples (int)`: Optional (default: 1). The number of diffusion samples to use for prediction. Range: 1-25.

- `step_scale (float)`: Optional (default: 1.638). Controls the magnitude of change applied at each diffusion sampling step. Larger values can speed up convergence but may reduce coordinate precision; smaller values can improve precision but require more sampling steps. Recommended range: 1.0-2.0. Range: 0.5-5.0.

- `without_potentials (boolean)`: Optional (default: false). Returns the results without potentials.

- `output_format (string)`: Optional (default: "mmcif"). The output format of the returned structure. Currently only "mmcif" is supported.

- `concatenate_msas (boolean)`: Optional (default: false). Concatenate Multiple Sequence Alignments for a polymer into one alignment.

- `sampling_steps_affinity (int)`: Optional (default: 200). The number of sampling steps to use for affinity prediction. Range: 10-1,000. Higher values may improve accuracy but increase runtime. Reduce for faster results.

- `diffusion_samples_affinity (int)`: Optional (default: 5). The number of diffusion samples to use for affinity prediction. Range: 1-10. Higher values may improve reliability but increase runtime. Reduce to 1 for faster results.

- `affinity_mw_correction (boolean)`: Optional (default: false). Enable molecular weight correction for affinity prediction, especially useful for metal-containing ligands.

- `write_full_pae (boolean)`: Optional (default: false). Include the full Predicted Aligned Error (PAE) matrix for each diffusion sample in the `pae` response field. Full matrices scale as O(tokens²) per diffusion sample and can produce very large JSON responses for large complexes.

- `write_full_pde (boolean)`: Optional (default: false). Include the full Predicted Distance Error (PDE) matrix for each diffusion sample in the `pde` response field. Full matrices scale as O(tokens²) per diffusion sample and can produce very large JSON responses for large complexes.

<Note>
PAE and PDE values are expressed in ångströms (Å). Lower values generally indicate higher confidence in the predicted structure or pairwise relationships. Aggregate PDE scores (`complex_pde_scores`, `complex_ipde_scores`) are always returned in the JSON response. Full PAE/PDE matrices are returned only when the corresponding request flags are enabled. Aggregate PAE scores (such as `complex_pae` or `complex_ipae` in Boltz OSS confidence files) are not exposed as separate fields in the NIM JSON API.
</Note>

#### Outputs

- `structures (list[Structure])`: The predicted protein structures. Each structure contains:
  - `structure (string)`: The contents of a single structural prediction in the specified format.
  - `format (string)`: The format of the structure record (currently "mmcif").
  - `name (string)`: Optional name for the structure.
  - `source (string)`: Optional source file for the structure.

- `confidence_scores (list[float])`: Confidence scores for each predicted structure.

- `ptm_scores (list[float])`: Predicted TM score for the complete complex for each diffusion sample.

- `iptm_scores (list[float])`: Predicted TM score aggregated at interfaces for each diffusion sample.

- `ligand_iptm_scores (list[float])`: Interface TM score aggregated at protein-ligand interfaces for each diffusion sample.

- `protein_iptm_scores (list[float])`: Interface TM score aggregated at protein-protein interfaces for each diffusion sample.

- `complex_plddt_scores (list[float])`: Average pLDDT score for the complete complex for each diffusion sample.

- `complex_iplddt_scores (list[float])`: Average pLDDT score with interface tokens upweighted for each diffusion sample.

- `complex_pde_scores (list[float])`: Contact-weighted average PDE score for the complete complex, in ångströms. Always returned with one scalar per diffusion sample; no request flag is required. Lower values generally indicate higher confidence.

- `complex_ipde_scores (list[float])`: Contact-weighted average PDE score aggregated at interfaces (ipDE), in ångströms. Always returned with one scalar per diffusion sample; no request flag is required. Lower values generally indicate higher confidence.

- `chains_ptm_scores (list[float])`: Predicted TM score within each chain.

- `pair_chains_iptm_scores (list[dict[str, dict[str, float]]])`: Predicted interface TM scores between each pair of chains. The response contains one dictionary keyed by chain ID.

- `pae (list[list[list[float]]])`: The full PAE matrix for each diffusion sample, in ångströms. This field is included only when `write_full_pae` is `true`; otherwise it is omitted from the response. Its shape is `[diffusion_samples][tokens][tokens]`; `pae[sample][i][j]` is the expected position error at token `i` when the predicted and true structures are aligned on token `j`. Lower values generally indicate higher confidence.

- `pde (list[list[list[float]]])`: The full PDE matrix for each diffusion sample, in ångströms. This field is included only when `write_full_pde` is `true`; otherwise it is omitted from the response. Its shape is `[diffusion_samples][tokens][tokens]`; `pde[sample][i][j]` is the expected distance error between tokens `i` and `j`. Lower values generally indicate higher confidence.

- `affinities (dict[str, AffinityPrediction])`: Always returned as an object. When no ligand has `predict_affinity` enabled, this object is empty. When affinity prediction is enabled, keys are ligand IDs and values contain:
  - `affinity_pic50 (list[float])`: Predicted pIC50 binding affinity.
  - `affinity_pred_value (list[float])`: Predicted log(IC50).
  - `affinity_probability_binary (list[float])`: Binding probability in the range 0-1.
  - `model_1_affinity_pred_value (list[float])`: Predicted log(IC50) from affinity ensemble model 1.
  - `model_1_affinity_probability_binary (list[float])`: Binding probability from affinity ensemble model 1.
  - `model_2_affinity_pred_value (list[float])`: Predicted log(IC50) from affinity ensemble model 2.
  - `model_2_affinity_probability_binary (list[float])`: Binding probability from affinity ensemble model 2.
  - `affinity_embedding (list[list[float]] | null)`: Combined affinity embedding, with one 384-dimensional vector per diffusion sample. Returned when `output_affinity_embedding` is enabled on the affinity ligand.
  - `model_1_affinity_embedding (list[list[float]] | null)`: Embedding from affinity ensemble model 1.
  - `model_2_affinity_embedding (list[list[float]] | null)`: Embedding from affinity ensemble model 2.

- `metrics (dictionary)`: Runtime metrics for the request. Common keys include `total_time_seconds`, `input_preparation_time_seconds`, `dataloader_setup_time_seconds`, `model_inference_time_seconds`, `postprocessing_time_seconds`, `response_construction_time_seconds`, and `affinity_prediction_time_seconds` when affinity prediction runs.

#### Validation and Errors

- Unknown request fields are rejected with HTTP **422** because the request schema does not allow additional properties.
- Validation failures and processing errors return JSON shaped like `{"error": "<message>"}` rather than a FastAPI `detail` array.
- Common validation failures include invalid sequence characters, duplicate ligand identifiers for affinity prediction, using `output_affinity_embedding` without `predict_affinity` on the same ligand, and providing structural templates for non-protein polymers.

#### Examples

##### Basic Protein Structure Prediction

<Tabs>
<Tab title="Curl">

```bash
#!/bin/bash

# Create JSON payload for protein structure prediction
JSON='{
"polymers": [
    {
    "id": "A",
    "molecule_type": "protein",
    "sequence": "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN"
    }
],
"recycling_steps": 3,
"sampling_steps": 50,
"diffusion_samples": 1,
"step_scale": 1.638,
"output_format": "mmcif"
}'

# Make request
echo "Making request..."
curl -s -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
http://localhost:8000/biology/mit/boltz2/predict
```

</Tab>
<Tab title="Python">

```python
import requests
import json


if __name__ == "__main__":
    sequence = "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN"  # Replace with your sequence value of interest
    headers = {
    "content-type": "application/json"
    }
    data = {
    "polymers": [
        {
        "id": "A",
        "molecule_type": "protein",
        "sequence": sequence
        }
    ],
    "recycling_steps": 3,
    "sampling_steps": 50,
    "diffusion_samples": 1,
    "step_scale": 1.638,
    "output_format": "mmcif"
    }
    print("Making request...")
    response = requests.post("http://localhost:8000/biology/mit/boltz2/predict", headers=headers, data=json.dumps(data))
    result = response.json()
    print("Structure prediction completed")
    # Access the first predicted structure
    if result.get("structures"):
        structure = result["structures"][0]
        print(f"Structure format: {structure['format']}")
        print(f"Confidence score: {result['confidence_scores'][0]}")
        print(f"Complex PDE score: {result['complex_pde_scores'][0]}")
```

</Tab>
</Tabs>

##### Protein-Ligand Complex Prediction

<Tabs>
<Tab title="Curl">

```bash
#!/bin/bash

# Create JSON payload for protein-ligand complex prediction
JSON='{
"polymers": [
    {
    "id": "A",
    "molecule_type": "protein",
    "sequence": "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN"
    }
],
"ligands": [
    {
    "id": "B1",
    "smiles": "CC(=O)OC1=CC=CC=C1C(=O)O"
    }
],
"recycling_steps": 3,
"sampling_steps": 50,
"output_format": "mmcif"
}'

# Make request
echo "Making request..."
curl -s -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
http://localhost:8000/biology/mit/boltz2/predict
```

</Tab>
<Tab title="Python">

```python
import requests
import json


if __name__ == "__main__":
    sequence = "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN"
    headers = {
    "content-type": "application/json"
    }
    data = {
    "polymers": [
        {
        "id": "A",
        "molecule_type": "protein",
        "sequence": sequence
        }
    ],
    "ligands": [
        {
        "id": "B1",
        "smiles": "CC(=O)OC1=CC=CC=C1C(=O)O"  # Aspirin
        }
    ],
    "recycling_steps": 3,
    "sampling_steps": 50,
    "output_format": "mmcif"
    }
    print("Making request...")
    response = requests.post("http://localhost:8000/biology/mit/boltz2/predict", headers=headers, data=json.dumps(data))
    result = response.json()
    print("Protein-ligand complex prediction completed")
```

</Tab>
</Tabs>

#### Example with Multiple Features

<Tabs>
<Tab title="Curl">

```bash
#!/bin/bash

# Example combining polymers, a ligand, constraints, and output options
JSON='{
"polymers": [
    {
    "id": "A",
    "molecule_type": "protein",
    "sequence": "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN",
    "cyclic": false,
    "modifications": [
        {
        "ccd": "SEP",
        "position": 15
        }
    ]
    }
],
"ligands": [
    {
    "id": "L1",
    "smiles": "CC(=O)OC1=CC=CC=C1C(=O)O"
    }
],
"constraints": [
    {
    "constraint_type": "pocket",
    "binder": "L1",
    "contacts": [
        {
        "id": "A",
        "residue_index": 25
        }
    ]
    }
],
"recycling_steps": 3,
"sampling_steps": 50,
"diffusion_samples": 1,
"step_scale": 1.638,
"without_potentials": false,
"output_format": "mmcif",
"concatenate_msas": false,
"write_full_pae": true,
"write_full_pde": true
}'

echo "Making comprehensive prediction request..."
curl -s -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
http://localhost:8000/biology/mit/boltz2/predict | jq '.'
```

</Tab>
<Tab title="Python">

```python
import requests
import json


if __name__ == "__main__":
    # Example combining polymers, ligands, constraints, and output options
    headers = {
        "content-type": "application/json"
    }
    data = {
        # Required: At least one polymer
        "polymers": [
            {
                "id": "A",                          # Chain identifier
                "molecule_type": "protein",         # DNA, RNA, or protein
                "sequence": "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN",
                "cyclic": False,                    # Whether polymer is cyclic
                "modifications": [                  # Chemical modifications
                    {
                        "ccd": "SEP",               # CCD code for modification
                        "position": 15              # 1-based position to modify
                    }
                ]
                # Note: msa field would go here for proteins with MSA data
            },
            {
                "id": "B",
                "molecule_type": "dna",
                "sequence": "ATCGATCGATCG",
                "cyclic": False
            }
        ],

        # Optional: Ligands
        "ligands": [
            {
                "id": "L1",
                "smiles": "CC(=O)OC1=CC=CC=C1C(=O)O"  # Using SMILES
            },
            {
                "id": "L2",
                "ccd": "ATP"                        # Using CCD code instead
            }
        ],

        # Optional: Constraints
        "constraints": [
            {
                "constraint_type": "pocket",
                "binder": "L1",
                "contacts": [
                    {
                        "id": "A",
                        "residue_index": 25
                    }
                ]
            }
        ],

        # Optional: Prediction parameters (all with defaults shown)
        "recycling_steps": 3,                      # 1-10, controls model iterations
        "sampling_steps": 50,                      # 10-1000, diffusion sampling steps
        "diffusion_samples": 1,                    # 1-25, number of samples to generate
        "step_scale": 1.638,                       # 0.5-5.0, controls sampling step magnitude
        "without_potentials": False,               # Whether to include potentials
        "output_format": "mmcif",                  # Output format (currently only mmcif)
        "concatenate_msas": False,                 # Whether to concatenate MSAs
        "write_full_pae": True,                    # Include one full PAE matrix per diffusion sample
        "write_full_pde": True                     # Include one full PDE matrix per diffusion sample
    }

    print("Making comprehensive prediction request...")
    response = requests.post("http://localhost:8000/biology/mit/boltz2/predict",
                           headers=headers, data=json.dumps(data))

    if response.status_code == 200:
        result = response.json()
        print(f"Prediction completed successfully!")
        print(f"Number of structures returned: {len(result['structures'])}")
        print(f"Confidence scores: {result['confidence_scores']}")
        print(f"Complex PDE scores: {result.get('complex_pde_scores', [])}")
        print(f"Complex ipDE scores: {result.get('complex_ipde_scores', [])}")
        if "pae" in result:
            print(f"PAE matrix shape: {len(result['pae'])} x {len(result['pae'][0])} x {len(result['pae'][0][0])}")
        if "pde" in result:
            print(f"PDE matrix shape: {len(result['pde'])} x {len(result['pde'][0])} x {len(result['pde'][0][0])}")
        print(f"Runtime metrics: {result.get('metrics', {})}")

        # Access first structure
        if result['structures']:
            structure = result['structures'][0]
            print(f"Structure format: {structure['format']}")
            print(f"Structure length: {len(structure['structure'])} characters")
    else:
        print(f"Request failed with status {response.status_code}")
        print(response.text)
```

</Tab>
</Tabs>

##### PAE and PDE Outputs

The following example requests full PAE and PDE matrices and reads both aggregate PDE scores and optional full matrices from the response.

<Tabs>
<Tab title="Curl">

```bash
#!/bin/bash

JSON='{
"polymers": [
    {
    "id": "A",
    "molecule_type": "protein",
    "sequence": "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"
    }
],
"diffusion_samples": 1,
"write_full_pae": true,
"write_full_pde": true
}'

response=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
http://localhost:8000/biology/mit/boltz2/predict)

echo "Complex PDE score: $(echo "$response" | jq -r '.complex_pde_scores[0]')"
echo "Complex ipDE score: $(echo "$response" | jq -r '.complex_ipde_scores[0]')"
echo "PAE entries: $(echo "$response" | jq '.pae | length')"
echo "PDE entries: $(echo "$response" | jq '.pde | length')"
```

</Tab>
<Tab title="Python">

```python
import requests
import json

if __name__ == "__main__":
    data = {
        "polymers": [
            {
                "id": "A",
                "molecule_type": "protein",
                "sequence": "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
            }
        ],
        "diffusion_samples": 1,
        "write_full_pae": True,
        "write_full_pde": True,
    }
    response = requests.post(
        "http://localhost:8000/biology/mit/boltz2/predict",
        headers={"content-type": "application/json"},
        data=json.dumps(data),
    )
    result = response.json()
    print(f"Complex PDE score: {result['complex_pde_scores'][0]}")
    print(f"Complex ipDE score: {result['complex_ipde_scores'][0]}")
    if "pae" in result:
        print(f"PAE matrix shape: {len(result['pae'])} x {len(result['pae'][0])} x {len(result['pae'][0][0])}")
    if "pde" in result:
        print(f"PDE matrix shape: {len(result['pde'])} x {len(result['pde'][0])} x {len(result['pde'][0][0])}")
```

</Tab>
</Tabs>

### Check Readiness

Endpoint path: `/v1/health/ready`

#### Input parameters

None.

#### Outputs

The output of the endpoint is a JSON response with a value that indicates the readiness of the microservice. When the NIM is ready, it returns the response `200`.

#### Example

<Tabs>
<Tab title="Curl">

```bash
#!/bin/bash
URL=${NIM_URL:-"http://localhost:8000/v1/health/ready"}
curl -s -w "\nStatus code: %{http_code}\n" -H "Content-Type: application/json" $URL
```

</Tab>
<Tab title="Python">

```python
import requests
import os

if __name__ == "__main__":
    url = os.environ.get("NIM_URL", "http://localhost:8000/v1/health/ready")
    headers = {
        "content-type": "application/json"
    }
    try:
        response = requests.get(url, headers=headers)
        print(f"NIM readiness check returned {response.status_code}")
        assert response.status_code == 200, f"Unexpected status code: {response.status_code}"
    except Exception as e:
        print(f"Health query failed: {e}")
```

</Tab>
</Tabs>