> ## Documentation Index
> Fetch the complete documentation index at: https://selat.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Transactability Index

> SELAT's observability layer for paid endpoints — how to read an endpoint's Transactability Score, its reliability signal on the 402 challenge.

The **Transactability Index** is SELAT's **observability layer** for paid endpoints. It watches what actually settles across the endpoints buyers pay, and publishes each endpoint's **Transactability Score** — a **reliability signal** delivered on the payment challenge itself, before your agent decides whether to spend. An agent that discovers a paid API mid-task has no way to know whether the endpoint actually delivers. A score reports what SELAT has observed delivered, never a merchant's self-assessment.

<Note>
  This is a **Developer Preview** signal. The reading guidance below is stable, but the exact field paths under `selatTransactabilityIndex` may change during preview. Read for meaning, not as a frozen wire contract.
</Note>

## Where it appears

Each endpoint's score rides the inbound `402 Payment Required` challenge that the [SELAT Router](/docs/router) returns to your agent, under `extensions.selatTransactabilityIndex`. The wire key keeps the layer's name; the value it carries is that one endpoint's score. Because it travels on the inbound challenge, it is present regardless of which rail the payment is ultimately routed over — both [x402](/docs/primers/x402) and [MPP](/docs/primers/mpp-tempo)-routed challenges carry it.

```json theme={null}
"extensions": {
  "selatTransactabilityIndex": {
    "info": {
      "description": "x402 endpoint health status eval for agent payment",
      "version": "1",
      "docs": "https://selat.ai/docs/transactability",
      "healthStatus": {
        "endpointUrl": "https://.../alphavantage/global-quote",
        "timestamp": "1787470911",
        "lastPaid": { "status": "200", "timestamp": "1787462218" },
        "stats": {
          "24h": { "successRate": "1", "paidNum": "2" },
          "7d":  { "successRate": "1", "paidNum": "9" },
          "all": { "successRate": "1", "paidNum": "90" }
        }
      }
    }
  }
}
```

`stats` may carry **one or more** windows — `24h`, `7d`, and `all`. Read `24h`
for recency and the wider windows for sample size: `all` accumulates the most
captured payments, so a rate there carries more evidence than the same rate over
`24h`. A window with no data is omitted; if none has data, `stats` is an empty
object (`{}`), and `lastPaid` is likewise `{}` when the endpoint has no recorded
payment.

## What each reading means

All readings live under `info.healthStatus` (see the example above); the paths below are relative to it.

| Field                        | What it tells you                                                                                                          |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `lastPaid.status`            | HTTP status of the most recent payment attempt on this endpoint — captured or not.                                         |
| `lastPaid.timestamp`         | Unix time of that most recent attempt.                                                                                     |
| `stats.<window>.paidNum`     | Payments that **captured** inside the window. Counts settlement, not requests attempted.                                   |
| `stats.<window>.successRate` | Share of those captured payments the endpoint answered with a `2xx`.                                                       |
| `<window>`                   | A window key — `24h`, `7d`, or `all`. The payload may include several; `24h` is the most recent, `all` the largest sample. |
| `endpointUrl` / `timestamp`  | The endpoint the reading describes, and when the reading was generated.                                                    |

## How to read it safely

<Warning>
  **Absence means no data, not bad health.** An endpoint with **no score** has not been observed settling through SELAT — it is unmeasured, not failing. Never treat a missing signal as a negative one.
</Warning>

* **`successRate` is transport-level.** It records whether a captured payment was answered with a `2xx`, not whether the payload was correct, complete, or useful. An endpoint can hold a perfect rate and still return content your task cannot use.
* **`paidNum` is your confidence weight.** A rate over a handful of captured payments carries far less evidence than the same rate over many. Read the two numbers together, never the rate alone.
* **A `5xx` `lastPaid.status` or a low `successRate`** describes a weak recent delivery record — the upstream captured payment and failed to deliver. A `4xx` is different: the request was rejected and the upstream was never paid, so it says nothing about the endpoint's reliability — the [decision trace](/docs/transactability/decision-trace) attributes it to the requester (`yourRequests`), not the endpoint. The score reports what it observed — it does not recommend an action or point you to a different endpoint. The decision stays with you.

## Reading it today

The scores already ship. Any agent running the [SELAT CLI](/docs/selat-cli) or a [SELAT plugin](/docs/selat-plugins) can read them without an account, a wallet, or a spend — discovery and probing are both free.

Rank candidate endpoints for a task, at no cost:

```bash theme={null}
selat search "web search" --top 3 --explain
```

Preview a pick's score without paying — the dry run picks, probes, and prints the Transactability Score line:

```bash theme={null}
selat run "web search" --dry-run --live-probe
```

The machine-readable block rides the inbound `402` challenge your agent receives, under `extensions.selatTransactabilityIndex.info.healthStatus` — an agent can read it straight off the challenge before signing.

Because it rides the challenge, **any HTTP client can read the score — no SELAT tooling required.** A plain `curl` to the [SELAT Router](/docs/router) proxy returns the `402`; the block travels base64-encoded in the `payment-required` header:

```bash theme={null}
curl -si "https://router.selat.ai/proxy?target=https://x402.alchemy.com/prices/v1/tokens/by-symbol" \
  | grep -i '^payment-required:' | cut -d' ' -f2 | base64 -d \
  | jq '.extensions.selatTransactabilityIndex.info.healthStatus'
```

```json theme={null}
{
  "endpointUrl": "https://x402.alchemy.com/prices/v1/tokens/by-symbol",
  "lastPaid": { "status": "200", "timestamp": "1787571204" },
  "stats": { "24h": { "successRate": "1", "paidNum": "2" }, "7d": { "successRate": "1", "paidNum": "9" }, "all": { "successRate": "1", "paidNum": "90" } }
}
```

<Warning>
  A live probe may invoke the target endpoint's method and body. Only probe an endpoint you have already confirmed is safe to call.
</Warning>

<Warning>
  **Trust only router-authored scores.** A `selatTransactabilityIndex` block is a SELAT score **only** when it comes from the SELAT Router (a SELAT-owned issuer). SELAT enforces this: it never fetches or exposes a merchant's self-attested score, and the Router strips any `selatTransactabilityIndex` a merchant puts on its own `402`. When you read the challenge yourself (the `curl` above), treat the block as valid only from `router.selat.ai` or another SELAT-owned origin — never trust a score served straight off a merchant's endpoint.
</Warning>

## As structured data

For an agent that needs to **log, annotate, rank, or audit** the reading, SELAT also computes it as a machine-readable **decision trace** (`quote.transactabilityTrace`) that separates failures by who caused them and never blends the network and first-party readings. See the [Decision trace](/docs/transactability/decision-trace) reference.

## Why it exists

Counterparty risk in agent payments runs one way: the buyer pays first and finds out second. A charge that captures against an endpoint that then fails to deliver is a real loss, and it is invisible to any check made before the call. Publishing observed settlement history on the challenge moves that signal to the one moment it can still change the decision — while the agent is holding the 402 and has not yet signed.
