Skip to content

Query API ​

Every CLI command is sugar over one REST endpoint per entity:

POST /v2/{drugs|trials|companies|deals|news}/query

It takes a query object: a predicate tree whose reference values are names or ids. The server resolves the names to Gosset ids, runs the query, and returns the results plus a resolved block showing what each name became. Use it directly when you want programmatic access (agents, notebooks, services) without resolving ids yourself.

Auth is the same Bearer token as everything else (Authorization: Bearer <token>).

The query object ​

jsonc
{
  "where":  { "field": "target", "op": "is", "value": "TL1A" },  // predicate tree
  "sort":   "-phase",        // optional; entity default otherwise
  "limit":  25,
  "offset": 0,
  "fields": ["name", "phase", "developers"]   // optional projection
}

where is one of:

ShapeMeaning
{ "field": …, "op": …, "value": … }a leaf predicate
{ "and": [ … ] }all sub-trees must match
{ "or": [ … ] }any sub-tree matches
{ "not": … }negation (see caveats)

Ops: is, in (a list, or a comma string), contains (free-text search). A leaf value may be a single value or a list; a list means "any of".

Fields per entity ​

Reference fields (bold) accept a name or an id (a 24-hex ObjectId or a G[DMT]-… class id); everything else is matched verbatim.

EntityReference fieldsOther fields
drugsname/drug, target, target_class, disease, modality, companyphase, route, industry_only
trialsdrug, disease, target, target_class, sponsorsearch, phase, status, registry, since, until, industry_only, has_results
companiesname/company, disease, modalitycountry, type, stage, public
dealsdrug, target, disease, buyer, sellerdeal_type, since, until, min_value
newsdrug, disease, companysearch, category, since, until

disease names resolve through the disease classifier (to disease_classes); target_class resolves through the target ontology; the other reference fields resolve through autocomplete.

target vs target_class ​

A target name can mean two things, so drugs and trials have two fields for it:

  • target matches target entity ids. On trials it matches a target on any arm of the trial.
  • target_class matches the target ontology class of the drug's primary target. On trials it uses the main drug's primary target. Classes include their children, so IL-23 also returns the p40 antibody ustekinumab and the p19 antibodies risankizumab and guselkumab.

trials target_class=IL-23 returns the same trials as the join trials drug.target=IL-23. target_class takes a name or a GT-… class id. A name with no ontology class returns no results with an unresolved note. It does not fall back to entity ids; use target for those.

bash
curl -s -X POST https://api.gosset.ai/v2/trials/query \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"where":{"field":"target_class","value":"IL-23"},"limit":5}'

Reference resolution and the resolved echo ​

You pass names; the response tells you exactly what they matched. This request:

bash
curl -s -X POST https://api.gosset.ai/v2/drugs/query \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"where":{"field":"target","value":"TL1A"},"limit":3,"fields":["name","phase","developers"]}'

returns (truncated):

json
{
  "total": 49,
  "results": [
    { "name": "afimkibart",  "phase": "3", "developers": ["Roche", "Roivant Sciences", "Pfizer", "Telavant"] },
    { "name": "duvakitug",   "phase": "3", "developers": ["Teva Pharmaceutical Industries", "Sanofi"] },
    { "name": "tulisokibart","phase": "3", "developers": ["Schering-Plough", "Prometheus Biosciences"] }
  ],
  "resolved": {
    "target": {
      "matched": [
        { "as": "autocomplete", "name": "Tumor Necrosis Factor-like Cytokine 1A (TL1A)", "ids": 14 }
      ],
      "candidates": []
    }
  }
}

resolved shows the matched entity name, how many ids it expanded to, and any runner-up candidates, so you can always see how a name was interpreted (for example whether "Merck" matched the entity you meant).

Unresolved names never widen the query

If a name matches nothing, the response is {"results": [], "total": 0, "message": "could not resolve …"}. A dropped filter never silently falls through to an unfiltered, whole-database result. The CLI surfaces this and exits 2.

Examples ​

bash
# AND across fields: TROP2 drugs in breast cancer
-d '{"where":{"and":[
      {"field":"target","value":"TROP2"},
      {"field":"disease","value":"breast cancer"}]},"limit":25}'

# phase as a list (OR within a field)
-d '{"where":{"and":[
      {"field":"target","value":"PD-1"},
      {"field":"phase","op":"in","value":["Approved","3"]}]}}'

# free-text trial search + a structured filter
-d '{"where":{"and":[
      {"field":"search","op":"contains","value":"semaglutide"},
      {"field":"phase","value":"3"}]}}'   // POST /v2/trials/query

# deals: parties, type, value, date
-d '{"where":{"and":[
      {"field":"buyer","value":"Pfizer"},
      {"field":"deal_type","value":"M&A"},
      {"field":"min_value","value":"1000000000"},
      {"field":"since","value":"2024-01-01"}]}}'   // POST /v2/deals/query

Cross-field OR ​

bash
# every TL1A or TROP2 drug, in one call
-d '{"where":{"or":[
      {"field":"target","value":"TL1A"},
      {"field":"target","value":"TROP2"}]},"limit":25,"fields":["name","phase"]}'
json
{
  "total": 149,
  "note": "one or more OR-branches hit the 500-row cap; total is a lower bound",
  "results": [
    { "name": "sacituzumab govitecan",  "phase": "Approved" },
    { "name": "datopotamab deruxtecan", "phase": "Approved" }
  ]
}

From the SDK ​

python
from gosset import GossetClient

client = GossetClient(api_key="…")
res = client.query(
    "drugs",
    where={"and": [
        {"field": "target", "value": "TL1A"},
        {"field": "phase", "value": "3"},
    ]},
    sort="-phase",
    limit=25,
    fields=["name", "phase", "developers"],
)
print(res["total"], [r["name"] for r in res["results"]])

Caveats ​

  • not reaching a leaf returns HTTP 501. not over and/or is pushed inward (De Morgan), but the underlying filters have no negation seam yet, so a negated leaf is not supported. Negate at the value level where you can (for example an explicit phase list) instead.
  • OR totals can be a lower bound. A cross-field OR runs each branch and unions the results. If a branch hits the per-request row cap, the response carries a note and total is a floor, not an exact count. Narrow the branch or paginate for a complete set.
  • total semantics follow the underlying entity. Trials, for instance, report -1 when an exact count is not computed, matching the flat /v2/trials/ endpoint.

Gosset Documentation