UMA Invoice and Request

An UMA invoice is a data structure that describes payments that can be coordinated using UMA and provides a way for a payment sender to have proof of payment–without having to use the existing LNURLPRequest/Response handshake flow.
UMA invoices allow a payment recipient to specify an amount they want to receive in any currency, along with some details on how to pay. This is useful in many cases where the recipient is the initiator of a payment. For example, merchant checkout flows, a bill from any vendor or service provider, etc.
UMA requests are a way to deliver UMA invoices to sending wallets through methods like deep/universal links on mobile, notifications, etc.
The invoice format looks like this:
/**
 * Invoice
 * represents a UMA invoice
 *
 * @param receiverUma
 * @param invoiceUUID - Invoice UUID Served as both the identifier of the UMA invoice, and the validation of proof of payment
 * @param amount - The amount of invoice to be paid in the smallest unit of the ReceivingCurrency.
 * @param receivingCurrency - The currency of the invoice
 * @param expiration - The unix timestamp of when the UMA invoice expires
 * @param isSubjectToTravelRule -  Indicates whether the VASP is a financial institution that requires travel rule information.
 * @param requiredPayerData - the data about the payer that the sending VASP must provide in order to send a payment
 * @param umaVersion - UmaVersion is a list of UMA versions that the VASP supports for this transaction. It should be
 * containing the lowest minor version of each major version it supported, separated by commas
 * @param commentCharsAllowed - is the number of characters that the sender can include in the comment field of the pay request.
 * @param senderUma - The sender's UMA address. If this field presents, the UMA invoice should directly go to the sending VASP
 * instead of showing in other formats
 * @param invoiceLimit - The maximum number of the invoice can be paid
 * @param kycStatus - YC status of the receiver, default is verified
 * @param callback - The callback url that the sender should send the PayRequest to
 * @param signature - The signature of the UMA invoice
 */
export type Invoice {
  receiverUma,
  invoiceUUID,
  amount,
  receivingCurrency,
  expiration,
  isSubjectToTravelRule,
  requiredPayerData,
  umaVersion,
  commentCharsAllowed,
  senderUma,
  invoiceLimit,
  kycStatus,
  callback,
  signature,
}
UMA SDK provides an easy way to create an UMA invoice. Most of the fields are similar to the fields in LNURLPResponse:
const invoice = await createUmaInvoice(
    {
    receiverUma: receiverUma,
    invoiceUUID: UUID,
    amount: receivingCurrencyAmount,
    receivingCurrency: {
        code: currency.code,
        name: currency.name,
        symbol: currency.symbol,
        decimals: currency.decimals,
    },
    expiration: expirationTimestamp,
    isSubjectToTravelRule: true|false,
    requiredPayerData: payerData,
    kycStatus: KycStatus,
    callback: vaspCallbackURL,
    },
    privateKey,
)
Once the invoice object is created, the receiver can encode it to a bech32 string:
const invoiceString = InvoiceSerializer.toBech32(invoice);
The invoice string can be displayed in QR code, or as a deep link:
uma://<invoice_string>
Then it's up to the sending wallet to implement this url scheme for deep linking to redirect to the wallet app.
When the sending wallet receives an UMA invoice string, it should decode it to an UMA invoice object and validate the signature:
const invoice = InvoiceSerializer.fromBech32(invoiceString);
verifyUmaInvoiceSignature(invoice, receiverVaspPublicKey);
When decoding the invoice string, the SDK will automatically validate that all the required fields are present.
After this step, the sending VASP should validate that the invoice has not expired. It should then proceed directly to the PayRequest step of the protocol. All information needed should be included in the invoice object.
For a sending VASP that supports UMA requests, a request endpoint should be defined in the api configuration:
"uma_request_endpoint": "https://vasp1.com/path/to/request/url"
This must be a POST endpoint with a body payload of the invoice string.
When requesting a payment from a specific sender, the receiving VASP should create the invoice with the sender field filled:
When requesting a payment from a specific sender, the receiving VASP should create the invoice with the sender field filled:
const invoice = await createUmaInvoice(
    {
    receiverUma: receiverUma,
    invoiceUUID: UUID,
    amount: receivingCurrencyAmount,
    receivingCurrency: {
        code: currency.code,
        name: currency.name,
        symbol: currency.symbol,
        decimals: currency.decimals,
    },
    expiration: expirationTimestamp,
    isSubjectToTravelRule: true|false,
    requiredPayerData: payerData,
    kycStatus: KycStatus,
    callback: vaspCallbackURL,
    },
    privateKey,
    senderUma: "$alice@vasp1.com" 
)
Then the receiving VASP should query the sending VASP's configuration to get the request endpoint to send the invoice to sending VASP:
vars = {"invoice": invoice_str}
res = requests.post(
    url,
    json=vars,
    timeout=20,
)
Once the sending VASP receives the request, it should validate the invoice and then send a push notification to the sender's wallet app to let the sender confirm before sending the payment.