https://huangfulab.com/endoderm-perturbseq/api/v1/ — a single JSON document
describing every endpoint, parameter, enum value, error code and example response.
Nothing on this page is missing from it.
import requests
BASE = "https://huangfulab.com/endoderm-perturbseq/api/v1"
gene = requests.get(f"{BASE}/gene/SOX17").json()["data"]
print(gene["supermodule"], len(gene["elements"]), "linked peaks")
# Paginated endpoints expose links.next; follow it until it is null.
def fetch_all(path, **params):
rows, page = [], 1
while True:
r = requests.get(f"{BASE}{path}", params={**params, "page": page, "per_page": 500})
r.raise_for_status()
body = r.json()
rows += body["data"]
if not body["links"]["next"]:
return rows
page += 1
library(httr2) library(jsonlite) base <- "https://huangfulab.com/endoderm-perturbseq/api/v1" gene <- request(paste0(base, "/gene/SOX17")) |> req_perform() |> resp_body_json(simplifyVector = TRUE) gene$data$supermodule as.data.frame(gene$data$elements)
{"data": {...}, "links": {...}}. Collections return
{"data": [...], "page", "per_page", "total", "pages", "links"}.
links sits beside data, never inside it, so
data flattens cleanly into a data frame.
{"error": "...", "status": 404, "code": "gene_not_found", "path": "..."}.
The code is stable and safe to branch on; the error text is for humans
and may be reworded.
page with per_page (default 25,
maximum 500). A per_page above the maximum is rejected rather
than silently reduced, so a short response always means you reached the end.
Follow links.next until it is null.
null. Where a Fisher test separated perfectly, the odds ratio
is reported as null with odds_ratio_infinite: true beside it —
bare Infinity is not valid JSON and a sentinel number would be mistaken for a
measurement.
include=, and the
default response carries their size as n_<field>.
links, row url
fields and pagination.
*_truncated flag, so a capped list is always
distinguishable from a genuinely short one.
meta.resolved_from and meta.match_type say what matched.
Gene clusters accept GC1, TC-1, gene_cluster_1 or
cluster_1 and always answer with the public GC1 form.
https://huangfulab.com/endoderm-perturbseq/api/v1, so browser-side tools can call it directly.One gene: identifiers, coordinates, expression over the differentiation time course, module membership and gRNAs, plus counts of its GO annotations, perturbation effects and linked ATAC peaks. The lists themselves are opt-in via include=.
| Parameter | Type | Description |
|---|---|---|
| gene required | string | HGNC symbol, Ensembl gene ID, or a synonym. Symbols with duplicate entries resolve to the primary_gene=1 row. Example: SOX17 |
| include | enum_list | Comma-separated optional lists, each counted in the default response as n_<name>. perturbation_effects is the effect of every gRNA in the screen on this gene (~400 rows); coexpression is the slowest (~2 s cold). One of: go_terms, perturbation_effects, elements, coexpression. |
| coexpression_limit | integer · default 100 · max 500 | Top co-expressed partners by |z|. Only used with include=coexpression. |
When the input was not the canonical symbol, meta.resolved_from and meta.match_type report what was matched.
One transcription factor: which modules it regulates, by perturbation (GSEA over the CRISPR screen) and by binding (ChIP/ATAC enrichment).
| Parameter | Type | Description |
|---|---|---|
| tf required | string | Gene symbol of a TF. There is no separate TF table — a TF is a gene that is either perturbed in the screen or has binding datasets. Example: ARID1A |
| level | enum · default hotspot_supermodule | Which module collection module_regulation covers. The default (13 supermodules) keeps the response small; n_module_regulation gives the row count for every collection. 'all' returns ~300 rows. One of: hotspot_supermodule, hotspot_submodule, mfuzz_k7, all. |
| include | enum_list | Comma-separated optional blocks. 'binding_datasets' can be large (up to ~1,073 datasets for CTCF); 'pathway_enrichment' adds GO/KEGG GSEA. One of: binding_datasets, pathway_enrichment. |
is_perturbed_tf and is_binding_tf are reported separately; they are different populations (75 perturbed, ~1,705 with binding data).
odds_ratio is null with odds_ratio_infinite=true where the underlying Fisher test returned an infinite estimate.
One co-expression module: title, description, size and hierarchy, plus counts of its member genes, enrichment terms and TF regulators. The lists themselves are opt-in via include=.
| Parameter | Type | Description |
|---|---|---|
| module required | string | Supermodule (DE-1), submodule (DE-1.2), or gene cluster (GC1). GC1 / TC-1 / gene_cluster_1 / cluster_1 all resolve to the same module. Example: DE-1 |
| source | enum · default | Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule. One of: hotspot_supermodule, hotspot_submodule, mfuzz_k7. |
| include | enum_list | Comma-separated optional lists. 'genes' is paged by genes_offset and genes_limit; 'tf_regulators' merges perturbation and binding evidence (up to 500 rows); 'expression' is skipped above 2,500 genes. One of: genes, enrichment, tf_regulators, grna_gsea, expression. |
| genes_offset | integer · default 0 | Offset into the member-gene list. Used with include=genes. |
| genes_limit | integer · default 100 · max 500 | Member genes per response. Used with include=genes. The largest module has 4,691; /link/gene-module pages through membership too. |
Gene clusters are reported with their public display name (GC1), never the internal cluster_1 form; the full alias set is in the 'aliases' field.
One submodule. Identical in shape to /module, but pinned to the hotspot_submodule collection so the name can never be ambiguous.
| Parameter | Type | Description |
|---|---|---|
| submodule required | string | Submodule name, e.g. DE-1.1. Example: DE-1.1 |
| include | enum_list | Comma-separated optional lists, as for /module. One of: genes, enrichment, tf_regulators, grna_gsea, expression. |
| genes_offset | integer · default 0 | Offset into the member-gene list. Used with include=genes. |
| genes_limit | integer · default 100 · max 500 | Member genes per response. Used with include=genes. |
One Gene Ontology term: its definition and the number of genes annotated to it. The gene list and enrichment results are opt-in via include=.
| Parameter | Type | Description |
|---|---|---|
| go_term required | string | GO accession. 'GO:0030183', 'GO_0030183' and '0030183' are all accepted. Example: GO:0030183 |
| include | enum_list | Optional lists: genes (paged by genes_offset/genes_limit), module_enrichment, tf_enrichment. One of: genes, module_enrichment, tf_enrichment. |
| genes_offset | integer · default 0 | Offset into the annotated-gene list. Used with include=genes. |
| genes_limit | integer · default 100 · max 500 | Annotated genes per response. Used with include=genes. The largest terms have ~12,800. |
n_genes is the exact annotation count, whether or not include=genes is set.
One source dataset — either a TF binding experiment or a histone-PTM experiment. The two are separate namespaces that happen to share the word.
| Parameter | Type | Description |
|---|---|---|
| namespace required | enum | 'tf' for TF binding datasets, 'ptm' for histone PTM. Example: tf |
| dataset_id required | integer | Numeric dataset id within that namespace. Example: 1 |
Peak lists are not served. A TF dataset averages ~6,900 peaks over a 121M-row table; use the original accession in the 'dataset' field to fetch peaks from ENCODE or ReMap.
One ATAC peak: coordinates, accessibility across the time course, linked genes, and overlapping histone PTM datasets.
| Parameter | Type | Description |
|---|---|---|
| peak required | string | Numeric atac_peak_id or a peak name such as ESC_DE_peak_99081. Example: 58938 |
Only the count of TF overlaps is returned here — a peak can overlap 10,000+ TF peaks. Use /atac-peak/{peak}/tfs for the list.
Transcription factors with a binding peak overlapping this ATAC peak, aggregated per TF.
| Parameter | Type | Description |
|---|---|---|
| peak required | string | Numeric atac_peak_id or a peak name. Example: 58938 |
| page | integer · default 1 | 1-based page number. |
| per_page | integer · default 25 · max 500 | Rows per page. Values above 500 are rejected, not clamped. |
total is null: counting distinct TFs on a busy peak is as expensive as the query itself, so it is deliberately not computed.
Evidence that a TF regulates a gene: how many datasets place the TF at the gene and the strongest binding score, plus the perturbation effect of knocking the TF out. Per-dataset and per-peak detail are opt-in.
| Parameter | Type | Description |
|---|---|---|
| tf required | string | TF gene symbol. Example: FOXA2 |
| gene required | string | Target gene symbol. Example: SOX17 |
| include | enum_list | 'datasets' lists each binding dataset with its scores (up to 500; CTCF has 1,000+). 'elements' adds peak-level evidence — the most expensive query in the API, skipped entirely when there is no dataset-level binding to explain. One of: datasets, elements. |
binding_evidence is false when no dataset places this TF at this gene; the elements block is then empty regardless of include.
Evidence that a TF regulates a module, from both the perturbation screen and binding enrichment, with the per-gRNA detail behind it.
| Parameter | Type | Description |
|---|---|---|
| tf required | string | TF gene symbol. Example: ARID1A |
| module required | string | Module name; the same aliases as /module are accepted. Example: DE-1 |
| source | enum · default | Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule. One of: hotspot_supermodule, hotspot_submodule, mfuzz_k7. |
Gene-to-module membership edges. At least one filter is required.
| Parameter | Type | Description |
|---|---|---|
| gene | string | Return this gene's memberships. |
| module | string | Return this module's members. |
| source | enum · default | Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule. One of: hotspot_supermodule, hotspot_submodule, mfuzz_k7. |
| include_unassigned | boolean · default False | Include the 'unassigned' pseudo-modules, which hold 5,805 genes between them and are a non-result rather than a module. |
| page | integer · default 1 | 1-based page number. |
| per_page | integer · default 25 · max 500 | Rows per page. Values above 500 are rejected, not clamped. |
The TF-to-module regulatory network as an edge list, merging perturbation and binding evidence.
| Parameter | Type | Description |
|---|---|---|
| level | enum · default hotspot_supermodule | Which module collection to build the network over. One of: hotspot_supermodule, hotspot_submodule, mfuzz_k7. |
| evidence | enum · default any | Restrict to edges with this kind of support. One of: any, perturbation, binding, both. |
| min_odds_ratio | number · default 1.0 | Minimum binding enrichment odds ratio. |
| max_padj | number · default 0.05 · max 1 | Maximum adjusted p-value for the binding arm. |
| min_abs_nes | number · default 0 | Minimum |NES| for the perturbation arm. |
| page | integer · default 1 | 1-based page number. |
| per_page | integer · default 25 · max 500 | Rows per page. Values above 500 are rejected, not clamped. |
At the default supermodule level the whole network is small enough to page through in full. The submodule level is ~20x larger, so the significance defaults matter more.
https://huangfulab.com/endoderm-perturbseq/api/v1/edgesAll genes in the dataset, filterable by biotype, chromosome and perturbation-library membership.
| Parameter | Type | Description |
|---|---|---|
| biotype | string | Exact gene_biotype, e.g. protein_coding or lncRNA. |
| chr | string | Chromosome. '7' and 'chr7' are both accepted. |
| perturbed | boolean | Restrict to genes that are (or are not) in the perturbation library. |
| page | integer · default 1 | 1-based page number. |
| per_page | integer · default 25 · max 500 | Rows per page. Values above 500 are rejected, not clamped. |
Only primary_gene=1 rows are listed, so each symbol appears once.
https://huangfulab.com/endoderm-perturbseq/api/v1/genes?per_page=5Transcription factors. There is no TF table in the database, so which population you get is an explicit choice.
| Parameter | Type | Description |
|---|---|---|
| set | enum · default perturbed | 'perturbed' = the 75 TFs targeted in the CRISPR screen; 'binding' = the ~1,705 genes with a binding dataset; 'all' = either. One of: perturbed, binding, all. |
| page | integer · default 1 | 1-based page number. |
| per_page | integer · default 25 · max 500 | Rows per page. Values above 500 are rejected, not clamped. |
A few perturbed TFs carry stale HGNC symbols with no gene_table row; they are returned with gene_id null and symbol_status 'stale' rather than dropped.
https://huangfulab.com/endoderm-perturbseq/api/v1/tfsAll modules across the three collections, with sizes and titles. Full descriptions are on /module/{module}.
| Parameter | Type | Description |
|---|---|---|
| source | enum · default | Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule. One of: hotspot_supermodule, hotspot_submodule, mfuzz_k7. |
| include_unassigned | boolean · default False | Include the 'unassigned' pseudo-modules. |
| page | integer · default 1 | 1-based page number. |
| per_page | integer · default 25 · max 500 | Rows per page. Values above 500 are rejected, not clamped. |
Gene clusters carry both display_name (GC1) and the full alias list.
https://huangfulab.com/endoderm-perturbseq/api/v1/modulesPrefix search across genes, synonyms, TFs, modules and GO terms.
| Parameter | Type | Description |
|---|---|---|
| q | string | Search string, 2-64 characters. Matched as a prefix for names and as a substring for GO term descriptions. Wildcards are escaped, not interpreted. |
| type | enum_list | Restrict to these result types. One of: gene, tf, module, submodule, gene_cluster, go_term, synonym. |
| limit | integer · default 25 · max 100 | Maximum results across all types. |
Each result carries matched_on, so an exact symbol hit can be told apart from a synonym or a GO description match.
Machine-readable index of every endpoint, with limits and enum values.
| Parameter | Type | Description |
|---|---|---|
| examples | boolean · default True | Set false for a compact listing without example response bodies. |
https://huangfulab.com/endoderm-perturbseq/api/v1/ returns this endpoint list as JSON, including every enum value and limit, so a script can discover the API without scraping this page. For column-level detail on the underlying tables, see the database schema.