Docs / API

API reference

A public, CORS-open REST surface under /api/v1, plus a GraphQL endpoint. No key required. Reads are licensed CC-BY-4.0.

Response envelope

Every REST response wraps its payload the same way:

json
{
  "data": { /* the payload, shape depends on the endpoint */ },
  "meta": {
    "source": "https://www.vioscale.ai",
    "license": "CC-BY-4.0",
    "generatedAt": "2026-07-06T00:00:00.000Z",
    "disclaimer": "Independent, evidence-based. Every fact carries provenance."
  }
}

Errors return { "error": "…" } with the appropriate status (e.g. 404 for an unknown slug).

Endpoints

MethodPathdataDescription
GET/api/v1ApiIndexSelf-describing index of every endpoint.
GET/api/v1/softwareEntityListItem[]List entities. Query: category, limit, sort=score|name, intent, weights.
GET/api/v1/software/{slug}EntityViewOne entity with all provenanced facts (canonical balanced score). 404 if unknown.
GET/api/v1/categoriesCategoryView[]List all categories (tree).
GET/api/v1/categories/{slug}CategoryViewOne category with its ranked entities. Query: intent, weights.
GET/api/v1/compareComparisonViewAligned comparison. Query: tools=a,b,c (required), intent, weights.
GET/api/v1/searchEntityListItem[]Fuzzy search. Query: q (required), limit, intent, weights.
GET/api/v1/alternatives/{slug}EntityListItem[]Same-category alternatives. Query: limit, intent, weights.
GET/api/v1/signals/{slug}SignalBreakdownViewThe signal breakdown behind an entity's score.
GET/api/v1/intentsIntentCatalogueCatalogue of ranking profiles + signal glossary (for intent/weights).

Intent-conditioned ranking

Every list and ranking endpoint (and the same GraphQL queries) accepts optional re-weighting. The facts and signals never change, only the weight vector does. The balanced default is the canonical, citeable score; pass intent (a named profile) or weights (an explicit override) to re-rank. The resolved profile and normalised weights come back in meta, so you can verify the ranking. Each signal is capped at 0.5 of the total, so no single signal can dominate. See the full catalogue at /api/v1/intents.

shell
# named profile
curl "https://www.vioscale.ai/api/v1/categories/ci-cd?intent=most-secure"

# explicit weights (signal:number, comma-separated)
curl "https://www.vioscale.ai/api/v1/search?q=orm&weights=package_downloads:0.5,github_activity:0.5"

# GraphQL takes the same args
curl -X POST https://www.vioscale.ai/api/graphql -H 'content-type: application/json' \
  -d '{"query":"{ compare(tools:[\"prisma\",\"drizzle-orm\"], intent:\"most-active\"){ leader } }"}'

# the response meta echoes the applied ranking:
#   "meta": { "profile": "most-secure", "weights": { "security_posture": 0.48, ... } }

Content negotiation

You don't have to use /api/v1 at all. A canonical page URL responds to your Accept header:

curl
curl -H "Accept: application/json" https://www.vioscale.ai/software/nextjs   # → JSON
curl -H "Accept: text/markdown"   https://www.vioscale.ai/software/nextjs   # → Markdown
curl https://www.vioscale.ai/software/nextjs.md                              # → Markdown (suffix)

GraphQL

POST /api/graphql: open GraphiQL in a browser at the same URL. Schema:

graphql schema
type Query {
  software(slug: String!): Entity
  softwareList(category: String, limit: Int): [Entity!]!
  categories: [Category!]!
  category(slug: String!): Category
  compare(tools: [String!]!): Comparison!
  search(q: String!, limit: Int): [Entity!]!
  alternatives(slug: String!, limit: Int): [Entity!]!
}
curl
curl https://www.vioscale.ai/api/graphql \
  -H 'Content-Type: application/json' \
  -d '{"query":"{ compare(tools:[\"prisma\",\"drizzle-orm\"]){ leader entities{ name score{ composite } } } }"}'
API reference · Vioscale