How @inflowpayai/x402-* types map to the x402 V2 wire format, plus the rules the SDK applies to network identifiers
and decimals.
Every type the SDK reads or writes is defined in @inflowpayai/x402 and is wire-shape-compatible with
@x402/core@^2.22.0's V2 types. Wire types come from @x402/core/types; foundation route configuration and
PaymentOption[] (returned by inflowAccepts) come from @x402/core/http. The following table maps the names the SDK
exposes to the corresponding upstream V2 names.
| SDK type | V2 wire counterpart | Notes |
|---|---|---|
PaymentRequirements |
@x402/core/types PaymentRequirements |
Network field widened — see below. |
PaymentRequired |
PaymentRequired |
accepts: PaymentRequirements[]. |
InflowPaymentPayload |
PaymentPayload |
The SDK refines payload into a discriminated union (BalancePayloadData / ExactPayloadData / Permit2PayloadData / InstrumentPayloadData). |
VerifyResponse |
VerifyResponse |
Re-exported verbatim. |
SettleResponse |
SettleResponse |
Network field widened. transaction and payer are optional (absent on failures); extensions exposed for ext data. |
ResourceInfo |
ResourceInfo |
Re-exported verbatim. |
X402SupportedKind |
SupportedKind |
Network widened; otherwise identical. |
V2 spec mandates CAIP-2. EVM uses eip155:<chainId> (e.g. eip155:8453); Solana uses the spec-strict
solana:<first-32-base58-chars-of-genesis-hash> (e.g. solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp for mainnet,
solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 for devnet — the foundation's @x402/svm rejects the shorthand
solana:mainnet/solana:devnet). InFlow extends this with the literal 'inflow:1' for balance and (reserved)
instrument schemes. As a result:
- The SDK's
network: stringfield accepts either form. @x402/core'sNetworktemplate literal type (`${string}:${string}`) is strict about which<family>:<reference>values it recognises and does not include'inflow:1'. The SDK re-definesPaymentRequirements,PaymentRequired,InflowPaymentPayload,SettleResponse, andX402SupportedKindlocally with widenednetwork: stringto accommodate it.'inflow:1'is the onlyinflow:-family value the SDK emits or accepts; everything else is standard CAIP-2.- On the seller side,
InflowSellerClient.getSignerAddresses(network)does exact-match first; if no exact entry exists it falls back to a<family>:*wildcard key (e.g.eip155:*,inflow:*).
SCHEMES = {
EXACT: 'exact',
BALANCE: 'balance',
INSTRUMENT: 'instrument',
};'exact'is used for every on-chain transfer. Theextramap carriesassetTransferMethod('eip3009'or'permit2'for EVM, chain-specific for non-EVM),nameandversion(EIP-712 domain), andpermit2Proxywhen applicable.'balance'is used for InFlow-internal ledger transfers.networkis always'inflow:1';payTois the seller's UUID;assetis empty.'instrument'is reserved.inflowAcceptspasses every scheme the server publishes through unchanged, so an'instrument'entry will flow intoPaymentOption[]if the server ever advertises one; settlement support is not yet enabled end-to-end.
The atomic-unit amount carried in each PaymentOption.price.amount (after inflowAccepts) is computed from the
seller's PriceSpec using the decimals from the source the entry came from:
- For
exactentries:X402AssetInfo.decimals(per(blockchain, currency)— e.g.6for USDC on Base). - For
balanceentries:PaymentMethodInfo.decimals(currently18for InFlow balance accounting). - The SDK never hard-codes a decimal scale.
inflowAccepts does this math entirely as strings to avoid Number / BigInt precision loss. Up to 8 decimal places
of input precision are accepted; precision the target asset can't represent throws X402PriceParseError rather than
silently truncating.
PriceSpec.amount accepts three string forms:
| Form | Example | Resolved currency |
|---|---|---|
$<integer>(.<decimals>)? |
'$0.01', '$10.00000001' |
'USD' |
<integer>(.<decimals>)? <CURRENCY> |
'0.01 USDC', '1 USDT', '0.5 PYUSD' |
from the suffix |
<integer>(.<decimals>)? (bare) |
'0.01' |
from PriceSpec.currency (required) |
When PriceSpec.currency is set alongside an amount that also embeds a currency, currency wins on conflict.
'USD' is a wildcard that matches any stablecoin the seller has configured (USDC, USDT, PYUSD, …). Concrete currency
codes only match the exact asset.
V2 spec header names, used verbatim on the write path; read-side lookups are case-insensitive:
| Constant | Value | Direction |
|---|---|---|
HEADERS.PAYMENT_REQUIRED |
PAYMENT-REQUIRED |
server → buyer (402 response) |
HEADERS.PAYMENT_SIGNATURE |
PAYMENT-SIGNATURE |
buyer → server (paid retry) |
HEADERS.PAYMENT_RESPONSE |
PAYMENT-RESPONSE |
server → buyer (after settle) |
The SDK does not read or emit the V1 X-PAYMENT / X-PAYMENT-RESPONSE forms; it's V2-only and rejects responses
with any other x402Version via X402VersionMismatchError.
EXTRA_KEYS = {
NAME: 'name',
VERSION: 'version',
ASSET_TRANSFER_METHOD: 'assetTransferMethod',
PERMIT2_PROXY: 'permit2Proxy',
FEE_PAYER: 'feePayer',
};PaymentRequirements.extra and PaymentMethodInfo.extra are intentionally open-ended on the wire. The SDK ships typed
accessors at @inflowpayai/x402/extras for reading and writing keys safely under noUncheckedIndexedAccess:
import { getExtra, setExtra } from '@inflowpayai/x402/extras';
import { EXTRA_KEYS } from '@inflowpayai/x402';
const method = getExtra<string>(req.extra, EXTRA_KEYS.ASSET_TRANSFER_METHOD);
const updated = setExtra(req.extra, EXTRA_KEYS.FEE_PAYER, '0xfee');InflowPaymentPayload.payload is a discriminated union by accepted.scheme:
| Scheme | Payload shape |
|---|---|
'balance' |
BalancePayloadData — { transactionId }. |
'exact' |
ExactPayloadData — { authorization: { from, to, value, validAfter, validBefore, nonce }, signature } (EIP-3009 form). |
'exact' |
Permit2PayloadData — Permit2 form of the exact scheme; discriminate with isPermit2Payload. |
'instrument' |
InstrumentPayloadData — { transactionId, signature, instrumentId?, instrumentType? }. Reserved. |
Narrowing helpers isBalancePayload, isExactPayload, isPermit2Payload, isInstrumentPayload discriminate without
bangs. Use isExactPayload + isPermit2Payload together to split the two 'exact' variants.
- architecture.md for the seller/buyer composition story.
- extensions.md for
PaymentRequired.extensionsandPaymentPayload.extensions.