> ## Documentation Index
> Fetch the complete documentation index at: https://lnurl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# LUD-18: Payer identity in `payRequest` protocol.

> Display inline code and code blocks

`author: akumaigorodski` `author: hampus_s` `discussion: https://t.me/lnurl/14436` `author: fiatjaf` `author: dpad85` `discussion: https://t.me/lnurl/24003` `discussion: https://github.com/fiatjaf/lnurl-rfc/pull/101`

***

The idea here is that the payer can identify itself when paying. The scope varies from free-form names (or [LUD-16](16.md) internet identifiers) useful for loose identification in comments or similar things, to cryptographic keys for proof of payment, to authentication keys for future login into a `SERVICE`'s website after a payment and other use cases.

Aside from that, the payer ids are also committed to the invoice by means of the `descriptionHash` property, which ensures strong cryptographic guarantees for proof of payment.

## 1. `payerData` record

If `SERVICE` wants to get one or more types of payer identities from `WALLET` then it MUST alter its JSON response to the first callback to include a `payerData` field, as follows (notice that the `payerData` record below has a bunch of fields only for completion, an actual response will likely contain just a subset of these):

```diff theme={null}
 {
   "callback": String,
   "maxSendable": number,
   "minSendable": number,
   "metadata": string,
+  "payerData": {
+    "name": { "mandatory": boolean },
+    "pubkey": { "mandatory": boolean },
+    "identifier": { "mandatory": boolean },
+    "email": { "mandatory": boolean },
+    "auth": {
+       "mandatory": boolean,
+       "k1": string // hex encoded 32 bytes of challenge
+    },
+    ...other fields may be negotiated
+  },
   "tag": "payRequest",
 }
```

Notice that just including the payer id kind ("name", "pubkey" etc.) in the `payerData` record is enough to signal acceptance of that kind.

## 2. Specifying payer identity before sending a payment

In response to seeing a `payerData` record in the initial response from `SERVICE`, `WALLET` attaches a `payerdata` query parameter to LNURL-PAY callback with value set to a JSON object:

```diff theme={null}
- <callback><?|&>amount=<milliSatoshi>
+ <callback><?|&>amount=<milliSatoshi>&payerdata=<urlencode({json object})>
```

The JSON object MUST be of the following format (notice that these fields are shown only for completion, in practice it will likely contain just a subset of these):

```Typescript theme={null}
{
  "name": string, // free form string
  "pubkey": string, // hex(<randomly generated secp256k1 pubkey>),
  "auth": {
    "key": string, // hex(<linkingKey>)
    "k1": string, // same as received from service on section 1
    "sig": string, // following LUD-04: hex(sign(hexToBytes(<k1>), <linkingPrivKey>))
  },
  "email": string,
  "identifier": string,
  ...other fields may be included if supported by wallet and requested by service
}
```

Each key in this JSON object should correspond to a requested payerdata from the `payerData` record received from `SERVICE`.

`WALLET` CAN send any of the payer id kinds if they are listed in the `payerData` record. But if any is marked as `"mandatory": true` then `WALLET` MUST send or otherwise do not proceed with the payment flow.

`WALLET` SHOULD NOT send payer identity types omitted in `payerData` record, none at all if record is not present.

## 3. Committing payer to the invoice

If `SERVICE` requests (section 1) and `WALLET` sends a `payerdata` record in the callback (section 2), the payer ids MUST be committed to the metadata before the invoice is created.

`SERVICE` MUST append it to the metadata as it was received (after url-decoding), as in the following example:

```diff theme={null}
 [["text/plain", "description"], ["image/png;base64", "AAA=="]]
+[["text/plain", "description"], ["image/png;base64", "AAA=="]]{<identity records>}
```

After doing that, `SERVICE` proceeds to hash the metadata and include that hash in the generated BOLT11 invoice as the `descriptionHash` field.

On its own side, `WALLET` MUST do the same thing before hashing the metadata and checking its hashed value against the `descriptionHash` field of the invoice received from `SERVICE`.

Even if `WALLET` sends more `payerdata` fields than requested by `SERVICE`, `SERVICE` MUST still append everything as received.

`WALLET` MUST NOT expect `SERVICE` to append the identity records to the metadata if `SERVICE` hadn't included the `payerData` record in the first response, as that would mean `SERVICE` doesn't understand LUD-18 at all.

### Pseudocode example for calculating `descriptionHash` with `payerdata`

```
originalServiceMetadata = '[["text/plain", "description"], ["image/png;base64", "AAA=="]]'
urlEncodedPayerIds = '%7B%22name%22%3A%22bob%22%2C%22auth%22%3A%7B%22key%22%3A%2202c9323d02fc164f89c8f688dbfba8aad69a96fa8f6253ba8cce2c6f1546073fa3%22%2C%22sig%22%3A%222afd21794e2a801d0d516584ceebe1a24ed8991dd5ec708259aeaee5c0d2d1437542b689ee5d39e619a01a257142d49c18a4af3088c46ce87e2d941a1bcc7210%22%7D%2C%22identifier%22%3A%22bob%40bob.com%22%2C%22pubkey%22%3A%2203ee58475055820fbfa52e356a8920f62f8316129c39369dbdde3e5d0198a9e315%22%7D'
payerData = urldecode(urlEncodedPayerIds)
descriptionToBeHashed = metadata + payerData
descriptionToBeHashed == '[["text/plain", "description"], ["image/png;base64", "AAA=="]]{"name":"bob","auth":{"key":"02c9323d02fc164f89c8f688dbfba8aad69a96fa8f6253ba8cce2c6f1546073fa3","sig":"2afd21794e2a801d0d516584ceebe1a24ed8991dd5ec708259aeaee5c0d2d1437542b689ee5d39e619a01a257142d49c18a4af3088c46ce87e2d941a1bcc7210"},"identifier":"bob@bob.com","pubkey":"03ee58475055820fbfa52e356a8920f62f8316129c39369dbdde3e5d0198a9e315"}'
descriptionHash = sha256(utf8(descriptionToBeHashed))
```
