> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crypto-cash.world/llms.txt
> Use this file to discover all available pages before exploring further.

# Fiat Webhooks

> Webhook-и Fiat Module для інтеграторів: типи подій, структура payload, перевірка підпису та приклади.

# Fiat Webhooks

> **Примітка:** усі числові значення, суми та ідентифікатори в прикладах є ілюстративними та наведені лише для демонстрації.

## Огляд

Fiat Module використовує webhook-и Crypto-Cash, які надсилаються мерчанту після зміни статусу транзакції. Вони працюють лише якщо на Fiat API key налаштований параметр `webhookUrl`. Якщо `webhookUrl` не заданий, webhook-и не надсилаються.

> URL для сповіщень у платіжного провайдера та `webhookUrl` на Fiat API key — це різні речі. `webhookUrl` на Fiat API key — це адреса, на яку Crypto-Cash надсилає свої події мерчанту.

## Ключові параметри

| Параметр                 | Значення                                   |
| ------------------------ | ------------------------------------------ |
| Ціль webhook Crypto-Cash | `webhookUrl`, налаштований на Fiat API key |
| HTTP-метод               | `POST`                                     |
| Доставка                 | Асинхронна                                 |
| Формат даних             | `application/json`                         |

## Як працюють webhook-и

```
Користувач відкриває платіжний віджет
↓
Платіжний провайдер обробляє платіж
↓
Платіжний провайдер надсилає webhook у Crypto-Cash
↓
Crypto-Cash перевіряє підпис провайдера
↓
Crypto-Cash оновлює статус транзакції
↓
Crypto-Cash формує payment-подію
↓
Якщо на Fiat API key налаштований webhookUrl,
Crypto-Cash надсилає webhook асинхронно
```

## Webhook-и Crypto-Cash

Webhook-и Crypto-Cash надсилаються після payment-подій. Вони працюють лише якщо на Fiat API key налаштований `webhookUrl`.

При зміні статусу транзакції система формує payment-подію та асинхронно надсилає webhook на налаштований `webhookUrl`. Якщо `webhookUrl` не налаштований, webhook не надсилається.

HTTP-формат:

```
Method: POST
Content-Type: application/json
```

Кожен webhook містить поле `signature` у тілі payload. Мерчант використовує Fiat API key, щоб переконатися, що webhook надісланий Crypto-Cash і не був змінений.

Webhook payload і підпис зберігаються для аудиту та історії.

## Типи подій

| Подія               | Коли надсилається             | Тип          |
| ------------------- | ----------------------------- | ------------ |
| `payment::created`  | Транзакцію створено           | Проміжне     |
| `payment::waiting`  | Статус змінився на `Waiting`  | Проміжне     |
| `payment::paid`     | Статус змінився на `Paid`     | **Фінальне** |
| `payment::failed`   | Статус змінився на `Fail`     | **Фінальне** |
| `payment::canceled` | Статус змінився на `Canceled` | **Фінальне** |

**Проміжні події** (`payment::created`, `payment::waiting`) означають, що транзакція в роботі й можливі подальші зміни статусу.

**Фінальні події** (`payment::paid`, `payment::failed`, `payment::canceled`) означають, що транзакція досягла термінального стану:

| Фінальна подія      | Значення                                           |
| ------------------- | -------------------------------------------------- |
| `payment::paid`     | Криптовалюту успішно відправлено на адресу гаманця |
| `payment::failed`   | Платіж не був завершений                           |
| `payment::canceled` | Платіж скасовано                                   |

## Що має перевірити мерчант

При отриманні webhook Crypto-Cash:

1. Перевірити поле `signature` за допомогою Fiat API key (див. розділ «Підпис webhook»).
2. Прочитати `event.event_type`, щоб визначити подію.
3. Прочитати `event.data` — там повний стан транзакції.
4. Обробити подію залежно від того, проміжна вона чи фінальна.

> Поле `id` унікальне для кожної доставки webhook. Використовуйте його для дедуплікації обробки на своїй стороні.

## Підпис webhook Crypto-Cash

Кожен webhook Crypto-Cash містить поле `signature` у тілі payload.

Підпис формується за ідентифікатором і вмістом webhook:

```
payload = { id, delivered_at, event }
```

Мерчант перевіряє підпис так: перескладає той самий payload з отриманого webhook, **виключаючи поле `signature`**, і перевіряє його за допомогою Fiat API key.

Спосіб перевірки залежить від типу Fiat API key:

* `ED25519` — перевірте отриманий `signature`, використовуючи `publicKey` Fiat API.
* `LEGACY` — перескладіть очікуване значення signature, використовуючи `privateKey` Fiat API, і порівняйте його з отриманим.

Використовуйте ту саму пару Fiat API key, яка використовується для підписаних запитів мерчанта в API. Приватний ключ має залишатися на стороні мерчанта — не надсилайте його у відповідях на webhook, у логах або в зверненнях до підтримки.

## Приклади payload

### `payment::created`

```json theme={null}
{
  "id": "webhook-id",
  "delivered_at": "2026-04-16T10:00:01.000Z",
  "event": {
    "event_type": "payment::created",
    "timestamp": "2026-04-16T10:00:01.000Z",
    "data": {
      "id": "crypto-cash-transaction-id",
      "externalId": "merchant-order-id",
      "status": "New",
      "fiatCurrency": "SGD",
      "fiatAmount": "51",
      "currency": "USDT",
      "network": "TRC20",
      "address": "wallet-address",
      "cryptoAmount": null,
      "exchangeRate": null,
      "paymentMethod": null,
      "hash": null,
      "buyId": null,
      "withdrawId": null,
      "customerId": null,
      "merchantEarning": null,
      "merchantId": "merchant-id",
      "createdAt": "2026-04-16T10:00:00.000Z",
      "updatedAt": "2026-04-16T10:00:00.000Z"
    }
  },
  "signature": "signature"
}
```

### `payment::waiting`

```json theme={null}
{
  "id": "webhook-id",
  "delivered_at": "2026-04-16T10:00:15.000Z",
  "event": {
    "event_type": "payment::waiting",
    "timestamp": "2026-04-16T10:00:15.000Z",
    "data": {
      "id": "crypto-cash-transaction-id",
      "externalId": "merchant-order-id",
      "status": "Waiting",
      "fiatCurrency": "SGD",
      "fiatAmount": "51",
      "currency": "USDT",
      "network": "TRC20",
      "address": "wallet-address",
      "cryptoAmount": null,
      "exchangeRate": null,
      "paymentMethod": "card",
      "hash": null,
      "buyId": "provider-operation-id",
      "withdrawId": null,
      "customerId": "customer-id",
      "merchantEarning": null,
      "merchantId": "merchant-id",
      "createdAt": "2026-04-16T10:00:00.000Z",
      "updatedAt": "2026-04-16T10:00:10.000Z"
    }
  },
  "signature": "signature"
}
```

### `payment::paid`

```json theme={null}
{
  "id": "webhook-id",
  "delivered_at": "2026-04-16T10:07:30.000Z",
  "event": {
    "event_type": "payment::paid",
    "timestamp": "2026-04-16T10:07:30.000Z",
    "data": {
      "id": "crypto-cash-transaction-id",
      "externalId": "merchant-order-id",
      "status": "Paid",
      "fiatCurrency": "SGD",
      "fiatAmount": "51",
      "currency": "USDT",
      "network": "TRC20",
      "address": "wallet-address",
      "cryptoAmount": "50.12",
      "exchangeRate": "1.02",
      "paymentMethod": "card",
      "hash": "blockchain-hash",
      "buyId": "provider-operation-id",
      "withdrawId": "provider-withdraw-id",
      "customerId": "customer-id",
      "merchantEarning": "0.9306",
      "merchantId": "merchant-id",
      "createdAt": "2026-04-16T10:00:00.000Z",
      "updatedAt": "2026-04-16T10:07:00.000Z"
    }
  },
  "signature": "signature"
}
```

### `payment::failed`

```json theme={null}
{
  "id": "webhook-id",
  "delivered_at": "2026-04-16T10:02:05.000Z",
  "event": {
    "event_type": "payment::failed",
    "timestamp": "2026-04-16T10:02:05.000Z",
    "data": {
      "id": "crypto-cash-transaction-id",
      "externalId": "merchant-order-id",
      "status": "Fail",
      "fiatCurrency": "SGD",
      "fiatAmount": "51",
      "currency": "USDT",
      "network": "TRC20",
      "address": "wallet-address",
      "cryptoAmount": null,
      "exchangeRate": null,
      "paymentMethod": "card",
      "hash": null,
      "buyId": "provider-operation-id",
      "withdrawId": null,
      "customerId": "customer-id",
      "merchantEarning": null,
      "merchantId": "merchant-id",
      "createdAt": "2026-04-16T10:00:00.000Z",
      "updatedAt": "2026-04-16T10:02:00.000Z"
    }
  },
  "signature": "signature"
}
```

### `payment::canceled`

```json theme={null}
{
  "id": "webhook-id",
  "delivered_at": "2026-04-16T10:03:05.000Z",
  "event": {
    "event_type": "payment::canceled",
    "timestamp": "2026-04-16T10:03:05.000Z",
    "data": {
      "id": "crypto-cash-transaction-id",
      "externalId": "merchant-order-id",
      "status": "Canceled",
      "fiatCurrency": "SGD",
      "fiatAmount": "51",
      "currency": "USDT",
      "network": "TRC20",
      "address": "wallet-address",
      "cryptoAmount": null,
      "exchangeRate": null,
      "paymentMethod": "card",
      "hash": null,
      "buyId": "provider-operation-id",
      "withdrawId": null,
      "customerId": "customer-id",
      "merchantEarning": null,
      "merchantId": "merchant-id",
      "createdAt": "2026-04-16T10:00:00.000Z",
      "updatedAt": "2026-04-16T10:03:00.000Z"
    }
  },
  "signature": "signature"
}
```
