{"id":"a1ad5a4547622ee64a1d78fc037c8b47ce700f4f7cfd70c88bdcd0dc2eef15ce","pubkey":"d1678e7ef965374bbea308a1215609a78376dc158277a7d657680f9d5efd5c38","created_at":1784647992,"kind":30817,"tags":[["d","nut-18"],["title","NUT-18: Payment Requests"],["summary","A request format carrying everything a sending wallet needs, so a transaction can be started by whoever is being paid."],["s","optional"],["t","cashu"],["t","ecash"],["t","nut"],["alt","A specification: NUT-18: Payment Requests"],["client","openspecs-import"],["published_at","1729272613"],["proxy","https://github.com/cashubtc/nuts/blob/a845dfc998abae501fc3419592d53dc995d34b12/18.md","web"],["x","30dad911d8573b722dfa10696ff15ae6ebb08d4a34f91f468cce8786db20953b"]],"content":"# NUT-18: Payment Requests\n\n`optional`\n\n---\n\nThis NUT introduces a standardised format for payment requests, that supply a sending wallet with all information necessary to complete the transaction. This enables many use-cases where a transaction is better initiated by the receiver (e.g. point of sale).\n\n## Flow\n\n1. Receiver creates a payment request, encodes it and displays it to the sender\n2. Sender scans the request and constructs a matching token\n3. Sender sends the token according to the transport specified in the payment request\n4. Receiver receives the token and finalises the transaction\n\n## Payment Request\n\nA Payment Request is defined as follows\n\n```json\n{\n  \"i\": str <optional>,\n  \"a\": int <optional>,\n  \"u\": str <optional>,\n  \"s\": bool <optional>,\n  \"m\": Array[str] <optional>,\n  \"mp\": bool <optional>,\n  \"sm\": Array[SupportedMethod] <optional>,\n  \"d\": str <optional>,\n  \"t\": Array[Transport] <optional>,\n  \"nut10\": NUT10Option <optional>,\n}\n```\n\nHere, the fields are\n\n- `i`: Payment id to be included in the payment payload\n- `a`: The amount of the requested payment, net of input fees (see [Input fees](#input-fees))\n- `u`: The unit of the requested payment (MUST be set if `a` or `sm` is set)\n- `s`: Whether the payment request is for single use\n- `m`: The mint list from which payment will be accepted\n- `mp`: Whether the mint list is advisory (`true`) or strict (`false` or omitted)\n- `sm`: A list of `SupportedMethod` entries (e.g. `\"bolt11\"`, `\"bolt12\"`, `\"onchain\"`) that the payee will accept, each with an optional per-method fee\n- `d`: A human readable description that the sending wallet will display after scanning the request\n- `t`: The method of `Transport` chosen to transmit the payment (can be multiple, sorted by preference)\n- `nut10`: The required [NUT-10][10] locking condition\n\n## Mint list\n\nA Payment Request containing a mint list `m` describes the mints the receiver accepts payments from or prefers.\n\nIf `m` is set and `mp` is not present, or is `false`, the mint list is strict: the sender MUST only send proofs from these mints, and the receiver SHOULD ignore payments sent from other mints.\n\nIf `m` is set and `mp` is `true`, the mint list is preferred: the receiver accepts payments from other mints, but the payer SHOULD use a mint in `m` when possible.\n\nIf `m` is not set, `mp` SHOULD be ignored.\n\n## Supported payment methods\n\nIf `sm` is set, the payer MUST send ecash from a mint that supports melting the request unit (see [NUT-05][05]) via at least one of the listed payment methods. Each `SupportedMethod` is defined as:\n\n```json\n{\n  \"mn\": str,\n  \"mf\": int <optional> // omitted = 0\n}\n```\n\n- `mn`: the method name (e.g. `\"bolt11\"`, `\"bolt12\"`, `\"onchain\"`)\n- `mf`: additional fee, in the request unit, that compensates the receiver for melting out via this method\n\nThe per-method fee applies only to payments the receiver may need to melt out of: those from a mint outside `m`, or from any mint if `m` is not set. Payments from a mint in `m` carry no per-method fee.\n\nWhen a fee applies, the payer owes the lowest `mf` among the listed methods their mint supports, and MUST add it to the requested amount. For example, if the request lists `bolt11` (no fee) and `onchain` (`mf` = 50), a mint supporting both owes nothing, while an onchain-only mint owes 50.\n\n## Input fees\n\nReceived proofs cost the receiver an input fee when they are later swapped or melted (see [NUT-02][02]). The requested amount is therefore net of input fees: the payer MUST select proofs such that\n\n`sum(proofs) - input_fee(proofs) >= a + mf (where applicable)`\n\nwith `input_fee` computed from the sending mint's keyset `input_fee_ppk` values as described in [NUT-02][02]. This protects the receiver from dust proof sets that are expensive to redeem (e.g. 1000 x 1 sat proofs at 250 ppk would cost the receiver 250 sats to swap).\n\n## Locking conditions\n\nThe payment request can include _optional_ locking conditions the payee requires from the payer. For example, the payee might require a P2PK-locked token so that they can receive payments offline.\n\nThe `nut10` field specifies the payee's requested locking condition as a `NUT10Option` object. Its elements are derived from NUT-10's [well-known secret](nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnqx5tye7#well-known-secret). The `NUT10Option` is defined as follows:\n\n```json\n{\n  \"k\": str,\n  \"d\": str,\n  \"t\": Array[Array[str, str]] <optional>\n}\n```\n\n- `k`: NUT-10 secret kind,\n- `d`: NUT-10 secret data,\n- `t`: optional NUT-10 payment tags\n\n> [!IMPORTANT]\n> The payee must validate the incoming tokens themselves in order to decide whether they can accept the payment. This includes checking the DLEQ proof and whether the token includes a long-enough timelock to satisfy the payee.\n\n## Transport\n\n`Transport` specifies methods for sending the ecash to the receiver. A transport consists of a type and a target.\n\n> [!IMPORTANT]\n> The transport can be empty! If the transport is empty, we implicitly assume that the payment will be in-band. An example is X-Cashu where the payment is expected in the HTTP header of a request. We can only hope that the protocol you're using has a well-defined transport.\n\n```json\n{\n  \"t\": str,\n  \"a\": str,\n  \"g\": Array[Array[str, str]] <optional>\n}\n```\n\n- `t`: type of Transport\n- `a`: target of Transport\n- `g`: optional tags for the Transport\n\n### Tags\n\nTags are an optional array of `[tag, value, value, ...]` tuples that can be used to specify additional features about the transport. A single tag can have multiple values.\n\n### Transport types\n\nThe supported transport types are described below.\n\n#### Nostr\n\n- type: `nostr`\n- target: `<nprofile>`\n- tags: `[[\"n\", \"17\"]]`\n\nThe `n` tag specifies the NIPs the receiver supports. At least one tag value MUST be specified. For [NIP-17](nostr:naddr1qvzqqqrcvypzq2eeknl7v2fnm7tsuxfkds3vrcyjl9fls070a465urcy6k3mgk0eqqrxu6ts95cnwr4j8fh) direct messages, the sender sends a `PaymentRequestPayload` as the message content.\n\n#### HTTP POST\n\n- type: `post`\n- target: `<endpoint url>`\n\nThe execute the payment, the sender makes a `POST` request to the specified endpoint URL with the `PaymentRequestPayload` as the body.\n\n## Payment payload\n\nIf not specified otherwise, the payload sent to the receiver is a `PaymentRequestPayload` JSON serialized object as follows:\n\n```json\n{\n  \"id\": str <optional>,\n  \"memo\": str <optional>,\n  \"mint\": str,\n  \"unit\": <str_enum>,\n  \"proofs\": Array<Proof>\n}\n```\n\nHere, `id` is the payment id (corresponding to `i` in request), `memo` is an optional memo to be sent to the receiver with the payment, `mint` is the mint URL from which the ecash is from, `unit` is the unit of the payment, and `proofs` is an array of proofs (see [NUT-00][00], can also include DLEQ proofs).\n\n## Encoded Request\n\nThe payment request is serialized using CBOR, encoded in `base64_urlsafe`, together with a prefix `creq` and a version `A`:\n\n`\"creq\" + \"A\" + base64_urlsafe(CBOR(PaymentRequest))`\n\n### Example\n\nThis is an example payment request expressed as JSON:\n\n```json\n{\n  \"i\": \"b7a90176\",\n  \"a\": 10,\n  \"u\": \"sat\",\n  \"m\": [\"https://nofees.testnut.cashu.space\"],\n  \"t\": [\n    {\n      \"t\": \"nostr\",\n      \"a\": \"nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5\",\n      \"g\": [[\"n\", \"17\"]]\n    }\n  ]\n}\n```\n\nThis payment request serializes to:\n\n```sh\ncreqApWF0gaNhdGVub3N0cmFheKlucHJvZmlsZTFxeTI4d3VtbjhnaGo3dW45ZDNzaGp0bnl2OWtoMnVld2Q5aHN6OW1od2RlbjV0ZTB3ZmprY2N0ZTljdXJ4dmVuOWVlaHFjdHJ2NWhzenJ0aHdkZW41dGUwZGVoaHh0bnZkYWtxcWd5ZGFxeTdjdXJrNDM5eWtwdGt5c3Y3dWRoZGh1NjhzdWNtMjk1YWtxZWZkZWhrZjBkNDk1Y3d1bmw1YWeBgmFuYjE3YWloYjdhOTAxNzZhYQphdWNzYXRhbYF4Imh0dHBzOi8vbm9mZWVzLnRlc3RudXQuY2FzaHUuc3BhY2U=\n```\n\n[00]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crqqpd6d9\n[02]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cry0t0uzl\n[05]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cr2dsg4q4\n[10]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnqx5tye7\n","sig":"9c7d2f33b0fb136fe44cb2d04bf7468ccd14e8f9a9f6d50409cf4ce9ece0dec7378e9099695bfd7f799360a39834324ae9a3d12b57882bc23abfd29e692bc658"}