# Recipient Resolution

Recipient resolution is the first step in the Cheqi receipt and credit note
flows. You submit `IdentificationDetails`, and Cheqi returns:

- whether a delivery route was found
- the `matchId` used for later submission
- an explicit `deliveryRouteType`
- for digital delivery, one temporary recipient and public key per owner device
- server-known customer context such as `buyerCountryCode` and `buyerType`


## Supported identifiers

The current API and SDKs support these fields on `IdentificationDetails`:

| Field | Typical use |
|  --- | --- |
| `pairingCode` | Customer-generated code from the Cheqi app |
| `cardDetails` | In-store card payments using PAR or other card identifiers |
| `paymentAccountDetails` | IBAN or other payment-account-based matching |
| `recipientEmail` | Matching an existing Cheqi user, including in webshop flows |
| `cheqiReceiptId` | Follow-up flows tied to an existing receipt, especially credit notes |


Check [Payment Provider Compatibility](/receipts/payment-provider-compatibility) for
PAR and IBAN availability, required account settings, and QR collection using
the last four card digits. Identifier availability and Cheqi connector support
are separate.

## Priority order

The backend resolves identifiers in this order:

1. `cheqiReceiptId`
2. `pairingCode`
3. `paymentAccountDetails`
4. `cardDetails`
5. `recipientEmail`


`cheqiReceiptId` is an explicit follow-up-flow override. For new checkout flows,
pairing code takes precedence over payment-account, card, and email matching.
Cheqi stops at the first successful strategy; lower-priority identifiers are
fallback opportunities and are not compared after a match. Supply only
identifiers appropriate to the intended customer.

## Card-payment receipt metadata

`merchantId` and `paymentTerminalId` are not fields on the current
`IdentificationDetails` model. Put those display values in the definitive,
encrypted `ReceiptPayload.paymentDetails` object. They are not customer
identifiers and do not change matching priority.

The card's last four digits alone do not identify a customer during this
merchant-side resolution. If PAR or another reliable identifier is unavailable,
include `paymentDetails.cardLastFour` in the encrypted receipt and use the
enabled [web wallet link](/receipts/qr-collection). For this case,
`IdentificationDetails` may contain the payment type
without `cardDetails`; the four digits belong in the receipt payload, not in
this matching request.

## Pairing code example

```java Java
IdentificationDetails identificationDetails = new IdentificationDetails()
    .paymentType(PaymentType.CARD_PAYMENT)
    .pairingCode("84739201");

ReceiptResult result = sdk.getReceiptService()
    .issueReceipt(identificationDetails, receiptPayload);
```

```javascript JavaScript
const identificationDetails = {
  paymentType: PaymentType.CARD_PAYMENT,
  pairingCode: "84739201"
};

const result = await sdk.receiptService.issueReceipt(
  identificationDetails,
  receiptPayload
);
```

```csharp .NET
var identificationDetails = new IdentificationDetails
{
    PaymentType = PaymentType.CARDPAYMENT,
    PairingCode = "84739201"
};

var result = await sdk.ReceiptService.IssueReceiptAsync(
    identificationDetails,
    receiptPayload);
```

```python Python
identification_details = IdentificationDetails(
    payment_type=PaymentType.CARD_PAYMENT,
    pairing_code="84739201",
)

result = sdk.receipt_service.issue_receipt(identification_details, receipt_payload)
```

## Card and email matching

```java Java
IdentificationDetails customer = new IdentificationDetails()
    .paymentType(PaymentType.CARD_PAYMENT)
    .cardDetails(new CardDetails()
        .paymentAccountReference("PAR123456789")
        .cardProvider(CardDetails.CardProviderEnum.VISA))
    .recipientEmail("customer@example.com");
```

```javascript JavaScript
const customer = {
  paymentType: PaymentType.CARD_PAYMENT,
  cardDetails: {
    paymentAccountReference: "PAR123456789",
    cardProvider: "VISA"
  },
  recipientEmail: "customer@example.com"
};
```

```csharp .NET
var customer = new IdentificationDetails
{
    PaymentType = PaymentType.CARDPAYMENT,
    CardDetails = new CardDetails("PAR123456789") { CardProvider = CardDetails.CardProviderEnum.VISA },
    RecipientEmail = "customer@example.com"
};
```

```python Python
customer = IdentificationDetails(
    payment_type=PaymentType.CARD_PAYMENT,
    card_details=CardDetails(
        payment_account_reference="PAR123456789",
        card_provider="VISA",
    ),
    recipient_email="customer@example.com",
)
```

## Payment-account matching

```java Java
IdentificationDetails customer = new IdentificationDetails()
    .paymentType(PaymentType.DIRECT_DEBIT)
    .paymentAccountDetails(new PaymentAccountDetails()
        .identifier("NL91ABNA0417164300")
        .accountIdentifierType(AccountIdentifierType.IBAN))
    .recipientEmail("customer@example.com");
```

```javascript JavaScript
const customer = {
  paymentType: PaymentType.DIRECT_DEBIT,
  paymentAccountDetails: {
    identifier: "NL91ABNA0417164300",
    accountIdentifierType: AccountIdentifierType.IBAN
  },
  recipientEmail: "customer@example.com"
};
```

```csharp .NET
var customer = new IdentificationDetails
{
    PaymentType = PaymentType.DIRECTDEBIT,
    PaymentAccountDetails = new PaymentAccountDetails("NL91ABNA0417164300", AccountIdentifierType.IBAN),
    RecipientEmail = "customer@example.com"
};
```

```python Python
from cheqi.models.generated.account_identifier_type import AccountIdentifierType

customer = IdentificationDetails(
    payment_type=PaymentType.DIRECT_DEBIT,
    payment_account_details=PaymentAccountDetails(
        identifier="NL91ABNA0417164300",
        account_identifier_type=AccountIdentifierType.IBAN,
    ),
    recipient_email="customer@example.com",
)
```

## Match response

Typical fields in the current response:

```json
{
  "routeFound": true,
  "deliveryRouteType": "DIGITAL",
  "matchId": "match_123456789",
  "recipients": [
    {
      "id": "rcpt_abc123",
      "publicKey": "base64-encoded-key",
      "keyAlgorithm": "RSA_2048",
      "acceptedFormats": ["CHEQI"]
    }
  ],
  "expiresAt": "2026-01-26T20:00:00Z",
  "buyerCountryCode": "DE",
  "buyerType": "BUSINESS"
}
```

The returned digital recipients are the devices to encrypt for in this match.

Recipient IDs are temporary, opaque, and scoped to this match. Do not expose
them as customer identifiers or reuse them in another transaction.

### Delivery routes are explicit

Use `deliveryRouteType` to choose the next step:

- `DIGITAL` returns owner-device recipients. Encrypt the same definitive
generation payload independently for every returned device and submit it to
`/receipt/encrypted`.
- `DOWNLOAD_FALLBACK` returns no device recipients. Build the client-encrypted
download envelope locally and upload it through `/receipt/download`. The
resulting URL works for the browser wallet and [Cheqi app collection](/receipts/qr-collection).
- `routeFound: false` means no enabled route was found.


Do not infer the route from the number of recipients. Use the SDK to handle
the selected route; download uploads use `/receipt/download`.

A request without a customer locator can deliberately select the anonymous
download fallback when that route is enabled. See
[Download Links](/receipts/download-fallback).

An email address can match an existing Cheqi user for `DIGITAL` delivery. If it
does not match, the enabled download route gives the customer a browser wallet
link.

## How the flow uses this response

- For `DIGITAL`, `matchId` is sent back with `/receipt/encrypted` and consumed
by that submission.
- `recipients` provide the temporary device IDs and public keys used to encrypt
the merchant generation input.
- Send the same definitive payload to every device. Do not pre-generate or
filter final CHEQI or UBL documents on the merchant side.
- `buyerCountryCode` and `buyerType` are returned customer context. Do not use
them to replace the issuer-supplied payment or jurisdiction data.


## Best practices

- Include `recipientEmail` when it is an available recipient-resolution identifier.
- Enable the [download fallback](/receipts/download-fallback) when you want to offer a receipt to every customer, including unmatched or anonymous ones, via a QR code or link.
- Treat the returned device set as exact: submit one independently encrypted
delivery for every recipient and no extras.
- Use a fresh symmetric content key for each device.
- Branch on `deliveryRouteType`; do not treat fallback routes as normal device
matches.
- Use `cheqiReceiptId` for follow-up flows such as issuing credit notes against an existing receipt.