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":   "-latest_phase",        // optional; entity default otherwise
  "limit":  25,
  "offset": 0,
  "fields": ["name", "latest_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, disease, modality, companyphase, route, industry_only
trialsdrug, disease, target, 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); the other reference fields resolve through autocomplete.

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","latest_phase","developers"]}'

returns (truncated):

json
{
  "total": 49,
  "results": [
    { "name": "afimkibart",  "latest_phase": "3", "developers": ["Roche", "Roivant Sciences", "Pfizer", "Telavant"] },
    { "name": "duvakitug",   "latest_phase": "3", "developers": ["Teva Pharmaceutical Industries", "Sanofi"] },
    { "name": "tulisokibart","latest_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","latest_phase"]}'
json
{
  "total": 149,
  "note": "one or more OR-branches hit the 500-row cap; total is a lower bound",
  "results": [
    { "name": "sacituzumab govitecan",  "latest_phase": "Approved" },
    { "name": "datopotamab deruxtecan", "latest_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="-latest_phase",
    limit=25,
    fields=["name", "latest_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