Capabilities
What this account can execute right now, rail by rail, and public eligibility by country.
Jump to an operation:
What this account can execute right now, rail by rail — available
Status: Available · Callers: business key, agent (business key), dashboard session · Scope:
capabilities.read· Test mode: unavailable
One resource, five product projections (payment_links, payouts, payroll, buy_sell, wallet_bank — D-23, D-34), behind the same authentication boundary. Payment and banking projections resolve the calling account's verification and eligibility facts. The buy_sell projection instead combines provider lifecycle and runtime switches with route coverage; it does not establish the caller's provider KYC eligibility. buy_sell also takes country, method and provider to narrow the coverage grid. Its defaults and coverage cells come from one fresh route snapshot; this endpoint does not quote, reserve a price, or promise a first quote. Call it before quoting or offering anything — it reports availability only and authorizes nothing; the server re-checks at create and at the money boundary (RESOURCE-MODEL §0.10). verification_checked_at names when the account's Bridge verification facts behind corridors were checked; with verification=snapshot they come from Swaps' stored check while it is no more than 24 hours old (no Bridge call), and a live read that cannot reach Bridge answers 503, never the older status. BL-60 (C4-D37): for product=payroll, funding_currencies[] additionally publishes, per fiat currency, whether Bridge can issue a FUNDING account for THIS account today — COP stays a selectable run currency (C4-D37) even though it answers funding_account_available: false and, since 13.10, has no payout corridor either. Payroll corridors (13.10): corridors[] carries ONE bank_bridge corridor, USD — bank payouts exist for USD runs only (bank_payout_fx_unsupported for every other run currency, PAYROLL-CANON §1); a run in EUR, GBP, BRL or MXN is paid to USDC wallets where the source-currency allowlist (PAYROLL_BRIDGE_CRYPTO_WALLET_SOURCE_CURRENCIES, runtime config — PAYROLL-CANON §4) admits the run currency, which this projection does not list per run currency. Fix round 1 (#1/#3): a Bridge funding rail existing is not sufficient — an unverified account reads funding_account_available: false, reason: 'verification_required' for every fundable currency while the account's bank_bridge corridor (corridors[] above; its KYC + base status is the gate every payroll funding currency shares) has not resolved to available yet; corridors[] and funding_currencies[] answer different questions (paying a recipient by bank vs. funding a run in a currency) and must never be read as the same fact. PAYROLL-CRYPTO-1: each funding_currencies[] entry also carries crypto_funding — whether a run in that currency can be funded with USDC sent to the employer's Bridge payroll wallet (and, when it can, which asset on which chain), gated by the same switch the funding service reads and never available while the currency itself cannot be funded. K6 correction: this operation requires a credential — an anonymous, account-free public claims projection (no entitlement, no route id, no flag, no preview row) is a DIFFERENT operation (a public corridor/rail grid with no caller identity behind it at all) and is not this one; the router has no optional-auth route class to serve it from yet. If a public projection is wanted, it should be specified and built as its own path, not folded into this operation's security. BL-40: for payment_links/payroll/wallet_bank, an account that already has a Bridge customer but whose live status read failed answers 503 temporarily_unavailable for the whole projection — never a fabricated not_started on every corridor. NB-5: a buy_sell answer with degraded: true means the route snapshot could not be obtained (unreachable or no fresh lease) — report that the check failed and offer a retry, never report that no route exists. A4-FIX-6 — Test mode: unavailable. These projections use live verification, eligibility or route-snapshot sources, with no supported test-mode projection. The router refuses a test-mode caller (503 temporarily_unavailable, side-effect free, no Retry-After) and the handler refuses it a second time before any read. It is never forwarded to the dev project. CP-T2: for product=payment_links, the crypto_tempo corridor carries crypto_only — whether this account can activate a crypto-only link (settled to its own Swaps Wallet) without any Bridge customer, and the first gate that blocks it. A read failure behind it answers 503 temporarily_unavailable for the whole projection. #3932: the crypto_relay corridor reads available only while the crypto_tempo corridor does — Relay delivers on the Tempo leg and the payer page never offers it otherwise; its max_amount (the per-invoice cap) is published even while it reads not_enabled. WALLET-VA-OVERRIDE-1: for product=wallet_bank, the wallet_bank_virtual_account corridor names why it is not available in one order, the order POST /wallet/virtual_accounts refuses by — first what no step of the person opens, each not_enabled with action: none: owner_only, rail_not_enabled, verification_closed (with detail_code: verification_attempts_exhausted when the account has used every verification attempt), payin_fiat_refused, endorsement_not_requestable, route_unavailable, collection_account_uses_currency; then the person's own steps: a verification step with no blocked_reason, payin_fiat_pending (gathering_no_path), and last wallet_not_found. CapabilityCorridor.blocked_reason defines each.
query Parameters
productcountryproduct=buy_sell only — narrows the coverage grid to one country. This filter never resolves residency or personal KYC.
methodproduct=buy_sell only — narrows the coverage grid to one payment method.
providerproduct=buy_sell only — narrows the coverage grid to one provider.
verificationWhere the account's verification facts come from. live (the default) reads the verification provider on this request. snapshot answers from the copy Swaps stored the last time it received the customer's whole state from the provider — a live read or a provider webhook — while that copy is no more than 24 hours old, and reads the provider live otherwise. Either way the answer names when its facts were checked (verification_checked_at): show it. With snapshot, a live read that cannot reach the provider answers 503 temporarily_unavailable, never the older stored status. Use snapshot only to display status; every money operation (orders, payouts, payroll, wallet bank accounts and withdrawals, payment-link settlement) checks the provider live itself, whatever this read said.
Headers
Swaps-VersionPins behaviour within /v1 to a dated version; defaults to the key's version; echoed on every response.
Swaps-AccountA1-2. Selects which of the caller's account memberships this request acts on, by Account.id (acct_…), when the credential can reach more than one; the caller's default account otherwise (D-109, supabase/functions/api-v1/auth.ts). Declared on every operation a dashboard session can call (#3561: the runtime caller class, not the formal security list, which names only businessKey on operations both credential classes reach). A value the session is not a member of answers 404 not_found. A business key already resolves to exactly one account (its own) and ignores this header.
What this account can execute right now, rail by rail — available › Responses
The capability snapshot for this product — public or authenticated projection depending on the credential presented.
versionverification_checked_atWhen the account's Bridge verification facts behind corridors were last checked: the moment of a live read, or, with verification=snapshot, when Swaps last received the customer's whole state from Bridge (never more than 24 hours earlier). Show it next to the corridors ("Checked …"). Absent for product=buy_sell, when the account has no Bridge customer, and for a degraded read of a check whose time is unknown.
Shape varies by product: payouts publishes {kind, bps, applies_to}; payment_links publishes {kind, bps, applies_to, rails, rounding, rounding_decimals}; payroll publishes {bps, shape, enabled} (employer-funded-on-top, never a percentage deducted from the recipient — §2.5). All keys are optional here to cover every shape.
payment_links — the Swaps fee on the splitter rails named in rails (crypto_tempo, crypto_relay), the same constant the server charges: applies_to: payer — added on top of the invoice and paid by the payer; the merchant receives the full invoice. For an invoice of amount, the payer's deposit instructions charge fee = floor(amount × 10^rounding_decimals × bps / 10000) / 10^rounding_decimals (a USD invoice with at most two decimals is never rounded); Payment.fee and Payment.amount_expected on these rails publish the same figures at that scale. It applies to crypto subscriptions too: every subscription invoice is a crypto-only payment link paid on these rails. A rail not listed in rails carries no fee claim from this object (no rate, no bearer); the fee on a Bridge-routed rail (bank rails, crypto_bridge) is deducted from what the merchant receives and is published separately as deducted_fee. Provider fees (Relay relay/gas, Bridge network/processing) are not this fee and are quoted per payment. Present whatever the rails' current availability (corridors[]).
product=payment_links only — the Swaps fee on the Bridge-routed rails named in rails (bank rails and crypto_bridge): applies_to: merchant — the payer pays exactly the invoice and the provider deducts this percentage from what arrives, so the merchant receives what arrived minus it (founder ruling «Bank: 1% is deducted from what you receive»). This is the rate configured now; the figure a payment was charged, to the cent and rounded up, is that payment's own Payment.deducted_fee, read from the provider receipt (null there when the payer paid in another currency than the invoice — crypto_bridge's USDC source included — or no consistent receipt was recorded). Omitted when no fee is configured.
product=buy_sell only (D-86b) — a charge a provider makes on a rail that Swaps passes through at cost, named after the provider: never a Swaps fee and never Swaps revenue. Today one entry: Bridge's wire fee on Bridge wire BUYS (a wire Bridge receives) — withheld from the amount together with the Swaps fee (both inside the transfer's developer fee) and published on every such offer as its own «Bridge wire fee» part of total_fees.provider; final_out is already net of it. A sell's outgoing wire carries none (its Bridge charge is unknown, so nothing is deducted); ACH and Bridge's other rails carry none.
product=payouts only — the «Pay with» sources for this caller: external_wallet (USDC from any wallet, always available) and swaps_wallet («Wallet balance», coming_soon while its kill switch is off; unavailable to a business key and in test mode).
product=buy_sell only — the resolved first-load defaults (exchange_bootstrap, D-23, BS-G4).
product=buy_sell only — the country × method × provider availability grid (D-23, BS-G5).
sideGET /v1/capabilities/buy_sell?side=sell only — present, sell, on every sell answer (a degraded one included); absent on a buy answer. A sell answer carries sell_defaults and sell_coverage, never defaults or coverage. A1-2: open — an unrecognized member is an opaque string.
GET /v1/capabilities/buy_sell?side=sell — where a sell starts for this country (A1 §2.1): the payout currency by the D-65 rule over sell routes, USDC on Base, the first selectable payout method and its limits. Omitted on a degraded answer.
side=sell only — one cell per payout method and fiat the country can be paid in by Bridge's residency rule, Bridge only, with the assets that may be sent. A person is paid in their own currency where a rail pays it; a resident no rail pays in their own currency is paid in USD (ACH, wire), EUR (SEPA) or GBP (Faster Payments) instead, to an account in their own name on that rail's network — a US account, an IBAN, a UK account (D-100). Omitted on a degraded answer — never an empty grid for a check that could not be made.
product=wallet_bank only — the currency → endorsement → status map (§2.3 v2 amendments).
product=payroll only (BL-60, C4-D37) — for each payroll fiat currency (the SAME set supabase/functions/payroll/lib.ts's FIAT_CURRENCIES accepts as a run currency), whether Bridge can issue a FUNDING account for it today, with a reason when it cannot. Additive: the run-currency picker keeps every fiat currency (the founder rejected removing COP over dropping it just because it has no Bridge funding rail — C4-D37; since 13.10 COP has no payout corridor either: bank payouts exist for USD runs only and the USDC-wallet allowlist does not admit it, so corridors above carries no COP row) and reads this array to warn honestly up front instead of the gap surfacing only after a run is created. funding_account_available is the bank-transfer method; crypto_funding (PAYROLL-CRYPTO-1) is the USDC method for the same currency, and its absence means the USDC method is not available.
product=payment_links only (§52.33, PL-TEMPO-BRIDGE-1-T) — for each link fiat currency (the same currencies the bank corridors above cover), whether a link in that currency can settle its Tempo-wallet destination and through which rail. An entry without tempo_wallet.available: true reads as not available for that currency today.
product=wallet_bank only — the V1 ceiling ($3,000, §2.3 v2 amendments).
degradedproduct=buy_sell only — true when this read is not backed by a fresh route snapshot: the upstream hop (best-quote) was unreachable or itself had no fresh route-truth lease (NB-5). providers[] is still a live, independent read; defaults/coverage (on a sell, sell_defaults/sell_coverage) are OMITTED — never an empty grid or a fabricated "nothing is available" claim, and never a permanent 503 for a condition that cannot change.
degraded_reasonPresent only when degraded is true. Reserved: unavailable_in_test_mode is never emitted since A4-FIX-6; a test-mode caller gets 503.
Buy or sell coverage by country, without signing in — dark-flag
Status: Dark-flag — live behind a cohort or flag · Callers: public token · Test mode: unavailable
This operation is dark-flag — live behind a cohort or flag. While its resource switch (
api_v1.<resource>) is off, calling it answers503 temporarily_unavailable; with the switch on, a closed product or launch flag, or a cohort the account is outside, answers409 capability_unavailable. Check its product page before relying on it.
The same account-independent projection GET /v1/capabilities?product=buy_sell returns — provider status, the country's defaults (fiat, methods, families, limits) and the coverage grid (fiat → method → provider → state), all from one fresh route snapshot — served to an anonymous caller (D-11). PUBLIC and UNAUTHENTICATED: no key or session is read. It is a separate path only because one operation cannot sit in both of the router's route tables; without side (or with side=buy) the body is the same Capabilities object for the same country, method and provider. Sell (side=sell, this path only): the body carries side: sell, sell_defaults and sell_coverage instead of defaults and coverage — never both. sell_coverage has one cell per payout method and fiat the country can be paid in by Bridge's residency rule (Bridge is the only provider that sells today), its state from the same route truth, and per cell the assets that may be sent — each with its network, its state and, when selectable, Bridge's own minimum and the single-order maximum in that asset (min, max). Bre-B (COP) is blocked (route_disabled): Bridge prices it, a sell order cannot execute it. USDT and USDB are blocked (policy_blocked) for a country in the EEA. sell_defaults names the first-screen currency (the country's own, else its fallback, else USD, EUR or GBP — fiat_reason), USDC on Base, the first selectable payout method and that method's USDC limits; provider_fees is empty (no pass-through fee on a sell). country is the country the person picked, defaulting to US when omitted, exactly as on the authenticated projection — it is not residence and it does not establish anyone's provider verification. It reports availability and authorizes nothing: an estimate, a quote and an order each re-check. A degraded: true answer means the route snapshot could not be read — report that the check failed and offer a retry, never that no route exists. Cache-Control: public, max-age=0, must-revalidate (private, no-store on a degraded answer). A non-degraded answer may be served from the Swaps edge cache for up to 60 seconds, never past its snapshot's expiry: it can be up to a minute old, repeat another caller's x-request-id and still list a provider switched off within that minute. Protection: a persistent per-client-IP limit (429), and a client IP on the Swaps block list is refused 403 ip_not_allowed. Switch: dark-flag — the api_v1.capabilities_public kill switch answers 503 temporarily_unavailable while it is off, which it is until the founder turns it on at launch. No MCP tool: an agent reads coverage through the authenticated list_capabilities; the public review surface stays as it is (API-CANON §13).
query Parameters
countryThe country the person picked, ISO 3166-1 alpha-2 from the supported catalog; US when omitted. Never residence, never personal verification.
methodNarrows the coverage grid to one payment method.
providerNarrows the coverage grid to one provider.
sidebuy (the default) or sell. sell answers side, sell_defaults and sell_coverage in place of defaults and coverage. Any other value, or the parameter given twice, is 400 (param: side).
Headers
Swaps-VersionPins behaviour within /v1 to a dated version; defaults to the key's version; echoed on every response.
Buy or sell coverage by country, without signing in — dark-flag › Responses
The coverage snapshot — for a buy, the same body the authenticated product=buy_sell projection returns; for side=sell, the sell projection.
versionverification_checked_atWhen the account's Bridge verification facts behind corridors were last checked: the moment of a live read, or, with verification=snapshot, when Swaps last received the customer's whole state from Bridge (never more than 24 hours earlier). Show it next to the corridors ("Checked …"). Absent for product=buy_sell, when the account has no Bridge customer, and for a degraded read of a check whose time is unknown.
Shape varies by product: payouts publishes {kind, bps, applies_to}; payment_links publishes {kind, bps, applies_to, rails, rounding, rounding_decimals}; payroll publishes {bps, shape, enabled} (employer-funded-on-top, never a percentage deducted from the recipient — §2.5). All keys are optional here to cover every shape.
payment_links — the Swaps fee on the splitter rails named in rails (crypto_tempo, crypto_relay), the same constant the server charges: applies_to: payer — added on top of the invoice and paid by the payer; the merchant receives the full invoice. For an invoice of amount, the payer's deposit instructions charge fee = floor(amount × 10^rounding_decimals × bps / 10000) / 10^rounding_decimals (a USD invoice with at most two decimals is never rounded); Payment.fee and Payment.amount_expected on these rails publish the same figures at that scale. It applies to crypto subscriptions too: every subscription invoice is a crypto-only payment link paid on these rails. A rail not listed in rails carries no fee claim from this object (no rate, no bearer); the fee on a Bridge-routed rail (bank rails, crypto_bridge) is deducted from what the merchant receives and is published separately as deducted_fee. Provider fees (Relay relay/gas, Bridge network/processing) are not this fee and are quoted per payment. Present whatever the rails' current availability (corridors[]).
product=payment_links only — the Swaps fee on the Bridge-routed rails named in rails (bank rails and crypto_bridge): applies_to: merchant — the payer pays exactly the invoice and the provider deducts this percentage from what arrives, so the merchant receives what arrived minus it (founder ruling «Bank: 1% is deducted from what you receive»). This is the rate configured now; the figure a payment was charged, to the cent and rounded up, is that payment's own Payment.deducted_fee, read from the provider receipt (null there when the payer paid in another currency than the invoice — crypto_bridge's USDC source included — or no consistent receipt was recorded). Omitted when no fee is configured.
product=buy_sell only (D-86b) — a charge a provider makes on a rail that Swaps passes through at cost, named after the provider: never a Swaps fee and never Swaps revenue. Today one entry: Bridge's wire fee on Bridge wire BUYS (a wire Bridge receives) — withheld from the amount together with the Swaps fee (both inside the transfer's developer fee) and published on every such offer as its own «Bridge wire fee» part of total_fees.provider; final_out is already net of it. A sell's outgoing wire carries none (its Bridge charge is unknown, so nothing is deducted); ACH and Bridge's other rails carry none.
product=payouts only — the «Pay with» sources for this caller: external_wallet (USDC from any wallet, always available) and swaps_wallet («Wallet balance», coming_soon while its kill switch is off; unavailable to a business key and in test mode).
product=buy_sell only — the resolved first-load defaults (exchange_bootstrap, D-23, BS-G4).
product=buy_sell only — the country × method × provider availability grid (D-23, BS-G5).
sideGET /v1/capabilities/buy_sell?side=sell only — present, sell, on every sell answer (a degraded one included); absent on a buy answer. A sell answer carries sell_defaults and sell_coverage, never defaults or coverage. A1-2: open — an unrecognized member is an opaque string.
GET /v1/capabilities/buy_sell?side=sell — where a sell starts for this country (A1 §2.1): the payout currency by the D-65 rule over sell routes, USDC on Base, the first selectable payout method and its limits. Omitted on a degraded answer.
side=sell only — one cell per payout method and fiat the country can be paid in by Bridge's residency rule, Bridge only, with the assets that may be sent. A person is paid in their own currency where a rail pays it; a resident no rail pays in their own currency is paid in USD (ACH, wire), EUR (SEPA) or GBP (Faster Payments) instead, to an account in their own name on that rail's network — a US account, an IBAN, a UK account (D-100). Omitted on a degraded answer — never an empty grid for a check that could not be made.
product=wallet_bank only — the currency → endorsement → status map (§2.3 v2 amendments).
product=payroll only (BL-60, C4-D37) — for each payroll fiat currency (the SAME set supabase/functions/payroll/lib.ts's FIAT_CURRENCIES accepts as a run currency), whether Bridge can issue a FUNDING account for it today, with a reason when it cannot. Additive: the run-currency picker keeps every fiat currency (the founder rejected removing COP over dropping it just because it has no Bridge funding rail — C4-D37; since 13.10 COP has no payout corridor either: bank payouts exist for USD runs only and the USDC-wallet allowlist does not admit it, so corridors above carries no COP row) and reads this array to warn honestly up front instead of the gap surfacing only after a run is created. funding_account_available is the bank-transfer method; crypto_funding (PAYROLL-CRYPTO-1) is the USDC method for the same currency, and its absence means the USDC method is not available.
product=payment_links only (§52.33, PL-TEMPO-BRIDGE-1-T) — for each link fiat currency (the same currencies the bank corridors above cover), whether a link in that currency can settle its Tempo-wallet destination and through which rail. An entry without tempo_wallet.available: true reads as not available for that currency today.
product=wallet_bank only — the V1 ceiling ($3,000, §2.3 v2 amendments).
degradedproduct=buy_sell only — true when this read is not backed by a fresh route snapshot: the upstream hop (best-quote) was unreachable or itself had no fresh route-truth lease (NB-5). providers[] is still a live, independent read; defaults/coverage (on a sell, sell_defaults/sell_coverage) are OMITTED — never an empty grid or a fabricated "nothing is available" claim, and never a permanent 503 for a condition that cannot change.
degraded_reasonPresent only when degraded is true. Reserved: unavailable_in_test_mode is never emitted since A4-FIX-6; a test-mode caller gets 503.
How many ways to pay or get paid each country has, without signing in — dark-flag
Status: Dark-flag — live behind a cohort or flag · Callers: public token · Test mode: unavailable
This operation is dark-flag — live behind a cohort or flag. While its resource switch (
api_v1.<resource>) is off, calling it answers503 temporarily_unavailable; with the switch on, a closed product or launch flag, or a cohort the account is outside, answers409 capability_unavailable. Check its product page before relying on it.
One row per country of the supported catalog: the paying currencies that have at least one way to pay and, per currency, how many distinct payment methods are selectable for buying (ways) — the same count GET /v1/capabilities/buy_sell?country=XX gives for that country, from the same stored route snapshot (D-93). Use it to label a country list; use GET /v1/capabilities/buy_sell for the country the person picks, which also carries methods, providers and limits. A row is status: ok only when it was built from a fresh snapshot; otherwise it is unknown and carries no currencies and no count — never read unknown as "not available". A country with status: ok and no currencies has no way to pay today. Computed from the stored snapshots alone: no route-truth read, no quote, no provider call. Sell (side=sell): the same rows from the stored sell snapshots — the currencies a person can be paid out in and, per currency, how many distinct payout methods are selectable with at least one asset that may be sent (sell_coverage of GET /v1/capabilities/buy_sell?country=XX&side=sell). It reports availability and authorizes nothing: an estimate, a quote and an order each re-check. PUBLIC and UNAUTHENTICATED: no key or session is read. Cache-Control: private for at most 60 seconds and never past the earliest snapshot's expiry (no shared cache: every answer carries its own x-request-id). no-store when no row is ok. Protection: the same persistent per-client-IP limit as GET /v1/capabilities/buy_sell (429), and a client IP on the Swaps block list is refused 403 ip_not_allowed. Switch: dark-flag — the same api_v1.capabilities_public kill switch answers 503 temporarily_unavailable while it is off. No MCP tool: an agent reads coverage through the authenticated list_capabilities; the public review surface stays as it is (API-CANON §13).
query Parameters
sidebuy (the default) or sell — which side's ways are counted. Any other value, or the parameter given twice, is 400 (param: side).
Headers
Swaps-VersionPins behaviour within /v1 to a dated version; defaults to the key's version; echoed on every response.
How many ways to pay or get paid each country has, without signing in — dark-flag › Responses
Every catalog country, sorted by country code, each ok with its counts or unknown.
One row per catalog country, sorted by country.
degradedtrue when any row is unknown (its snapshot is missing, expired or not usable). The ok rows are still true; report the others as not checked, never as not available.
as_ofWhen the route truth behind the oldest snapshot used was read. Absent when no row is ok.
Which products this country and customer type can likely use — dark-flag
Status: Dark-flag — live behind a cohort or flag · Callers: public token · Test mode: unavailable
This operation is dark-flag — live behind a cohort or flag. While its resource switch (
api_v1.<resource>) is off, calling it answers503 temporarily_unavailable; with the switch on, a closed product or launch flag, or a cohort the account is outside, answers409 capability_unavailable. Check its product page before relying on it.
The compliance-navigator engine's own four statuses, verbatim — never collapse likely_available and conditional into one available (RESOURCE-MODEL §2.4). PUBLIC and UNAUTHENTICATED (L3-2): resolved off the router's public-token table with no caller identity at all (RESOURCE-MODEL §0.9), the same class payment_sessions.get uses. The public projection takes only country + customer_type. This PR drops monthly_volume_band/purpose/regulated_activities from this operation ENTIRELY, not just to "authenticated callers only": D-16 already forbids them on any anonymous path, this operation has no other path, and capabilities.get's own description already names the structural reason an authenticated variant can't be folded into this one's security — "the router has no optional-auth route class to serve it from yet... it should be specified and built as its own path." A richer, authenticated eligibility projection accepting those three fields is a real future operation once that route class exists; it is not this one. payroll is one of the five published products (the compliance-navigator engine's exchange/wallet/payment_links/ payouts/payroll — NOT /v1/capabilities's unrelated payment_links|payouts|payroll|buy_sell|wallet_bank product enum, a different question for a different, authenticated caller). limits is populated only for payouts, and only for a country whose currency AND whose payout rail this catalog actually covers (a real per-currency corridor minimum, published as Money — fix round 1, P1: a currency match alone is not a country match, e.g. Zimbabwe uses USD but has no US-domestic ACH/wire rail; fix round 2, P2 corrected the EUR corridor's country scope again — Monaco/San Marino/Vatican City are EUR-currency SEPA members the EEA-only gate wrongly excluded — every other product omits limits rather than publish an approximate or fabricated figure, and limits itself never carries a max: no producer publishes one today (fix round 2, P3). limits.confidence is exact only for a hard-rule match (EEA membership, or country === 'US'); Monaco/San Marino/Vatican City's match is this operation's OWN widening onto a rail with no country dimension in its payout SSOT, so it reads approximate there, never the same exact an EEA country gets for the identical eur_sepa corridor. requires_bridge_verification (fix round 1, P1 as requires_verification; renamed fix round 2, P2 — the bare name over-claimed for exchange, whose false means only "no Bridge customer needed," not "no KYC anywhere") marks the three products gated on a Bridge customer/endorsement the caller may not have yet (payment_links/payouts/payroll) — those three also lead reasons[] with bridge_customer_missing and, for an EEA country, add eea_verification_required to both reasons[] and blockers[]; exchange also publishes eea_verification_required in reasons[] for an EEA country as of fix round 2, P3 (matching the canon engine's own code for that branch), even though it needs no Bridge customer and so never gets a blockers[] entry for it; never conflate a Bridge-gated likely_available with wallet's true, unconditional one. notes[] carries the fact reasons[]' shared code cannot: exchange always publishes dex_no_kyc + fiat_provider_kyc, and adds eea_assets for an EEA country — the MiCA asset restriction its eea_verification_required reason code alone would otherwise conflate with the other three products' real Bridge-verification gate. disclaimers[] (fix round 1, P2) mirrors the engine's own hedging (not_advice always; approximate/eea/sanctioned/unknown_country per branch, spelling corrected fix round 2, P3) — this is the one operation whose x-swaps-status: dark-flag exists because public capability claims need the founder's legal sign-off, so the claims never ship without the hedges that go with them everywhere else this engine speaks. x-swaps-test-mode: unavailable (A1-3, 2026-09-22): every available/dark-flag operation in this document was corrected to unavailable because K11's cross-project test-mode dispatch does not exist yet (apps/docs/pages/test-mode.mdx) — this operation is a strong first K11 candidate to restore, since it takes no token/key of any kind (security: []) and so has no sk_test_/live distinction to make, unlike its two public-token siblings (payment_sessions.get/payroll_recipient_sessions.get, fix round 1, P3 note) whose resolved session DOES belong to a livemode-bearing resource, but the claim stays unavailable here too until K11 names it in its evidence list with its own test, exactly like every other operation below. CORS: the 200 response carries a wildcard Access-Control-Allow-Origin: * for a header-free cross-origin GET (fix round 1, P2) — this is narrower than "any browser page can call this" (corrected fix round 2, P2): a caller that sends a custom request header (e.g. Swaps-Version) triggers a CORS preflight this router does not yet answer with a public wildcard, and every refusal this operation can return (400s, and the 503 while its flag row is unseeded) still carries an origin-specific ACAO. Fixing both needs a router-level change outside this operation's own file; tracked as a follow-up, not attempted here.
query Parameters
country^[A-Za-z]{2}$ · requiredISO 3166-1 alpha-2 country code, matched against this exact pattern server-side — no leading/trailing whitespace is trimmed (fix round 1, P3: a previous handler bug trimmed before validating, accepting an input this published pattern refuses).
customer_typeHeaders
Swaps-VersionPins behaviour within /v1 to a dated version; defaults to the key's version; echoed on every response.
Which products this country and customer type can likely use — dark-flag › Responses
The engine's answer for this country and customer type.
countryThe normalized (upper-cased) country the caller passed.
customer_typedisclaimersMachine-readable disclaimer codes (fix round 1, P2) — mirrors resolveEligibility's own disclaimerKeys (src/lib/eligibility/engine.ts), stripped of the complianceNav.disclaimer. i18n prefix. not_advice is present on every response; approximate when any product's confidence is approximate; eea for an EEA country; sanctioned/unknown_country replace the other three for those two hard-block branches (fix round 2, P3 corrected the spelling — round 1 shipped the reversed country_unknown, which is actually the SEPARATE reasons[] code this same branch publishes; disclaimers[] and reasons[] are deliberately different vocabularies and this was their one accidental collision). Never omitted — an empty array would itself be a false "no caveats" claim on the operation this dark-flag legal sign-off exists to gate.