Quickstart: submit a yeast display experiment
Six API calls from candidates in hand to enriched hits in JSON. The full sequence, in Python.
Before you start
- ✓A Ranomics tools account (the login flow on tools.ranomics.com handles signup).
- ✓A Bearer token (rk_live_...) minted at tools.ranomics.com/account/api-keys.
- ✓A list of candidate amino acid sequences from your design pipeline, plus a target antigen (sequence or PDB).
Configure the client
No SDK is required. We use the standard requests library in this walkthrough.
import os
import requests
API = "https://tools.ranomics.com/api/v1"
TOKEN = os.environ["RANOMICS_API_KEY"]
HEADERS = {"Authorization": f"Bearer {TOKEN}"} Submit the experiment
A minimal yeast display submission needs a target, a library design, and a sequences dictionary. The response includes the experiment_id you will use for every subsequent call.
spec = {
"name": "her2-mpnn-pool-r1",
"webhook_url": "https://my-agent.example/hooks/ranomics",
"experiment_spec": {
"experiment_type": "yeast_display",
"target": {"custom": {
"name": "HER2 ECD",
"antigen_sequence": her2_ecd_aa,
}},
"library_design": {
"mode": "designed_panel",
"diversity_estimate": len(candidates),
},
"sequences": candidates, # {"des_0001": "MASR...", ...}
},
}
r = requests.post(f"{API}/experiments", headers=HEADERS, json=spec)
exp = r.json()
exp_id = exp["experiment_id"]
print(exp["status"]) # "Draft" Get a cost estimate
Non-binding ballpark, derived from the spec alone. Calibrated targets return a concrete number; custom targets return a placeholder range and route to a human-scoped quote.
r = requests.post(
f"{API}/experiments/cost-estimate",
headers=HEADERS,
json={
"experiment_type": "yeast_display",
"candidate_count": len(candidates),
"library_diversity": len(candidates),
"target_kind": "custom",
},
)
print(r.json())
# {"requires_human_quote": true,
# "estimated_range_usd": [12000, 28000],
# "scoping_url": "..."} Retrieve and confirm the quote
Wait for status to advance past QuoteSent, then pull the quote, review the line items, and confirm. Confirmation moves the experiment to WaitingForMaterials and triggers library construction.
quote = requests.get(
f"{API}/experiments/{exp_id}/quote",
headers=HEADERS,
).json()
print(quote["total_usd"], quote["line_items"])
# When the budget owner approves:
requests.post(
f"{API}/quotes/{quote['quote_id']}/confirm",
headers=HEADERS,
) Poll for status or subscribe via webhook
Either pattern works. Polling is cheap because GET /experiments/{id} returns only the status fields, not the result payload. If you passed a webhook_url at submission, you also get a signed POST on every status transition.
import time
while True:
state = requests.get(
f"{API}/experiments/{exp_id}",
headers=HEADERS,
).json()
print(state["status"], state["results_status"])
if state["results_status"] in ("partial", "all"):
break
time.sleep(300) # 5 min between polls is plenty Fetch the enrichment results
Per-sequence enrichment, called-hit flag, percentile within the experiment, and signed download URLs for the raw NGS reads, hits FASTA, and enrichment table CSV.
results = requests.get(
f"{API}/experiments/{exp_id}/results",
headers=HEADERS,
).json()
hits = [s for s in results["sequences"] if s["called_hit"]]
print(f"{len(hits)} called hits from {len(results['sequences'])} candidates")
# Ranked top-K for handoff to BLI / SPR
top = sorted(
results["sequences"],
key=lambda s: s["log2_enrichment"],
reverse=True,
)[:100] Where to go from here
Endpoint reference
Full surface: endpoints, status FSM, webhook signature, error format, rate limits.
Result format reference
Complete yeast display result schema with field-by-field semantics.
Yeast display platform overview
The wet-lab side of what the API submits to. Sort strategies, library size limits, controls.