Articles

Agent commerce

API Comparison Matrix for Agent Buyers: The Minimum Columns

An API comparison matrix for agent buyers has to carry a fixed minimum column set — identity, normalized price, measured performance, input fit — to be actionable.

7 min read

An API comparison matrix for agent buyers is not a page someone reads on a Tuesday. It is a payload a program reads once, mid-task, with no second tab to open and nobody to ask, and the columns it carries are the only evidence the buyer will ever have. That single read sets a hard floor on what the matrix has to contain.

A human comparison table can be thin because the reader fills the gaps. They know that one provider bills per record and another per request. They know the latency number on a marketing page is a best case. An agent knows none of this. It reads the cells it is given, applies whatever rule it was configured with, and calls someone. Every gap in the matrix becomes a wrong call, and the wrong call costs real money because the request is paid.

The minimum column set

Before an agent can treat two listings as substitutable offers, each row has to carry these:

  • A stable identifier for the candidate that survives the next call, so the choice can be passed to a decision step without re-resolving names.
  • Price expressed on one declared unit of work, not each provider's own meter.
  • Measured latency, with the number of observed calls behind it.
  • Measured success rate, on the same observation window as the latency.
  • An input compatibility verdict against the parameters this buyer actually holds.
  • The settlement path, so the agent knows whether it can pay in the same flow it discovered the offer in.

That is six columns. A score is a seventh, and it only earns its place under a condition covered further down. Anything else — documentation quality, region, brand — is context for a human reviewing the list later, not input the agent can act on in one read.

Price is not a column until the meter is normalized

Two rows that both say a price are not yet comparable. One meters per request, one per returned record, one per thousand tokens, and one charges for calls that return nothing. Dropping those four numbers into a single column produces an ordering that is arithmetically valid and practically wrong.

The fix is to declare one workload for the whole matrix and convert every listing to that workload before the column is written. The conversion rules matter as much as the result, which is why normalizing API pricing units belongs upstream of the comparison rather than inside the buyer's own prompt. A price column whose conversion is invisible is a ranking the buyer has to take on trust.

Latency and success rate are the columns nobody self-reports

Price is the one column a provider can publish about itself honestly, because it is a term the provider sets. Latency and success rate are different. They are outcomes, not terms, and no provider is in a position to report its own alongside a competitor's.

This is also where most published comparisons quietly go missing. Vendor pages report a favourable percentile or no percentile at all, and success rate rarely appears anywhere, because a provider has no reason to publish the share of its own calls that returned nothing usable. A matrix that carries these columns at all is carrying something the market does not otherwise produce — which is exactly why the distinction between measured latency and advertised latency has to be visible in the cell, not buried in a methodology note.

The practical rule: a measured cell states what was observed and how much of it. A cell with no observations behind it says so. Mixing the two in one column destroys the column.

Input compatibility is a gate, not a tiebreak

The cheapest, fastest provider in the matrix is useless if the agent holds an email address and that provider takes a domain. Input compatibility is not a scoring dimension to be traded off against price; it decides whether the row belongs in the ranking at all.

So the compatibility column answers a specific question — do the parameters this buyer holds map onto this provider's required inputs — and it answers it per buyer, not per listing. The same provider is compatible for one agent and impossible for another. Getting input compatibility mapping into the matrix as a hard verdict is what stops the ranking from recommending something the agent cannot call.

A score column is worthless without its weights, and a gap is not a zero

A single number per row is the most useful column in a matrix and the easiest one to abuse. It is only defensible when two things ship beside it.

First, the weights that produced it, plus each candidate's contribution per dimension. A buyer that cares about latency more than price should be able to redo the arithmetic and get its own answer. A score you cannot recompute is an advertisement wearing a number.

Second, the score is relative to the candidates in that one comparison. Move a candidate into a different set and its score changes, because it is a ranking signal, not a rating of the endpoint in isolation.

And a dimension nobody has measured for a candidate is dropped from the weighting and named, never scored zero. A zero says "measured, and bad". An empty labelled cell says "not measured", which is a different fact and often a temporary one. Result quality and provider terms are not measured anywhere in this model, and a matrix that pretends otherwise is inventing its most persuasive column.

Rows that cannot join the matrix

Discovery finds more than the reviewed catalogue. Sweeping external x402 sources surfaces endpoints that exist and might well be the right answer, but they arrive with no stable identifier, nothing measured, and no settlement path. They cannot be scored, and they cannot be chained into a comparison or a decision.

They are still worth returning — just not as rows. Keeping the reviewed and unreviewed split structurally separate is what keeps the measured rows meaningful. The moment an unmeasured hit sits in the same table as a measured one, every cell in the table becomes a maybe.

What a provider should check in its own row

If you run an endpoint, the matrix is the surface where you are actually being bought. Three checks are worth running on your own row:

  • Does your price convert cleanly to a common unit, or does your meter make you look expensive in someone else's arithmetic? Per-record pricing with a high null rate reads worse than it costs.
  • Is your latency cell measured or empty? An empty cell drops you out of that dimension's weighting rather than sinking you, but it also means the fastest thing about you is invisible.
  • Does your required input set exclude buyers who hold a common alternative identifier? Accepting one more input format sometimes moves you from ineligible to first.

None of this is reputation work. It is column work, and it is the difference between appearing in the ranking and being filtered before the ranking runs.

Where Apiosk fits

Apiosk builds this matrix as a call rather than a page. `GET /v1/compare?candidates={id},{id}` returns price, measured latency, measured success rate and input compatibility side by side, each scored 0–100 with the weights and per-dimension contributions attached, so the ranking can be recomputed rather than trusted. `GET /v1/decide` takes the same candidate set and returns one provider, the rule that picked it, and every rejected candidate with the exact constraint that removed it. Requirements like `max_price`, `max_latency_ms`, `min_reliability` and `optimize_for` are passed once and reused down the chain.

What Apiosk does not do is score result quality or provider terms, and it does not put unreviewed external hits in the same block as measured candidates. If you run an endpoint and want your row to carry real measured columns rather than empty ones, listing your API is where that starts; the gateway's `/.well-known/x402` document remains the live source for payment terms, and the integration examples show what a buyer copies to call you.

Frequently asked questions

How many columns does an agent-readable comparison actually need?

Six carry the decision: a stable candidate identifier, a normalized price, measured latency, measured success rate, an input compatibility verdict, and the settlement path. Any score is a seventh column that only counts when the weights behind it travel with it. Everything beyond that is useful context, not decision input.

Why can a comparison not just copy each provider's published latency?

Published latency is a claim made under conditions the publisher chose, and it is usually reported without the percentile or the failure cases. A column that mixes observed measurements with vendor claims is not comparable down its own length, so the two have to be different columns or the claim has to be left out.

What should the matrix do about a dimension it has not measured?

Name the gap and drop that dimension from the weighting. Filling the cell with a zero punishes the candidate for the observer's missing data, and filling it with an average invents a measurement. A labelled empty cell is information; a fabricated one is noise the buyer cannot detect.

Can unreviewed listings appear in the same matrix as measured ones?

They can appear in the same response, but not in the same table. Unreviewed hits have no stable identifier, no measured columns and no settlement path, so putting them in rows next to measured candidates implies a comparison that was never made. They belong in a separate block that is clearly marked as a lead rather than an offer.

Your API is one key away from AI revenue.

Built for APIs, MCP servers, datasets and digital services.