# Providers & coverage

Coverage is a resource, not a claim on a marketing page. `GET /v1/capabilities?product=…` answers "can this account do X" — read it instead of hard-coding an assumption about a corridor, a country or a payment method. A second endpoint, `GET /v1/eligibility`, is specified for "could an account in this country generally do X", but it is closed in production (see Eligibility below).

## Capabilities — what *this* account can do right now

`GET /v1/capabilities?product=payment_links|payouts|payroll|buy_sell|wallet_bank` returns, per product, the corridors or rails this specific authenticated account is actually eligible for — not a static list of everything Swaps theoretically supports.

Every corridor row states its own status honestly rather than a blanket "supported":

| Field | Meaning |
|---|---|
| `lifecycle` | `public` (advertised), `preview` (soft-launched), or `blocked` |
| `public_claim_status` | `live`, `unverified`, or `planned` — the honest gap between what's claimed and what's been probed |
| `executable` | whether *this* account can execute today — a capability read is availability, not a green light to skip re-checking at the money boundary |
| `blocked_reason` | present whenever `executable` is false, so an agent has something to act on instead of a bare no |

`blocked_reason` is an open enum: a client that meets a value it does not know treats the corridor as not executable and shows the reason as text. Two values name an environment or account fact rather than a missing provider:

| `blocked_reason` | Where | What it says |
|---|---|---|
| `relay_requires_tempo_mainnet` | `product=payment_links`, the `crypto_relay` corridor | The deployment settles on a Tempo test network (or the network cannot be resolved), and the payer page admits Relay only on Tempo mainnet. The corridor reads `not_enabled` with `source_chains: []` whatever the Relay switch says. `max_amount` is still published while the per-invoice cap is set. |
| `collection_account_uses_currency` | `product=wallet_bank`, the `wallet_bank_virtual_account` corridor | A Payment links collection account already receives this currency into the same wallet, so a new wallet bank account would only hand that one back. The corridor reads `not_enabled` with `action: none`. `POST /v1/wallet/virtual_accounts` for that currency answers `409 conflict`. |

For `product=payment_links` the answer also carries `fee`, the Swaps fee the payer is charged on top of the invoice (you receive the full invoice), read from the same constant the charge uses: `kind: "percentage"`, `bps: 100`, `applies_to: "payer"`, `rails: ["crypto_tempo", "crypto_relay"]`, `rounding` (`floor`) and `rounding_decimals` (`6`). A rail that is not in `rails` carries no fee claim from this object. The fee is a price, so it is published even while those corridors read `not_enabled`. See [Payment links](/products/payment-links#the-swaps-fee) for what the payer is asked for.

There is also an unauthenticated **public projection** of capabilities (product-wide fee and corridor claims with no entitlement or per-account detail) for anyone building a comparison surface before a user signs up.

> **Availability is not permission**
>
> A capability answering `executable: true` is not authorization to move money. The server re-checks eligibility at create time and again at the money boundary (funding, activation, execution) — routing output is never chained straight into execution. See [Agents & MCP → what a tool can never do](/agents-mcp#what-a-tool-can-never-do).

## Eligibility — what a country and account type could generally expect

`GET /v1/eligibility` is `dark-flag` and closed in production: it answers `503 temporarily_unavailable`, and it stays closed until the public claims it makes are signed off. Do not build on it; for an authenticated account, read `GET /v1/capabilities?product=…` instead. What follows is the contract it will carry once it opens.

`GET /v1/eligibility` (public: country + customer type) answers a coarser, pre-signup question — "if someone in this country opened this kind of account, what would likely work" — using the same eligibility engine the dashboard's own onboarding reads, with its own four honest states:

- `likely_available`
- `conditional`
- `unavailable`
- `unknown`

`likely_available` and `conditional` are never collapsed into one "available" bucket — an agent told a flat "available" for something the engine only called *likely* would tell an end user something the engine itself won't promise.

## Providers behind a corridor

A capability row can name the provider handling a corridor (`display_label`, `logo_url` where relevant) — the point of the resource is honesty about *whether* a corridor works, not brand attribution. Swaps fans a request out across multiple connected providers per product (banking rails, on/off-ramp providers, DEX and CEX liquidity) and returns the best executable route; which provider actually serviced a given order is visible on that order's own record, not guessed from the corridor list.

## Keeping this honest

Coverage claims drift when a provider's own availability changes faster than a document does. The [KPI page](https://github.com/swapsapp/swaps/blob/main/docs/api/KPI.md) tracks **K12 — provider truth**: capability rows whose claimed status disagrees with the last live probe, target zero stale claims older than 24 hours. If a corridor this page or the `/v1/capabilities` response describes turns out wrong, that is a defect against K12, not a documentation nuance.

Next: [Products](/products/payment-links) for what each product actually does with a resolved capability · [Agents & MCP](/agents-mcp) for how a tool reads this same resource.
