From 9c2c766e63692eaf401cd1fa97b1633a18d75c11 Mon Sep 17 00:00:00 2001 From: Patrick Tobler <129864078+PatrickTobler@users.noreply.github.com> Date: Thu, 23 Oct 2025 06:09:33 +0530 Subject: [PATCH 01/16] Create scheme_exact_cardano.md --- specs/schemes/exact/scheme_exact_cardano.md | 58 +++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 specs/schemes/exact/scheme_exact_cardano.md diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md new file mode 100644 index 0000000000..f432d22bb7 --- /dev/null +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -0,0 +1,58 @@ +# Scheme: exact on Cardano + +## Summary + +This document specifies the `exact` payment scheme for the x402 protocol on Cardano. + +This scheme facilitates payments of Cardano Native Tokens to a Cardano Wallet or a Smart Contract. + +## Protocol Flow + +The protocol flow for `exact` on Cardano is server-driven. + +1. **Client** makes an HTTP request to a **Resource Server**. +2. **Resource Server** responds with a `402 Payment Required` status. The response body contains the finalised transaction body. +3. **Client** signs the transaction body with their wallet. +6. **Client** sends a new HTTP request to the resource server with the `X-PAYMENT` header containing the Base64-encoded partially-signed transaction payload. +7. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator Server's** `/verify` endpoint. +9. **Facilitator** inspects the transaction to ensure it is valid and only contains the expected payment instruction. +10. **Facilitator** returns a response to the **Resource Server** verifying the **client** transaction. +11. **Resource Server**, upon successful verification, forwards the payload to the facilitator's `/settle` endpoint. +12. **Facilitator Server** provides its final signature as the `feePayer` and submits the now fully-signed transaction to the Solana network. +13. Upon successful on-chain settlement, the **Facilitator Server** responds to the **Resource Server**. +14. **Resource Server** grants the **Client** access to the resource in its response. + +## `X-PAYMENT` Header Payload + +The `X-PAYMENT` header is base64 encoded and sent in the request from the client to the resource server when paying for a resource. + +Once decoded, the `X-PAYMENT` header is a JSON string with the following properties: + +```json +{ + "x402Version": 1, + "scheme": "exact", + "network": "cardano", + "payload": { + "transaction": "AAAAAAAAAAAAA...AAAAAAAAAAAAA=" + } +} +``` + +The `payload` field contains the base64-encoded, serialized, **partially-signed** versioned Solana transaction. + + +## `X-PAYMENT-RESPONSE` Header Payload + +The `X-PAYMENT-RESPONSE` header is base64 encoded and returned to the client from the resource server. + +Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: + +```json +{ + "success": true | false, + "transaction": "base58 encoded transaction signature", + "network": "solana" | "solana-devnet", + "payer": "base58 encoded public address of the transaction fee payer" +} +``` From 44b2a719b39891c5d8648a4155d6b0ce14cd1510 Mon Sep 17 00:00:00 2001 From: Patrick Tobler <129864078+PatrickTobler@users.noreply.github.com> Date: Thu, 23 Oct 2025 06:45:14 +0530 Subject: [PATCH 02/16] Update scheme_exact_cardano.md --- specs/schemes/exact/scheme_exact_cardano.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index f432d22bb7..eb7d4ce00c 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -11,16 +11,17 @@ This scheme facilitates payments of Cardano Native Tokens to a Cardano Wallet or The protocol flow for `exact` on Cardano is server-driven. 1. **Client** makes an HTTP request to a **Resource Server**. -2. **Resource Server** responds with a `402 Payment Required` status. The response body contains the finalised transaction body. -3. **Client** signs the transaction body with their wallet. -6. **Client** sends a new HTTP request to the resource server with the `X-PAYMENT` header containing the Base64-encoded partially-signed transaction payload. -7. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator Server's** `/verify` endpoint. -9. **Facilitator** inspects the transaction to ensure it is valid and only contains the expected payment instruction. -10. **Facilitator** returns a response to the **Resource Server** verifying the **client** transaction. -11. **Resource Server**, upon successful verification, forwards the payload to the facilitator's `/settle` endpoint. -12. **Facilitator Server** provides its final signature as the `feePayer` and submits the now fully-signed transaction to the Solana network. -13. Upon successful on-chain settlement, the **Facilitator Server** responds to the **Resource Server**. -14. **Resource Server** grants the **Client** access to the resource in its response. +3. **Resource Server** responds with a `402 Payment Required` status. Detiling the Paymsnt Information and specifying which information is still required from the client to create a transaction. +4. **Client** responds with required information. +5. **Ressource Server** sends information to Facilitator. +6. **Facilitator** checks validity, constructs transaction body & returns it to Ressource Server. +8. **Ressource Server** forwards transaction body to client. +9. **Client** signs the transaction body with their wallet. +11. **Client** sends a new HTTP request to the resource server with the `X-PAYMENT` header containing signed transaction payload. +12. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator Server's** `/verify` endpoint. +13. **Facilitator** checks that only the required assets are being moved in the transaction & submits transction. +15. Upon successful on-chain settlement, the **Facilitator Server** responds to the **Resource Server**. +16. **Resource Server** grants the **Client** access to the resource in its response. ## `X-PAYMENT` Header Payload From 81eb11dc95488f097aa3f6442a5a81b2dcc19cef Mon Sep 17 00:00:00 2001 From: Patrick Tobler <129864078+PatrickTobler@users.noreply.github.com> Date: Sun, 26 Oct 2025 02:56:20 +0530 Subject: [PATCH 03/16] Update and rename scheme_exact_cardano.md to scheme_exact_cardano-masumi.md --- .../exact/scheme_exact_cardano-masumi.md | 97 +++++++++++++++++++ specs/schemes/exact/scheme_exact_cardano.md | 59 ----------- 2 files changed, 97 insertions(+), 59 deletions(-) create mode 100644 specs/schemes/exact/scheme_exact_cardano-masumi.md delete mode 100644 specs/schemes/exact/scheme_exact_cardano.md diff --git a/specs/schemes/exact/scheme_exact_cardano-masumi.md b/specs/schemes/exact/scheme_exact_cardano-masumi.md new file mode 100644 index 0000000000..12535c75b9 --- /dev/null +++ b/specs/schemes/exact/scheme_exact_cardano-masumi.md @@ -0,0 +1,97 @@ +# Scheme: exact on Cardano-Masumi + +## Summary + +This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. It utilizes the Masumi Smart Protocol, which offers additional refund mechanics & decision logging mechanisms in a decentralized way. + +## Protocol Flow + +The protocol flow for `exact` on Cardano is client-driven. + +1. **Client** makes an HTTP request to a **Resource Server**. +2. **Resource Server** responds with a `402 Payment Required` status. Detailing the Payment Information +3. **Client** constructs transaction body & returns it to Ressource Server. +4. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. +5. **Facilitator** confirms, then **Resource Server** sends the request to the **Facilitator** `/settle` endpoint. +6. **Facilitator** submits the transaction. +7. Upon successful on-chain settlement, the **Facilitator** responds to the **Resource Server**. +8. **Resource Server** grants the **Client** access to the resource in its response. + +## Expanded `PaymentRequirementsResponse` Schema + +The PaymentRequirementsResponse has been expanded with fields in "extra" and needs to return information that is required to create a valid Masumi Smart Contract interaction. + +```json +{ + "x402Version": 1, + "error": "X-PAYMENT header is required", + "accepts": [ + { + "scheme": "exact", + "network": "cardano-masumi", + "maxAmountRequired": "10000", + "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", + "resource": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json", + "outputSchema": null, + "maxTimeoutSeconds": 60, + "extra": { + "identifierFromPurchaser": "aabbaabb11221122aabb", + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } + } + ] +} +``` + + +## `X-PAYMENT` Header Payload + +The X-PAYMENT header is base64 encoded and sent in the request from the client to the resource server when paying for a resource. + +```json +{ + "x402Version": 1, + "scheme": "exact", + "network": "cardano", + "payload": { + "identifierFromPurchaser": "aabbaabb11221122aabb", + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } +} +``` + + +## `X-PAYMENT-RESPONSE` Header Payload + +The `X-PAYMENT-RESPONSE` header is base64 encoded and returned to the client from the resource server. + +Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: + +```json +{ + "success": "true | false", + "network": "cardano", + "type": "masumi | direct" +} +``` diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md deleted file mode 100644 index eb7d4ce00c..0000000000 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ /dev/null @@ -1,59 +0,0 @@ -# Scheme: exact on Cardano - -## Summary - -This document specifies the `exact` payment scheme for the x402 protocol on Cardano. - -This scheme facilitates payments of Cardano Native Tokens to a Cardano Wallet or a Smart Contract. - -## Protocol Flow - -The protocol flow for `exact` on Cardano is server-driven. - -1. **Client** makes an HTTP request to a **Resource Server**. -3. **Resource Server** responds with a `402 Payment Required` status. Detiling the Paymsnt Information and specifying which information is still required from the client to create a transaction. -4. **Client** responds with required information. -5. **Ressource Server** sends information to Facilitator. -6. **Facilitator** checks validity, constructs transaction body & returns it to Ressource Server. -8. **Ressource Server** forwards transaction body to client. -9. **Client** signs the transaction body with their wallet. -11. **Client** sends a new HTTP request to the resource server with the `X-PAYMENT` header containing signed transaction payload. -12. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator Server's** `/verify` endpoint. -13. **Facilitator** checks that only the required assets are being moved in the transaction & submits transction. -15. Upon successful on-chain settlement, the **Facilitator Server** responds to the **Resource Server**. -16. **Resource Server** grants the **Client** access to the resource in its response. - -## `X-PAYMENT` Header Payload - -The `X-PAYMENT` header is base64 encoded and sent in the request from the client to the resource server when paying for a resource. - -Once decoded, the `X-PAYMENT` header is a JSON string with the following properties: - -```json -{ - "x402Version": 1, - "scheme": "exact", - "network": "cardano", - "payload": { - "transaction": "AAAAAAAAAAAAA...AAAAAAAAAAAAA=" - } -} -``` - -The `payload` field contains the base64-encoded, serialized, **partially-signed** versioned Solana transaction. - - -## `X-PAYMENT-RESPONSE` Header Payload - -The `X-PAYMENT-RESPONSE` header is base64 encoded and returned to the client from the resource server. - -Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: - -```json -{ - "success": true | false, - "transaction": "base58 encoded transaction signature", - "network": "solana" | "solana-devnet", - "payer": "base58 encoded public address of the transaction fee payer" -} -``` From 91812fcd010c075fb14ddd64e4c64127014d8f8d Mon Sep 17 00:00:00 2001 From: Patrick Tobler <129864078+PatrickTobler@users.noreply.github.com> Date: Sun, 26 Oct 2025 17:20:31 +0530 Subject: [PATCH 04/16] Added Address-To-Address on Cardano Specs --- .../exact/scheme_exact_cardano-masumi.md | 97 --------- specs/schemes/exact/scheme_exact_cardano.md | 205 ++++++++++++++++++ 2 files changed, 205 insertions(+), 97 deletions(-) delete mode 100644 specs/schemes/exact/scheme_exact_cardano-masumi.md create mode 100644 specs/schemes/exact/scheme_exact_cardano.md diff --git a/specs/schemes/exact/scheme_exact_cardano-masumi.md b/specs/schemes/exact/scheme_exact_cardano-masumi.md deleted file mode 100644 index 12535c75b9..0000000000 --- a/specs/schemes/exact/scheme_exact_cardano-masumi.md +++ /dev/null @@ -1,97 +0,0 @@ -# Scheme: exact on Cardano-Masumi - -## Summary - -This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. It utilizes the Masumi Smart Protocol, which offers additional refund mechanics & decision logging mechanisms in a decentralized way. - -## Protocol Flow - -The protocol flow for `exact` on Cardano is client-driven. - -1. **Client** makes an HTTP request to a **Resource Server**. -2. **Resource Server** responds with a `402 Payment Required` status. Detailing the Payment Information -3. **Client** constructs transaction body & returns it to Ressource Server. -4. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. -5. **Facilitator** confirms, then **Resource Server** sends the request to the **Facilitator** `/settle` endpoint. -6. **Facilitator** submits the transaction. -7. Upon successful on-chain settlement, the **Facilitator** responds to the **Resource Server**. -8. **Resource Server** grants the **Client** access to the resource in its response. - -## Expanded `PaymentRequirementsResponse` Schema - -The PaymentRequirementsResponse has been expanded with fields in "extra" and needs to return information that is required to create a valid Masumi Smart Contract interaction. - -```json -{ - "x402Version": 1, - "error": "X-PAYMENT header is required", - "accepts": [ - { - "scheme": "exact", - "network": "cardano-masumi", - "maxAmountRequired": "10000", - "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", - "resource": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json", - "outputSchema": null, - "maxTimeoutSeconds": 60, - "extra": { - "identifierFromPurchaser": "aabbaabb11221122aabb", - "network": "Mainnet | Preprod", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - } - } - ] -} -``` - - -## `X-PAYMENT` Header Payload - -The X-PAYMENT header is base64 encoded and sent in the request from the client to the resource server when paying for a resource. - -```json -{ - "x402Version": 1, - "scheme": "exact", - "network": "cardano", - "payload": { - "identifierFromPurchaser": "aabbaabb11221122aabb", - "network": "Mainnet | Preprod", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - } -} -``` - - -## `X-PAYMENT-RESPONSE` Header Payload - -The `X-PAYMENT-RESPONSE` header is base64 encoded and returned to the client from the resource server. - -Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: - -```json -{ - "success": "true | false", - "network": "cardano", - "type": "masumi | direct" -} -``` diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md new file mode 100644 index 0000000000..10d78dcb28 --- /dev/null +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -0,0 +1,205 @@ +# Scheme: exact on Cardano + +## Summary + +This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. + +It offers two ways to do x402 interactions: + +a) Doing **Address-To-Address** Payments, similar to the regular x402 specifications on other chains. +b) Using the **Masumi Smart Protocol**, which offers additional refund mechanics & decision logging mechanisms in a decentralised way. + +## Protocol Flow + +![](../../../static/masumi-cardano-sequency-diagram-x402.png) + + +The protocol flow for `exact` on Cardano is client-driven. + +1. **Client** makes an HTTP request to a **Resource Server**. +2. **Resource Server** responds with a `402 Payment Required` status. Detailing the Payment Information +3. **Client** constructs transaction body & returns it to Ressource Server. +4. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. +5. **Facilitator** confirms, then **Resource Server** sends the request to the **Facilitator** `/settle` endpoint. +6. **Facilitator** submits the transaction. +7. Upon successful on-chain settlement, the **Facilitator** responds to the **Resource Server**. +8. **Resource Server** grants the **Client** access to the resource in its response. + +## Version 1: Address-To-Address + +### `PaymentRequirementsResponse` + +```json +{ + "x402Version": 1, + "error": "X-PAYMENT header is required", + "accepts": [ + { + "scheme": "exact", + "network": "cardano-mainnet", + "maxAmountRequired": "10000", // 1 USDM = 1000000000 + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad", // USDM on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod + "payTo": "addr1...", + "resource": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json", + "outputSchema": null, + "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "extra": { + } + } + ] +} +``` + +### `X-PAYMENT` Header Payload + +The X-PAYMENT header is base64-encoded and sent in the client's request to the resource server when paying for a resource. + +The payload field of the X-PAYMENT header must contain the following fields: + +transaction: The Base64 encoded Cardano transaction. +Example: + +```json +{ + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" +} +``` + +Full X-PAYMENT header: + +```json +{ + "x402Version": 1, + "scheme": "exact", + "network": "cardano", + "payload": { + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + } +} +``` + +Schema: + +```json +{ + "x402Version": 1, + "scheme": "exact", + "network": "cardano", + "payload": { + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } +} +``` + +### `X-PAYMENT-RESPONSE` Header Payload + +The `X-PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. + +Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: + +Schema: + +```json +{ + "success": "true | false", + "network": "cardano-masumi" + "transaction": "transaction-id", +} +``` + +## Version 2: Using Masumi Protocol + + +### Expanded `PaymentRequirementsResponse` Schema + +The PaymentRequirementsResponse has been expanded to include fields in "extra" and must return the information required to create a valid Masumi Smart Contract interaction. + +Schema: + +```json +{ + "x402Version": 1, + "error": "X-PAYMENT header is required", + "accepts": [ + { + "scheme": "exact", + "network": "cardano-masumi", + "maxAmountRequired": "10000", + "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", + "resource": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json", + "outputSchema": null, + "maxTimeoutSeconds": 60, + "extra": { + "identifierFromPurchaser": "aabbaabb11221122aabb", + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } + } + ] +} +``` + +### `X-PAYMENT` Header Payload + +The X-PAYMENT header is base64-encoded and sent in the client's request to the resource server when paying for a resource. + +Schema: + +```json +{ + "x402Version": 1, + "scheme": "exact", + "network": "cardano", + "payload": { + "identifierFromPurchaser": "aabbaabb11221122aabb", + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } +} +``` + +### `X-PAYMENT-RESPONSE` Header Payload + +The `X-PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. + +Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: + +Schema: + +```json +{ + "success": "true | false", + "network": "cardano-masumi" + "transaction": "transaction-id", +} +``` From 34c9f1a879388f9b0d4f3fbf0bda53bbd303f8c9 Mon Sep 17 00:00:00 2001 From: Patrick Tobler <129864078+PatrickTobler@users.noreply.github.com> Date: Sun, 26 Oct 2025 17:36:23 +0530 Subject: [PATCH 05/16] Update scheme_exact_cardano.md --- specs/schemes/exact/scheme_exact_cardano.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 10d78dcb28..20495af37d 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -113,7 +113,7 @@ Schema: ```json { "success": "true | false", - "network": "cardano-masumi" + "network": "cardano-mainnet" "transaction": "transaction-id", } ``` From 4317a7ea4165f22168d2745c7eef68eac59df752 Mon Sep 17 00:00:00 2001 From: fabianbormann Date: Mon, 17 Nov 2025 15:25:35 +0100 Subject: [PATCH 06/16] feat: add optional session management to final response --- specs/schemes/exact/scheme_exact_cardano.md | 225 ++++++++++++-------- 1 file changed, 132 insertions(+), 93 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 20495af37d..e6e66314bc 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -4,28 +4,92 @@ This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. -It offers two ways to do x402 interactions: +It offers different flavors to do x402 interactions: -a) Doing **Address-To-Address** Payments, similar to the regular x402 specifications on other chains. -b) Using the **Masumi Smart Protocol**, which offers additional refund mechanics & decision logging mechanisms in a decentralised way. +1. Doing **Address-To-Address** Payments, similar to the regular x402 specifications on other chains. -## Protocol Flow +2. Using the **Masumi Smart Protocol**, which offers additional refund mechanics & decision logging mechanisms in a decentralised way. -![](../../../static/masumi-cardano-sequency-diagram-x402.png) +3. Performing payments to scripts using parameters that can be applied to scripts while transaction building. +## Protocol Flow +```mermaid +sequenceDiagram + participant Client as Client/Agent + participant Server as Server + participant Facilitator as Facilitator + participant Cardano as Cardano Blockchain + + %% Initial Request + Client->>Server: 1. HTTP GET /api + + %% Payment Required Response + Server->>Client: 2. HTTP 402 and Payment Details + + %% Client Prepares Payment + Note over Client: 3. Client selects payment option,
creates and
signs a Transaction + + %% Request with Payment + Client->>Server: 4. HTTP GET /api
Header: X-PAYMENT (signed transaction) + Note right of Client: Retries with payment header + + %% Server Verification + alt Server Verification + Server->>Server: 5. Verify transaction locally + else Remote Verification (via Facilitator) + Server->>Facilitator: 5. POST /verify
(Payment Payload + Requirements) + Note right of Facilitator: Facilitator validates:
- Payment amount
- Correct recipient
- Nonce in Transaction + end + + %% Server Verification + alt Server Submission + Server->>Cardano: 6a. Submit signed transaction + Note right of Cardano: Transaction included in mempool or block + Cardano-->>Server: 6b. Transaction hash + confirmation + else Remote Submission (via Facilitator) + Server->>Facilitator: 6a. POST /settle
(Payment details) + Facilitator->>Cardano: 6b. Submit signed transaction + Note right of Cardano: Transaction included in mempool or block + Cardano-->>Facilitator: 6c. Transaction hash + confirmation + Facilitator->>Server: 6d. Settlement Response
(txHash, status) + end + + Note right of Server: 7. Receives transaction hash and status + + %% Final Response + Server->>Client: 8. HTTP 200 OK + Resource
Header: X-PAYMENT-RESPONSE + Note left of Server: Returns requested resource
with transaction confirmation:
- txHash
- network: "cardano-mainnet"
- status: "x confirmed" or "mempool" +``` The protocol flow for `exact` on Cardano is client-driven. 1. **Client** makes an HTTP request to a **Resource Server**. -2. **Resource Server** responds with a `402 Payment Required` status. Detailing the Payment Information -3. **Client** constructs transaction body & returns it to Ressource Server. -4. **Resource Server** receives the request and forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. -5. **Facilitator** confirms, then **Resource Server** sends the request to the **Facilitator** `/settle` endpoint. -6. **Facilitator** submits the transaction. -7. Upon successful on-chain settlement, the **Facilitator** responds to the **Resource Server**. -8. **Resource Server** grants the **Client** access to the resource in its response. -## Version 1: Address-To-Address +2. **Resource Server** responds with a `402 Payment Required` status, detailing the payment information: + - If using the Masumi Protocol, the `extra` field will contain additional information required to build a Masumi Smart Contract interaction. + - If using Address-To-Address payments, the `payTo` field will contain the address to which the payment must be sent. + - If using Script payments, the `extra` field will contain parameters to be applied to scripts during transaction building. + +3. **Client** constructs the transaction body, signs it, and returns it to the **Resource Server** via the `X-PAYMENT` header. + +4. **Resource Server** verifies the transaction is valid: + - **Local verification**: The server validates the transaction structure, amount, and recipient address directly. + - **Remote verification**: The server forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. + +5. After successful verification, the signed transaction is submitted to the Cardano blockchain: + - **Server submission**: The **Resource Server** submits the transaction directly to the Cardano blockchain. + - **Facilitator submission**: The **Resource Server** sends the transaction to the **Facilitator's** `/settle` endpoint, which then submits it to the blockchain. + +6. The Cardano blockchain includes the transaction in the mempool or a block and returns the transaction hash and confirmation status. + +7. **Resource Server** receives the transaction hash and status: + - If submitted via the **Facilitator**, it receives a settlement response containing the `txHash` and `status`. + - If the **Facilitator** supports mempool monitoring, it may notify the **Resource Server** upon mempool inclusion, reducing end-to-end latency but with higher risk of accepting unconfirmed transactions. + +8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with an `X-PAYMENT-RESPONSE` header containing: + - `txHash`: The Cardano transaction hash + - `network`: The Cardano network (e.g., `cardano-mainnet`) + - `status`: The transaction status (e.g., `confirmed` or `mempool`) ### `PaymentRequirementsResponse` @@ -36,9 +100,9 @@ The protocol flow for `exact` on Cardano is client-driven. "accepts": [ { "scheme": "exact", - "network": "cardano-mainnet", + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets "maxAmountRequired": "10000", // 1 USDM = 1000000000 - "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad", // USDM on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", "resource": "https://api.example.com/premium-data", "description": "Access to premium market data", @@ -46,6 +110,19 @@ The protocol flow for `exact` on Cardano is client-driven. "outputSchema": null, "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { + "flavor": "masumi", // optional, can be "default" | "masumi" | "script" + // Additional fields for masumi or script flavors can be added here + "identifierFromPurchaser": "aabbaabb11221122aabb", + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" } } ] @@ -73,22 +150,23 @@ Full X-PAYMENT header: { "x402Version": 1, "scheme": "exact", - "network": "cardano", + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets "payload": { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" } } ``` -Schema: +Expanded Schema based on flavors: ```json { "x402Version": 1, "scheme": "exact", - "network": "cardano", + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets "payload": { - "network": "Mainnet | Preprod", + "transaction": "base64-encoded-cardano-transaction", + "flavor": "masumi", // optional, can be "default" | "masumi" | "script" "sellerVkey": "sdasdqweqwewewewqe", "paymentType": "Web3CardanoV1", "blockchainIdentifier": "blockchain_identifier", @@ -97,7 +175,9 @@ Schema: "unlockTime": "1713636260", "externalDisputeUnlockTime": "1713636260", "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "identifierFromPurchaser": "aabbaabb11221122aabb" + // Additional fields for script flavor can be added here } } ``` @@ -112,94 +192,53 @@ Schema: ```json { - "success": "true | false", - "network": "cardano-mainnet" - "transaction": "transaction-id", + "status": "confirmed", // "confirmed", "mempool" or "failed" + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "txHash": "2f9a7b3c..." // Transaction hash of the payment if successful } ``` -## Version 2: Using Masumi Protocol +### `X-SESSION-TOKEN` Header Payload +In case of a successful payment, the Resource Server *may* return an *optional* `X-SESSION-TOKEN` header to allow the Client to access the resource without making additional payments until the session expires. -### Expanded `PaymentRequirementsResponse` Schema +The session token should be implemented as a **JSON Web Token (JWT)** to manage the session after initial payment authentication. This approach provides a smoother user experience by eliminating the need for wallet signatures on every subsequent request. -The PaymentRequirementsResponse has been expanded to include fields in "extra" and must return the information required to create a valid Masumi Smart Contract interaction. +#### JWT Structure -Schema: +The `X-SESSION-TOKEN` is a standard JWT (RFC 7519) with the following structure: +**Header:** ```json { - "x402Version": 1, - "error": "X-PAYMENT header is required", - "accepts": [ - { - "scheme": "exact", - "network": "cardano-masumi", - "maxAmountRequired": "10000", - "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", - "resource": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json", - "outputSchema": null, - "maxTimeoutSeconds": 60, - "extra": { - "identifierFromPurchaser": "aabbaabb11221122aabb", - "network": "Mainnet | Preprod", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - } - } - ] + "alg": "HS256", + "typ": "JWT" } ``` -### `X-PAYMENT` Header Payload - -The X-PAYMENT header is base64-encoded and sent in the client's request to the resource server when paying for a resource. - -Schema: - +**Payload (Claims):** ```json { - "x402Version": 1, - "scheme": "exact", - "network": "cardano", - "payload": { - "identifierFromPurchaser": "aabbaabb11221122aabb", - "network": "Mainnet | Preprod", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - } + "iss": "api.example.com", + "sub": "addr1qxclient...", + "exp": 1731866400, + "iat": 1731862800, + "jti": "7f234e8b-1c4a-49b7-8a5f-d321e567890a", + "txHash": "2f9a7b3c4d5e6f789a0bc...", + "scope": "/api/premium/*,/api/data/*", + "network": "cardano-mainnet" } ``` -### `X-PAYMENT-RESPONSE` Header Payload - -The `X-PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. - -Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: - -Schema: - -```json -{ - "success": "true | false", - "network": "cardano-masumi" - "transaction": "transaction-id", -} -``` +**Claims Description:** +- `iss` (issuer): The domain of the Resource Server +- `sub` (subject): The Cardano address of the client who made the payment +- `exp` (expiration): Unix timestamp when the session expires +- `iat` (issued at): Unix timestamp when the session was created +- `jti` (JWT ID): Unique session identifier +- `txHash`: Transaction hash of the payment that created this session +- `scope`: Comma-separated list of resource paths accessible with this token +- `network`: Cardano network where the payment was made + +**Signature:** +The JWT is signed using the server's secret key (HS256) or RSA private key (RS256). The signature ensures the token cannot be tampered with. From 5a4ca01daa9c3abc48079d951c01eda1149ff79d Mon Sep 17 00:00:00 2001 From: fabianbormann Date: Tue, 18 Nov 2025 09:39:25 +0100 Subject: [PATCH 07/16] chore: add instructions for script flavor --- specs/schemes/exact/scheme_exact_cardano.md | 121 ++++++++++++++++++-- 1 file changed, 112 insertions(+), 9 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index e6e66314bc..573d010c9e 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -93,7 +93,39 @@ The protocol flow for `exact` on Cardano is client-driven. ### `PaymentRequirementsResponse` -```json +#### Default Schema + +When the Resource Server responds with a `402 Payment Required`, the body of the response contains the payment requirements in the following schema: + +```js +{ + "x402Version": 1, + "error": "X-PAYMENT header is required", + "accepts": [ + { + "scheme": "exact", + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "maxAmountRequired": "10000", // 1 USDM = 1000000000 + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' + "payTo": "addr1...", + "resource": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json", + "outputSchema": null, + "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "extra": { + // In case of default address-to-address payments, this may be empty or contain additional metadata + } + } + ] +} +``` + +#### Masumi Flavor Schema + +When the Resource Server requires payment via the Masumi Smart Protocol, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for Masumi interactions. + +```js { "x402Version": 1, "error": "X-PAYMENT header is required", @@ -111,7 +143,7 @@ The protocol flow for `exact` on Cardano is client-driven. "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { "flavor": "masumi", // optional, can be "default" | "masumi" | "script" - // Additional fields for masumi or script flavors can be added here + // If the masumi flavor is used, make sure to include all masumi related fields "identifierFromPurchaser": "aabbaabb11221122aabb", "network": "Mainnet | Preprod", "sellerVkey": "sdasdqweqwewewewqe", @@ -123,6 +155,48 @@ The protocol flow for `exact` on Cardano is client-driven. "externalDisputeUnlockTime": "1713636260", "agentIdentifier": "agent_identifier", "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + // Additional fields for masumi or script flavors can be added here + } + } + ] +} +``` + +#### Script Flavor Schema + +When the Resource Server requires payment to a script, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for script interactions. + +```js +{ + "x402Version": 1, + "error": "X-PAYMENT header is required", + "accepts": [ + { + "scheme": "exact", + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "maxAmountRequired": "10000", // 1 USDM = 1000000000 + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' + "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the X-PAYMENT header, so that the server can reconstruct the script address and verify the payment) + "resource": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json", + "outputSchema": null, + "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "extra": { + "flavor": "script", // optional, can be "default" | "masumi" | "script" + // If the script flavor is used, make sure to include all script related fields + "scriptHash": "script_hash_here", // If the script is already on-chain, provide its hash and the client can resolve the full script + "script": { + // Optional full script object if not on-chain yet + "type": "plutusV3", + "code": "", + }, + "parameters": { + "param1": {"value": "Hello World", "type": "bytes"}, + "param2": {"value": 42, "type": "bigint"} + // Script-specific parameters required for transaction building + } + // Additional fields for script flavors can be added here } } ] @@ -138,7 +212,7 @@ The payload field of the X-PAYMENT header must contain the following fields: transaction: The Base64 encoded Cardano transaction. Example: -```json +```js { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" } @@ -146,7 +220,7 @@ Example: Full X-PAYMENT header: -```json +```js { "x402Version": 1, "scheme": "exact", @@ -159,14 +233,16 @@ Full X-PAYMENT header: Expanded Schema based on flavors: -```json +#### Masumi Flavor + +```js { "x402Version": 1, "scheme": "exact", "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets "payload": { - "transaction": "base64-encoded-cardano-transaction", "flavor": "masumi", // optional, can be "default" | "masumi" | "script" + "transaction": "base64-encoded-cardano-transaction", "sellerVkey": "sdasdqweqwewewewqe", "paymentType": "Web3CardanoV1", "blockchainIdentifier": "blockchain_identifier", @@ -182,6 +258,33 @@ Expanded Schema based on flavors: } ``` +#### Script Flavor + +```js +{ + "x402Version": 1, + "scheme": "exact", + "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "payload": { + "flavor": "script", // optional, can be "default" | "masumi" | "script" + "transaction": "base64-encoded-cardano-transaction", + "scriptHash": "script_hash_here", // If the script is already on-chain, provide its hash and the client can resolve the full script + "script": { + // Optional full script object if not on-chain yet + "type": "plutusV3", + "code": "", + }, + "parameters": { + // Script-specific parameters required for transaction building + "param1": {"value": "Hello World", "type": "bytes"}, + "param2": {"value": 42, "type": "bigint"} + // Make sure to include all parameters that were applied to the script, even if they were not part of the payment requirements + } + // Additional fields for script flavor can be added here + } +} +``` + ### `X-PAYMENT-RESPONSE` Header Payload The `X-PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. @@ -190,7 +293,7 @@ Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following prope Schema: -```json +```js { "status": "confirmed", // "confirmed", "mempool" or "failed" "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets @@ -209,7 +312,7 @@ The session token should be implemented as a **JSON Web Token (JWT)** to manage The `X-SESSION-TOKEN` is a standard JWT (RFC 7519) with the following structure: **Header:** -```json +```js { "alg": "HS256", "typ": "JWT" @@ -217,7 +320,7 @@ The `X-SESSION-TOKEN` is a standard JWT (RFC 7519) with the following structure: ``` **Payload (Claims):** -```json +```js { "iss": "api.example.com", "sub": "addr1qxclient...", From cef73dd55cd72878b3cb7b2d2b1ae4964220ca02 Mon Sep 17 00:00:00 2001 From: fabianbormann Date: Thu, 5 Feb 2026 11:36:00 +0100 Subject: [PATCH 08/16] feat: update cardano schema according to x402 v2 migration guide --- specs/schemes/exact/scheme_exact_cardano.md | 64 ++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 573d010c9e..785cdba5e6 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -30,7 +30,7 @@ sequenceDiagram Note over Client: 3. Client selects payment option,
creates and
signs a Transaction %% Request with Payment - Client->>Server: 4. HTTP GET /api
Header: X-PAYMENT (signed transaction) + Client->>Server: 4. HTTP GET /api
Header: PAYMENT-SIGNATURE (signed transaction) Note right of Client: Retries with payment header %% Server Verification @@ -57,7 +57,7 @@ sequenceDiagram Note right of Server: 7. Receives transaction hash and status %% Final Response - Server->>Client: 8. HTTP 200 OK + Resource
Header: X-PAYMENT-RESPONSE + Server->>Client: 8. HTTP 200 OK + Resource
Header: PAYMENT-RESPONSE Note left of Server: Returns requested resource
with transaction confirmation:
- txHash
- network: "cardano-mainnet"
- status: "x confirmed" or "mempool" ``` @@ -70,11 +70,11 @@ The protocol flow for `exact` on Cardano is client-driven. - If using Address-To-Address payments, the `payTo` field will contain the address to which the payment must be sent. - If using Script payments, the `extra` field will contain parameters to be applied to scripts during transaction building. -3. **Client** constructs the transaction body, signs it, and returns it to the **Resource Server** via the `X-PAYMENT` header. +3. **Client** constructs the transaction body, signs it, and returns it to the **Resource Server** via the `PAYMENT-SIGNATURE` header. 4. **Resource Server** verifies the transaction is valid: - **Local verification**: The server validates the transaction structure, amount, and recipient address directly. - - **Remote verification**: The server forwards the `X-PAYMENT` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. + - **Remote verification**: The server forwards the `PAYMENT-SIGNATURE` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. 5. After successful verification, the signed transaction is submitted to the Cardano blockchain: - **Server submission**: The **Resource Server** submits the transaction directly to the Cardano blockchain. @@ -86,9 +86,9 @@ The protocol flow for `exact` on Cardano is client-driven. - If submitted via the **Facilitator**, it receives a settlement response containing the `txHash` and `status`. - If the **Facilitator** supports mempool monitoring, it may notify the **Resource Server** upon mempool inclusion, reducing end-to-end latency but with higher risk of accepting unconfirmed transactions. -8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with an `X-PAYMENT-RESPONSE` header containing: +8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with an `PAYMENT-RESPONSE` header containing: - `txHash`: The Cardano transaction hash - - `network`: The Cardano network (e.g., `cardano-mainnet`) + - `network`: The Cardano network (e.g., `cardano:mainnet`) - `status`: The transaction status (e.g., `confirmed` or `mempool`) ### `PaymentRequirementsResponse` @@ -99,12 +99,12 @@ When the Resource Server responds with a `402 Payment Required`, the body of the ```js { - "x402Version": 1, - "error": "X-PAYMENT header is required", + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", "accepts": [ { "scheme": "exact", - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "maxAmountRequired": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", @@ -127,12 +127,12 @@ When the Resource Server requires payment via the Masumi Smart Protocol, the `ex ```js { - "x402Version": 1, - "error": "X-PAYMENT header is required", + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", "accepts": [ { "scheme": "exact", - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "maxAmountRequired": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", @@ -168,15 +168,15 @@ When the Resource Server requires payment to a script, the `extra` field in the ```js { - "x402Version": 1, - "error": "X-PAYMENT header is required", + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", "accepts": [ { "scheme": "exact", - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "maxAmountRequired": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' - "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the X-PAYMENT header, so that the server can reconstruct the script address and verify the payment) + "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the PAYMENT-SIGNATURE header, so that the server can reconstruct the script address and verify the payment) "resource": "https://api.example.com/premium-data", "description": "Access to premium market data", "mimeType": "application/json", @@ -203,11 +203,11 @@ When the Resource Server requires payment to a script, the `extra` field in the } ``` -### `X-PAYMENT` Header Payload +### `PAYMENT-SIGNATURE` Header Payload -The X-PAYMENT header is base64-encoded and sent in the client's request to the resource server when paying for a resource. +The PAYMENT-SIGNATURE header is base64-encoded and sent in the client's request to the resource server when paying for a resource. -The payload field of the X-PAYMENT header must contain the following fields: +The payload field of the PAYMENT-SIGNATURE header must contain the following fields: transaction: The Base64 encoded Cardano transaction. Example: @@ -218,13 +218,13 @@ Example: } ``` -Full X-PAYMENT header: +Full PAYMENT-SIGNATURE header: ```js { - "x402Version": 1, + "x402Version": 2, "scheme": "exact", - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "payload": { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" } @@ -237,12 +237,12 @@ Expanded Schema based on flavors: ```js { - "x402Version": 1, + "x402Version": 2, "scheme": "exact", - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "payload": { "flavor": "masumi", // optional, can be "default" | "masumi" | "script" - "transaction": "base64-encoded-cardano-transaction", + "transaction": "base64-encoded-cardano:transaction", "sellerVkey": "sdasdqweqwewewewqe", "paymentType": "Web3CardanoV1", "blockchainIdentifier": "blockchain_identifier", @@ -262,9 +262,9 @@ Expanded Schema based on flavors: ```js { - "x402Version": 1, + "x402Version": 2, "scheme": "exact", - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "payload": { "flavor": "script", // optional, can be "default" | "masumi" | "script" "transaction": "base64-encoded-cardano-transaction", @@ -285,18 +285,18 @@ Expanded Schema based on flavors: } ``` -### `X-PAYMENT-RESPONSE` Header Payload +### `PAYMENT-RESPONSE` Header Payload -The `X-PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. +The `PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. -Once decoded, the `X-PAYMENT-RESPONSE` is a JSON string with the following properties: +Once decoded, the `PAYMENT-RESPONSE` is a JSON string with the following properties: Schema: ```js { "status": "confirmed", // "confirmed", "mempool" or "failed" - "network": "cardano-mainnet", // cardano-preprod or cardano-preview for public testnets + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets "txHash": "2f9a7b3c..." // Transaction hash of the payment if successful } ``` @@ -329,7 +329,7 @@ The `X-SESSION-TOKEN` is a standard JWT (RFC 7519) with the following structure: "jti": "7f234e8b-1c4a-49b7-8a5f-d321e567890a", "txHash": "2f9a7b3c4d5e6f789a0bc...", "scope": "/api/premium/*,/api/data/*", - "network": "cardano-mainnet" + "network": "cardano:mainnet" } ``` From a0076a527e8a14f09bfcc7b29fea14694cc8ae2f Mon Sep 17 00:00:00 2001 From: Fabian Bormann Date: Thu, 5 Feb 2026 11:49:49 +0100 Subject: [PATCH 09/16] chore: update mermaid diagram for x402 v2 --- specs/schemes/exact/scheme_exact_cardano.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 785cdba5e6..0fe7783296 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -58,7 +58,7 @@ sequenceDiagram %% Final Response Server->>Client: 8. HTTP 200 OK + Resource
Header: PAYMENT-RESPONSE - Note left of Server: Returns requested resource
with transaction confirmation:
- txHash
- network: "cardano-mainnet"
- status: "x confirmed" or "mempool" + Note left of Server: Returns requested resource
with transaction confirmation:
- transaction: "2f9a7b3c..."
- network: "cardano:mainnet"
- success: true ``` The protocol flow for `exact` on Cardano is client-driven. From 99979e5b304637103b48b2a56f24e41251ce5236 Mon Sep 17 00:00:00 2001 From: fabianbormann Date: Thu, 5 Feb 2026 12:48:11 +0100 Subject: [PATCH 10/16] chore: reapply v2 changes that might got lost in the merging process --- specs/schemes/exact/scheme_exact_cardano.md | 149 +++++++++++++------- 1 file changed, 98 insertions(+), 51 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 785cdba5e6..bc0863fdf6 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -101,6 +101,11 @@ When the Resource Server responds with a `402 Payment Required`, the body of the { "x402Version": 2, "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, "accepts": [ { "scheme": "exact", @@ -108,10 +113,6 @@ When the Resource Server responds with a `402 Payment Required`, the body of the "maxAmountRequired": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", - "resource": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json", - "outputSchema": null, "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { // In case of default address-to-address payments, this may be empty or contain additional metadata @@ -129,6 +130,11 @@ When the Resource Server requires payment via the Masumi Smart Protocol, the `ex { "x402Version": 2, "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, "accepts": [ { "scheme": "exact", @@ -136,10 +142,6 @@ When the Resource Server requires payment via the Masumi Smart Protocol, the `ex "maxAmountRequired": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", - "resource": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json", - "outputSchema": null, "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { "flavor": "masumi", // optional, can be "default" | "masumi" | "script" @@ -170,6 +172,11 @@ When the Resource Server requires payment to a script, the `extra` field in the { "x402Version": 2, "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, "accepts": [ { "scheme": "exact", @@ -177,10 +184,6 @@ When the Resource Server requires payment to a script, the `extra` field in the "maxAmountRequired": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the PAYMENT-SIGNATURE header, so that the server can reconstruct the script address and verify the payment) - "resource": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json", - "outputSchema": null, "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { "flavor": "script", // optional, can be "default" | "masumi" | "script" @@ -209,7 +212,7 @@ The PAYMENT-SIGNATURE header is base64-encoded and sent in the client's request The payload field of the PAYMENT-SIGNATURE header must contain the following fields: -transaction: The Base64 encoded Cardano transaction. +transaction: The signed Cardano transaction (Base64 encoded). Example: ```js @@ -223,10 +226,25 @@ Full PAYMENT-SIGNATURE header: ```js { "x402Version": 2, - "scheme": "exact", - "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", + "maxTimeoutSeconds": 600, + "extra": { + // In case of default address-to-address payments, this may be empty or contain additional metadata + } + }, "payload": { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480" } } ``` @@ -238,22 +256,36 @@ Expanded Schema based on flavors: ```js { "x402Version": 2, - "scheme": "exact", - "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", + "maxTimeoutSeconds": 600, + "extra": { + "flavor": "masumi", + "identifierFromPurchaser": "aabbaabb11221122aabb", + "network": "Mainnet | Preprod", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } + }, "payload": { - "flavor": "masumi", // optional, can be "default" | "masumi" | "script" - "transaction": "base64-encoded-cardano:transaction", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", - "identifierFromPurchaser": "aabbaabb11221122aabb" - // Additional fields for script flavor can be added here + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480" } } ``` @@ -263,24 +295,34 @@ Expanded Schema based on flavors: ```js { "x402Version": 2, - "scheme": "exact", - "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", // script address + "maxTimeoutSeconds": 600, + "extra": { + "flavor": "script", + "scriptHash": "script_hash_here", + "script": { + "type": "plutusV3", + "code": "" + }, + "parameters": { + "param1": {"value": "Hello World", "type": "bytes"}, + "param2": {"value": 42, "type": "bigint"} + } + } + }, "payload": { - "flavor": "script", // optional, can be "default" | "masumi" | "script" - "transaction": "base64-encoded-cardano-transaction", - "scriptHash": "script_hash_here", // If the script is already on-chain, provide its hash and the client can resolve the full script - "script": { - // Optional full script object if not on-chain yet - "type": "plutusV3", - "code": "", - }, - "parameters": { - // Script-specific parameters required for transaction building - "param1": {"value": "Hello World", "type": "bytes"}, - "param2": {"value": 42, "type": "bigint"} - // Make sure to include all parameters that were applied to the script, even if they were not part of the payment requirements - } - // Additional fields for script flavor can be added here + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480" } } ``` @@ -295,9 +337,14 @@ Schema: ```js { - "status": "confirmed", // "confirmed", "mempool" or "failed" - "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "txHash": "2f9a7b3c..." // Transaction hash of the payment if successful + "success": "true", // "true" or "false" + "network": "cardano:mainnet", + "transaction": "2f9a7b3c..." // Transaction hash of the payment if successful + "extensions": { + "status": "confirmed", // "confirmed" or "mempool" + } + // Optional error field in case of failure + "errorReason": "Utxo not found in utxo set" // Example error reason } ``` @@ -327,7 +374,7 @@ The `X-SESSION-TOKEN` is a standard JWT (RFC 7519) with the following structure: "exp": 1731866400, "iat": 1731862800, "jti": "7f234e8b-1c4a-49b7-8a5f-d321e567890a", - "txHash": "2f9a7b3c4d5e6f789a0bc...", + "transaction": "2f9a7b3c4d5e6f789a0bc...", "scope": "/api/premium/*,/api/data/*", "network": "cardano:mainnet" } From 99f75e39b3326339982c8e6c2c710b27020fd76a Mon Sep 17 00:00:00 2001 From: fabianbormann Date: Mon, 23 Mar 2026 12:53:53 +0100 Subject: [PATCH 11/16] chore: address x402 schema feedback around nonce, legacy v1 fields, flavor and session tokens --- specs/schemes/exact/scheme_exact_cardano.md | 95 ++++++--------------- 1 file changed, 27 insertions(+), 68 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 19be0cbecc..de81f3e3f3 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -4,7 +4,7 @@ This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. -It offers different flavors to do x402 interactions: +It offers different assetTransferMethods to do x402 interactions: 1. Doing **Address-To-Address** Payments, similar to the regular x402 specifications on other chains. @@ -110,7 +110,7 @@ When the Resource Server responds with a `402 Payment Required`, the body of the { "scheme": "exact", "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "maxAmountRequired": "10000", // 1 USDM = 1000000000 + "amount": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed @@ -122,7 +122,7 @@ When the Resource Server responds with a `402 Payment Required`, the body of the } ``` -#### Masumi Flavor Schema +#### Masumi assetTransferMethod Schema When the Resource Server requires payment via the Masumi Smart Protocol, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for Masumi interactions. @@ -139,15 +139,14 @@ When the Resource Server requires payment via the Masumi Smart Protocol, the `ex { "scheme": "exact", "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "maxAmountRequired": "10000", // 1 USDM = 1000000000 + "amount": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { - "flavor": "masumi", // optional, can be "default" | "masumi" | "script" - // If the masumi flavor is used, make sure to include all masumi related fields + "assetTransferMethod": "masumi", // optional, can be "default" | "masumi" | "script" + // If the masumi assetTransferMethod is used, make sure to include all masumi related fields "identifierFromPurchaser": "aabbaabb11221122aabb", - "network": "Mainnet | Preprod", "sellerVkey": "sdasdqweqwewewewqe", "paymentType": "Web3CardanoV1", "blockchainIdentifier": "blockchain_identifier", @@ -157,14 +156,14 @@ When the Resource Server requires payment via the Masumi Smart Protocol, the `ex "externalDisputeUnlockTime": "1713636260", "agentIdentifier": "agent_identifier", "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - // Additional fields for masumi or script flavors can be added here + // Additional fields for masumi or script assetTransferMethods can be added here } } ] } ``` -#### Script Flavor Schema +#### Script assetTransferMethod Schema When the Resource Server requires payment to a script, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for script interactions. @@ -181,13 +180,13 @@ When the Resource Server requires payment to a script, the `extra` field in the { "scheme": "exact", "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "maxAmountRequired": "10000", // 1 USDM = 1000000000 + "amount": "10000", // 1 USDM = 1000000000 "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the PAYMENT-SIGNATURE header, so that the server can reconstruct the script address and verify the payment) "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed "extra": { - "flavor": "script", // optional, can be "default" | "masumi" | "script" - // If the script flavor is used, make sure to include all script related fields + "assetTransferMethod": "script", // optional, can be "default" | "masumi" | "script" + // If the script assetTransferMethod is used, make sure to include all script related fields "scriptHash": "script_hash_here", // If the script is already on-chain, provide its hash and the client can resolve the full script "script": { // Optional full script object if not on-chain yet @@ -199,7 +198,7 @@ When the Resource Server requires payment to a script, the `extra` field in the "param2": {"value": 42, "type": "bigint"} // Script-specific parameters required for transaction building } - // Additional fields for script flavors can be added here + // Additional fields for script assetTransferMethods can be added here } } ] @@ -244,14 +243,14 @@ Full PAYMENT-SIGNATURE header: }, "payload": { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" - "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480" + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" } } ``` -Expanded Schema based on flavors: +Expanded Schema based on assetTransferMethods: -#### Masumi Flavor +#### Masumi assetTransferMethod ```js { @@ -269,9 +268,8 @@ Expanded Schema based on flavors: "payTo": "addr1...", "maxTimeoutSeconds": 600, "extra": { - "flavor": "masumi", + "assetTransferMethod": "masumi", "identifierFromPurchaser": "aabbaabb11221122aabb", - "network": "Mainnet | Preprod", "sellerVkey": "sdasdqweqwewewewqe", "paymentType": "Web3CardanoV1", "blockchainIdentifier": "blockchain_identifier", @@ -285,12 +283,12 @@ Expanded Schema based on flavors: }, "payload": { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" - "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480" + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" } } ``` -#### Script Flavor +#### Script assetTransferMethod ```js { @@ -308,7 +306,7 @@ Expanded Schema based on flavors: "payTo": "addr1...", // script address "maxTimeoutSeconds": 600, "extra": { - "flavor": "script", + "assetTransferMethod": "script", "scriptHash": "script_hash_here", "script": { "type": "plutusV3", @@ -322,11 +320,17 @@ Expanded Schema based on flavors: }, "payload": { "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" - "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480" + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" } } ``` +### Facilitator Verification Steps + +1. Nonce Verification: The nonce needs to be a UTXO that is included in the transaction and the facilitator needs to verify that this UTXO exists in the current UTXO set of the blockchain and is not spent. This ensures the transaction is unique and prevents replay attacks. +2. Network Validation: Confirm the transaction is on the correct network +3. Amount Verification: Check that the provided Amount (assets) exactly matches the required amount + ### `PAYMENT-RESPONSE` Header Payload The `PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. @@ -337,7 +341,7 @@ Schema: ```js { - "success": "true", // "true" or "false" + "success": true, // true or false "network": "cardano:mainnet", "transaction": "2f9a7b3c..." // Transaction hash of the payment if successful "extensions": { @@ -347,48 +351,3 @@ Schema: "errorReason": "Utxo not found in utxo set" // Example error reason } ``` - -### `X-SESSION-TOKEN` Header Payload - -In case of a successful payment, the Resource Server *may* return an *optional* `X-SESSION-TOKEN` header to allow the Client to access the resource without making additional payments until the session expires. - -The session token should be implemented as a **JSON Web Token (JWT)** to manage the session after initial payment authentication. This approach provides a smoother user experience by eliminating the need for wallet signatures on every subsequent request. - -#### JWT Structure - -The `X-SESSION-TOKEN` is a standard JWT (RFC 7519) with the following structure: - -**Header:** -```js -{ - "alg": "HS256", - "typ": "JWT" -} -``` - -**Payload (Claims):** -```js -{ - "iss": "api.example.com", - "sub": "addr1qxclient...", - "exp": 1731866400, - "iat": 1731862800, - "jti": "7f234e8b-1c4a-49b7-8a5f-d321e567890a", - "transaction": "2f9a7b3c4d5e6f789a0bc...", - "scope": "/api/premium/*,/api/data/*", - "network": "cardano:mainnet" -} -``` - -**Claims Description:** -- `iss` (issuer): The domain of the Resource Server -- `sub` (subject): The Cardano address of the client who made the payment -- `exp` (expiration): Unix timestamp when the session expires -- `iat` (issued at): Unix timestamp when the session was created -- `jti` (JWT ID): Unique session identifier -- `txHash`: Transaction hash of the payment that created this session -- `scope`: Comma-separated list of resource paths accessible with this token -- `network`: Cardano network where the payment was made - -**Signature:** -The JWT is signed using the server's secret key (HS256) or RSA private key (RS256). The signature ensures the token cannot be tampered with. From 27fb9f2272fc474753492b66863fd331ab0d3832 Mon Sep 17 00:00:00 2001 From: fabianbormann Date: Mon, 23 Mar 2026 12:59:07 +0100 Subject: [PATCH 12/16] chore: add warning for mempool status, rewrite facilitator verification rules --- specs/schemes/exact/scheme_exact_cardano.md | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index de81f3e3f3..77ca60e997 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -84,7 +84,7 @@ The protocol flow for `exact` on Cardano is client-driven. 7. **Resource Server** receives the transaction hash and status: - If submitted via the **Facilitator**, it receives a settlement response containing the `txHash` and `status`. - - If the **Facilitator** supports mempool monitoring, it may notify the **Resource Server** upon mempool inclusion, reducing end-to-end latency but with higher risk of accepting unconfirmed transactions. + - Cardano uses Ouroboros Praos, which has probabilistic finality. A transaction that appears in the mempool or even in a recent block can be rolled back. Granting access upon mempool inclusion (`status: "mempool"`) is therefore **strongly discouraged** and SHOULD NOT be used for any resource with real economic value. Servers that choose to accept mempool status MUST document this risk and accept full liability for rolled-back transactions. 8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with an `PAYMENT-RESPONSE` header containing: - `txHash`: The Cardano transaction hash @@ -325,11 +325,21 @@ Expanded Schema based on assetTransferMethods: } ``` -### Facilitator Verification Steps +### Facilitator Verification Rules -1. Nonce Verification: The nonce needs to be a UTXO that is included in the transaction and the facilitator needs to verify that this UTXO exists in the current UTXO set of the blockchain and is not spent. This ensures the transaction is unique and prevents replay attacks. -2. Network Validation: Confirm the transaction is on the correct network -3. Amount Verification: Check that the provided Amount (assets) exactly matches the required amount +A facilitator MUST enforce all of the following rules before accepting a payment as valid. Any failure MUST result in a rejection. + +1. **Network Validation**: The transaction MUST be destined for the correct Cardano network (mainnet, preprod, or preview) as declared in `PaymentRequirements.network`. The facilitator MUST reject transactions built for a different network. + +2. **Recipient Verification**: At least one transaction output MUST send funds to the address specified in `PaymentRequirements.payTo`. The facilitator MUST NOT accept transactions where the recipient address differs from `payTo`. + +3. **Amount Verification**: The output sent to `payTo` MUST contain a value greater than or equal to the amount declared in `PaymentRequirements.amount` for the asset identified by `PaymentRequirements.asset`. The facilitator MUST verify both the policy ID and the asset name match exactly. + +4. **Asset Verification**: The asset unit in the transaction MUST exactly match `PaymentRequirements.asset` (format: `${policyId}.${assetNameHex}`). The facilitator MUST NOT accept a different asset, even one of equal market value. + +5. **Nonce / Replay Prevention**: The `payload.nonce` MUST be a valid UTXO reference (`txHash#index`) that is included as an input in the transaction. The facilitator MUST verify that this UTXO exists in the current on-chain UTXO set and has not been spent. This ensures uniqueness and prevents replay attacks. + +6. **TTL / Expiry Check**: The transaction's TTL (time-to-live slot) MUST not have already passed at the time of verification. The facilitator MUST reject transactions whose TTL is in the past. The TTL SHOULD be consistent with `PaymentRequirements.maxTimeoutSeconds`. ### `PAYMENT-RESPONSE` Header Payload @@ -345,7 +355,7 @@ Schema: "network": "cardano:mainnet", "transaction": "2f9a7b3c..." // Transaction hash of the payment if successful "extensions": { - "status": "confirmed", // "confirmed" or "mempool" + "status": "confirmed", // "confirmed" is the recommended value; "mempool" is permitted but strongly discouraged — see settlement warning above } // Optional error field in case of failure "errorReason": "Utxo not found in utxo set" // Example error reason From 84353d56b626d3dd563dd3f3067dff7caa49482a Mon Sep 17 00:00:00 2001 From: "a.dacapo21" Date: Thu, 23 Apr 2026 15:20:18 +0300 Subject: [PATCH 13/16] docs(cardano): make exact scheme vendor-neutral, add masumi extension rewrite specs/schemes/exact/scheme_exact_cardano.md so the core compliance surface describes only generic cardano primitives (address-to-address payments, script-parameterized payments, ttl/nonce/amount/asset verification). remove the masumi-named enum value and masumi-specific fields from the core scheme. add specs/extensions/cardano_masumi.md carrying the masumi-specific fields under the x402 v2 extensions model, preserving full masumi support without coupling it to the core cardano compliance path. add docs/cardano-open-standard-rationale.md and docs/cardano-open-standard-pr-summary.md explaining the standards-boundary correction. --- docs/cardano-open-standard-pr-summary.md | 98 +++++++ docs/cardano-open-standard-rationale.md | 67 +++++ specs/extensions/cardano_masumi.md | 216 ++++++++++++++ specs/schemes/exact/scheme_exact_cardano.md | 302 +++++++++----------- 4 files changed, 517 insertions(+), 166 deletions(-) create mode 100644 docs/cardano-open-standard-pr-summary.md create mode 100644 docs/cardano-open-standard-rationale.md create mode 100644 specs/extensions/cardano_masumi.md diff --git a/docs/cardano-open-standard-pr-summary.md b/docs/cardano-open-standard-pr-summary.md new file mode 100644 index 0000000000..bd40b2f0a2 --- /dev/null +++ b/docs/cardano-open-standard-pr-summary.md @@ -0,0 +1,98 @@ +# PR Draft — Cardano `exact` scheme: open-standard boundary correction + +**Branch:** `QBTLabs/cardano-open-standard-update` +**Target:** `x402-foundation/x402:main` (via Cardano Foundation review first) + +## Summary + +Revise the Cardano `exact` payment scheme so that its core compliance surface is facilitator-neutral, vendor-neutral, and implementation-agnostic. Move Masumi-specific semantics out of the core scheme and into a new `cardano-masumi` extension that follows the x402 v2 extensions architecture. + +Masumi support is preserved in full. Only its placement in the specification changes. + +## Motivation + +The Cardano scheme as merged in commit `4840c8dfb82e27e92a0b584391ad10be473c59bb` includes: + +- `assetTransferMethod: "default" | "masumi" | "script"` — an enum that names a specific third-party protocol as a peer of generic Cardano primitives. +- Masumi-specific fields inlined into `PaymentRequirements.extra` (`sellerVkey`, `paymentType: "Web3CardanoV1"`, `blockchainIdentifier`, `payByTime`, `submitResultTime`, `unlockTime`, `externalDisputeUnlockTime`, `agentIdentifier`, `inputHash`, `identifierFromPurchaser`). + +This couples the core Cardano x402 scheme to a single ecosystem implementation. The consequences are: + +- Every Cardano facilitator has to reason about Masumi-specific fields even when it does not support Masumi. +- Additional Cardano agent-payment or escrow protocols would need either their own enum value or second-class status. +- Future Masumi evolution forces a revision of a core scheme document. + +The x402 v2 specification already defines the `extensions` object (`PaymentRequired.extensions`, `PaymentPayload.extensions`, `SettlementResponse.extensions`) as the canonical place for optional, composable functionality. Other ecosystems in the repo (Algorand, Sui, SVM, Stellar, Aptos, Hedera) keep their core schemes focused on ledger primitives and use extensions or scheme-specific `extra` fields that are generic to the network. Cardano should follow the same pattern. + +## What changed + +### Modified + +- **`specs/schemes/exact/scheme_exact_cardano.md`** — rewritten so the core compliance surface describes only: + - Address-to-address payments (ADA via reserved `"lovelace"` asset, or Cardano native tokens). + - Script-parameterized payments (a generic Cardano primitive; Plutus scripts with applied parameters). + - Facilitator verification rules (network, recipient, amount, asset, nonce/replay, TTL) that are independent of any off-chain protocol. + - An explicit statement that ecosystem-specific semantics MUST be carried via the x402 v2 extensions model. + - The `assetTransferMethod` enum has been removed. `"default"` and `"script"` are now described via field-shape rather than as vendor-adjacent enum values. + +### Added + +- **`specs/extensions/cardano_masumi.md`** — new extension that defines: + - Where Masumi-specific fields live on the wire (`extensions["cardano-masumi"].info`). + - The schema, semantics, and echo behaviour for `paymentType`, `blockchainIdentifier`, `sellerVkey`, `agentIdentifier`, `identifierFromPurchaser`, `inputHash`, and the four Masumi timing windows. + - Responsibilities for clients, servers, and facilitators. + - Core-compatibility rules so a non-Masumi facilitator can still verify the underlying script-parameterized payment. + +- **`docs/cardano-open-standard-rationale.md`** — design note explaining the standards-architecture rationale. + +- **`docs/cardano-open-standard-pr-summary.md`** — this document. + +## What was moved from core into an extension + +| Element | Was | Now | +| -------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------- | +| `assetTransferMethod: "masumi"` | core enum value in `PaymentRequirements.extra` | removed; replaced by the `cardano-masumi` extension | +| `sellerVkey` | core `extra` field | `extensions["cardano-masumi"].info.sellerVkey` | +| `paymentType: "Web3CardanoV1"` | core `extra` field | `extensions["cardano-masumi"].info.paymentType` | +| `blockchainIdentifier` | core `extra` field | `extensions["cardano-masumi"].info.blockchainIdentifier` | +| `agentIdentifier` | core `extra` field | `extensions["cardano-masumi"].info.agentIdentifier` | +| `identifierFromPurchaser` | core `extra` field | `extensions["cardano-masumi"].info.identifierFromPurchaser` | +| `inputHash` | core `extra` field | `extensions["cardano-masumi"].info.inputHash` | +| `payByTime` / `submitResultTime` / `unlockTime` / `externalDisputeUnlockTime` | core `extra` fields | `extensions["cardano-masumi"].info.*` | + +## What stayed in core + +- Network identifiers `cardano:mainnet` / `cardano:preprod` / `cardano:preview`. +- `asset` convention `${policyId}.${assetNameHex}`, plus the reserved value `"lovelace"` for native ADA. +- `payTo` addresses (regular or script). +- `maxTimeoutSeconds`, TTL checks. +- `payload.transaction` (Base64-encoded signed CBOR) and `payload.nonce` (UTXO reference for replay prevention). +- Facilitator verification rules. +- Script-parameterized payments (`extra.scriptHash`, `extra.script`, `extra.parameters`) as a generic Cardano primitive. + +## How this preserves openness while still supporting Masumi + +- The core scheme makes no normative reference to Masumi. +- The extension makes Masumi fully expressible on the x402 wire, using the v2 extensions pattern that clients, servers, and facilitators already implement. +- A Masumi payment still flows through the core Cardano scheme as a script-parameterized payment, so a minimally conformant stack can verify the underlying transaction without understanding Masumi's off-chain semantics. +- Other ecosystem-level Cardano payment protocols (present or future) can publish their own extensions alongside `cardano-masumi` without any change to the core scheme. + +## Backward compatibility + +- Implementations that only supported the prior Masumi-in-core shape will need to either: + 1. Emit the same Masumi fields under `extensions["cardano-masumi"].info`, and keep `payTo`/`extra` pointed at the Masumi script, or + 2. Declare themselves as core-only Cardano `exact` implementations and drop the Masumi fields. +- The underlying on-chain transaction shape does not change. +- Facilitators that only implement the core scheme continue to verify payments correctly; they simply do not enforce Masumi-specific off-chain invariants (which they were never in a position to enforce anyway). + +## Review path + +1. Internal review by QBT Labs. +2. Cardano Foundation review (Fabian). +3. Upstream proposal to `x402-foundation/x402`. + +## Non-goals + +- This PR does not change Masumi's on-chain protocol or off-chain rules. +- This PR does not add or remove any chain, scheme, or facilitator implementation. +- This PR does not take a position on which Cardano agent-payment protocol implementations should be preferred. diff --git a/docs/cardano-open-standard-rationale.md b/docs/cardano-open-standard-rationale.md new file mode 100644 index 0000000000..c7207a68b7 --- /dev/null +++ b/docs/cardano-open-standard-rationale.md @@ -0,0 +1,67 @@ +# Cardano on x402: Open-Standard Boundary Rationale + +## TL;DR + +The core `exact` scheme on Cardano should define **only the minimum interoperable payment semantics** needed to make a Cardano x402 payment verifiable by any facilitator, on any Cardano network, by any implementation. Any semantics that are tied to a specific off-chain protocol, product, operator, or ecosystem implementation — including the Masumi escrow / agent-payment protocol — belong in an **x402 extension**, not in the core scheme. + +This is not a rejection of Masumi. Masumi can remain fully supported on Cardano x402 through the `cardano-masumi` extension defined in [`specs/extensions/cardano_masumi.md`](../specs/extensions/cardano_masumi.md). The goal of this note is to explain why drawing the standards boundary in this place yields a better open standard. + +## What changed + +1. The core Cardano `exact` scheme no longer declares an `assetTransferMethod` enum whose values name a specific third-party protocol. The previous enum `"default" | "masumi" | "script"` has been collapsed into two neutral, generic Cardano flows: + - address-to-address payments + - script-parameterized payments (a generic Cardano primitive; Plutus scripts with applied parameters) +2. The Masumi-specific fields (`sellerVkey`, `paymentType: "Web3CardanoV1"`, `blockchainIdentifier`, `payByTime`, `submitResultTime`, `unlockTime`, `externalDisputeUnlockTime`, `agentIdentifier`, `inputHash`, `identifierFromPurchaser`) are removed from the core scheme and relocated to the `cardano-masumi` extension. +3. The core scheme adds explicit language stating that it is facilitator-neutral, vendor-neutral, and implementation-agnostic, and that ecosystem-specific behaviour MUST be expressed through extensions. + +Full Masumi functionality is preserved. Only its **placement** in the specification changes. + +## Why core schemes should describe MUST-support behaviour only + +An x402 scheme document defines the minimum surface every conformant implementation must understand to interoperate. When vendor-specific semantics leak into that surface, three concrete harms follow: + +- **Every implementation pays the cost.** A facilitator that never intends to handle Masumi still has to parse, schema-validate, and ignore Masumi-specific fields, because they live in the core `extra` object. This inflates the conformance surface. +- **Naming a vendor in an enum privileges it.** `assetTransferMethod: "masumi"` is qualitatively different from `"default"` or `"script"`: it treats one ecosystem project as a peer of generic Cardano primitives. Future ecosystem projects would either have to negotiate their own enum value (turning the standard into a registry of vendors) or accept second-class status. +- **Standards boundaries calcify.** Once a vendor field is in the core, removing it later is a breaking change. Moving it to an extension while the scheme is young and adoption is still small is much cheaper than doing so later. + +The x402 v2 core specification already provides the correct mechanism for optional, composable functionality: the `extensions` object in `PaymentRequired`, `PaymentPayload`, and `SettlementResponse`. That mechanism is exactly where ecosystem-specific semantics should live. + +## Why script-parameterized payments belong in core + +Plutus scripts with applied parameters are a **generic Cardano primitive**, not a vendor feature. Any Cardano-native payment flow — Masumi's escrow, an alternative agent-payment protocol, a milestone-release protocol, a subscription escrow, a vault — ultimately expresses itself as a payment to a script address with some datum and redeemer. The core scheme therefore needs to describe "pay to a script address, with the client able to reconstruct that address from the declared script and parameters." It does not need to describe the off-chain semantics attached to any particular script. + +Keeping script-parameterized payments in core while pushing off-chain semantics into extensions is the standards-architecturally correct split: core describes what the ledger verifies, extensions describe what off-chain protocols verify. + +## Why this improves interoperability + +- **Multi-facilitator support.** A facilitator can claim conformance with the Cardano `exact` scheme without committing to any specific agent-payment protocol. New facilitators can enter the ecosystem without first implementing Masumi. +- **Multi-ecosystem support.** Other Cardano agent-payment or escrow protocols (present or future) can declare extensions alongside `cardano-masumi` without a spec change. The core scheme doesn't need to list them. +- **Cleaner client contracts.** A client library targeting the Cardano `exact` scheme has a small, stable contract: address-to-address and script-parameterized payments. Ecosystem-specific stacks are opt-in via extension libraries. +- **Clearer verification.** Facilitator verification rules depend only on the transaction and the declared `PaymentRequirements`. They do not depend on interpreting off-chain identifiers tied to a specific ecosystem. +- **Predictable forward evolution.** When Masumi itself evolves — a `Web3CardanoV2`, new windows, new identifiers — the core Cardano scheme does not need to version. The extension versions independently. + +## Why this is a standards-boundary correction, not anti-Masumi + +Masumi is one of the earliest and most substantial Cardano agent-payment deployments, and its on-chain and off-chain design are sophisticated. Shipping Cardano x402 support with Masumi as a reference integration is a good thing. The problem is strictly one of layering: + +- Masumi-specific fields currently sit where every Cardano x402 implementation has to reason about them. +- The x402 v2 extensions model exists precisely for these kinds of fields. +- Moving the fields one layer up costs Masumi nothing in functionality and gains the standard everything in neutrality. + +Said differently: the revised placement improves Masumi's position in the ecosystem, because it gives Masumi a clean, named, versioned extension it can evolve on its own cadence, instead of being coupled to the cadence of the Cardano core scheme. + +## Design principles applied + +The revised Cardano `exact` scheme follows three principles that the broader x402 spec already applies to other chains: + +1. **If it's a ledger primitive, it can live in core.** Address transfers, native-asset references, Plutus script parameterization, TTL, UTXO-based replay prevention. +2. **If it's an off-chain protocol or product-specific behaviour, it belongs in an extension.** Escrow timing windows, dispute windows, vendor-specific identifiers, agent/seller identities, vendor-specific datum shapes. +3. **The core scheme MUST NOT name a specific vendor, operator, or ecosystem implementation as a first-class value or field.** Extensions are the correct place for those names. + +These principles are neither novel nor controversial. They are applied consistently across the `eip155`, `svm`, `sui`, `aptos`, `algorand`, `stellar`, and `hedera` schemes already in the repository. Applying them to Cardano brings Cardano in line with the rest of the standard. + +## Open questions (non-blocking) + +- **Optional receipt-style acknowledgement.** Masumi has a natural notion of commitment to off-chain inputs (`inputHash`) and delivery windows. The `offer-receipt` extension in the x402 repo may be a good fit for some of these; future work can explore whether a Cardano-flavoured offer/receipt is useful. +- **Alternative Cardano agent-payment protocols.** If other teams propose agent-payment extensions on Cardano, the shape of `cardano-masumi` can serve as a template for common field placement (timing windows, agent identifiers, commitments). +- **ADA vs. native-asset normalisation.** The revised core scheme reserves the string `"lovelace"` for native ADA payments, which is a straightforward convention; implementers should confirm this aligns with existing Cardano SDK idioms in the repository. diff --git a/specs/extensions/cardano_masumi.md b/specs/extensions/cardano_masumi.md new file mode 100644 index 0000000000..3fa537cdc7 --- /dev/null +++ b/specs/extensions/cardano_masumi.md @@ -0,0 +1,216 @@ +# Extension: `cardano-masumi` + +## Status + +**Draft — v0.1**. This extension is specified as an optional, composable addition to the Cardano `exact` scheme. Its behavioral requirements are stable; its wire shape MAY evolve to align with future updates to the x402 extensions architecture. + +## Summary + +The `cardano-masumi` extension adds escrow-based, agent-oriented payment semantics on top of the core Cardano `exact` scheme defined in [`specs/schemes/exact/scheme_exact_cardano.md`](../schemes/exact/scheme_exact_cardano.md). It is the canonical way to carry Masumi-specific fields — seller verification keys, purchaser/agent identifiers, input-hash commitments, and the escrow timing windows (`payByTime`, `submitResultTime`, `unlockTime`, `externalDisputeUnlockTime`) — across an x402 flow without embedding them in the core scheme. + +Resource servers that integrate with Masumi MUST declare their Masumi intent via this extension. Resource servers, clients, and facilitators that do not implement this extension MUST remain able to process the underlying Cardano `exact` payment as a generic script-parameterized payment (see §Core Compatibility below). + +This placement preserves three properties: + +1. The core Cardano scheme remains implementation-agnostic and vendor-neutral. +2. Masumi support continues to be fully expressible and unambiguous. +3. Multiple agent-payment protocols can coexist on Cardano without each needing a privileged slot in the core scheme. + +## Relationship to the Core Cardano Scheme + +The core Cardano `exact` scheme supports payments to script addresses via script-parameterized payments. A Masumi payment is, on-chain, a script-parameterized payment to the Masumi smart contract address, with a specific datum and redeemer shape. + +All core verification rules (network, recipient, amount, asset, nonce/replay, TTL) from the Cardano scheme continue to apply. This extension layers the off-chain Masumi semantics on top of those rules. + +## `PaymentRequired` + +A resource server advertises Masumi support by including the `cardano-masumi` extension in the `extensions` object of the **402 Payment Required** response, alongside a Cardano `exact` `accepts[]` entry that points at the Masumi script address. + +```json +{ + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", // Masumi script address for this payment + "maxTimeoutSeconds": 600, + "extra": { + "scriptHash": "masumi_script_hash", + "script": { + "type": "plutusV3", + "code": "" + }, + "parameters": { + // generic script parameters, as defined by the core Cardano scheme + } + } + } + ], + "extensions": { + "cardano-masumi": { + "info": { + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "sellerVkey": "sdasdqweqwewewewqe", + "agentIdentifier": "agent_identifier", + "identifierFromPurchaser": "aabbaabb11221122aabb", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260" + }, + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "paymentType": { "type": "string" }, + "blockchainIdentifier": { "type": "string" }, + "sellerVkey": { "type": "string" }, + "agentIdentifier": { "type": "string" }, + "identifierFromPurchaser": { "type": "string" }, + "inputHash": { "type": "string" }, + "payByTime": { "type": "string" }, + "submitResultTime": { "type": "string" }, + "unlockTime": { "type": "string" }, + "externalDisputeUnlockTime": { "type": "string" } + }, + "required": [ + "paymentType", + "blockchainIdentifier", + "sellerVkey", + "agentIdentifier", + "identifierFromPurchaser", + "inputHash", + "payByTime", + "submitResultTime", + "unlockTime", + "externalDisputeUnlockTime" + ] + } + } + } +} +``` + +## `PaymentPayload` + +A client that recognises the `cardano-masumi` extension echoes it in the `extensions` field of the `PaymentPayload`, per the v2 rule that the client MUST include at least the info it received: + +```json +{ + "extensions": { + "cardano-masumi": { + "info": { + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "sellerVkey": "sdasdqweqwewewewqe", + "agentIdentifier": "agent_identifier", + "identifierFromPurchaser": "aabbaabb11221122aabb", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260" + }, + "schema": { /* same schema as above */ } + } + } +} +``` + +A client MAY add extension-defined fields that the server did not include (per the v2 rule that the client may append additional info but cannot delete or overwrite existing info). A client MUST NOT silently drop any field received from the server. + +## Field Semantics + +All fields are Masumi-specific and have no meaning in the core Cardano `exact` scheme. + +| Field | Type | Required | Description | +| ---------------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `paymentType` | string | Yes | Masumi payment-protocol tag (e.g., `"Web3CardanoV1"`). Identifies the Masumi variant in use. | +| `blockchainIdentifier` | string | Yes | Masumi blockchain identifier for the logical payment stream. | +| `sellerVkey` | string | Yes | Verification key of the seller in the Masumi protocol. | +| `agentIdentifier` | string | Yes | Masumi agent identifier for the service. | +| `identifierFromPurchaser` | string | Yes | Identifier supplied by the purchaser for the interaction. | +| `inputHash` | string | Yes | Hash commitment over the purchaser's inputs to the agent, as defined by Masumi. | +| `payByTime` | string | Yes | Unix timestamp (seconds, string-encoded) by which the purchaser must pay. | +| `submitResultTime` | string | Yes | Unix timestamp by which the seller must submit a result. | +| `unlockTime` | string | Yes | Unix timestamp at which funds become withdrawable by the seller absent dispute. | +| `externalDisputeUnlockTime` | string | Yes | Unix timestamp at which an external dispute path unlocks, as defined by Masumi. | + +The exact semantics of these fields are governed by the Masumi protocol specification. This extension records their on-the-wire placement and requires echo behaviour; it does not re-specify Masumi's off-chain rules. + +## Responsibilities + +**Resource server:** +- MUST place Masumi-specific fields in `extensions["cardano-masumi"].info`. +- MUST NOT place Masumi-specific fields in `PaymentRequirements.extra` or the core `payload` object. +- SHOULD populate `payTo` with the Masumi script address and `extra` with the script reference so that clients unaware of the Masumi extension can still construct a script-parameterized payment following the core scheme. + +**Client:** +- If the client recognises the `cardano-masumi` extension, it SHOULD use the Masumi-specific fields to construct a Masumi-compliant datum and redeemer. +- The client MUST echo the extension info back in `PaymentPayload.extensions["cardano-masumi"].info` unchanged. +- If the client does not recognise the extension, it MAY fall back to treating the payment as a generic script-parameterized Cardano payment, provided the server has also supplied `extra.script` / `extra.scriptHash` as required by the core scheme. Whether Masumi will ultimately accept such a payment is a Masumi-protocol matter, not an x402 matter. + +**Facilitator:** +- A facilitator that does not implement `cardano-masumi` MUST still enforce the core Cardano verification rules (network, recipient, amount, asset, nonce, TTL). +- A facilitator that does implement `cardano-masumi` MAY additionally enforce Masumi-specific checks (for example, verifying the datum structure, time-window consistency, or seller verification key binding). Such checks MUST NOT be used to reject payments from servers that only declare the core scheme. + +## Core Compatibility + +This extension is designed so that a minimally conformant x402 stack — one that implements only the core Cardano `exact` scheme — can still process a Masumi payment as a generic script-parameterized payment: + +- Recipient, amount, asset, nonce, and TTL checks are unchanged. +- The Masumi script address is visible in `payTo`. +- The Masumi script (or its hash) is visible in `extra`. +- The Masumi-specific fields are cleanly isolated under `extensions["cardano-masumi"]` and can be ignored without breaking verification. + +A non-Masumi stack cannot, of course, reproduce Masumi's off-chain invariants (escrow windows, dispute rights, agent accounting). That is precisely what makes these fields extension-level rather than core-level. + +## Settlement Response + +On success, the `PAYMENT-RESPONSE` payload MAY include extension-specific information under `extensions["cardano-masumi"]`: + +```json +{ + "success": true, + "network": "cardano:mainnet", + "transaction": "2f9a7b3c...", + "extensions": { + "status": "confirmed", + "cardano-masumi": { + "info": { + "blockchainIdentifier": "blockchain_identifier" + } + } + } +} +``` + +This extension does not currently specify additional normative fields in the settlement response; future versions MAY add them. + +## Security Considerations + +- This extension MUST NOT be used to weaken the core Cardano verification rules. In particular, possession of a valid Masumi datum does not substitute for the nonce/replay, TTL, or amount/asset checks. +- Implementers SHOULD treat Masumi-specific fields as untrusted off-chain assertions until validated against the Masumi protocol by an implementation that understands it. +- Facilitators that accept Masumi payments SHOULD clearly document which Masumi invariants they enforce and which they delegate to the resource server or the seller. + +## Privacy Considerations + +- Masumi identifiers (`agentIdentifier`, `identifierFromPurchaser`, `sellerVkey`) are identifying or near-identifying on an x402 wire. Implementations SHOULD treat them with the same care as other pseudonymous identifiers. +- Servers SHOULD NOT include Masumi extension fields in `PaymentRequired` responses for resources that do not actually route through Masumi. + +## Version History + +| Version | Date | Changes | Author | +| ------- | ---------- | ----------------------------------------------------------------------------- | -------- | +| 0.1 | 2026-04-23 | Initial draft; moves Masumi-specific fields out of the core Cardano scheme. | QBT Labs | diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index 77ca60e997..e36b2fc831 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -2,15 +2,17 @@ ## Summary -This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. +This document specifies the `exact` payment scheme for the x402 protocol on Cardano. The scheme facilitates payments of ADA and Cardano Native Tokens over the Cardano ledger, using signed transactions produced by the client and verified/settled by a resource server or facilitator. -It offers different assetTransferMethods to do x402 interactions: +This scheme is intentionally defined as an **implementation-agnostic, facilitator-neutral, vendor-neutral** core. It does not name, require, or privilege any specific third-party protocol, operator, or ecosystem implementation. Optional ecosystem-specific semantics (for example, escrow-based agent payment protocols, dispute windows, off-chain identifiers, or reputation systems) MUST be expressed through the x402 v2 **extensions** model, not through the core scheme. -1. Doing **Address-To-Address** Payments, similar to the regular x402 specifications on other chains. +The core scheme supports: -2. Using the **Masumi Smart Protocol**, which offers additional refund mechanics & decision logging mechanisms in a decentralised way. +1. **Address-to-address payments** — the canonical Cardano x402 flow, sending ADA or a native asset to a payment address specified by the resource server. +2. **Script-parameterized payments** — a generic Cardano-native flow in which `payTo` is a script address and `extra` carries the information required for a client to reconstruct or validate that script address during transaction building. + +Any additional flow that embeds the semantics of a specific external protocol (for example, Masumi) MUST be declared as an x402 extension; see [`specs/extensions/cardano_masumi.md`](../../extensions/cardano_masumi.md) for the Masumi extension. -3. Performing payments to scripts using parameters that can be applied to scripts while transaction building. ## Protocol Flow ```mermaid @@ -61,70 +63,50 @@ sequenceDiagram Note left of Server: Returns requested resource
with transaction confirmation:
- transaction: "2f9a7b3c..."
- network: "cardano:mainnet"
- success: true ``` -The protocol flow for `exact` on Cardano is client-driven. +The protocol flow for `exact` on Cardano is client-driven. -1. **Client** makes an HTTP request to a **Resource Server**. +1. **Client** makes an HTTP request to a **Resource Server**. -2. **Resource Server** responds with a `402 Payment Required` status, detailing the payment information: - - If using the Masumi Protocol, the `extra` field will contain additional information required to build a Masumi Smart Contract interaction. - - If using Address-To-Address payments, the `payTo` field will contain the address to which the payment must be sent. - - If using Script payments, the `extra` field will contain parameters to be applied to scripts during transaction building. +2. **Resource Server** responds with a `402 Payment Required` status, detailing the payment information: + - For address-to-address payments, `payTo` is the address to which the payment MUST be sent; `extra` MAY be empty or carry facilitator-neutral hints. + - For script-parameterized payments, `payTo` is the script address and `extra` carries the script reference (and any applied parameters) required for the client to build the transaction. -3. **Client** constructs the transaction body, signs it, and returns it to the **Resource Server** via the `PAYMENT-SIGNATURE` header. +3. **Client** constructs the transaction body, signs it, and returns it to the **Resource Server** via the `PAYMENT-SIGNATURE` header. -4. **Resource Server** verifies the transaction is valid: - - **Local verification**: The server validates the transaction structure, amount, and recipient address directly. - - **Remote verification**: The server forwards the `PAYMENT-SIGNATURE` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. +4. **Resource Server** verifies the transaction is valid: + - **Local verification**: The server validates the transaction structure, amount, and recipient directly. + - **Remote verification**: The server forwards the `PAYMENT-SIGNATURE` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint. -5. After successful verification, the signed transaction is submitted to the Cardano blockchain: - - **Server submission**: The **Resource Server** submits the transaction directly to the Cardano blockchain. - - **Facilitator submission**: The **Resource Server** sends the transaction to the **Facilitator's** `/settle` endpoint, which then submits it to the blockchain. +5. After successful verification, the signed transaction is submitted to the Cardano blockchain: + - **Server submission**: The **Resource Server** submits the transaction directly. + - **Facilitator submission**: The **Resource Server** sends the transaction to the **Facilitator's** `/settle` endpoint, which submits it to the blockchain. -6. The Cardano blockchain includes the transaction in the mempool or a block and returns the transaction hash and confirmation status. +6. The Cardano blockchain includes the transaction in the mempool or a block and returns the transaction hash and confirmation status. -7. **Resource Server** receives the transaction hash and status: - - If submitted via the **Facilitator**, it receives a settlement response containing the `txHash` and `status`. - - Cardano uses Ouroboros Praos, which has probabilistic finality. A transaction that appears in the mempool or even in a recent block can be rolled back. Granting access upon mempool inclusion (`status: "mempool"`) is therefore **strongly discouraged** and SHOULD NOT be used for any resource with real economic value. Servers that choose to accept mempool status MUST document this risk and accept full liability for rolled-back transactions. +7. **Resource Server** receives the transaction hash and status. + - Cardano uses Ouroboros Praos, which has probabilistic finality. A transaction that appears in the mempool or in a recent block can be rolled back. Granting access upon mempool inclusion (`status: "mempool"`) is therefore **strongly discouraged** and SHOULD NOT be used for any resource with real economic value. Servers that choose to accept mempool status MUST document this risk and accept full liability for rolled-back transactions. -8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with an `PAYMENT-RESPONSE` header containing: - - `txHash`: The Cardano transaction hash - - `network`: The Cardano network (e.g., `cardano:mainnet`) - - `status`: The transaction status (e.g., `confirmed` or `mempool`) +8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with a `PAYMENT-RESPONSE` header containing: + - `transaction`: The Cardano transaction hash + - `network`: The Cardano network (e.g., `cardano:mainnet`) + - `status`: The transaction status (e.g., `confirmed` or `mempool`) -### `PaymentRequirementsResponse` +## Core Compliance Surface -#### Default Schema +An implementation claims conformance with the Cardano `exact` scheme by supporting the two core flows defined in this document (address-to-address and script-parameterized) and enforcing the verification rules in §Facilitator Verification Rules. -When the Resource Server responds with a `402 Payment Required`, the body of the response contains the payment requirements in the following schema: +The core scheme: -```js -{ - "x402Version": 2, - "error": "PAYMENT-SIGNATURE header is required", - "resource": { - "url": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json" - }, - "accepts": [ - { - "scheme": "exact", - "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "amount": "10000", // 1 USDM = 1000000000 - "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' - "payTo": "addr1...", - "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed - "extra": { - // In case of default address-to-address payments, this may be empty or contain additional metadata - } - } - ] -} -``` +- MUST NOT name, require, or privilege any specific third-party protocol, facilitator operator, product, or ecosystem implementation. +- MUST NOT embed ecosystem-specific fields (off-chain identifiers, agent-protocol fields, escrow timing windows, dispute windows, reputation identifiers, or similar) into the core `PaymentRequirements.extra` or the `payload` object. +- SHOULD treat any unknown fields in `extra` as pass-through information that does not affect core verification. +- SHOULD expose ecosystem-specific behavior through the x402 v2 extensions model (see §Extensions below). + +## `PaymentRequirementsResponse` -#### Masumi assetTransferMethod Schema +### Core Schema (Address-to-Address) -When the Resource Server requires payment via the Masumi Smart Protocol, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for Masumi interactions. +When the Resource Server responds with a `402 Payment Required`, the body contains the payment requirements: ```js { @@ -139,33 +121,27 @@ When the Resource Server requires payment via the Masumi Smart Protocol, the `ex { "scheme": "exact", "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "amount": "10000", // 1 USDM = 1000000000 - "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' + "amount": "10000", // atomic units of the asset + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetNameHex}; for ADA, use the reserved value "lovelace" "payTo": "addr1...", - "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "maxTimeoutSeconds": 600, "extra": { - "assetTransferMethod": "masumi", // optional, can be "default" | "masumi" | "script" - // If the masumi assetTransferMethod is used, make sure to include all masumi related fields - "identifierFromPurchaser": "aabbaabb11221122aabb", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - // Additional fields for masumi or script assetTransferMethods can be added here + // MAY be empty. MAY contain facilitator-neutral hints. + // MUST NOT embed fields tied to a specific external protocol or operator. } } ] } ``` -#### Script assetTransferMethod Schema +**Notes:** + +- The `asset` field follows the Cardano convention `${policyId}.${assetNameHex}`. For native ADA payments, implementations MUST use the reserved value `"lovelace"`. +- The `maxTimeoutSeconds` value SHOULD account for Cardano's slot/block cadence; values meaningfully below a single-block round trip SHOULD be avoided. -When the Resource Server requires payment to a script, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for script interactions. +### Core Schema (Script-Parameterized Payment) + +When the Resource Server requires payment to a script address, `payTo` is the script address and `extra` carries the information required to build and verify the payment against that script. Script-parameterized payments are a generic Cardano primitive and do not imply any specific off-chain protocol. ```js { @@ -179,78 +155,64 @@ When the Resource Server requires payment to a script, the `extra` field in the "accepts": [ { "scheme": "exact", - "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets - "amount": "10000", // 1 USDM = 1000000000 - "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' - "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the PAYMENT-SIGNATURE header, so that the server can reconstruct the script address and verify the payment) - "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", // script address; MUST match the address derived from `extra.script` (plus any applied `extra.parameters`) after parameterization + "maxTimeoutSeconds": 600, "extra": { - "assetTransferMethod": "script", // optional, can be "default" | "masumi" | "script" - // If the script assetTransferMethod is used, make sure to include all script related fields - "scriptHash": "script_hash_here", // If the script is already on-chain, provide its hash and the client can resolve the full script + "scriptHash": "script_hash_here", // OPTIONAL; if the script is already on-chain, its hash is sufficient for the client to resolve the full script "script": { - // Optional full script object if not on-chain yet - "type": "plutusV3", - "code": "", + // OPTIONAL; provided when the script is not yet on-chain or when the server wishes to attach the script body directly + "type": "plutusV2" | "plutusV3" | "native", + "code": "" }, "parameters": { - "param1": {"value": "Hello World", "type": "bytes"}, - "param2": {"value": 42, "type": "bigint"} - // Script-specific parameters required for transaction building + // OPTIONAL; script-specific parameters to be applied to a parameterised script during transaction building + "param1": { "value": "Hello World", "type": "bytes" }, + "param2": { "value": 42, "type": "bigint" } } - // Additional fields for script assetTransferMethods can be added here } } ] } ``` -### `PAYMENT-SIGNATURE` Header Payload +**Normative rules:** -The PAYMENT-SIGNATURE header is base64-encoded and sent in the client's request to the resource server when paying for a resource. +- Servers MUST include enough information in `extra` for a conforming client to derive the script address declared in `payTo`. A bare `scriptHash` is sufficient when the script is already on-chain; otherwise the full `script` body MUST be provided. +- If `parameters` are supplied, the client MUST apply them deterministically when constructing the transaction, and the derived address MUST equal `payTo`. +- A facilitator performing remote verification MUST validate that the transaction pays the declared `asset` and `amount` to `payTo`; it is NOT required to re-execute the script or interpret ecosystem-level semantics attached to it. -The payload field of the PAYMENT-SIGNATURE header must contain the following fields: +### Extensions (Ecosystem-Specific Semantics) -transaction: The signed Cardano transaction (Base64 encoded). -Example: +Any payment flow that depends on the semantics of a specific off-chain protocol (for example, escrow accounts, dispute windows, agent identifiers, seller verification keys, or inputs-hash commitments used by a particular agentic-payment framework) MUST be expressed as an x402 extension under the `extensions` field of the `PaymentRequired` and `PaymentPayload` objects. -```js -{ - "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" -} -``` +Such extensions MUST NOT require changes to the fields specified in this document. Facilitators that do not implement a given extension MUST remain capable of verifying the core scheme, treating the extension as advisory. + +For the Masumi escrow/agent-payment extension, see [`specs/extensions/cardano_masumi.md`](../../extensions/cardano_masumi.md). -Full PAYMENT-SIGNATURE header: +## `PAYMENT-SIGNATURE` Header Payload + +The `PAYMENT-SIGNATURE` header is base64-encoded and sent in the client's request to the resource server when paying for a resource. + +The `payload` field of the `PAYMENT-SIGNATURE` header MUST contain: + +| Field | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------------------------------------------------------------- | +| `transaction` | string | Yes | The fully signed Cardano transaction, Base64-encoded (CBOR-serialised). | +| `nonce` | string | Yes | A UTXO reference of the form `${txHash}#${index}` consumed as an input, used for replay prevention. | + +Example `payload`: ```js { - "x402Version": 2, - "resource": { - "url": "https://api.example.com/premium-data", - "description": "Access to premium market data", - "mimeType": "application/json" - }, - "accepted": { - "scheme": "exact", - "network": "cardano:mainnet", - "amount": "10000", - "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", - "payTo": "addr1...", - "maxTimeoutSeconds": 600, - "extra": { - // In case of default address-to-address payments, this may be empty or contain additional metadata - } - }, - "payload": { - "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" - "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" - } + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=", + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" } ``` -Expanded Schema based on assetTransferMethods: - -#### Masumi assetTransferMethod +Full `PAYMENT-SIGNATURE` header (address-to-address): ```js { @@ -267,28 +229,16 @@ Expanded Schema based on assetTransferMethods: "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", "payTo": "addr1...", "maxTimeoutSeconds": 600, - "extra": { - "assetTransferMethod": "masumi", - "identifierFromPurchaser": "aabbaabb11221122aabb", - "sellerVkey": "sdasdqweqwewewewqe", - "paymentType": "Web3CardanoV1", - "blockchainIdentifier": "blockchain_identifier", - "payByTime": "1713626260", - "submitResultTime": "1713636260", - "unlockTime": "1713636260", - "externalDisputeUnlockTime": "1713636260", - "agentIdentifier": "agent_identifier", - "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" - } + "extra": {} }, "payload": { - "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "transaction": "AAAIAQDi1Hwj...AAAAAAA=", "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" } } ``` -#### Script assetTransferMethod +Full `PAYMENT-SIGNATURE` header (script-parameterized): ```js { @@ -305,47 +255,46 @@ Expanded Schema based on assetTransferMethods: "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", "payTo": "addr1...", // script address "maxTimeoutSeconds": 600, - "extra": { - "assetTransferMethod": "script", - "scriptHash": "script_hash_here", - "script": { - "type": "plutusV3", - "code": "" - }, - "parameters": { - "param1": {"value": "Hello World", "type": "bytes"}, - "param2": {"value": 42, "type": "bigint"} - } + "extra": { + "scriptHash": "script_hash_here", + "script": { + "type": "plutusV3", + "code": "" + }, + "parameters": { + "param1": { "value": "Hello World", "type": "bytes" }, + "param2": { "value": 42, "type": "bigint" } } + } }, "payload": { - "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "transaction": "AAAIAQDi1Hwj...AAAAAAA=", "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" } } ``` -### Facilitator Verification Rules +## Facilitator Verification Rules -A facilitator MUST enforce all of the following rules before accepting a payment as valid. Any failure MUST result in a rejection. +A facilitator MUST enforce all of the following rules before accepting a payment as valid. Any failure MUST result in a rejection. These rules are intentionally facilitator-neutral: they depend only on the signed Cardano transaction, the declared `PaymentRequirements`, and the current on-chain UTXO set. -1. **Network Validation**: The transaction MUST be destined for the correct Cardano network (mainnet, preprod, or preview) as declared in `PaymentRequirements.network`. The facilitator MUST reject transactions built for a different network. +1. **Network Validation**: The transaction MUST be destined for the Cardano network declared in `PaymentRequirements.network` (`cardano:mainnet`, `cardano:preprod`, or `cardano:preview`). Transactions built for a different network MUST be rejected. -2. **Recipient Verification**: At least one transaction output MUST send funds to the address specified in `PaymentRequirements.payTo`. The facilitator MUST NOT accept transactions where the recipient address differs from `payTo`. +2. **Recipient Verification**: At least one transaction output MUST pay funds to the address specified in `PaymentRequirements.payTo`. The facilitator MUST NOT accept transactions where no output targets `payTo`. When `payTo` is a script address declared via script-parameterized payment, the facilitator MAY verify that the declared script (with applied `parameters`) hashes to the same address, but MUST NOT be required to re-execute the script. -3. **Amount Verification**: The output sent to `payTo` MUST contain a value greater than or equal to the amount declared in `PaymentRequirements.amount` for the asset identified by `PaymentRequirements.asset`. The facilitator MUST verify both the policy ID and the asset name match exactly. +3. **Amount Verification**: The aggregate value sent to `payTo` for the declared `asset` MUST be greater than or equal to `PaymentRequirements.amount`. -4. **Asset Verification**: The asset unit in the transaction MUST exactly match `PaymentRequirements.asset` (format: `${policyId}.${assetNameHex}`). The facilitator MUST NOT accept a different asset, even one of equal market value. +4. **Asset Verification**: The asset unit in the transaction MUST exactly match `PaymentRequirements.asset`. For native tokens, both the policy ID and the asset name MUST match. For ADA, the reserved value `"lovelace"` MUST be used and the lovelace output MUST satisfy `amount`. The facilitator MUST NOT accept a different asset, even one of equal market value. -5. **Nonce / Replay Prevention**: The `payload.nonce` MUST be a valid UTXO reference (`txHash#index`) that is included as an input in the transaction. The facilitator MUST verify that this UTXO exists in the current on-chain UTXO set and has not been spent. This ensures uniqueness and prevents replay attacks. +5. **Nonce / Replay Prevention**: `payload.nonce` MUST be a valid UTXO reference (`txHash#index`) that is consumed as an input of the transaction. The facilitator MUST verify that this UTXO exists in the current on-chain UTXO set and has not been spent. This ensures uniqueness and prevents replay. -6. **TTL / Expiry Check**: The transaction's TTL (time-to-live slot) MUST not have already passed at the time of verification. The facilitator MUST reject transactions whose TTL is in the past. The TTL SHOULD be consistent with `PaymentRequirements.maxTimeoutSeconds`. +6. **TTL / Expiry Check**: The transaction's TTL (time-to-live slot) MUST NOT have already passed at the time of verification. The facilitator MUST reject transactions whose TTL is in the past. The TTL SHOULD be consistent with `PaymentRequirements.maxTimeoutSeconds`. -### `PAYMENT-RESPONSE` Header Payload +Facilitators MAY enforce additional checks introduced by extensions when they implement those extensions, but extension-specific checks MUST NOT be treated as core conformance requirements. -The `PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. +## `PAYMENT-RESPONSE` Header Payload -Once decoded, the `PAYMENT-RESPONSE` is a JSON string with the following properties: +The `PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. Schema: @@ -353,11 +302,32 @@ Schema: { "success": true, // true or false "network": "cardano:mainnet", - "transaction": "2f9a7b3c..." // Transaction hash of the payment if successful + "transaction": "2f9a7b3c...", // Cardano transaction hash if successful "extensions": { - "status": "confirmed", // "confirmed" is the recommended value; "mempool" is permitted but strongly discouraged — see settlement warning above - } - // Optional error field in case of failure - "errorReason": "Utxo not found in utxo set" // Example error reason + "status": "confirmed" // "confirmed" is the recommended value; "mempool" is permitted but strongly discouraged — see settlement warning above + }, + "errorReason": "Utxo not found in utxo set" // OPTIONAL; present only on failure } ``` + +## Extensions + +Cardano-specific ecosystem semantics that go beyond the rules above MUST be carried through the x402 v2 extensions model, following the pattern: + +``` +extensions[extensionId].info // extension-specific data +extensions[extensionId].schema // JSON Schema for `info` +``` + +Known Cardano-related extensions (non-exhaustive): + +- [`cardano-masumi`](../../extensions/cardano_masumi.md) — Masumi escrow/agent-payment semantics, including seller verification keys, purchaser/agent identifiers, escrow timing windows, dispute windows, and input-hash commitments. + +Additional Cardano-related extensions MAY be proposed to cover other ecosystem-level behaviors (e.g., alternative escrow protocols, metadata-label commitments, chain-of-custody attestations). They MUST follow the extensions architecture defined in the x402 v2 core specification and MUST NOT require changes to this document. + +## Version History + +| Version | Date | Changes | Author | +| ------- | ---------- | ----------------------------------------------------------------------------------------------- | --------- | +| 0.2 | 2026-04-23 | Remove vendor-specific `assetTransferMethod: "masumi"` and Masumi-named fields from the core scheme; move Masumi semantics to `specs/extensions/cardano_masumi.md`. Clarify that the core scheme is facilitator- and vendor-neutral. Add reserved `"lovelace"` value for native ADA `asset`. | QBT Labs | +| 0.1 | 2026-02-06 | Initial Cardano `exact` scheme merged upstream. | Masumi | From caf790b833f73753a547cabc4bc12f7ef77e3c44 Mon Sep 17 00:00:00 2001 From: "a.dacapo21" Date: Thu, 23 Apr 2026 15:35:20 +0300 Subject: [PATCH 14/16] fix(cardano): correct mempool-vs-block-inclusion wording in exact scheme the prior wording said cardano "includes the transaction in the mempool or a block" at submission time, and the mermaid notes said the same. submission only returns a synchronous mempool-acceptance ack; block inclusion is a separate, later, probabilistic event. this contradicted the spec's own warning that mempool status SHOULD NOT be treated as final. clarify both mermaid notes, the return-arrow label, and step 6. --- specs/schemes/exact/scheme_exact_cardano.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md index e36b2fc831..54453ea25d 100644 --- a/specs/schemes/exact/scheme_exact_cardano.md +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -46,13 +46,13 @@ sequenceDiagram %% Server Verification alt Server Submission Server->>Cardano: 6a. Submit signed transaction - Note right of Cardano: Transaction included in mempool or block - Cardano-->>Server: 6b. Transaction hash + confirmation + Note right of Cardano: Node accepts tx into mempool;
block inclusion is asynchronous + Cardano-->>Server: 6b. Transaction hash (submission ack) else Remote Submission (via Facilitator) Server->>Facilitator: 6a. POST /settle
(Payment details) Facilitator->>Cardano: 6b. Submit signed transaction - Note right of Cardano: Transaction included in mempool or block - Cardano-->>Facilitator: 6c. Transaction hash + confirmation + Note right of Cardano: Node accepts tx into mempool;
block inclusion is asynchronous + Cardano-->>Facilitator: 6c. Transaction hash (submission ack) Facilitator->>Server: 6d. Settlement Response
(txHash, status) end @@ -81,10 +81,10 @@ The protocol flow for `exact` on Cardano is client-driven. - **Server submission**: The **Resource Server** submits the transaction directly. - **Facilitator submission**: The **Resource Server** sends the transaction to the **Facilitator's** `/settle` endpoint, which submits it to the blockchain. -6. The Cardano blockchain includes the transaction in the mempool or a block and returns the transaction hash and confirmation status. +6. The Cardano node validates the submitted transaction and, if accepted, places it in its mempool and returns the transaction hash synchronously. Block inclusion — and any subsequent probabilistic confirmation — happens asynchronously and is observed later via the settlement `status` field. 7. **Resource Server** receives the transaction hash and status. - - Cardano uses Ouroboros Praos, which has probabilistic finality. A transaction that appears in the mempool or in a recent block can be rolled back. Granting access upon mempool inclusion (`status: "mempool"`) is therefore **strongly discouraged** and SHOULD NOT be used for any resource with real economic value. Servers that choose to accept mempool status MUST document this risk and accept full liability for rolled-back transactions. + - Cardano uses Ouroboros Praos, which has probabilistic finality. A transaction that has only been accepted into the mempool, or that appears in a recent block, can still be rolled back. Granting access on the basis of mempool acceptance alone (`status: "mempool"`) is therefore **strongly discouraged** and SHOULD NOT be used for any resource with real economic value. Servers that choose to accept mempool status MUST document this risk and accept full liability for rolled-back transactions. 8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with a `PAYMENT-RESPONSE` header containing: - `transaction`: The Cardano transaction hash From d8f1d6d49aeb9a285b3828c1334dca475beaa174 Mon Sep 17 00:00:00 2001 From: "a.dacapo21" Date: Fri, 24 Apr 2026 10:44:47 +0300 Subject: [PATCH 15/16] docs(cardano): drop supplementary rationale docs from PR tree per PR review feedback: these docs were meant as scaffolding for review, not as files to flow upstream into x402-foundation. remove them from the repo; the rationale and summary content already lives in the PR description on github. --- docs/cardano-open-standard-pr-summary.md | 98 ------------------------ docs/cardano-open-standard-rationale.md | 67 ---------------- 2 files changed, 165 deletions(-) delete mode 100644 docs/cardano-open-standard-pr-summary.md delete mode 100644 docs/cardano-open-standard-rationale.md diff --git a/docs/cardano-open-standard-pr-summary.md b/docs/cardano-open-standard-pr-summary.md deleted file mode 100644 index bd40b2f0a2..0000000000 --- a/docs/cardano-open-standard-pr-summary.md +++ /dev/null @@ -1,98 +0,0 @@ -# PR Draft — Cardano `exact` scheme: open-standard boundary correction - -**Branch:** `QBTLabs/cardano-open-standard-update` -**Target:** `x402-foundation/x402:main` (via Cardano Foundation review first) - -## Summary - -Revise the Cardano `exact` payment scheme so that its core compliance surface is facilitator-neutral, vendor-neutral, and implementation-agnostic. Move Masumi-specific semantics out of the core scheme and into a new `cardano-masumi` extension that follows the x402 v2 extensions architecture. - -Masumi support is preserved in full. Only its placement in the specification changes. - -## Motivation - -The Cardano scheme as merged in commit `4840c8dfb82e27e92a0b584391ad10be473c59bb` includes: - -- `assetTransferMethod: "default" | "masumi" | "script"` — an enum that names a specific third-party protocol as a peer of generic Cardano primitives. -- Masumi-specific fields inlined into `PaymentRequirements.extra` (`sellerVkey`, `paymentType: "Web3CardanoV1"`, `blockchainIdentifier`, `payByTime`, `submitResultTime`, `unlockTime`, `externalDisputeUnlockTime`, `agentIdentifier`, `inputHash`, `identifierFromPurchaser`). - -This couples the core Cardano x402 scheme to a single ecosystem implementation. The consequences are: - -- Every Cardano facilitator has to reason about Masumi-specific fields even when it does not support Masumi. -- Additional Cardano agent-payment or escrow protocols would need either their own enum value or second-class status. -- Future Masumi evolution forces a revision of a core scheme document. - -The x402 v2 specification already defines the `extensions` object (`PaymentRequired.extensions`, `PaymentPayload.extensions`, `SettlementResponse.extensions`) as the canonical place for optional, composable functionality. Other ecosystems in the repo (Algorand, Sui, SVM, Stellar, Aptos, Hedera) keep their core schemes focused on ledger primitives and use extensions or scheme-specific `extra` fields that are generic to the network. Cardano should follow the same pattern. - -## What changed - -### Modified - -- **`specs/schemes/exact/scheme_exact_cardano.md`** — rewritten so the core compliance surface describes only: - - Address-to-address payments (ADA via reserved `"lovelace"` asset, or Cardano native tokens). - - Script-parameterized payments (a generic Cardano primitive; Plutus scripts with applied parameters). - - Facilitator verification rules (network, recipient, amount, asset, nonce/replay, TTL) that are independent of any off-chain protocol. - - An explicit statement that ecosystem-specific semantics MUST be carried via the x402 v2 extensions model. - - The `assetTransferMethod` enum has been removed. `"default"` and `"script"` are now described via field-shape rather than as vendor-adjacent enum values. - -### Added - -- **`specs/extensions/cardano_masumi.md`** — new extension that defines: - - Where Masumi-specific fields live on the wire (`extensions["cardano-masumi"].info`). - - The schema, semantics, and echo behaviour for `paymentType`, `blockchainIdentifier`, `sellerVkey`, `agentIdentifier`, `identifierFromPurchaser`, `inputHash`, and the four Masumi timing windows. - - Responsibilities for clients, servers, and facilitators. - - Core-compatibility rules so a non-Masumi facilitator can still verify the underlying script-parameterized payment. - -- **`docs/cardano-open-standard-rationale.md`** — design note explaining the standards-architecture rationale. - -- **`docs/cardano-open-standard-pr-summary.md`** — this document. - -## What was moved from core into an extension - -| Element | Was | Now | -| -------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------- | -| `assetTransferMethod: "masumi"` | core enum value in `PaymentRequirements.extra` | removed; replaced by the `cardano-masumi` extension | -| `sellerVkey` | core `extra` field | `extensions["cardano-masumi"].info.sellerVkey` | -| `paymentType: "Web3CardanoV1"` | core `extra` field | `extensions["cardano-masumi"].info.paymentType` | -| `blockchainIdentifier` | core `extra` field | `extensions["cardano-masumi"].info.blockchainIdentifier` | -| `agentIdentifier` | core `extra` field | `extensions["cardano-masumi"].info.agentIdentifier` | -| `identifierFromPurchaser` | core `extra` field | `extensions["cardano-masumi"].info.identifierFromPurchaser` | -| `inputHash` | core `extra` field | `extensions["cardano-masumi"].info.inputHash` | -| `payByTime` / `submitResultTime` / `unlockTime` / `externalDisputeUnlockTime` | core `extra` fields | `extensions["cardano-masumi"].info.*` | - -## What stayed in core - -- Network identifiers `cardano:mainnet` / `cardano:preprod` / `cardano:preview`. -- `asset` convention `${policyId}.${assetNameHex}`, plus the reserved value `"lovelace"` for native ADA. -- `payTo` addresses (regular or script). -- `maxTimeoutSeconds`, TTL checks. -- `payload.transaction` (Base64-encoded signed CBOR) and `payload.nonce` (UTXO reference for replay prevention). -- Facilitator verification rules. -- Script-parameterized payments (`extra.scriptHash`, `extra.script`, `extra.parameters`) as a generic Cardano primitive. - -## How this preserves openness while still supporting Masumi - -- The core scheme makes no normative reference to Masumi. -- The extension makes Masumi fully expressible on the x402 wire, using the v2 extensions pattern that clients, servers, and facilitators already implement. -- A Masumi payment still flows through the core Cardano scheme as a script-parameterized payment, so a minimally conformant stack can verify the underlying transaction without understanding Masumi's off-chain semantics. -- Other ecosystem-level Cardano payment protocols (present or future) can publish their own extensions alongside `cardano-masumi` without any change to the core scheme. - -## Backward compatibility - -- Implementations that only supported the prior Masumi-in-core shape will need to either: - 1. Emit the same Masumi fields under `extensions["cardano-masumi"].info`, and keep `payTo`/`extra` pointed at the Masumi script, or - 2. Declare themselves as core-only Cardano `exact` implementations and drop the Masumi fields. -- The underlying on-chain transaction shape does not change. -- Facilitators that only implement the core scheme continue to verify payments correctly; they simply do not enforce Masumi-specific off-chain invariants (which they were never in a position to enforce anyway). - -## Review path - -1. Internal review by QBT Labs. -2. Cardano Foundation review (Fabian). -3. Upstream proposal to `x402-foundation/x402`. - -## Non-goals - -- This PR does not change Masumi's on-chain protocol or off-chain rules. -- This PR does not add or remove any chain, scheme, or facilitator implementation. -- This PR does not take a position on which Cardano agent-payment protocol implementations should be preferred. diff --git a/docs/cardano-open-standard-rationale.md b/docs/cardano-open-standard-rationale.md deleted file mode 100644 index c7207a68b7..0000000000 --- a/docs/cardano-open-standard-rationale.md +++ /dev/null @@ -1,67 +0,0 @@ -# Cardano on x402: Open-Standard Boundary Rationale - -## TL;DR - -The core `exact` scheme on Cardano should define **only the minimum interoperable payment semantics** needed to make a Cardano x402 payment verifiable by any facilitator, on any Cardano network, by any implementation. Any semantics that are tied to a specific off-chain protocol, product, operator, or ecosystem implementation — including the Masumi escrow / agent-payment protocol — belong in an **x402 extension**, not in the core scheme. - -This is not a rejection of Masumi. Masumi can remain fully supported on Cardano x402 through the `cardano-masumi` extension defined in [`specs/extensions/cardano_masumi.md`](../specs/extensions/cardano_masumi.md). The goal of this note is to explain why drawing the standards boundary in this place yields a better open standard. - -## What changed - -1. The core Cardano `exact` scheme no longer declares an `assetTransferMethod` enum whose values name a specific third-party protocol. The previous enum `"default" | "masumi" | "script"` has been collapsed into two neutral, generic Cardano flows: - - address-to-address payments - - script-parameterized payments (a generic Cardano primitive; Plutus scripts with applied parameters) -2. The Masumi-specific fields (`sellerVkey`, `paymentType: "Web3CardanoV1"`, `blockchainIdentifier`, `payByTime`, `submitResultTime`, `unlockTime`, `externalDisputeUnlockTime`, `agentIdentifier`, `inputHash`, `identifierFromPurchaser`) are removed from the core scheme and relocated to the `cardano-masumi` extension. -3. The core scheme adds explicit language stating that it is facilitator-neutral, vendor-neutral, and implementation-agnostic, and that ecosystem-specific behaviour MUST be expressed through extensions. - -Full Masumi functionality is preserved. Only its **placement** in the specification changes. - -## Why core schemes should describe MUST-support behaviour only - -An x402 scheme document defines the minimum surface every conformant implementation must understand to interoperate. When vendor-specific semantics leak into that surface, three concrete harms follow: - -- **Every implementation pays the cost.** A facilitator that never intends to handle Masumi still has to parse, schema-validate, and ignore Masumi-specific fields, because they live in the core `extra` object. This inflates the conformance surface. -- **Naming a vendor in an enum privileges it.** `assetTransferMethod: "masumi"` is qualitatively different from `"default"` or `"script"`: it treats one ecosystem project as a peer of generic Cardano primitives. Future ecosystem projects would either have to negotiate their own enum value (turning the standard into a registry of vendors) or accept second-class status. -- **Standards boundaries calcify.** Once a vendor field is in the core, removing it later is a breaking change. Moving it to an extension while the scheme is young and adoption is still small is much cheaper than doing so later. - -The x402 v2 core specification already provides the correct mechanism for optional, composable functionality: the `extensions` object in `PaymentRequired`, `PaymentPayload`, and `SettlementResponse`. That mechanism is exactly where ecosystem-specific semantics should live. - -## Why script-parameterized payments belong in core - -Plutus scripts with applied parameters are a **generic Cardano primitive**, not a vendor feature. Any Cardano-native payment flow — Masumi's escrow, an alternative agent-payment protocol, a milestone-release protocol, a subscription escrow, a vault — ultimately expresses itself as a payment to a script address with some datum and redeemer. The core scheme therefore needs to describe "pay to a script address, with the client able to reconstruct that address from the declared script and parameters." It does not need to describe the off-chain semantics attached to any particular script. - -Keeping script-parameterized payments in core while pushing off-chain semantics into extensions is the standards-architecturally correct split: core describes what the ledger verifies, extensions describe what off-chain protocols verify. - -## Why this improves interoperability - -- **Multi-facilitator support.** A facilitator can claim conformance with the Cardano `exact` scheme without committing to any specific agent-payment protocol. New facilitators can enter the ecosystem without first implementing Masumi. -- **Multi-ecosystem support.** Other Cardano agent-payment or escrow protocols (present or future) can declare extensions alongside `cardano-masumi` without a spec change. The core scheme doesn't need to list them. -- **Cleaner client contracts.** A client library targeting the Cardano `exact` scheme has a small, stable contract: address-to-address and script-parameterized payments. Ecosystem-specific stacks are opt-in via extension libraries. -- **Clearer verification.** Facilitator verification rules depend only on the transaction and the declared `PaymentRequirements`. They do not depend on interpreting off-chain identifiers tied to a specific ecosystem. -- **Predictable forward evolution.** When Masumi itself evolves — a `Web3CardanoV2`, new windows, new identifiers — the core Cardano scheme does not need to version. The extension versions independently. - -## Why this is a standards-boundary correction, not anti-Masumi - -Masumi is one of the earliest and most substantial Cardano agent-payment deployments, and its on-chain and off-chain design are sophisticated. Shipping Cardano x402 support with Masumi as a reference integration is a good thing. The problem is strictly one of layering: - -- Masumi-specific fields currently sit where every Cardano x402 implementation has to reason about them. -- The x402 v2 extensions model exists precisely for these kinds of fields. -- Moving the fields one layer up costs Masumi nothing in functionality and gains the standard everything in neutrality. - -Said differently: the revised placement improves Masumi's position in the ecosystem, because it gives Masumi a clean, named, versioned extension it can evolve on its own cadence, instead of being coupled to the cadence of the Cardano core scheme. - -## Design principles applied - -The revised Cardano `exact` scheme follows three principles that the broader x402 spec already applies to other chains: - -1. **If it's a ledger primitive, it can live in core.** Address transfers, native-asset references, Plutus script parameterization, TTL, UTXO-based replay prevention. -2. **If it's an off-chain protocol or product-specific behaviour, it belongs in an extension.** Escrow timing windows, dispute windows, vendor-specific identifiers, agent/seller identities, vendor-specific datum shapes. -3. **The core scheme MUST NOT name a specific vendor, operator, or ecosystem implementation as a first-class value or field.** Extensions are the correct place for those names. - -These principles are neither novel nor controversial. They are applied consistently across the `eip155`, `svm`, `sui`, `aptos`, `algorand`, `stellar`, and `hedera` schemes already in the repository. Applying them to Cardano brings Cardano in line with the rest of the standard. - -## Open questions (non-blocking) - -- **Optional receipt-style acknowledgement.** Masumi has a natural notion of commitment to off-chain inputs (`inputHash`) and delivery windows. The `offer-receipt` extension in the x402 repo may be a good fit for some of these; future work can explore whether a Cardano-flavoured offer/receipt is useful. -- **Alternative Cardano agent-payment protocols.** If other teams propose agent-payment extensions on Cardano, the shape of `cardano-masumi` can serve as a template for common field placement (timing windows, agent identifiers, commitments). -- **ADA vs. native-asset normalisation.** The revised core scheme reserves the string `"lovelace"` for native ADA payments, which is a straightforward convention; implementers should confirm this aligns with existing Cardano SDK idioms in the repository. From adab35d6c7c4118a1e1c553d3fea5f2bc59947f5 Mon Sep 17 00:00:00 2001 From: "a.dacapo21" Date: Fri, 24 Apr 2026 10:46:02 +0300 Subject: [PATCH 16/16] docs(cardano): add end-to-end masumi extension example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit per PR review feedback: add a full worked example showing a complete masumi-routed flow — PaymentRequired, PAYMENT-SIGNATURE header, and PAYMENT-RESPONSE/SettlementResponse — so reviewers can see concrete json for each step of the extension in use, plus a note on what a non-masumi-aware stack sees of the same flow. --- specs/extensions/cardano_masumi.md | 201 +++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/specs/extensions/cardano_masumi.md b/specs/extensions/cardano_masumi.md index 3fa537cdc7..ed3c84f734 100644 --- a/specs/extensions/cardano_masumi.md +++ b/specs/extensions/cardano_masumi.md @@ -198,6 +198,207 @@ On success, the `PAYMENT-RESPONSE` payload MAY include extension-specific inform This extension does not currently specify additional normative fields in the settlement response; future versions MAY add them. +## End-to-End Example + +This section shows a complete Masumi-routed flow using the Cardano `exact` scheme together with the `cardano-masumi` extension. All three messages — `PaymentRequired`, `PAYMENT-SIGNATURE`, `PAYMENT-RESPONSE` — are shown consistently. + +For brevity, the signed transaction is truncated; in practice it is the Base64-encoded CBOR of a fully signed Cardano transaction that pays the declared `amount` of the declared `asset` to `payTo` (the Masumi script address) and consumes the UTXO referenced by `payload.nonce` as an input. + +### Step 1 — `402 Payment Required` (server → client) + +```json +{ + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1wxmasumiscriptaddressexample000000000000000000000000000000000", + "maxTimeoutSeconds": 600, + "extra": { + "scriptHash": "masumi_script_hash", + "script": { + "type": "plutusV3", + "code": "" + }, + "parameters": {} + } + } + ], + "extensions": { + "cardano-masumi": { + "info": { + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "sellerVkey": "sdasdqweqwewewewqe", + "agentIdentifier": "agent_identifier", + "identifierFromPurchaser": "aabbaabb11221122aabb", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260" + }, + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "paymentType": { "type": "string" }, + "blockchainIdentifier": { "type": "string" }, + "sellerVkey": { "type": "string" }, + "agentIdentifier": { "type": "string" }, + "identifierFromPurchaser": { "type": "string" }, + "inputHash": { "type": "string" }, + "payByTime": { "type": "string" }, + "submitResultTime": { "type": "string" }, + "unlockTime": { "type": "string" }, + "externalDisputeUnlockTime": { "type": "string" } + }, + "required": [ + "paymentType", + "blockchainIdentifier", + "sellerVkey", + "agentIdentifier", + "identifierFromPurchaser", + "inputHash", + "payByTime", + "submitResultTime", + "unlockTime", + "externalDisputeUnlockTime" + ] + } + } + } +} +``` + +### Step 2 — `PAYMENT-SIGNATURE` header (client → server) + +The client selects the offer above, builds and signs a Cardano transaction that pays the Masumi script address with a datum consistent with the Masumi fields, and submits it via the `PAYMENT-SIGNATURE` header. The decoded (pre-Base64) header payload is: + +```json +{ + "x402Version": 2, + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1wxmasumiscriptaddressexample000000000000000000000000000000000", + "maxTimeoutSeconds": 600, + "extra": { + "scriptHash": "masumi_script_hash", + "script": { + "type": "plutusV3", + "code": "" + }, + "parameters": {} + } + }, + "payload": { + "transaction": "AAAIAQDi1Hwj...AAAAAAA=", + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" + }, + "extensions": { + "cardano-masumi": { + "info": { + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "sellerVkey": "sdasdqweqwewewewqe", + "agentIdentifier": "agent_identifier", + "identifierFromPurchaser": "aabbaabb11221122aabb", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260" + }, + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "paymentType": { "type": "string" }, + "blockchainIdentifier": { "type": "string" }, + "sellerVkey": { "type": "string" }, + "agentIdentifier": { "type": "string" }, + "identifierFromPurchaser": { "type": "string" }, + "inputHash": { "type": "string" }, + "payByTime": { "type": "string" }, + "submitResultTime": { "type": "string" }, + "unlockTime": { "type": "string" }, + "externalDisputeUnlockTime": { "type": "string" } + }, + "required": [ + "paymentType", + "blockchainIdentifier", + "sellerVkey", + "agentIdentifier", + "identifierFromPurchaser", + "inputHash", + "payByTime", + "submitResultTime", + "unlockTime", + "externalDisputeUnlockTime" + ] + } + } + } +} +``` + +Notes on this step: + +- The client MUST echo `extensions["cardano-masumi"].info` unchanged from what it received in Step 1 (per the v2 rule that the client may append but not delete or overwrite server-supplied extension info). +- The `extra` object still carries the generic script reference required by the core Cardano scheme; this is what allows a non-Masumi facilitator to verify the underlying payment independent of the extension. +- `payload.nonce` references a UTXO consumed as an input of the signed transaction, as required by the core scheme's replay-prevention rule. + +### Step 3 — `PAYMENT-RESPONSE` / `SettlementResponse` (server → client, on success) + +```json +{ + "success": true, + "network": "cardano:mainnet", + "transaction": "2f9a7b3c1d4e5f60718293a4b5c6d7e8f90112233445566778899aabbccddeeff", + "extensions": { + "status": "confirmed", + "cardano-masumi": { + "info": { + "blockchainIdentifier": "blockchain_identifier" + } + } + } +} +``` + +Notes on this step: + +- Core fields (`success`, `network`, `transaction`, `extensions.status`) follow the core Cardano scheme. +- The `cardano-masumi` settlement-extension payload echoes the `blockchainIdentifier` so clients and downstream consumers can correlate the on-chain tx with the Masumi off-chain payment stream. Future versions of this extension MAY specify additional settlement-side fields (e.g., Masumi state transitions); this example reflects the minimum required today. +- A non-Masumi-aware client receiving this response can still interpret the core fields correctly and SHOULD ignore `extensions["cardano-masumi"]`. + +### What a non-Masumi-aware stack sees + +A minimally conformant Cardano `exact` stack that does not implement the `cardano-masumi` extension processes the same flow as a generic script-parameterized Cardano payment: + +- Recipient, amount, asset, nonce, and TTL checks apply to the transaction exactly as specified in the core scheme. +- The Masumi script address is visible in `payTo`; the Masumi script (or hash) is visible in `extra`. +- The `cardano-masumi` extension block is ignored. + +Such a stack will not enforce Masumi's off-chain invariants (escrow timing, dispute windows, agent/seller accounting) — those are, by design, the exclusive responsibility of Masumi-aware implementations. + ## Security Considerations - This extension MUST NOT be used to weaken the core Cardano verification rules. In particular, possession of a valid Masumi datum does not substitute for the nonce/replay, TTL, or amount/asset checks.