Skip to content

Predictions

POST /v1/predictions predicts the 3D structure and, with Boltz-2, the binding affinity of a protein or complex. It returns a job to poll (see Jobs). Every example sends your key from $JAPANFOLD_API_KEY (see Authentication).

Three ways to specify input

Provide exactly one of these.

1. sequence: a single protein chain

curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model":"boltz2","name":"myprotein","sequence":"MKTAYIAKQRQISFVKSHFSRQLEE"}'

2. input: one FASTA or Boltz YAML string

Use this for complexes, multiple chains, ligands, nucleic acids, affinity and constraints. The string is a full Boltz YAML or a FASTA. A FASTA header can be anything, a plain name or a UniProt header as UniProt gives it: a record without a usable chain id gets the next free letter (A, B, ...) and its type is read from the sequence, and the job's warnings list which record became which chain. To pick the ids and types yourself, write headers as >A|protein (or dna, rna, ccd, smiles). Boltz-2 holds chain ids of up to five characters, so a longer id in a YAML input is refused. Note the \n newlines when embedding it in JSON:

# Human insulin: two protein chains
curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"boltz2","name":"human-insulin",
    "input":"sequences:\n  - protein: {id: A, sequence: GIVEQCCTSICSLYQLENYCN}\n  - protein: {id: B, sequence: FVNQHLCGSHLVEALYLVCGERGFFYTPKT}\n"
  }'

3. targets: a list, to fold many inputs in one job

Each target is { "content": "<FASTA or YAML>", "name": "<optional>" }.

curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"esmfold2-fast",
    "targets":[
      {"name":"a","content":">a\nMKTAYIAKQRQISFVKSHFSRQLEE"},
      {"name":"b","content":">b\nGIVEQCCTSICSLYQLENYCN"}
    ]
  }'

Choosing a model

Set model, default boltz2. Boltz-2 is the most capable and the only one that returns a binding affinity or accepts constraints:; OpenDDE takes its own guided-sampling constraint: block (below); ESMFold-2 and OpenDDE are protein-only. The full capability matrix is on Models & limits.

Scoring a design you already have (AF2-IG)

af2ig takes a different input from every other model: not a chain list, but a designed complex. Put the structure carrying both the target chain and the binder backbone under target:, and the sequence to place on that backbone under binder:. It re-predicts the complex starting from those coordinates and returns ipTM and interface pAE, which is what tells a real binder from a plausible one.

curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"af2ig","name":"my-design",
    "targets":[{"content":"target:\n  structure: |\n    ATOM      1  N   MET A   1 ...\n  chain: A\nbinder:\n  sequence: LYRWIKSVDPSRPVQY\n  chain: B\n"}]
  }'

The binder chain has to be in the structure and the same length as the sequence. mmCIF is accepted, so a structure from POST /v1/designs can be scored as it comes back. There is nothing to tune: no alignment, no sampling, no seed, and the same input gives the same answer. Anything other than target: and binder: in the file is refused rather than ignored.

Co-folding with a ligand + affinity (Boltz-2)

Add a ligand chain (SMILES or CCD code) and a properties: affinity block naming the binder chain:

curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"boltz2","name":"prot-ligand",
    "input":"sequences:\n  - protein: {id: A, sequence: MKTAYIAKQRQISFVKSHFSRQLEE}\n  - ligand: {id: L, smiles: \"CC(=O)Oc1ccccc1C(=O)O\"}\nproperties:\n  - affinity: {binder: L}\n"
  }'

The result row then carries two affinity numbers alongside the structure and confidence scores (see Jobs → Results):

  • affinity_pred_value: predicted log10(IC50) with IC50 in μM, so lower is a stronger binder. Boltz's own guidance is to use it to rank actives against each other, not to call a compound active or inactive.
  • affinity_probability_binary: probability the ligand binds at all, 0-1, so higher is stronger.

Both also come back with a 1 and 2 suffix, the two ensemble members, plus affinity_runtime_s and structure_runtime_s.

Guided antibody docking (OpenDDE)

If you already know part of an antibody-antigen interface, from mutagenesis, HDX, crosslinks or a related structure, OpenDDE can use it. Add a top-level constraint: block to the YAML input and set use_tfg_guidance: true. During sampling the antibody chains are moved as a rigid body until the predicted complex agrees with what you gave; the model weights are not changed. This is OpenDDE 1.2.0's constraint guidance, and the block is the same as OpenDDE's own constraint field, so an input written for OpenDDE works unchanged. It runs on opendde and opendde-abag.

Two kinds of request:

  • Contact pairs: a residue on the antigen and a residue on the antibody that should be within min_distance..max_distance Angstrom (default 3.5 to 8).
  • Epitope residues (pocket mode): antigen residues the antibody should touch. The request is met when min_fraction of them (default 0.5) have a heavy atom within 5 A of the antibody. Use this when you know where it binds but not which antibody residues do the binding.

Residues are addressed the way OpenDDE does it: entity is the 1-based position of the entry in sequences, copy the 1-based copy within that entry, and position the 1-based residue. movable_chains names the antibody chains; it is required for an epitope, and for contacts unless the complex has exactly two chains.

sequences:
  - protein: {id: H, sequence: QVQLQQSGAELVKPGASVRM...}   # entity 1
  - protein: {id: L, sequence: DIELTQTTSSLSASLGDRVT...}   # entity 2
  - protein: {id: N, sequence: RDFNNLTKGLCTINSWHIYG...}   # entity 3, the antigen
constraint:
  movable_chains: [H, L]
  contact:
    - {entity1: 3, position1: 248, entity2: 2, position2: 93}
    - {entity1: 3, position1: 319, entity2: 1, position2: 55}
constraint:
  movable_chains: [H, L]
  epitope:
    residues:
      - {entity: 3, copy: 1, position: 248, residue: P}
      - {entity: 3, copy: 1, position: 249, residue: N}
      - {entity: 3, copy: 1, position: 318, residue: N}
    paratope: all        # or cdr, to let only the CDR loops count
    min_fraction: 0.5
curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "$(jq -n --rawfile input 1a14_contact.yaml \
        '{model: "opendde-abag", input: $input, params: {use_tfg_guidance: true, diffusion_samples: 5}}')"

What to expect:

  • A wrong contact can make the answer worse. Contacts are strict: the antibody is pulled towards every pair you give. OpenDDE's authors report that wrong contacts can push the success rate below an unguided fold. If you are unsure of a pair, leave it out, or use an epitope with min_fraction below 1, which tolerates a few wrong residues.
  • Guided folds take longer, about 20 to 45 %, mostly because a guided fold runs its diffusion in full precision. They are billed for the processor time they use, at the same rate as any other fold.
  • With use_tfg_guidance: true and no constraint: block, OpenDDE still applies its physics restraints (clash, bond geometry, chirality) at every step, as upstream does. Without the parameter nothing changes.
  • A constraint: block without use_tfg_guidance: true, or on a model other than OpenDDE, is refused rather than ignored. Boltz-2's constraints: list is a different input and OpenDDE does not read it.

Parameters

Pass a params object: use_msa_server, fast, recycling_steps, sampling_steps, diffusion_samples, output_format, seed, write_pae, use_tfg_guidance. Values are clamped to their allowed range. Defaults, ranges and per-model applicability are on Models & limits.

Every job's params carry the seed it ran with, 0 unless you sent one, so a result can be cited and requested again with the same seed. write_pae: true adds <name>_pae.npz to the artifacts: the full predicted aligned error matrix of the top-ranked structure (key pae), and PDE (pde) and contact probabilities (contact_probs) where the model computes them, listed in the sidecar <name>_pae.json. Every prediction model returns it; Confidence outputs has each model's arrays. Key pae is the input Adaptyv's ipSAE pipeline reads, so you can score our fold with their script. Scoring the same design with several diffusion_samples gives you its spread, which is what tells a stable score from a lucky one.

curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"boltz2","sequence":"MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ",
    "params":{"use_msa_server":true,"diffusion_samples":3,"output_format":"pdb"}
  }'

MSA and privacy. With use_msa_server on (the Boltz-2 default), the alignment is searched against UniRef30 (2023-02) on the server that runs your job. Your sequence is never sent to an outside MSA service; if the database is unavailable the job fails and is not charged. The parameter keeps its name for compatibility. To fold single-sequence, set use_msa_server: false.

Waiting inline: the Prefer: wait header

By default a submit returns immediately with a job to poll. Add Prefer: wait=<seconds> on the create or on a GET /v1/jobs/{id} poll to block until the job finishes or the timeout elapses, which turns a poll loop into one call for short jobs. Bare wait holds 25s; wait=N holds up to N seconds, capped at 60:

curl -s -H "Authorization: Bearer $JAPANFOLD_API_KEY" -H 'Prefer: wait=60' https://api.japanfold.aiand.com/v1/jobs/$JOB

On a GET, ?wait=60 does the same without a header: https://api.japanfold.aiand.com/v1/jobs/$JOB?wait=60. See Jobs for a loop.

Retrying safely: Idempotency-Key

Send an Idempotency-Key: <unique> header on a create, up to 255 characters. A retried submit with the same key and body returns the original job instead of launching and charging a duplicate. The same key with a different body is a 422, so use a new key for each new submission. Keys are remembered on your account for good: a readable name like ubq-fold you used last week still points at last week's job, so generate one (a UUID) per submission and reuse it only for retries:

curl -s -X POST https://api.japanfold.aiand.com/v1/predictions \
  -H "Authorization: Bearer $JAPANFOLD_API_KEY" \
  -H 'Content-Type: application/json' -H 'Idempotency-Key: 6f1c2a9e-1b7d-4c55-9a0e-3d2f8b7c4e10' \
  -d '{"model":"boltz2","sequence":"MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQ"}'

Response

The body is a Job. Poll links.self (or /v1/jobs/{id}) and read /v1/jobs/{id}/results once results_ready is true. Jobs has the object, the lifecycle and the result shape.