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_distanceAngstrom (default 3.5 to 8). - Epitope residues (pocket mode): antigen residues the antibody should touch.
The request is met when
min_fractionof 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_fractionbelow 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: trueand noconstraint: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 withoutuse_tfg_guidance: true, or on a model other than OpenDDE, is refused rather than ignored. Boltz-2'sconstraints: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_serveron (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, setuse_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.