# Payment Webhooks

Payment webhooks provide real-time notifications about payment events that occur between FarPay and payment service providers (card providers, MobilePay, NETS, etc.). These webhooks enable you to track payment status changes and respond immediately to payment events.

## Overview

Payment webhooks are triggered by events in the FarPay core system and provide detailed information about:

* Payment success or failure
* Customer cancellations
* Bank rejections and reimbursements
* Refund processing
* Payment method changes

## Payment Events

| Event                | Value | Description                                                            |
| -------------------- | ----- | ---------------------------------------------------------------------- |
| `Succeeded`          | 200   | Payment was successfully executed                                      |
| `Canceled`           | 210   | Customer has cancelled the payment                                     |
| `Failed`             | 220   | Payment failed (insufficient funds, expired card, etc.)                |
| `RejectedByCustomer` | 230   | Customer rejected a scheduled payment (e.g., cancelled in online bank) |
| `ReimbursedByBank`   | 240   | Financial institution cancelled the payment (insufficient funds, etc.) |
| `Refunded`           | 245   | Payment was refunded (transaction rolled back)                         |

## Payment Types

| Type                     | Description                                           |
| ------------------------ | ----------------------------------------------------- |
| `BS`                     | Betalingsservice (direct debit for private customers) |
| `LS`                     | Leverandørservice (direct debit for businesses)       |
| `FI`                     | FI-Indbetalingskort (+71)                             |
| `DanKort`                | Dankort (Danish debit card)                           |
| `Visa`                   | Visa credit/debit card                                |
| `MasterCard`             | MasterCard credit/debit card                          |
| `MobilePaySubscriptions` | MobilePay Subscriptions (recurring payments)          |
| `MobilePayPayment`       | MobilePay ePayment (single payments)                  |

## Webhook Payload Structure

### JSON Format (POST)

```json
{
  "Type": "Payment",
  "Event": "Succeeded",
  "InvoiceNumber": "1234567BAVV",
  "CustomerNumber": "66776655",
  "PaymentDueDate": "2023-02-15",
  "Currency": "DKK",
  "InvoiceAmount": "1215.0000",
  "Amount": "1125.0000",
  "PaymentType": "LS",
  "PaymentReference": "ABC123-Reference",
  "AgreementId": "1234"
}
```

### XML Format (POST)

```xml
<Payment>
  <Type>Payment</Type>
  <Event>Succeeded</Event>
  <InvoiceNumber>1234567BAVV</InvoiceNumber>
  <CustomerNumber>66776655</CustomerNumber>
  <PaymentDueDate>2023-02-15</PaymentDueDate>
  <Currency>DKK</Currency>
  <InvoiceAmount>1215.0000</InvoiceAmount>
  <Amount>1125.0000</Amount>
  <PaymentType>LS</PaymentType>
  <PaymentReference>ABC123-Reference</PaymentReference>
  <AgreementId>1234</AgreementId>
</Payment>
```

### URL Parameters (GET)

```
https://yourdomain.com/webhook?Type=Payment&Event=Succeeded&PaymentReference=ABC123-Reference&InvoiceNumber=1234567BAVV&CustomerNumber=66776655&PaymentDueDate=2023-02-15&Currency=DKK&InvoiceAmount=1215.000&Amount=1215.000&PaymentType=LS
```

## Payload Properties

| Property           | Type    | Description             | Format                     |
| ------------------ | ------- | ----------------------- | -------------------------- |
| `Type`             | string  | Always "Payment"        | Fixed value                |
| `Event`            | string  | Payment event type      | See Event table above      |
| `InvoiceNumber`    | string  | Invoice identifier      | Alphanumeric, max 15 chars |
| `CustomerNumber`   | string  | Customer identifier     | Alphanumeric, max 15 chars |
| `PaymentDueDate`   | string  | Payment due date        | YYYY-MM-DD                 |
| `Currency`         | string  | Payment currency        | "DKK", "EUR"               |
| `InvoiceAmount`    | decimal | Original invoice amount | 4 decimal places           |
| `Amount`           | decimal | Actual payment amount   | 4 decimal places           |
| `PaymentType`      | string  | Payment method used     | See Payment Types table    |
| `PaymentReference` | string  | Payment reference       | Optional                   |
| `AgreementId`      | string  | Associated agreement ID | Optional                   |

## Special Event Types

### RejectedByCustomer (230)

Occurs when a customer rejects a scheduled payment through their online bank.

#### Payload Example

```json
{
  "Type": "Payment",
  "Event": "RejectedByCustomer",
  "InvoiceNumber": "12345678abcnnn",
  "CustomerNumber": "abc123",
  "PaymentDueDate": "2023-07-01",
  "Currency": "DKK",
  "InvoiceAmount": "123.1234",
  "Amount": "123.1234",
  "PaymentType": "BS",
  "PaymentReference": "",
  "AgreementId": ""
}
```

#### Payment Type Behavior

| Type        | Amount Behavior                      | Reason                                           |
| ----------- | ------------------------------------ | ------------------------------------------------ |
| `BS`        | Amount = 0                           | Money not transferred from debtor account        |
| `BS`        | Amount > 0                           | Money transferred and will be returned to debtor |
| `MobilePay` | Amount may differ from InvoiceAmount | MobilePay provisioning differences               |

#### BS Rejection Examples

**Before bank transfer:**

```json
{
  "Type": "Payment",
  "Event": "RejectedByCustomer",
  "InvoiceNumber": "234-cvcv-445673",
  "CustomerNumber": "123123123123",
  "PaymentDueDate": "2023-07-01",
  "Currency": "DKK",
  "InvoiceAmount": "750.9900",
  "Amount": "0.0000",
  "PaymentType": "BS",
  "PaymentReference": "",
  "AgreementId": ""
}
```

**After bank transfer:**

```json
{
  "Type": "Payment",
  "Event": "RejectedByCustomer",
  "InvoiceNumber": "234-cvcv-445673",
  "CustomerNumber": "123123123123",
  "PaymentDueDate": "2023-07-01",
  "Currency": "DKK",
  "InvoiceAmount": "750.9900",
  "Amount": "750.9900",
  "PaymentType": "BS",
  "PaymentReference": "",
  "AgreementId": ""
}
```

### ReimbursedByBank (240)

Occurs when a financial institution cancels a payment and transfers money back to the customer.

#### Payload Example

```json
{
  "Type": "Payment",
  "Event": "ReimbursedByBank",
  "InvoiceNumber": "234-cvcv-445673",
  "CustomerNumber": "123123123123",
  "PaymentDueDate": "2023-07-01",
  "Currency": "DKK",
  "InvoiceAmount": "750.9900",
  "Amount": "750.9900",
  "PaymentType": "BS",
  "PaymentReference": "",
  "AgreementId": "12345"
}
```

#### Direct Debit Behavior

| Payment Type | Event            | TransCode     | Description                            |
| ------------ | ---------------- | ------------- | -------------------------------------- |
| `BS`         | ReimbursedByBank | 239           | Bank initiated reimbursement           |
| `BS`         | Rejected         | 237           | No amount available, payment cancelled |
| `BS`         | ReimbursedByBank | 237 w. amount | Amount implicated and transferred back |
| `LS`         | Reimbursed       | 555           | Bank initiated reimbursement           |
| `LS`         | Rejected         | 530 w. amount | Customer initiated reimbursement       |

## Best Practices

### 1. Event Handling

* **Handle all event types** - Don't ignore events you don't expect
* **Log all events** - Keep detailed logs for debugging and audit
* **Process asynchronously** - Use queues for heavy processing
* **Implement idempotency** - Handle duplicate webhooks gracefully

### 2. Data Validation

* **Validate required fields** - Check all required properties
* **Verify data types** - Ensure amounts are numeric, dates are valid
* **Check business logic** - Validate amounts match expectations
* **Handle edge cases** - Account for zero amounts, missing references

### 3. Error Handling

* **Always return 200** - Acknowledge webhook receipt
* **Log errors** - Keep detailed error logs
* **Graceful degradation** - Continue processing other events
* **Monitor failures** - Set up alerts for processing errors

### 4. Security

* **Verify webhook origin** - Use checksums when available
* **Validate data integrity** - Check for tampering
* **Use HTTPS** - Secure all webhook endpoints
* **Rate limiting** - Prevent abuse of your endpoints

## Testing

### Test Scenarios

1. **Payment success** - Verify correct processing of successful payments
2. **Payment failure** - Test handling of failed payments
3. **Customer rejection** - Test rejection scenarios
4. **Bank reimbursement** - Test reimbursement handling
5. **Refund processing** - Test refund event handling
6. **Invalid data** - Test error handling with malformed data
7. **Duplicate webhooks** - Test idempotency

### Test Data Examples

```json
// Successful payment
{
  "Type": "Payment",
  "Event": "Succeeded",
  "InvoiceNumber": "TEST-001",
  "CustomerNumber": "CUST-001",
  "PaymentDueDate": "2023-12-31",
  "Currency": "DKK",
  "InvoiceAmount": "100.0000",
  "Amount": "100.0000",
  "PaymentType": "Visa",
  "PaymentReference": "TEST-REF-001",
  "AgreementId": "AGREE-001"
}

// Failed payment
{
  "Type": "Payment",
  "Event": "Failed",
  "InvoiceNumber": "TEST-002",
  "CustomerNumber": "CUST-002",
  "PaymentDueDate": "2023-12-31",
  "Currency": "DKK",
  "InvoiceAmount": "200.0000",
  "Amount": "0.0000",
  "PaymentType": "Visa",
  "PaymentReference": "TEST-REF-002",
  "AgreementId": "AGREE-002"
}
```

## Related Documentation

* [Webhooks Overview](webhooks.md) - General webhook information
* [Agreement Webhooks](agreement-webhooks.md) - Agreement lifecycle events
* [Order Webhooks](order-webhooks.md) - Order status tracking
* [API Documentation](../README.md) - Main API documentation