- ❌
v1 - ✅
v2
This spec uses CAIP-2 style identifiers (provisional — no ratified Radix namespace exists in CAIP yet):
radix:mainnet— Radix Mainnet (network ID1)radix:stokenet— Radix Stokenet (network ID2)
The x402 exact scheme on Radix transfers an exact amount of a fungible resource from the client to the resource server (payTo).
This scheme transfers exactly one fungible resource per payment. Multi-resource payments are out of scope.
This specification supports two settlement modes:
- Sponsored (recommended): The client signs a payment subintent; the facilitator wraps it in a root transaction, pays gas, and submits.
- Non-sponsored: The client signs a complete transaction including gas payment; the facilitator verifies and submits it.
In both modes the facilitator MUST only submit transactions that pay exactly requirements.amount of requirements.asset to requirements.payTo.
- Client requests a protected resource.
- Resource Server returns
402 Payment RequiredwithPaymentRequirementscontainingextra.mode = "sponsored". - Client builds a Radix payment subintent that withdraws the exact fungible resource amount and yields it to the parent (see Client Subintent Construction).
- Client signs the subintent, producing a
SignedPartialTransactionV2. - Client hex-encodes the SBOR-serialized
SignedPartialTransactionV2and sends it inPaymentPayload.payload.transaction. - Resource Server forwards payload + requirements to Facilitator for verification.
- Facilitator deserializes the subintent, validates structure, signatures, exact transfer semantics, and facilitator safety.
- Resource Server requests settlement.
- Facilitator wraps the verified subintent as a child in a root transaction, pays gas via
lock_fee, ensures the yielded tokens reachpayTo, notarizes, and submits to the Radix network. - Facilitator polls for commit confirmation and reports the settlement result.
- Resource Server returns the protected response.
- Client requests a protected resource.
- Resource Server returns
402 Payment RequiredwithPaymentRequirementscontainingextra.mode = "nonSponsored". - Client builds and signs a complete Radix V2 transaction that locks fees, withdraws the asset, and deposits it to
payTo(see Client Transaction Construction). - Client hex-encodes the SBOR-serialized
NotarizedTransactionV2and sends it inPaymentPayload.payload.transaction. - Resource Server forwards payload + requirements to Facilitator for verification.
- Facilitator deserializes the transaction, validates structure, signatures, and exact transfer semantics.
- Resource Server requests settlement.
- Facilitator submits the verified transaction to the Radix network.
- Facilitator polls for commit confirmation and reports the settlement result.
- Resource Server returns the protected response.
In addition to the standard x402 PaymentRequirements fields:
network: MUST beradix:mainnetorradix:stokenet.asset: A valid Radix fungible resource address (bech32m-encoded;resource_rdx1...on mainnet,resource_tdx_2_1...on stokenet).payTo: The Radix account address that receives the payment.amount: An exact decimal amount of the asset to transfer.
The extra field MUST include:
extra.mode:"sponsored"or"nonSponsored".extra.notaryBadge(sponsored mode only): The facilitator's notary virtual badge as aNonFungibleGlobalIdstring. Clients pass this directly to theVERIFY_PARENTaccess rule (see Appendix A).extra.intentDiscriminator: A string-encodedu64value. The client MUST setIntentHeaderV2.intent_discriminatorto this value when constructing the subintent (sponsored) or transaction (non-sponsored). This allows the facilitator to control intent uniqueness for replay protection and correlation.
Example (sponsored):
{
"scheme": "exact",
"network": "radix:mainnet",
"amount": "10",
"asset": "resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd",
"payTo": "account_rdx129a9wuey40lducsne6r8e5q7xmt07068gcede0x0nrwtsnehpkf6zh",
"maxTimeoutSeconds": 60,
"extra": {
"mode": "sponsored",
"notaryBadge": "resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxx3e2cpa:[b24ed95ab09b486b64c1bf2eb2b39f8cb57cb6cff8a83f034730f457d4e06173]",
"intentDiscriminator": "8374029156381940237"
}
}Example (non-sponsored):
{
"scheme": "exact",
"network": "radix:stokenet",
"amount": "25",
"asset": "resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc",
"payTo": "account_tdx_2_129a9wuey40lducsne6r8e5q7xmt07068gcede0x0nrwtsnehpkf6zh",
"maxTimeoutSeconds": 120,
"extra": {
"mode": "nonSponsored",
"intentDiscriminator": "1629384750192837465"
}
}The payload field always contains a single transaction key with a hex-encoded SBOR byte string:
{
"transaction": "4d220504..."
}The facilitator determines how to deserialize the value by inspecting accepted.extra.mode:
extra.mode |
Serialized type | Description |
|---|---|---|
"sponsored" |
SignedPartialTransactionV2 |
Client-signed subintent (no root transaction) |
"nonSponsored" |
NotarizedTransactionV2 |
Fully signed and notarized transaction |
Hex strings MUST be lowercase, with no 0x prefix.
Full PaymentPayload example (sponsored):
{
"x402Version": 2,
"resource": {
"url": "https://example.com/resource",
"description": "Protected data",
"mimeType": "application/json"
},
"accepted": {
"scheme": "exact",
"network": "radix:mainnet",
"amount": "10",
"asset": "resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd",
"payTo": "account_rdx129a9wuey40lducsne6r8e5q7xmt07068gcede0x0nrwtsnehpkf6zh",
"maxTimeoutSeconds": 60,
"extra": {
"mode": "sponsored",
"notaryBadge": "resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxx3e2cpa:[b24ed95ab09b486b64c1bf2eb2b39f8cb57cb6cff8a83f034730f457d4e06173]",
"intentDiscriminator": "8374029156381940237"
}
},
"payload": {
"transaction": "4d220504..."
}
}Full PaymentPayload example (non-sponsored):
{
"x402Version": 2,
"resource": {
"url": "https://example.com/resource",
"description": "Protected data",
"mimeType": "application/json"
},
"accepted": {
"scheme": "exact",
"network": "radix:stokenet",
"amount": "25",
"asset": "resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc",
"payTo": "account_tdx_2_129a9wuey40lducsne6r8e5q7xmt07068gcede0x0nrwtsnehpkf6zh",
"maxTimeoutSeconds": 120,
"extra": {
"mode": "nonSponsored",
"intentDiscriminator": "1629384750192837465"
}
},
"payload": {
"transaction": "4d220504..."
}
}The client MUST construct a SubintentManifestV2 with exactly 5 instructions:
VERIFY_PARENT
Enum<AccessRule::Protected>(
Enum<CompositeRequirement::BasicRequirement>(
Enum<BasicRequirement::Require>(
Enum<ResourceOrNonFungible::NonFungible>(
NonFungibleGlobalId("<notary_badge>")
)
)
)
)
;
ASSERT_WORKTOP_IS_EMPTY;
CALL_METHOD
Address("<client_account>")
"withdraw"
Address("<asset>")
Decimal("<amount>")
;
TAKE_ALL_FROM_WORKTOP
Address("<asset>")
Bucket("payment")
;
YIELD_TO_PARENT Bucket("payment");
Where:
<notary_badge>is the value ofextra.notaryBadgefromPaymentRequirements.<client_account>is the client's Radix account address.<asset>isrequirements.asset.<amount>isrequirements.amount.
The client then:
- Sets
IntentHeaderV2.network_idto match the target network (1for mainnet,2for stokenet). - Sets
IntentHeaderV2.intent_discriminatorto the value ofextra.intentDiscriminator(parsed asu64). - Sets
max_proposer_timestamp_exclusivebased onmaxTimeoutSeconds(see Appendix B). - Sets epoch bounds to a wide safety window (see Appendix B).
- Signs the subintent with their account key(s), producing a
SignedPartialTransactionV2. - Serializes with
to_raw()and hex-encodes the result (lowercase, no prefix).
Note: The subintent is self-contained: it starts with
VERIFY_PARENT+ASSERT_WORKTOP_IS_EMPTY(receives nothing from the parent) and ends by yielding the payment bucket to the parent. This enables preview-style wallet UX with user-settable guarantees.
The client MUST construct a TransactionManifestV2 with exactly 4 instructions:
CALL_METHOD
Address("<client_account>")
"lock_fee"
Decimal("<fee>")
;
CALL_METHOD
Address("<client_account>")
"withdraw"
Address("<asset>")
Decimal("<amount>")
;
TAKE_ALL_FROM_WORKTOP
Address("<asset>")
Bucket("payment")
;
CALL_METHOD
Address("<payTo>")
"try_deposit_or_abort"
Bucket("payment")
None
;
Where:
<client_account>is the client's Radix account address.<fee>is a sufficient XRD amount to cover network fees (client's discretion).<asset>isrequirements.asset.<amount>isrequirements.amount.<payTo>isrequirements.payTo.
Why
try_deposit_or_abort? Usingtry_deposit_or_abortinstead ofdepositavoids requiring deposit authorization on the receiving account. IfpayTohas deposit restrictions that would reject the asset, the facilitator's preview step (§8) will detect the failure before submission.
The client then:
- Builds a
TransactionV2with appropriate headers (network ID, timestamp bounds, epoch safety window) (see Appendix B).IntentHeaderV2.intent_discriminatorMUST be set to the value ofextra.intentDiscriminator(parsed asu64). - Signs with their account key(s).
- Notarizes the transaction, producing a
NotarizedTransactionV2. - Serializes with
to_raw()and hex-encodes the result (lowercase, no prefix).
The transaction MUST NOT contain any subintents (non_root_subintents MUST be empty).
Before submitting any transaction, the facilitator MUST enforce all checks below. Failure on any check MUST result in rejection.
x402VersionMUST be2.payload.accepted.schemeandrequirements.schemeMUST both be"exact".payload.accepted.networkMUST equalrequirements.network.- Network MUST be one of
radix:mainnetorradix:stokenet. accepted.extra.modeMUST be"sponsored"or"nonSponsored".
- If
extra.modeis"sponsored": decodepayload.transactionas hex-encodedSignedPartialTransactionV2. - If
extra.modeis"nonSponsored": decodepayload.transactionas hex-encodedNotarizedTransactionV2. - Deserialization failure MUST result in rejection.
The decoded SignedPartialTransactionV2 MUST satisfy:
-
No nested subintents:
non_root_subintent_signaturesMUST be empty (thePartialTransactionV2contains exactly one root subintent and no children). -
Instruction count: The subintent manifest MUST contain exactly 5 instructions.
-
Instruction sequence:
Index Instruction Constraints 0 VERIFY_PARENTAccess rule is the client's security mechanism (not constrained by this spec) 1 ASSERT_WORKTOP_IS_EMPTYNo arguments 2 CALL_METHODaddress = client account, method = "withdraw", args =(asset, amount)3 TAKE_ALL_FROM_WORKTOPresource = asset4 YIELD_TO_PARENTyields exactly one bucket containing the withdrawn resource -
Resource match: The
Addressargument towithdrawandTAKE_ALL_FROM_WORKTOPMUST equalrequirements.asset. -
Amount match: The
Decimalargument towithdrawMUST equalrequirements.amountexactly.
The decoded NotarizedTransactionV2 MUST satisfy:
-
No subintents: The transaction MUST NOT contain any subintents.
-
Instruction count: The transaction manifest MUST contain exactly 4 instructions.
-
Instruction sequence:
Index Instruction Constraints 0 CALL_METHODmethod = "lock_fee", address = client account1 CALL_METHODaddress = client account, method = "withdraw", args =(asset, amount)2 TAKE_ALL_FROM_WORKTOPresource = asset3 CALL_METHODaddress = payTo, method ="try_deposit_or_abort", args =(bucket, None) -
Resource match:
assetin instructions 1 and 2 MUST equalrequirements.asset. -
Amount match:
amountin instruction 1 MUST equalrequirements.amountexactly. -
Destination match: The address in instruction 3 MUST equal
requirements.payTo.
Sponsored mode:
- The withdraw address (instruction 2) MUST NOT equal the facilitator's fee-paying account.
- The facilitator's fee-paying account MUST NOT appear as an
Addressargument in any instruction of the subintent. - The subintent MUST NOT contain
lock_feeorlock_contingent_feecalls (fee payment is the facilitator's root intent responsibility; subintents cannot lock uncontingent fees by protocol rule). - The subintent MUST NOT contain any instructions beyond the mandated sequence (no
CALL_FUNCTION, no additionalCALL_METHOD, etc.).
Non-sponsored mode:
- The facilitator's own address MUST NOT appear as an
Addressargument in any instruction of the transaction. - The
lock_feesource account MUST NOT equal the facilitator's address.
These checks prevent the facilitator from being tricked into paying for the transferred asset or authorizing unintended operations.
Sponsored mode:
IntentHeaderV2.network_idMUST match the target network (1for mainnet,2for stokenet).IntentHeaderV2.intent_discriminatorMUST equal the value provided inaccepted.extra.intentDiscriminator.max_proposer_timestamp_exclusiveMUST be set (notNone).max_proposer_timestamp_exclusiveMUST be in the future relative to the currentproposer_round_timestamp.max_proposer_timestamp_exclusiveMUST NOT exceedproposer_round_timestamp + maxTimeoutSeconds + 60(60 s construction tolerance).end_epoch_exclusiveMUST be greater than the current epoch.- The facilitator MUST reject subintents whose
SubintentHashhas already been settled or observed.
Non-sponsored mode:
IntentHeaderV2.network_idMUST match the target network.IntentHeaderV2.intent_discriminatorMUST equal the value provided inaccepted.extra.intentDiscriminator.max_proposer_timestamp_exclusiveMUST be set and satisfy the same timestamp rules as sponsored mode.end_epoch_exclusiveMUST be greater than the current epoch.- The facilitator MUST reject transactions whose
TransactionIntentHashhas already been settled or observed.
Replay hash retention: Facilitators MUST retain seen hashes (subintent or transaction intent) for at least maxTimeoutSeconds + 300 seconds (a 5-minute buffer past the latest possible expiry). Facilitators MAY prune hashes after this window because expired subintents and transactions are rejected by the ledger regardless.
Sponsored mode:
root_subintent_signaturesMUST contain at least one valid signature over theSubintentHash.- The signing key(s) MUST correspond to the client account's access rule (i.e., the signer is authorized to withdraw from the client account).
Non-sponsored mode:
- The transaction MUST contain valid intent signatures from key(s) authorized by the client account.
- The transaction MUST be validly notarized.
- The facilitator MUST preview the composed transaction against current ledger state before submitting.
- Sponsored mode: preview the full root transaction (with the client subintent as a child).
- Non-sponsored mode: preview the client's transaction as-is.
- The preview MUST return
CommitSuccess. - Balance deltas MUST reflect:
- Client decreases by exactly
requirements.amountofrequirements.asset. payToincreases by exactlyrequirements.amountofrequirements.asset.- Expected network fees (from the fee payer).
- No other unexpected balance changes.
- Client decreases by exactly
Implementations MAY apply stricter policy controls (allowlists, max amounts, method constraints) but MUST NOT relax the rules above.
The facilitator settles a verified sponsored payment as follows:
-
Compose root transaction: Wrap the client's
SignedPartialTransactionV2as a child subintent in a newTransactionV2. The facilitator's root intent MUST:- Pay gas via
lock_feefrom the facilitator's account. - Yield to the child subintent to trigger its execution.
- Ensure the yielded tokens reach
payTofor exactlyrequirements.amount.
The specific root manifest structure is a facilitator implementation detail — this spec only constrains the outcome (tokens reach
payTofor the exact amount). - Pay gas via
-
Set
notary_is_signatory: true: The facilitator MUST setnotary_is_signatory: truein theTransactionHeaderV2. This causes the notary's signature to produce a virtual Ed25519 badge in the auth zone, which is required forVERIFY_PARENTto succeed in the client's subintent (see Appendix A). -
Notarize: Sign and notarize the composed transaction with the facilitator's notary key (the key corresponding to
extra.notaryBadgeinPaymentRequirements). -
Submit: Submit the compiled transaction hex to the Gateway via
POST /transaction/submit. -
Confirm: Poll
POST /transaction/statuswith the transaction intent hash until the status isCommittedSuccessor a terminal failure.
-
Submit: Submit the client's
NotarizedTransactionV2hex to the Gateway viaPOST /transaction/submit. -
Confirm: Poll
POST /transaction/statuswith the transaction intent hash until the status isCommittedSuccessor a terminal failure.
{
"success": true,
"transaction": "txid_rdx1qfum8kywlta7gk4r5cf3p8xdvr6kv39dxfl06ykhzrclm8emwrex3jnj6s",
"network": "radix:mainnet",
"payer": "account_rdx129a9wuey40lducsne6r8e5q7xmt07068gcede0x0nrwtsnehpkf6zh"
}transaction: The bech32m-encoded transaction intent hash (txid_rdx1...on mainnet,txid_tdx_2_1...on stokenet).payer: The client's account address (the address that paid the transferred asset, not the gas sponsor).
When verification or settlement fails, the facilitator MUST return an appropriate error code in the invalidReason (verify) or errorReason (settle) field. Radix-specific error codes follow the invalid_exact_radix_* convention:
| Error Code | Description |
|---|---|
invalid_exact_radix_deserialization |
SBOR decode failure — hex string is malformed or does not decode to the expected type |
invalid_exact_radix_instruction_count |
Manifest contains the wrong number of instructions (expected 5 for sponsored, 4 for non-sponsored) |
invalid_exact_radix_instruction_sequence |
Unexpected instruction type or arguments at a given index |
invalid_exact_radix_asset_mismatch |
Asset address in the manifest does not match requirements.asset |
invalid_exact_radix_amount_mismatch |
Transfer amount does not match requirements.amount exactly |
invalid_exact_radix_destination_mismatch |
try_deposit_or_abort target does not match requirements.payTo (non-sponsored mode) |
invalid_exact_radix_facilitator_safety |
Fee payer appears in the subintent, or the facilitator's address appears in a non-sponsored transaction |
invalid_exact_radix_expired |
Timestamp or epoch bounds are out of range or already passed |
invalid_exact_radix_signature |
Missing or invalid subintent/transaction signatures |
invalid_exact_radix_preview_failed |
Transaction preview returned a status other than CommitSuccess |
invalid_exact_radix_replay |
Subintent or transaction intent hash has already been seen |
These codes are also registered in the protocol-level error table in x402-specification-v2.md §9.
All Radix transaction payloads use SBOR (Scrypto Binary Object Representation) encoding, transmitted as lowercase hex strings (no 0x prefix, no base64).
SignedPartialTransactionV2
├── partial_transaction: PartialTransactionV2
│ ├── root_subintent: SubintentV2
│ │ ├── intent_core: IntentCoreV2
│ │ │ ├── instructions: InstructionsV2 (the 5-instruction manifest)
│ │ │ ├── blobs: BlobsV1
│ │ │ └── message: MessageV2
│ │ └── intent_header: IntentHeaderV2
│ │ ├── network_id: u8
│ │ ├── start_epoch_inclusive: Epoch
│ │ ├── end_epoch_exclusive: Epoch
│ │ ├── intent_discriminator: u64
│ │ ├── min_proposer_timestamp_inclusive: Option<Instant>
│ │ └── max_proposer_timestamp_exclusive: Option<Instant>
│ └── non_root_subintents: [] (MUST be empty)
├── root_subintent_signatures: IntentSignaturesV2 (≥1 signature)
└── non_root_subintent_signatures: [] (MUST be empty)
NotarizedTransactionV2
├── signed_transaction: SignedTransactionIntentV2
│ ├── transaction_intent: TransactionIntentV2
│ │ ├── root_intent_core: IntentCoreV2
│ │ │ ├── instructions: InstructionsV2 (the 4-instruction manifest)
│ │ │ ├── blobs: BlobsV1
│ │ │ └── message: MessageV2
│ │ ├── root_intent_header: IntentHeaderV2
│ │ │ ├── network_id: u8
│ │ │ ├── start_epoch_inclusive: Epoch
│ │ │ ├── end_epoch_exclusive: Epoch
│ │ │ ├── intent_discriminator: u64
│ │ │ ├── min_proposer_timestamp_inclusive: Option<Instant>
│ │ │ └── max_proposer_timestamp_exclusive: Option<Instant>
│ │ ├── transaction_header: TransactionHeaderV2
│ │ │ ├── notary_public_key: PublicKey
│ │ │ ├── notary_is_signatory: bool
│ │ │ └── tip_basis_points: u32
│ │ └── non_root_subintents: [] (MUST be empty for x402)
│ └── transaction_intent_signatures: IntentSignaturesV2
└── notary_signature: NotarySignatureV2
| Platform | Package | Status |
|---|---|---|
| Rust | radix-transactions crate |
Available |
| Python, Swift, Kotlin | radix-engine-toolkit (UniFFI bindings) |
Available |
| TypeScript | @steleaio/radix-engine-toolkit npm package | Available |
In sponsored mode the facilitator pays gas on behalf of the client, creating a potential denial-of-service vector. Mitigations:
- Facilitators SHOULD rate-limit verification and settlement requests per client or resource-server identity.
- Facilitators MAY require resource-server authentication (e.g., API keys or mTLS) before accepting requests.
- Facilitators MUST bound the maximum gas expenditure per client or resource-server within a given time window to prevent unbounded cost from malicious or misconfigured callers.
A signed SignedPartialTransactionV2 is a bearer credential — anyone who obtains it could attempt to wrap it in their own root transaction and submit it. The VERIFY_PARENT instruction mitigates this by restricting which notary (and therefore which facilitator) can include the subintent. Without VERIFY_PARENT, any party could front-run the intended facilitator.
Additional security considerations (replay attack prevention, trust model, authentication integration) are specified in x402-specification-v2.md §10.
REQUIRED. Clients MUST prepend VERIFY_PARENT to their subintent to restrict which aggregator (facilitator) can include it. Without VERIFY_PARENT, any party who obtains the SignedPartialTransactionV2 can wrap it in their own root transaction.
On Radix, when a key signs a V2 transaction, the engine synthesizes a virtual signature badge in the transaction's auth zone. For Ed25519 keys, this badge is a NonFungibleGlobalId composed of:
- The well-known Ed25519 signature virtual badge resource address (network-specific, see below).
- A
NonFungibleLocalId::Bytes(blake2b_256(<public_key_bytes>)[6..])— the last 26 bytes of the Blake2b-256 hash of the public key.
VERIFY_PARENT checks that the parent transaction's auth zone contains a specified badge. By requiring the facilitator's notary badge, the client ensures only the intended facilitator can consume the subintent.
For the notary's virtual badge to appear in the auth zone, the facilitator MUST set notary_is_signatory: true in TransactionHeaderV2. Without this flag, the notary signature is used only for transaction validity — it does not produce a badge, and VERIFY_PARENT will fail.
V2 constraint: When
notary_is_signatoryistrue, the notary MUST NOT also appear in the intent signatures (V2 forbids duplicating a signer as notary).
The client reads extra.notaryBadge from PaymentRequirements and passes it directly as the NonFungibleGlobalId in the VERIFY_PARENT instruction. No derivation is required — the facilitator provides the badge in ready-to-use form.
Clients SHOULD validate that the resource address component of notaryBadge matches the well-known Ed25519 signature badge for the target network:
| Network | Ed25519 signature badge resource |
|---|---|
| Mainnet | resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxx3e2cpa |
| Stokenet | resource_tdx_2_1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed8fma |
VERIFY_PARENT
Enum<AccessRule::Protected>(
Enum<CompositeRequirement::BasicRequirement>(
Enum<BasicRequirement::Require>(
Enum<ResourceOrNonFungible::NonFungible>(
NonFungibleGlobalId("resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxx3e2cpa:[b24ed95ab09b486b64c1bf2eb2b39f8cb57cb6cff8a83f034730f457d4e06173]")
)
)
)
)
;
ASSERT_WORKTOP_IS_EMPTY;
CALL_METHOD
Address("account_rdx129a9wuey40lducsne6r8e5q7xmt07068gcede0x0nrwtsnehpkf6zh")
"withdraw"
Address("resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd")
Decimal("10")
;
TAKE_ALL_FROM_WORKTOP
Address("resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd")
Bucket("payment")
;
YIELD_TO_PARENT Bucket("payment");
The facilitator MUST accept VERIFY_PARENT at instruction index 0 and validate the remaining 4 instructions starting at index 1. The VERIFY_PARENT access rule content is not constrained by this spec — it is the client's security mechanism.
Radix V2's IntentHeaderV2 supports precise wall-clock validity via min_proposer_timestamp_inclusive and max_proposer_timestamp_exclusive (both Option<Instant>). These are validated against the ledger's proposer_round_timestamp at commit time, enabling exact mapping from maxTimeoutSeconds without the lossy epoch rounding of earlier approaches.
Timestamp conversion:
max_proposer_timestamp_exclusive = now + maxTimeoutSeconds
min_proposer_timestamp_inclusive = now (SHOULD be set; optional but recommended)
Epoch safety window:
Epoch fields (start_epoch_inclusive, end_epoch_exclusive) are mandatory in IntentHeaderV2. They serve as a wide safety window — not the normative expiry mechanism. Set them as:
start_epoch_inclusive = current_epoch
end_epoch_exclusive = current_epoch + ceil(maxTimeoutSeconds / 300) + 10
The +10 epochs (~50 min) ensures the epoch window never expires before the timestamp window, even under variable epoch durations.
Facilitator validation:
Facilitators MUST reject payloads where max_proposer_timestamp_exclusive exceeds proposer_round_timestamp + maxTimeoutSeconds + 60. The 60-second tolerance accounts for clock skew between the client's construction time and the facilitator's verification time.
Radix uses bech32m encoding with network-specific human-readable parts (HRPs):
| Entity | Mainnet HRP | Stokenet HRP |
|---|---|---|
| Account | account_rdx1 |
account_tdx_2_1 |
| Resource | resource_rdx1 |
resource_tdx_2_1 |
| Component | component_rdx1 |
component_tdx_2_1 |
| Transaction intent hash | txid_rdx1 |
txid_tdx_2_1 |
| Subintent hash | subtxid_rdx1 |
subtxid_tdx_2_1 |
| Operation | Endpoint | Purpose |
|---|---|---|
| Preview | POST /transaction/preview-v2 |
Simulate transaction before submission |
| Submit | POST /transaction/submit |
Submit compiled transaction |
| Status | POST /transaction/status |
Poll for commit status |
| Ledger state | POST /status/gateway-status |
Get current epoch and proposer_round_timestamp |
Base URLs:
- Mainnet:
https://mainnet.radixdlt.com - Stokenet:
https://stokenet.radixdlt.com
- Prefer sponsored mode for best user experience (client does not need XRD for gas).
- Clients MUST include
VERIFY_PARENTin sponsored subintents. - Always preview immediately before settlement.
- Maintain strict policy around allowed resources and maximum transfer amounts per request.