Skip to content

SDK API Reference

The Graffold SDK API (/v1/sdk/) provides programmatic access to the knowledge graph for external platform integrations. It's designed as a generic scientific KG API — entity lookup, relationship discovery, evidence retrieval, and enrichment.

Authentication

All SDK endpoints require a bearer token:

curl -H "Authorization: Bearer $API_AUTH_TOKEN" \
  http://localhost:8000/v1/sdk/entities/lookup \
  -d '{"query": "TP53"}'

Endpoints

Entity Lookup

Find entities by name, ID, or search term.

POST /v1/sdk/entities/lookup

Request:

{
  "query": "TP53",
  "entity_types": ["Protein", "Gene"],
  "limit": 10,
  "include_synonyms": true
}

Response:

[
  {
    "id": "P04637",
    "name": "TP53",
    "type": "Protein",
    "properties": {
      "uniprot_id": "P04637",
      "gene_symbol": "TP53",
      "function": "Tumor suppressor..."
    },
    "synonyms": ["p53", "tumor protein p53", "LFS1"]
  }
]

Batch Lookup

Multiple entity lookups in one call.

POST /v1/sdk/entities/batch

Request:

{
  "queries": [
    {"query": "TP53", "entity_types": ["Protein"]},
    {"query": "cardiovascular disease", "entity_types": ["Disease"]},
    {"query": "ENSG00000141510"}
  ]
}

Response: Array of arrays — one result set per query.


Neighborhood

Get the relationship graph around an entity.

POST /v1/sdk/entities/{entity_id}/neighborhood

Request:

{
  "entity_id": "P04637",
  "depth": 1,
  "relationship_types": ["ASSOCIATES_WITH", "INTERACTS_WITH"],
  "limit": 50
}

Response:

{
  "entity_id": "P04637",
  "neighbors": [
    {"id": "MONDO:0005070", "name": "cancer", "type": "Disease"},
    {"id": "P38398", "name": "BRCA1", "type": "Protein"}
  ],
  "relationships": [
    {
      "source_id": "P04637",
      "source_name": "TP53",
      "target_id": "MONDO:0005070",
      "target_name": "cancer",
      "type": "ASSOCIATES_WITH",
      "confidence": 0.95,
      "evidence_count": 47
    }
  ]
}

Evidence

Retrieve literature evidence supporting an entity or association.

POST /v1/sdk/evidence

Request (relationship evidence):

{
  "source_id": "P04637",
  "target_id": "MONDO:0005070",
  "min_confidence": 0.5,
  "limit": 10
}

Request (all evidence for an entity):

{
  "entity_id": "P04637",
  "limit": 20
}

Response:

[
  {
    "pmid": "12345678",
    "title": "TP53 mutations in cardiovascular disease",
    "abstract_excerpt": "We found that TP53 loss-of-function mutations...",
    "source": "ASSOCIATES_WITH",
    "confidence": 0.92,
    "study_design": "cohort_study",
    "publication_year": 2023
  }
]

Path Finding

Find paths between two entities in the knowledge graph.

POST /v1/sdk/paths

Request:

{
  "source_id": "P04637",
  "target_id": "MONDO:0004995",
  "max_hops": 3,
  "relationship_types": ["ASSOCIATES_WITH", "INTERACTS_WITH", "PART_OF"]
}

Response:

[
  {
    "nodes": [
      {"id": "P04637", "name": "TP53", "type": "Protein"},
      {"id": "R-HSA-69278", "name": "Cell Cycle", "type": "Pathway"},
      {"id": "MONDO:0004995", "name": "hypertension", "type": "Disease"}
    ],
    "edges": [
      {"source_id": "P04637", "target_id": "R-HSA-69278", "type": "PART_OF"},
      {"source_id": "R-HSA-69278", "target_id": "MONDO:0004995", "type": "ASSOCIATES_WITH"}
    ],
    "path_length": 2
  }
]

Enrich

Fetch annotations from external databases for given entities.

POST /v1/sdk/enrich

Request:

{
  "entity_ids": ["P04637", "ENSG00000141510"],
  "sources": ["uniprot", "opentargets"],
  "write_to_graph": true
}

Response:

[
  {
    "entity_id": "P04637",
    "source": "uniprot",
    "annotations": {
      "protein_name": "Cellular tumor antigen p53",
      "function": "Acts as a tumor suppressor in many tumor types...",
      "gene_names": ["TP53"],
      "organism": "Homo sapiens",
      "subcellular_location": ["Nucleus", "Cytoplasm"],
      "pathway": ["Apoptosis", "Cell cycle regulation"],
      "disease_involvement": ["Li-Fraumeni syndrome"]
    },
    "success": true
  },
  {
    "entity_id": "ENSG00000141510",
    "source": "opentargets",
    "annotations": {
      "associations": [
        {"disease": "neoplasm", "score": 0.98, "evidence_count": 1247},
        {"disease": "lung carcinoma", "score": 0.87, "evidence_count": 523}
      ]
    },
    "success": true
  }
]

Available sources: uniprot, opentargets, disgenet


Extract Entities from Text

Extract entities and relationships from text or artifact metadata.

POST /v1/sdk/extract

Request (text):

{
  "artifact_type": "text",
  "content": "TP53 mutations are frequently observed in cardiovascular disease patients with elevated NT-proBNP levels."
}

Request (structural file metadata):

{
  "artifact_type": "pdb",
  "metadata": {
    "uniprot_id": "P04637",
    "protein_name": "Cellular tumor antigen p53",
    "target_name": "TP53",
    "ligand_name": "Nutlin-3a"
  }
}

Response:

{
  "entities": [
    {"id": "TP53", "name": "TP53", "type": "Protein"},
    {"id": "NT-proBNP", "name": "NT-proBNP", "type": "Protein"}
  ],
  "relationships": [],
  "artifact_type": "text",
  "extraction_method": "text_ner"
}

Extract from Upload

Extract entities from an uploaded file (PDF, CSV, text).

POST /v1/sdk/extract/upload
Content-Type: multipart/form-data
curl -X POST http://localhost:8000/v1/sdk/extract/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@paper.pdf"

Response: Same as /extract endpoint.


Python Client Example

import httpx

class GraffoldClient:
    def __init__(self, base_url: str, token: str):
        self.client = httpx.Client(
            base_url=base_url,
            headers={"Authorization": f"Bearer {token}"},
        )

    def lookup(self, query: str, types: list[str] | None = None) -> list[dict]:
        resp = self.client.post("/v1/sdk/entities/lookup", json={
            "query": query,
            "entity_types": types,
        })
        resp.raise_for_status()
        return resp.json()

    def evidence(self, source_id: str, target_id: str) -> list[dict]:
        resp = self.client.post("/v1/sdk/evidence", json={
            "source_id": source_id,
            "target_id": target_id,
        })
        resp.raise_for_status()
        return resp.json()

    def enrich(self, entity_ids: list[str], sources: list[str] = None) -> list[dict]:
        resp = self.client.post("/v1/sdk/enrich", json={
            "entity_ids": entity_ids,
            "sources": sources or ["uniprot", "opentargets"],
        })
        resp.raise_for_status()
        return resp.json()

    def paths(self, source: str, target: str, max_hops: int = 3) -> list[dict]:
        resp = self.client.post("/v1/sdk/paths", json={
            "source_id": source,
            "target_id": target,
            "max_hops": max_hops,
        })
        resp.raise_for_status()
        return resp.json()


# Usage
kg = GraffoldClient("http://localhost:8000", token="your-token")
results = kg.lookup("BRCA1", types=["Protein"])
evidence = kg.evidence("P38398", "MONDO:0007254")
enriched = kg.enrich(["P04637", "P38398"])

Rate Limits

Tier Rate limit Notes
Default 120/minute All SDK endpoints
Batch 30/minute /entities/batch
Enrichment 30/minute /enrich (external API calls)

Error Responses

{
  "detail": "Entity not found: XYZ123"
}
Status Meaning
400 Invalid request (missing fields, bad filters)
401 Missing or invalid auth token
404 Entity/resource not found
422 Extraction failed (unreadable file)
429 Rate limit exceeded
500 Internal error