Public API · Anonymous · Read-only · v1

Normalized facts about AI model pricing, availability and capabilities. You control workloads, ranking and cost/quality trade-offs.

Base URL: https://aiforless.ai/api/v1 · No API key required · Raw OpenAPI 3.1 JSON

Quick start

Request only the providers you need; the full catalog can be several megabytes.

curl --header "Accept: application/json" \
  "https://aiforless.ai/api/v1/provider-catalog?providers=anthropic-direct,openai-direct"

Ranking

The API returns normalized facts and does not expose predefined ranking profiles. It does not accept custom quality, speed or ranking weights. Consumers apply their own ranking and cost/quality policy to the returned data.

Endpoints

MethodPathPurposeMain parametersCache
GET/api/v1/provider-catalogNormalized provider/model catalogproviders60 s + revalidation
GET/api/v1/provider-route-resolutionResolve exact route or safe exclusionprovider, model60 s + revalidation
GET/api/v1/modelsCanonical model listlimit, offset, filters60 s + revalidation
GET/api/v1/models/{slug}One canonical model and its offersslug60 s + revalidation
GET/api/v1/price-changesPrice transitions retained for 7 daysrange, filters, pagination; complete=true for one model60 s + revalidation
GET/api/v1/providersPublic provider directory—60 s + revalidation
GET/api/v1/sources/statusPublic freshness and collection health—30 s + revalidation

Provider filters are comma-delimited, trimmed and de-duplicated. Empty, malformed, unknown or inactive selections fail closed. See OpenAPI for every model-list filter and bound.

Pricing

pricingBands provides current published text-token tariff bands on provider-catalog rows. Each band preserves service tier, context tier, exclusive lower and inclusive upper input-token bounds, exact units, input/output/cache prices and source conditions. Missing prices are null. Historical lastKnown prices and NO_LONGER_LISTED components are excluded. Ambiguous or conflicting groups are not synthesized; non-token quotes remain in components.

applicability distinguishes unconditional, context-bound and conditional quotes. effectiveNow evaluates time or schedule applicability only; it does not select a band for an unknown request length or evaluate other request conditions. Unresolved conditions yield null. Any declared approximation also applies to this flag. Match context bounds and service tier before using a price. All currently published schedule phases remain represented, including temporarily inactive phases.

Raw normalized components are authoritative. Recurring schedules retain all phases in conditions.pricingSchedule; their optional effectiveNow flag identifies the phase active when the response was evaluated. Money uses exact decimal strings (nanoUsd, usd and display text), never floating-point JSON numbers.

listed

A non-zero canonical Money value is present.

free

State is free and canonical Money is exactly zero.

not_listed

The current price is null. listingState says whether it was never public or is no longer listed.

listingState separates CURRENTLY_LISTED, NO_LONGER_LISTED and NEVER_PUBLICLY_LISTED. Only the second carries lastKnown: an exact historical amount, confirmation time and source provenance. It is display evidence, never a current price and never an input to comparisons, rankings or Cost Index.

Never interpret numeric zero alone as free. State and Money must satisfy the contract together. Each provider-catalog model is one provider offer; differently priced routes are separate rows. providerModelAliases contains reviewed true synonyms only, never product/snapshot relationships. Match by provider slug plus exact provider-native ID. standardComparablePricing is a row-local deterministic projection from that row's own current components. It selects one coherent service/context tier and never mixes input and output tiers; supported recurring schedules resolve the active phase at the response instant; other conditional and unsupported dynamic routes remain null.

maximumRateComparisonPricing carries every complete eligible scenario and declares the maximum-rate comparison policy when current applicability is unresolved. It never claims that the selected comparison scenario is currently billed. An optional currentEstimate selects an approximate current scenario using UTC hours and weekdays while ignoring Chinese public holidays. Component approximation markers use the same server evaluation instant; they do not replace authoritative conditions or assert an exact billed price. The website labels this estimate and its Cost Index as approximate.

pricingState distinguishes a standard token pair, one-sided token price, non-token price, exact free price, no public price, conflict and stale evidence. Unknown identity, capability, context or price remains null. Source-native character/audio/image/request/video components never become text-token prices.

Cost Index reference

The reference basket is $0.05 input and $0.40 output per 1M tokens. The website and this reference use the same workload presets: Balanced 1:1, Chat 2:1 and RAG & Agents 10:1. Custom accepts a decimal input multiplier from 0.1 to 9999.

The calculation is transparent: each normalized input/output price is weighted against the same reference basket.

index = (input_price * input_weight + output_price * output_weight)
      / (reference_input * input_weight + reference_output * output_weight)

Balanced

1:1 · Weighted reference cost: $0.45

Chat

2:1 · Weighted reference cost: $0.5

RAG & Agents

10:1 · Weighted reference cost: $0.9

Custom

1.5:1 · Weighted reference cost: $0.475

Preset selection and the custom multiplier calculate locally for presentation. They are not Public API request parameters; the API exposes the normalized price components needed to apply the same workload calculation.

Capabilities

The provider-catalog endpoint accepts hideSpecialized, hideSnapshots, hideDeprecatedRetired, hideLocalRunnable and hideWithoutCostIndex as true or false. All default to false, independently of the website defaults, and combine with AND. Unknown flags and lifecycle evidence are retained. Hide runnable locally excludes only verified localRunnable=true. Hide models without Cost Index requires a coherent current standard text input/output pair per million tokens, including a starting context band, or supported maximum-rate comparison pricing. Historical, missing, ambiguous or incompatible prices do not qualify. No independent availability filter is applied. The explorer enables Hide snapshots, Hide specialized models and Hide models without Cost Index by default and sends their parameters explicitly; the other two start unchecked. Empty provider groups are omitted; explicitly requested providers with no matches have providerResults status empty. Counts are recalculated for retained rows using their existing definitions. Filtered responses retain content-based ETag revalidation and do not replace the unfiltered catalog cache.

/api/v1/provider-catalog?providers=openai-direct&hideSpecialized=true&hideSnapshots=true&hideDeprecatedRetired=true

releaseDate is the canonical model release date in YYYY-MM-DD format, or null when unknown. It is included in provider-catalog rows, the models list and model details. firstSeenAt records catalog discovery in UTC. sort=recent orders the models list by discovery time, not release date. For release chronology, sort the returned dates locally with unknown dates last.

specialized is available on provider-catalog rows and model details: true identifies media, speech, embedding, realtime or reviewed domain-specific models, false identifies text-generation models with no identified specialization, and null means unknown. Specialized models include image generation/editing, video generation, audio generation, transcription, speech synthesis, embeddings and realtime, plus explicitly reviewed domain models such as life sciences (GPT Rosalind Discovery/Research) and cybersecurity. Classification uses confirmed operations/output modalities and reviewed canonical identities, never a name heuristic. General text models that accept images, audio or video as input are not specialized for that reason alone. Unknown specialization remains visible under this filter. The website hides only confirmed specialized models when Hide specialized models is enabled.

capabilities.effective preserves the existing context and general capability projection. Each provider-catalog row also includes modelClassification.modalities for input/output media and modelClassification.operations for workloads such as text or image generation, image editing, embeddings, speech, realtime and moderation. Every classification field is true, false or null; null means that AIFORLESS has no current non-conflicting exact-route evidence. Unknown is not No, and clients must not infer capability from a model name.

Freshness & provenance

Public pricing identifies the source, parser version, observation and successful verification. Freshness describes age; collection status describes whether recent collection is healthy, degraded or unavailable. A degraded attempt does not invalidate the last successfully verified published fact. Application health/readiness is a separate operational concern and is not part of the data-freshness API.

lifecycle is an independent exact-route fact with CURRENT, DEPRECATED, RETIRED or UNKNOWN status, shutdown and replacement identifiers when first-party evidence states them, resolution/freshness state and evidence links. It is never inferred from price presence or absence. Canonical model responses aggregate resolved route facts and fail closed on disagreement.

In provider-catalog rows, lifecycle describes the provider route and developerLifecycle describes the original model at its developer. Hide deprecated & retired excludes rows when either status is DEPRECATED or RETIRED. Hide snapshots excludes only isSnapshot=true; Hide specialized models excludes only specialized=true. These checkboxes do not exclude unknown or absent flags; independent availability, price and other filters still apply. Hide runnable locally excludes only localRunnable=true. Unknown lifecycle evidence is not retirement.

Caching

Stable success responses carry a strong ETag over exact serialized bytes, Last-Modified as informational represented-data time and Cache-Control with no-transform. Store the ETag and send it in If-None-Match; a current representation returns an empty 304 Not Modified. If-Modified-Since is intentionally ignored because represented-data time is not a monotonic revision of filtered and time-windowed views. Filtered URLs are distinct representations, and 304 requests still consume quota.

curl -i -H 'If-None-Match: "stored-validator"' \
  'https://aiforless.ai/api/v1/providers'

Rate limits

Anonymous limits are per effective client IP. Read X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset from each response; honor Retry-After on 429. Do not hardcode a quota into client logic.

Errors

CodeMeaning
invalid_requestParameters failed validation
unknown_providerProvider filter contains unknown or inactive slugs
not_foundResource does not exist
rate_limitedClient quota exceeded
internal_errorSanitized unexpected failure
data_unavailableRepresentation cannot currently be published

Errors include request metadata for support correlation; stable success metadata deliberately does not include a request ID.

Versioning

/api/v1 promises semantic and structural compatibility. Additive fields, models and providers are normal v1 evolution. The lifecycle contract was added under schema version 2026-09-02.lifecycle-pricing-source-v1; clients should skip unknown future lifecycle, component and tier values rather than interpret them as known facts. Critical state and Money semantics do not silently change; breaking semantics require a new major API version. The transitional catalog field arenaOverall is deprecated; use quality.arenaOverall.

The API is suitable for server-side clients and same-origin use. Cross-origin browser access is not currently a guaranteed v1 contract.

Examples

JavaScript / TypeScript

// Node.js or same-origin browser code
const url = "/api/v1/provider-catalog?providers=anthropic-direct,openai-direct";
const first = await fetch(url, { headers: { Accept: "application/json" } });
if (!first.ok) throw new Error(`HTTP ${first.status}`);
const etag = first.headers.get("ETag");
const catalog = await first.json();
// Money is authoritative decimal text: catalog.data[0].models[0].components[0].price.usd

const next = await fetch(url, { headers: { Accept: "application/json", "If-None-Match": etag ?? "" } });
if (next.status === 304) console.log("Cached representation is current");
else if (next.ok) console.log(await next.json());
else throw new Error(`HTTP ${next.status}`);

Python standard library

from decimal import Decimal
import json, urllib.request, urllib.error

url = "https://aiforless.ai/api/v1/provider-catalog?providers=anthropic-direct,openai-direct"
request = urllib.request.Request(url, headers={"Accept": "application/json"})
with urllib.request.urlopen(request) as response:
    etag = response.headers.get("ETag")
    catalog = json.load(response)
    usd = Decimal(catalog["data"][0]["models"][0]["components"][0]["price"]["usd"])

try:
    urllib.request.urlopen(urllib.request.Request(url, headers={"If-None-Match": etag or ""}))
except urllib.error.HTTPError as error:
    if error.code != 304:
        raise

Try the API

Choose an endpoint, adjust the filters, then send a request.

GETRequest

Comma-separated slugs. Leave empty for all providers.

Visibility filters
Request URL/api/v1/provider-catalog?providers=anthropic-direct%2Copenai-direct&hideWithoutCostIndex=true&hideSpecialized=true&hideSnapshots=true
ResponseNot sent
Your response will appear here

Send a request to inspect the JSON response and HTTP headers.

Machine-readable contract

Download the deterministic OpenAPI 3.1 document. It contains exactly the seven stable data resources; operational and future product routes are intentionally excluded.