Cashu ecash transactions are initiated by the sender and can be pushed to the receiver without any additional help. However for many use cases requesting a payment may be more desirable (e.g. point-of-sales). This proposal introduces a standardised format for payment requests, that supply a sending wallet with all information necessary to complete the transaction.

Payment Requests

The payment request include all information necesarry for the sending wallet to create a matching token and push it through the desired transport channel. A Payment Request is defined as follows

	type PaymentRequest struct {
		A int         `amount`
		U string      `unit`
		M string      `mint`
		D string      `description`
		T []Transport `transport`

while Transport is defined as

	type Transport struct {
		T  string     `type`
		Ta string     `target`
	}
  • amount: The amount the token should have (payment amount)
  • unit: The unit the token should have (e.g. sats)
  • mint: The mint to use to mint the token
  • description: A human readable discription that the sending wallet will display after scanning the request
  • transport: The method of transport chosen to transmit the created token to the sender (can be multiple, sorted by preference)

Transport

Transport is an important part of Cashu Payment Requests. Receivers can choose what kind of transport they want to support and where they want to receive the token. By making this clear in the payment requests, wallets can handle payment requests accordingly (or decline them if they do not support the transport layer). A transport consists of a type and a target. There can be many transport layers, but here are some recommendations:

  • nostr: type "nostr", target nip-19 encoded entity (nprofile)
  • post: type "post", target post endpoint
  • email: type "email", target email address
  • sms: type "sms", target phone number

a

Reference Implementation

package main

import (
	"encoding/base64"
	"fmt"
	"log"
    
	"github.com/fxamacker/cbor/v2"
)

func main() {
	type Transport struct {
		T  string
		Ta string
	}
	type PaymentRequest struct {
		A int
		U string
		M string
		D string
		T []Transport
	}

	t := Transport{T: "nostr", Ta: "nprofile1qqsdmup6e2z6mcpeue6z6kl08he49hcen5xnrc3tnpvw0mdgtjemh0suxa0kj"}
	pr := PaymentRequest{A: 21, U: "sat", M: "https://mint.minibits.cash/Bitcoin", D: "Plesase pay the very first cashu pr", T: []Transport{t}}
	b, err := cbor.Marshal(pr)
	if err != nil {
		log.Fatal("CBOR encoding failed...")
	}
	pre := "cashrq"
	version := byte(0x01)
	b = append([]byte{version}, b...)
	encodedString := base64.RawURLEncoding.EncodeToString(b)
	res := pre + encodedString
	fmt.Printf("%s", res)
}