{
  "api_version": "v1",
  "base_url": "https://huangfulab.com/endoderm-perturbseq/api/v1",
  "docs": "https://huangfulab.com/endoderm-perturbseq/api",
  "data_updated": null,
  "description": "Read-only JSON API for the Endoderm Perturb-Seq Browser, a CRISPR transcription-factor perturbation screen in human definitive endoderm differentiation. No authentication and no rate limit. Every endpoint is GET. This document lists every endpoint, its parameters, and an example response.",
  "conventions": {"entity_response": "A single object returns {\"data\": {...}, \"links\": {...}} and, when there is something to report, \"meta\". 'links' sits beside 'data', never inside it, so 'data' flattens cleanly into a table or data frame.", "collection_response": "A listing returns {\"data\": [...], \"page\", \"per_page\", \"total\", \"pages\", \"total_is_exact\", \"links\"}. Follow links.next until it is null. A 'total' of null means the count was too expensive to compute, never that there are no rows.", "errors": "Always JSON: {\"error\": \"...\", \"status\": 404, \"code\": \"gene_not_found\", \"path\": \"...\"}. Branch on 'code', which is stable; 'error' is prose for humans and may be reworded.", "pagination": "1-based 'page' with 'per_page'. A per_page above the maximum is rejected with 400 rather than silently reduced, so a short page always means you reached the end.", "missing_and_infinite_values": "Absent measurements are null. Where a Fisher test separated perfectly the odds ratio is null with \"odds_ratio_infinite\": true beside it, because bare Infinity is not valid JSON and a sentinel number would be mistaken for a measurement.", "truncation": "Bounded lists carry a companion \"<field>_truncated\" boolean, so a capped list is always distinguishable from a genuinely short one.", "name_resolution": "Genes accept a symbol, an Ensembl gene ID or a synonym; when the input was not the canonical symbol, 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 GC1.", "urls": "Every URL in a response is absolute and can be fetched as-is. Chat assistants that only fetch URLs already seen in the conversation can therefore follow links, row 'url' fields and pagination from any response they have read.", "optional_blocks": "Entity responses are kept small. Long lists are opt-in via include= and are represented in the default response by a count named n_<field>.", "example_responses": "Captured from the live API and trimmed: arrays are cut to a single element and long strings to ~140 characters. Field names and types are verbatim. Examples are captured with every include= block enabled, so they show the fullest shape."},
  "limits": {
    "default_per_page": 25,
    "max_per_page": 500,
    "max_response_bytes": 5242880,
    "query_timeout_seconds": {"objects_and_links": 5.0, "collections_and_search": 2.0}
  },
  "enums": {
    "module_source": ["hotspot_supermodule", "hotspot_submodule", "mfuzz_k7"],
    "regulation_level": ["hotspot_supermodule", "hotspot_submodule", "mfuzz_k7", "all"],
    "gene_include": ["go_terms", "perturbation_effects", "elements", "coexpression"],
    "tf_include": ["binding_datasets", "pathway_enrichment"],
    "module_include": ["genes", "enrichment", "tf_regulators", "grna_gsea", "expression"],
    "tf_set": ["perturbed", "binding", "all"],
    "dataset_namespace": ["tf", "ptm"],
    "edge_evidence": ["any", "perturbation", "binding", "both"],
    "go_include": ["genes", "module_enrichment", "tf_enrichment"],
    "tf_gene_include": ["datasets", "elements"],
    "search_type": ["gene", "tf", "module", "submodule", "gene_cluster", "go_term", "synonym"]
  },
  "endpoints": [
    {
      "id": "index",
      "group": "meta",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/",
      "summary": "Machine-readable index of every endpoint, with limits and enum values.",
      "path_params": [],
      "query_params": [
        {"name": "examples", "type": "boolean", "default": true, "description": "Set false for a compact listing without example response bodies."}
      ],
      "returns": "index",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/",
      "errors": [],
      "notes": []
    },
    {
      "id": "gene",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/gene/{gene}",
      "summary": "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=.",
      "path_params": [
        {"name": "gene", "type": "string", "required": true, "example": "SOX17", "description": "HGNC symbol, Ensembl gene ID, or a synonym. Symbols with duplicate entries resolve to the primary_gene=1 row."}
      ],
      "query_params": [
        {"name": "include", "type": "enum_list", "enum": "gene_include", "default": "", "description": "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)."},
        {"name": "coexpression_limit", "type": "integer", "default": 100, "min": 1, "max": 500, "description": "Top co-expressed partners by |z|. Only used with include=coexpression."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/gene/SOX17",
      "errors": [
        {"status": 404, "code": "gene_not_found", "when": "No symbol, Ensembl ID or synonym matches."}
      ],
      "notes": ["When the input was not the canonical symbol, meta.resolved_from and meta.match_type report what was matched."],
      "example_response": {
        "data": {
          "gene_id": 21169,
          "ensg_id": "ENSG00000164736",
          "gene_name": "SOX17",
          "gene_biotype": "protein_coding",
          "chr": "8",
          "chrom_start": 54457935,
          "chrom_end": 54460892,
          "description": "SRY-box transcription factor 17",
          "other_designations": "transcription factor SOX-17|SRY (sex determining region Y)-box 17|SRY-box 17|SRY-related HMG-box transcription factor SOX17",
          "summary": "This gene encodes a member of the SOX (SRY-related HMG-box) family of transcription factors involved in the regulation of embryonic developm...",
          "in_perturbation_library": true,
          "publication_count": 86,
          "id": "SOX17",
          "type": "gene",
          "is_primary_symbol": true,
          "is_tf": true,
          "synonyms": [],
          "tss": [
            {"tss_id": 12215, "chr": "8", "tss_position": 54457934, "strand": "+", "promoter_source": "atacseq_DE_72h"}
          ],
          "expression": [{"timepoint": "ES_0h", "mean_tpm": 0.0, "replicates": [0.0]}],
          "modules": [
            {"module_id": 13, "module_name": "DE-1", "source": "hotspot_supermodule", "size": 2012, "display_name": "DE-1"}
          ],
          "supermodule": "DE-1",
          "submodule": null,
          "grnas": [{"grna_id": 70, "grna_name": "SOX17_1", "active": 1}],
          "n_go_terms": 77,
          "n_perturbation_effects": 398,
          "n_elements": 21,
          "go_terms": [
            {"go_accession": "GO:0048646", "go_name": "anatomical structure formation involved in morphogenesis", "namespace": "biological_process", "evidence": "IEA", "qualifier": "involved_in"}
          ],
          "go_terms_truncated": false,
          "perturbation_effects": [
            {"perturbed_gene": "SOX18", "grna_id": 167, "grna_name": "SOX18_4", "active": 1, "coef": -1.60627027018437, "z_coef": -5.95034709277612, "padj": 0.556856819734928}
          ],
          "perturbation_effects_truncated": false,
          "elements": [
            {"atac_peak_id": 58938, "atac_peak_name": "ESC_DE_peak_99081", "chr": "8", "chrom_start": 54457494, "chrom_end": 54460098, "min_distance_bp": 0, "link_type": "TSS", "multiome_cell_type": "DE", "multiome_padj": 0.0012321572297434, "peak_gene_correlation": 0.749432700965179}
          ],
          "elements_truncated": false,
          "coexpression": [{"gene_id": 15555, "gene_name": "MRPS6", "z_score": 39.6599714352318}]
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/gene/SOX17", "html": "https://www.huangfulab.com/endoderm-perturbseq/gene/SOX17", "tf": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/SOX17", "supermodule": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/module/DE-1"}
      }
    },
    {
      "id": "tf",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/tf/{tf}",
      "summary": "One transcription factor: which modules it regulates, by perturbation (GSEA over the CRISPR screen) and by binding (ChIP/ATAC enrichment).",
      "path_params": [
        {"name": "tf", "type": "string", "required": true, "example": "ARID1A", "description": "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."}
      ],
      "query_params": [
        {"name": "level", "type": "enum", "enum": "regulation_level", "default": "hotspot_supermodule", "description": "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."},
        {"name": "include", "type": "enum_list", "enum": "tf_include", "default": "", "description": "Comma-separated optional blocks. 'binding_datasets' can be large (up to ~1,073 datasets for CTCF); 'pathway_enrichment' adds GO/KEGG GSEA."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/tf/ARID1A",
      "errors": [
        {"status": 404, "code": "tf_not_found", "when": "The gene exists but is neither perturbed nor has binding data — the error points at /gene/{name}."},
        {"status": 404, "code": "gene_not_found", "when": "No such gene at all."}
      ],
      "notes": ["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."],
      "example_response": {
        "data": {
          "gene_id": 997,
          "ensg_id": "ENSG00000117713",
          "gene_name": "ARID1A",
          "description": "AT-rich interaction domain 1A",
          "in_perturbation_library": true,
          "id": "ARID1A",
          "type": "tf",
          "is_perturbed_tf": true,
          "is_binding_tf": true,
          "dataset_tf_labels": ["ARID1A"],
          "n_module_regulation": {"hotspot_supermodule": 12, "hotspot_submodule": 295, "mfuzz_k7": 7},
          "module_regulation_level": "hotspot_supermodule",
          "module_regulation": [
            {"module_collection": "hotspot_supermodule", "module": "DE-10", "module_id": 3, "evidence": "both", "direction": "up", "mean_NES": 3.17157729621603, "n_grnas": 2, "perturbation_padj": 1.5282838435537e-48, "odds_ratio": 1.6374269005848, "odds_ratio_infinite": false, "binding_padj": 0.44517837575501, "n_overlap": 308}
          ],
          "module_regulation_truncated": false,
          "grnas": [{"grna_id": 2, "grna_name": "ARID1A_2", "active": 0}],
          "n_binding_datasets": 17,
          "binding_datasets": [
            {"dataset_id": 5439, "dataset": "GSE104545.ARID1A.RMG-I", "dataset_tf_label": "ARID1A", "cell_type": "RMG-I", "cell_type_group": "other", "source": "remap_chipseq", "extra": "GSE104545", "match_type": "exact"}
          ],
          "binding_datasets_truncated": false,
          "pathway_enrichment": [
            {"gene_set_collection": "GO_Biological_Process_2026", "gene_set": "Mitotic Sister Chromatid Segregation (GO:0000070)", "go_id": 54, "direction": "up", "n_grnas": 2, "mean_NES": 2.31051019762884, "min_padj": 1.05296705312606e-07}
          ],
          "pathway_enrichment_truncated": false
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/ARID1A", "html": "https://www.huangfulab.com/endoderm-perturbseq/gene/ARID1A", "gene": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/gene/ARID1A"}
      }
    },
    {
      "id": "module",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/module/{module}",
      "summary": "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=.",
      "path_params": [
        {"name": "module", "type": "string", "required": true, "example": "DE-1", "description": "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."}
      ],
      "query_params": [
        {"name": "source", "type": "enum", "enum": "module_source", "required": false, "description": "Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule."},
        {"name": "include", "type": "enum_list", "enum": "module_include", "default": "", "description": "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."},
        {"name": "genes_offset", "type": "integer", "default": 0, "min": 0, "description": "Offset into the member-gene list. Used with include=genes."},
        {"name": "genes_limit", "type": "integer", "default": 100, "min": 1, "max": 500, "description": "Member genes per response. Used with include=genes. The largest module has 4,691; /link/gene-module pages through membership too."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/module/DE-1",
      "errors": [
        {"status": 400, "code": "ambiguous_name", "when": "The name exists in more than one collection (e.g. 'unassigned'); pass ?source=."},
        {"status": 404, "code": "module_not_found", "when": "No module with that name."}
      ],
      "notes": ["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."],
      "example_response": {
        "data": {
          "id": "DE-1",
          "type": "module",
          "module_id": 13,
          "module_name": "DE-1",
          "display_name": "DE-1",
          "aliases": [],
          "source": "hotspot_supermodule",
          "size": 2012,
          "title": "Ribosomal subunit and translation machinery",
          "description": "This 2012-gene module includes APOE, KRAS, GSTP1, HMGB1, and SOD1, and is highly enriched for ribosomal subunits, ribosomal structure, trans...",
          "description_extended": "This 2012-gene module is dominated by ribosomal and translation-related genes, including APOE, KRAS, GSTP1, HMGB1, and SOD1, with very stron...",
          "n_genes": 2012,
          "n_enrichment_terms": 3675,
          "n_tf_regulators": {"perturbation": 15, "binding": 1934},
          "genes": [
            {"gene_id": 7, "gene_name": "AAAS", "gene_biotype": "protein_coding", "in_perturbation_library": 0, "publication_count": 34}
          ],
          "genes_offset": 0,
          "genes_limit": 100,
          "enrichment": [
            {"term_id": "REAC:R-HSA-72766", "source": "REAC", "go_id": null, "term_name": "Translation", "p_value": 8.56591835939992e-95, "term_size": 277, "query_size": 1981, "intersection_size": 212, "term_precision": 0.107016658253407, "recall": 0.765342960288809}
          ],
          "enrichment_truncated": true,
          "tf_regulators": [
            {"tf_gene_name": "CTBP1", "gene_id": 3575, "evidence": "both", "direction": "up", "mean_NES": 2.53220578593969, "n_grnas": 2, "perturbation_padj": 3.23759626804026e-145, "odds_ratio": 4.40953525641026, "odds_ratio_infinite": false, "binding_padj": 2.69863655013188e-39, "n_overlap": 1948}
          ],
          "tf_regulators_truncated": true,
          "child_submodules": ["DE-1.1"],
          "parent_module": null,
          "grna_gsea": [
            {"perturbed_gene": "ARID5B", "grna_id": 4, "grna_name": "ARID5B_1", "active": 1, "NES": null, "pval": null, "padj": null, "size": 2149}
          ],
          "grna_gsea_truncated": false,
          "expression": [{"timepoint": "ES_0h", "mean_tpm": 206.097, "sd_tpm": 692.9638, "n_genes": 6030}]
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/module/DE-1", "html": "https://www.huangfulab.com/endoderm-perturbseq/module/DE-1"}
      }
    },
    {
      "id": "submodule",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/submodule/{submodule}",
      "summary": "One submodule. Identical in shape to /module, but pinned to the hotspot_submodule collection so the name can never be ambiguous.",
      "path_params": [
        {"name": "submodule", "type": "string", "required": true, "example": "DE-1.1", "description": "Submodule name, e.g. DE-1.1."}
      ],
      "query_params": [
        {"name": "include", "type": "enum_list", "enum": "module_include", "default": "", "description": "Comma-separated optional lists, as for /module."},
        {"name": "genes_offset", "type": "integer", "default": 0, "min": 0, "description": "Offset into the member-gene list. Used with include=genes."},
        {"name": "genes_limit", "type": "integer", "default": 100, "min": 1, "max": 500, "description": "Member genes per response. Used with include=genes."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/submodule/DE-1.1",
      "errors": [{"status": 404, "code": "module_not_found", "when": "No such submodule."}],
      "notes": [],
      "example_response": {
        "data": {
          "id": "DE-1.1",
          "type": "module",
          "module_id": 250,
          "module_name": "DE-1.1",
          "display_name": "DE-1.1",
          "aliases": [],
          "source": "hotspot_submodule",
          "size": 61,
          "title": "Cytosolic ribosome and protein biosynthesis",
          "description": "This 61-gene module is enriched for ribosomal proteins and translation machinery, including MIF, RACK1, FTH1, EEF1A1, and TPT1, with strong ...",
          "description_extended": "This 61-gene module is robustly enriched for components of the cytosolic ribosome and the protein biosynthetic machinery, featuring key gene...",
          "n_genes": 61,
          "n_enrichment_terms": 1172,
          "n_tf_regulators": {"perturbation": 40, "binding": 1872},
          "genes": [
            {"gene_id": 1730, "gene_name": "BTF3", "gene_biotype": "protein_coding", "in_perturbation_library": 0, "publication_count": 16}
          ],
          "genes_offset": 0,
          "genes_limit": 100,
          "enrichment": [
            {"term_id": "REAC:R-HSA-156902", "source": "REAC", "go_id": null, "term_name": "Peptide chain elongation", "p_value": 9.255197322842131e-111, "term_size": 87, "query_size": 61, "intersection_size": 54, "term_precision": 0.885245901639344, "recall": 0.620689655172414}
          ],
          "enrichment_truncated": true,
          "tf_regulators": [
            {"tf_gene_name": "TAF10", "gene_id": 21813, "evidence": "perturbation", "direction": "down", "mean_NES": -3.50775388001153, "n_grnas": 2, "perturbation_padj": 1.71098657277976e-35, "odds_ratio": null, "odds_ratio_infinite": false, "binding_padj": null, "n_overlap": null}
          ],
          "tf_regulators_truncated": true,
          "child_submodules": [],
          "parent_module": "DE-1",
          "grna_gsea": [
            {"perturbed_gene": "SOX17", "grna_id": 70, "grna_name": "SOX17_1", "active": 1, "NES": -3.52181098275996, "pval": 2.76526766985474e-44, "padj": 4.5903443319588795e-42, "size": 74}
          ],
          "grna_gsea_truncated": false,
          "expression": [{"timepoint": "ES_0h", "mean_tpm": 2023.3001, "sd_tpm": 1626.1359, "n_genes": 183}]
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/submodule/DE-1.1", "html": "https://www.huangfulab.com/endoderm-perturbseq/module/DE-1.1", "parent": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/module/DE-1"}
      }
    },
    {
      "id": "go_term",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/go-term/{go_term}",
      "summary": "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=.",
      "path_params": [
        {"name": "go_term", "type": "string", "required": true, "example": "GO:0030183", "description": "GO accession. 'GO:0030183', 'GO_0030183' and '0030183' are all accepted."}
      ],
      "query_params": [
        {"name": "include", "type": "enum_list", "enum": "go_include", "default": "", "description": "Optional lists: genes (paged by genes_offset/genes_limit), module_enrichment, tf_enrichment."},
        {"name": "genes_offset", "type": "integer", "default": 0, "min": 0, "description": "Offset into the annotated-gene list. Used with include=genes."},
        {"name": "genes_limit", "type": "integer", "default": 100, "min": 1, "max": 500, "description": "Annotated genes per response. Used with include=genes. The largest terms have ~12,800."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/go-term/GO:0030183",
      "errors": [
        {"status": 404, "code": "go_term_not_found", "when": "No such GO accession. An unparseable accession is treated as missing, not as a client error."}
      ],
      "notes": ["n_genes is the exact annotation count, whether or not include=genes is set."],
      "example_response": {
        "data": {
          "go_id": 13553,
          "go_accession": "GO:0030183",
          "go_name": "B cell differentiation",
          "namespace": "biological_process",
          "definition": "The process in which a precursor cell type acquires the specialized features of a B cell. A B cell is a lymphocyte of B lineage with the phe...",
          "is_obsolete": false,
          "id": "GO:0030183",
          "type": "go_term",
          "n_genes": 68,
          "genes": [
            {"gene_id": 233, "gene_name": "ADAM17", "gene_biotype": "protein_coding", "evidence": "IEA", "qualifier": "involved_in"}
          ],
          "genes_offset": 0,
          "genes_limit": 100,
          "module_enrichment": [],
          "tf_enrichment": []
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/go-term/GO%3A0030183", "html": "https://www.huangfulab.com/endoderm-perturbseq/go/B%20cell%20differentiation%20%28GO%3A0030183%29"}
      }
    },
    {
      "id": "dataset",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/dataset/{namespace}/{dataset_id}",
      "summary": "One source dataset — either a TF binding experiment or a histone-PTM experiment. The two are separate namespaces that happen to share the word.",
      "path_params": [
        {"name": "namespace", "type": "enum", "enum": "dataset_namespace", "required": true, "example": "tf", "description": "'tf' for TF binding datasets, 'ptm' for histone PTM."},
        {"name": "dataset_id", "type": "integer", "required": true, "example": "1", "description": "Numeric dataset id within that namespace."}
      ],
      "query_params": [],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/dataset/tf/1",
      "errors": [{"status": 404, "code": "dataset_not_found", "when": "No dataset with that id."}],
      "notes": ["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."],
      "example_response": {
        "data": {"dataset_id": 1, "dataset": "DED1_EOMES_A_Batch_III", "dataset_tf_label": "EOMES", "cell_type": "DE_D1", "cell_type_group": "ESC_DE_intermediate", "extra": null, "source": "huangfu-tf_chipseq", "tf_gene_id": 9887, "match_type": "exact", "tf_gene_name": "EOMES", "id": 1, "type": "dataset", "namespace": "tf", "n_tf_peaks": 0},
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/dataset/tf/1", "tf": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/EOMES"}
      }
    },
    {
      "id": "atac_peak",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/{peak}",
      "summary": "One ATAC peak: coordinates, accessibility across the time course, linked genes, and overlapping histone PTM datasets.",
      "path_params": [
        {"name": "peak", "type": "string", "required": true, "example": "58938", "description": "Numeric atac_peak_id or a peak name such as ESC_DE_peak_99081."}
      ],
      "query_params": [],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938",
      "errors": [{"status": 404, "code": "peak_not_found", "when": "No peak with that id or name."}],
      "notes": ["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."],
      "example_response": {
        "data": {
          "atac_peak_id": 58938,
          "chr": "8",
          "chrom_start": 54457494,
          "chrom_end": 54460098,
          "atac_peak_name": "ESC_DE_peak_99081",
          "id": 58938,
          "type": "atac_peak",
          "width": 2604,
          "linked_genes": [
            {"gene_id": 21169, "gene_name": "SOX17", "distance_bp": 0, "link_type": null, "cell_type": null, "beta": null, "z": null, "p": null, "padj": null, "correlation": 0.749432700965179}
          ],
          "linked_genes_truncated": false,
          "n_linked_genes": 7,
          "accessibility": [
            {
              "timepoint": "ES_0h",
              "mean": 475.2348,
              "mean_z": -0.7536,
              "replicates": [402.73],
              "z_replicates": [-1.3275]
            }
          ],
          "histone_ptms": [
            {"ptm_dataset_id": 1, "ptm_name": "H3K27ac", "cell_type": "DE", "timepoint": null, "dataset": "DE-H3K27ac", "source": "huangfu_ptm_chipseq"}
          ],
          "n_tf_peak_overlaps": 2924
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938", "tfs": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938/tfs"}
      }
    },
    {
      "id": "atac_peak_tfs",
      "group": "objects",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/{peak}/tfs",
      "summary": "Transcription factors with a binding peak overlapping this ATAC peak, aggregated per TF.",
      "path_params": [
        {"name": "peak", "type": "string", "required": true, "example": "58938", "description": "Numeric atac_peak_id or a peak name."}
      ],
      "query_params": [
        {"name": "page", "type": "integer", "default": 1, "min": 1, "description": "1-based page number."},
        {"name": "per_page", "type": "integer", "default": 25, "min": 1, "max": 500, "description": "Rows per page. Values above 500 are rejected, not clamped."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938/tfs",
      "errors": [{"status": 404, "code": "peak_not_found", "when": "No peak with that id or name."}],
      "notes": ["total is null: counting distinct TFs on a busy peak is as expensive as the query itself, so it is deliberately not computed."],
      "example_response": {
        "data": [
          {"tf_gene_name": "CTCF", "tf_gene_id": 3581, "dataset_source": "remap_chipseq", "n_datasets": 299, "max_overlap_bp": 1251, "url": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/CTCF"}
        ],
        "page": 1,
        "per_page": 2,
        "total": null,
        "total_is_exact": false,
        "pages": null,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938/tfs?page=1&per_page=2", "first": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938/tfs?page=1&per_page=2", "prev": null, "next": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/atac-peak/58938/tfs?page=2&per_page=2", "last": null}
      }
    },
    {
      "id": "link_tf_gene",
      "group": "links",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/link/tf-gene/{tf}/{gene}",
      "summary": "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.",
      "path_params": [
        {"name": "tf", "type": "string", "required": true, "example": "FOXA2", "description": "TF gene symbol."},
        {"name": "gene", "type": "string", "required": true, "example": "SOX17", "description": "Target gene symbol."}
      ],
      "query_params": [
        {"name": "include", "type": "enum_list", "enum": "tf_gene_include", "default": "", "description": "'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."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/link/tf-gene/FOXA2/SOX17",
      "errors": [{"status": 404, "code": "gene_not_found", "when": "Either name does not resolve."}],
      "notes": ["binding_evidence is false when no dataset places this TF at this gene; the elements block is then empty regardless of include."],
      "example_response": {
        "data": {
          "id": "FOXA2->SOX17",
          "type": "tf_gene_link",
          "tf_gene_name": "FOXA2",
          "tf_gene_id": 10678,
          "gene_name": "SOX17",
          "gene_id": 21169,
          "binding_evidence": true,
          "n_datasets_with_binding": 32,
          "max_binding_score_A": 15.2511416683968,
          "perturbation": [
            {"grna_id": 21, "grna_name": "FOXA2_2", "active": 1, "coef": -0.121044183808152, "z_coef": -0.385296653553392, "padj": 0.80415913951322}
          ],
          "perturbation_evidence": true,
          "datasets": [
            {"dataset_id": 4997, "dataset": "GSE92491.FOXA2.BJ1-hTERT_FOXA2_GATA4_Coexp", "dataset_tf_label": "FOXA2", "cell_type": "BJ1-hTERT_FOXA2_GATA4_Coexp", "cell_type_group": "other", "source": "remap_chipseq", "match_type": "exact", "binding_score_A": 15.2511416683968, "binding_score_B": 13.9640622169305, "binding_score_C": 16.6047494951281, "binding_score_D": 6.15058703084851}
          ],
          "datasets_truncated": false,
          "elements": [
            {"atac_peak_id": 58912, "atac_peak_name": "ESC_DE_peak_99055", "chr": "8", "chrom_start": 54223881, "chrom_end": 54225934, "overlap_bp": 1035, "peak_id": 57258057, "peak_source": "huangfu-tf_chipseq", "dataset_id": 11, "dataset": "DE-FOXA2-1", "cell_type": "DE"}
          ],
          "elements_truncated": false
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/link/tf-gene/FOXA2/SOX17", "tf": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/FOXA2", "gene": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/gene/SOX17", "html": "https://www.huangfulab.com/endoderm-perturbseq/link/FOXA2/SOX17"}
      }
    },
    {
      "id": "link_tf_module",
      "group": "links",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/link/tf-module/{tf}/{module}",
      "summary": "Evidence that a TF regulates a module, from both the perturbation screen and binding enrichment, with the per-gRNA detail behind it.",
      "path_params": [
        {"name": "tf", "type": "string", "required": true, "example": "ARID1A", "description": "TF gene symbol."},
        {"name": "module", "type": "string", "required": true, "example": "DE-1", "description": "Module name; the same aliases as /module are accepted."}
      ],
      "query_params": [
        {"name": "source", "type": "enum", "enum": "module_source", "required": false, "description": "Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule."}
      ],
      "returns": "entity",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/link/tf-module/ARID1A/DE-1",
      "errors": [
        {"status": 400, "code": "ambiguous_name", "when": "The module name needs ?source=."},
        {"status": 404, "code": "module_not_found", "when": "No such module."},
        {"status": 404, "code": "gene_not_found", "when": "No such TF."}
      ],
      "notes": [],
      "example_response": {
        "data": {
          "id": "ARID1A->DE-1",
          "type": "tf_module_link",
          "tf_gene_name": "ARID1A",
          "tf_gene_id": 997,
          "module_id": 13,
          "module_name": "DE-1",
          "module_display_name": "DE-1",
          "module_collection": "hotspot_supermodule",
          "evidence": "binding",
          "direction": null,
          "mean_NES": null,
          "n_grnas": null,
          "perturbation_padj": null,
          "odds_ratio": 4.41214098381629,
          "odds_ratio_infinite": false,
          "binding_padj": 1.2491000938415e-33,
          "binding_pval": 1.20626298722773e-36,
          "n_overlap": 1958,
          "n_tf_targets": 8327,
          "n_module_genes": 2012,
          "n_total": 9156,
          "n_module_genes_tested": 4014,
          "mean_coef": 0.0022804732411694333,
          "n_significant": 0,
          "per_grna": [
            {"grna_id": 2, "grna_name": "ARID1A_2", "active": 0, "NES": -1.22986286677535, "pval": 6.89503091746521e-05, "padj": 0.0008857462793974, "size": 2149}
          ],
          "per_grna_truncated": false
        },
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/link/tf-module/ARID1A/DE-1", "tf": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/ARID1A", "module": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/module/DE-1"}
      }
    },
    {
      "id": "link_gene_module",
      "group": "links",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/link/gene-module",
      "summary": "Gene-to-module membership edges. At least one filter is required.",
      "path_params": [],
      "query_params": [
        {"name": "gene", "type": "string", "default": "", "description": "Return this gene's memberships."},
        {"name": "module", "type": "string", "default": "", "description": "Return this module's members."},
        {"name": "source", "type": "enum", "enum": "module_source", "required": false, "description": "Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule."},
        {"name": "include_unassigned", "type": "boolean", "default": false, "description": "Include the 'unassigned' pseudo-modules, which hold 5,805 genes between them and are a non-result rather than a module."},
        {"name": "page", "type": "integer", "default": 1, "min": 1, "description": "1-based page number."},
        {"name": "per_page", "type": "integer", "default": 25, "min": 1, "max": 500, "description": "Rows per page. Values above 500 are rejected, not clamped."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/link/gene-module?module=DE-1",
      "errors": [
        {"status": 400, "code": "filter_required", "when": "None of gene, module or source was supplied — an unfiltered dump is 26K rows."}
      ],
      "notes": [],
      "example_response": {
        "data": [
          {"gene_id": 7, "gene_name": "AAAS", "gene_biotype": "protein_coding", "in_perturbation_library": false, "module_id": 13, "module_name": "DE-1", "source": "hotspot_supermodule", "module_size": 2012, "module_display_name": "DE-1"}
        ],
        "page": 1,
        "per_page": 2,
        "total": 2012,
        "total_is_exact": true,
        "pages": 1006,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/link/gene-module?module=DE-1&page=1&per_page=2", "first": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/link/gene-module?module=DE-1&page=1&per_page=2", "prev": null, "next": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/link/gene-module?module=DE-1&page=2&per_page=2", "last": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/link/gene-module?module=DE-1&page=1006&per_page=2"}
      }
    },
    {
      "id": "edges",
      "group": "links",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/edges",
      "summary": "The TF-to-module regulatory network as an edge list, merging perturbation and binding evidence.",
      "path_params": [],
      "query_params": [
        {"name": "level", "type": "enum", "enum": "module_source", "default": "hotspot_supermodule", "description": "Which module collection to build the network over."},
        {"name": "evidence", "type": "enum", "enum": "edge_evidence", "default": "any", "description": "Restrict to edges with this kind of support."},
        {"name": "min_odds_ratio", "type": "number", "default": 1.0, "min": 0, "description": "Minimum binding enrichment odds ratio."},
        {"name": "max_padj", "type": "number", "default": 0.05, "min": 0, "max": 1, "description": "Maximum adjusted p-value for the binding arm."},
        {"name": "min_abs_nes", "type": "number", "default": 0, "min": 0, "description": "Minimum |NES| for the perturbation arm."},
        {"name": "page", "type": "integer", "default": 1, "min": 1, "description": "1-based page number."},
        {"name": "per_page", "type": "integer", "default": 25, "min": 1, "max": 500, "description": "Rows per page. Values above 500 are rejected, not clamped."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/edges",
      "errors": [],
      "notes": ["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."],
      "example_response": {
        "data": [
          {"tf": "LIN9", "tf_gene_id": null, "module": "DE-11", "module_id": 5, "module_collection": "hotspot_supermodule", "evidence": "binding", "direction": null, "mean_NES": null, "n_grnas": null, "perturbation_padj": null, "odds_ratio": 18.0494168585444, "odds_ratio_infinite": false, "binding_padj": 1.00648368689005e-78, "n_overlap": 239, "strength": 18.0494168585444}
        ],
        "page": 1,
        "per_page": 2,
        "total": 3495,
        "total_is_exact": true,
        "pages": 1748,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/edges?page=1&per_page=2", "first": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/edges?page=1&per_page=2", "prev": null, "next": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/edges?page=2&per_page=2", "last": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/edges?page=1748&per_page=2"},
        "meta": {"level": "hotspot_supermodule", "evidence_filter": "any"}
      }
    },
    {
      "id": "genes",
      "group": "collections",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/genes",
      "summary": "All genes in the dataset, filterable by biotype, chromosome and perturbation-library membership.",
      "path_params": [],
      "query_params": [
        {"name": "biotype", "type": "string", "default": "", "description": "Exact gene_biotype, e.g. protein_coding or lncRNA."},
        {"name": "chr", "type": "string", "default": "", "description": "Chromosome. '7' and 'chr7' are both accepted."},
        {"name": "perturbed", "type": "boolean", "default": null, "description": "Restrict to genes that are (or are not) in the perturbation library."},
        {"name": "page", "type": "integer", "default": 1, "min": 1, "description": "1-based page number."},
        {"name": "per_page", "type": "integer", "default": 25, "min": 1, "max": 500, "description": "Rows per page. Values above 500 are rejected, not clamped."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/genes?per_page=5",
      "errors": [],
      "notes": ["Only primary_gene=1 rows are listed, so each symbol appears once."],
      "example_response": {
        "data": [
          {"gene_id": 1, "ensg_id": "ENSG00000202198", "gene_name": "7SK", "gene_biotype": "misc_RNA", "chr": "6", "chrom_start": 52995620, "chrom_end": 52995950, "description": "RNA component of 7SK nuclear ribonucleoprotein", "in_perturbation_library": false, "publication_count": null, "id": "7SK", "type": "gene", "url": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/gene/7SK"}
        ],
        "page": 1,
        "per_page": 5,
        "total": 24831,
        "total_is_exact": true,
        "pages": 4967,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/genes?page=1&per_page=5", "first": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/genes?page=1&per_page=5", "prev": null, "next": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/genes?page=2&per_page=5", "last": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/genes?page=4967&per_page=5"}
      }
    },
    {
      "id": "tfs",
      "group": "collections",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/tfs",
      "summary": "Transcription factors. There is no TF table in the database, so which population you get is an explicit choice.",
      "path_params": [],
      "query_params": [
        {"name": "set", "type": "enum", "enum": "tf_set", "default": "perturbed", "description": "'perturbed' = the 75 TFs targeted in the CRISPR screen; 'binding' = the ~1,705 genes with a binding dataset; 'all' = either."},
        {"name": "page", "type": "integer", "default": 1, "min": 1, "description": "1-based page number."},
        {"name": "per_page", "type": "integer", "default": 25, "min": 1, "max": 500, "description": "Rows per page. Values above 500 are rejected, not clamped."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/tfs",
      "errors": [],
      "notes": ["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."],
      "example_response": {
        "data": [
          {"id": "ADNP2", "type": "tf", "gene_name": "ADNP2", "gene_id": 350, "is_perturbed_tf": true, "is_binding_tf": false, "n_modules_regulated": 3, "n_binding_datasets": 0, "symbol_status": "current", "url": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/ADNP2"}
        ],
        "page": 1,
        "per_page": 2,
        "total": 75,
        "total_is_exact": true,
        "pages": 38,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tfs?page=1&per_page=2", "first": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tfs?page=1&per_page=2", "prev": null, "next": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tfs?page=2&per_page=2", "last": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tfs?page=38&per_page=2"}
      }
    },
    {
      "id": "modules",
      "group": "collections",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/modules",
      "summary": "All modules across the three collections, with sizes and titles. Full descriptions are on /module/{module}.",
      "path_params": [],
      "query_params": [
        {"name": "source", "type": "enum", "enum": "module_source", "required": false, "description": "Module collection. Required when the name is ambiguous — 'unassigned' exists in both hotspot_supermodule and hotspot_submodule."},
        {"name": "include_unassigned", "type": "boolean", "default": false, "description": "Include the 'unassigned' pseudo-modules."},
        {"name": "page", "type": "integer", "default": 1, "min": 1, "description": "1-based page number."},
        {"name": "per_page", "type": "integer", "default": 25, "min": 1, "max": 500, "description": "Rows per page. Values above 500 are rejected, not clamped."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/modules",
      "errors": [],
      "notes": ["Gene clusters carry both display_name (GC1) and the full alias list."],
      "example_response": {
        "data": [
          {"module_id": 250, "module_name": "DE-1.1", "source": "hotspot_submodule", "size": 61, "title": "Cytosolic ribosome and protein biosynthesis", "n_genes": 61, "display_name": "DE-1.1", "aliases": [], "id": "DE-1.1", "type": "module", "url": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/module/DE-1.1"}
        ],
        "page": 1,
        "per_page": 2,
        "total": 310,
        "total_is_exact": true,
        "pages": 155,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/modules?page=1&per_page=2", "first": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/modules?page=1&per_page=2", "prev": null, "next": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/modules?page=2&per_page=2", "last": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/modules?page=155&per_page=2"}
      }
    },
    {
      "id": "search",
      "group": "collections",
      "method": "GET",
      "url_template": "https://huangfulab.com/endoderm-perturbseq/api/v1/search",
      "summary": "Prefix search across genes, synonyms, TFs, modules and GO terms.",
      "path_params": [],
      "query_params": [
        {"name": "q", "type": "string", "required": true, "default": "", "description": "Search string, 2-64 characters. Matched as a prefix for names and as a substring for GO term descriptions. Wildcards are escaped, not interpreted."},
        {"name": "type", "type": "enum_list", "enum": "search_type", "default": "", "description": "Restrict to these result types."},
        {"name": "limit", "type": "integer", "default": 25, "min": 1, "max": 100, "description": "Maximum results across all types."}
      ],
      "returns": "collection",
      "example_url": "https://huangfulab.com/endoderm-perturbseq/api/v1/search?q=SOX",
      "errors": [
        {"status": 400, "code": "invalid_param", "when": "q is missing, shorter than 2 characters, or longer than 64."}
      ],
      "notes": ["Each result carries matched_on, so an exact symbol hit can be told apart from a synonym or a GO description match."],
      "example_response": {
        "data": [
          {"type": "tf", "id": "SOX1", "name": "SOX1", "display_name": "SOX1", "gene_id": 21162, "matched_on": "gene_name", "url": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/tf/SOX1", "html_url": "https://www.huangfulab.com/endoderm-perturbseq/gene/SOX1"}
        ],
        "page": 1,
        "per_page": 25,
        "total": 24,
        "total_is_exact": true,
        "pages": 1,
        "links": {"self": "https://www.huangfulab.com/endoderm-perturbseq/api/v1/search?q=SOX", "first": null, "prev": null, "next": null, "last": null}
      }
    }
  ]
}
