Fiatside

Developers

Webhooki

Webhook informuje Cię o zmianie stanu zamówienia. Nie zastępuje odczytu zamówienia: to powiadomienie, a nie źródło prawdy.

Opublikowany kontrakt, jeszcze nie otwarty

Webhooki nie są dziś wysyłane. Ich struktura, podpis i polityka ponowień są ustalone i opublikowane tutaj, aby można było wcześniej napisać i przetestować odbiornik.

01

Zdarzenia

Każde zdarzenie ma tę samą kopertę: id, typ, znacznik czasu i obiekt danych. Subskrybuj typy, które obsługujesz, i po cichu ignoruj pozostałe — nowe typy będą dodawane, a odbiornik, który zawiedzie na nieznanym typie, sam się psuje.

Zdarzenia
TypCo oznacza
order.createdZamówienie jest utworzone, a kurs zablokowany. Adres depozytowy jest przypisany.
order.deposit_detectedPrzychodząca transakcja jest widoczna w sieci przed potwierdzeniem. Użyj tego zdarzenia, aby uspokoić użytkownika, nigdy, aby cokolwiek dostarczyć.
order.confirmingLicznik potwierdzeń postępuje. Emitowany na każdym kroku, nie na każdym bloku.
order.deposit_confirmedOsiągnięto liczbę potwierdzeń wymaganą przez sieć.
order.underpaidOtrzymana kwota jest poniżej oczekiwanej kwoty poza tolerancją. Zamówienie nie jest utracone: oczekuje na wybór między doładowaniem, kontynuacją z otrzymaną kwotą lub zwrotem.
order.overpaidOtrzymana kwota przekracza oczekiwaną kwotę. Początkowa kwota pozostaje po zablokowanym kursie; nadwyżka jest obsługiwana osobno.
order.payout_sentPrzelew został wysłany w systemie płatności. Uwaga: wysłane nie jest otrzymane — pozostałe opóźnienie zależy od banku beneficjenta.
order.completedRozliczenie jest potwierdzone przez system płatności. Stan końcowy.
order.payout_failedSystem płatności odrzucił lub zwrócił przelew, podając powód. Nie wykonuje się automatycznej ponownej próby w przypadku zwrotu bankowego: przyczyna prawie zawsze leży w szczegółach.
order.refundedŚrodki zostały zwrócone, wyłącznie na adres źródłowy, pomniejszone o opłaty sieciowe.
02

Ładunek

Stała koperta, niezależnie od typu.

Przykładjson
{
  "id": "evt_01J9ZQF3K8N2M4X7",
  "type": "order.payout_sent",
  "created": 1788356981,
  "data": {
    "reference": "K7Q4-M2XB",
    "state": "PAYOUT_SENT",
    "railId": "sepa_instant",
    "netMinor": 91228,
    "currency": "EUR",
    "sentAt": "2026-09-02T12:21:44Z"
  }
}
03

Podpis

Każda dostawa zawiera nagłówek podpisu: znacznik czasu i HMAC-SHA256 obliczony na podstawie tego znacznika czasu, kropki i SUROWEGO treści żądania.

Fiatside-Signaturehttp
Fiatside-Signature: t=<timestamp unix>,v1=<hex hmac-sha256>
Weryfikacja, Node.jstypescript
import { createHmac, timingSafeEqual } from 'node:crypto'

// IMPORTANT : le corps doit etre le corps BRUT, avant tout parsing JSON.
// Re-serialiser l'objet change l'ordre des cles et invalide la signature.
export function verify(rawBody: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=') as [string, string]))
  const timestamp = Number(parts['t'])
  const signature = parts['v1']
  if (!timestamp || !signature) return false

  // Rejeu : une signature valide capturee hier ne doit pas etre rejouable aujourd'hui.
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false

  const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
  const a = Buffer.from(expected, 'hex')
  const b = Buffer.from(signature, 'hex')
  // Comparaison a temps constant : un === laisse fuiter la signature octet par octet.
  return a.length === b.length && timingSafeEqual(a, b)
}
  • Podpisuj surową treść przed jakimkolwiek parsowaniem. Ponowna serializacja obiektu JSON zmienia kolejność kluczy i białe znaki: podpis nie będzie już pasował i będziesz długo szukać błędu.
  • Porównuj w czasie stałym. Porównanie === zatrzymuje się na pierwszej różnej bajcie, co pozwala atakującemu zmierzyć oczekiwany podpis bajt po bajcie.
  • Odrzucaj poza 300-sekundowym oknem tolerancji. Bez tego sprawdzenia ważne żądanie przechwycone wczoraj pozostaje możliwe do odtworzenia dziś.
  • Odpowiadaj 200 przed przetwarzaniem. Umieść zdarzenie w kolejce i obsłuż je później: długie przetwarzanie powoduje przekroczenie limitu czasu, a tym samym ponowienie, mimo że zdarzenie zostało odebrane.
04

Ponowienia i kolejność

Każdy status inny niż 2xx lub brak odpowiedzi powoduje ponowienie zgodnie z poniższym harmonogramem.

Ponowienia i kolejność
PróbaOpóźnienie
1natychmiast
230 s
32 min
410 min
51 h
66 h
  • Kolejność dostarczania nie jest gwarantowana. Zdarzenie wypłaty może dotrzeć przed zdarzeniem potwierdzenia, które logicznie je poprzedza: ufaj stanowi zamówienia, a nie kolejności otrzymania.
  • To samo zdarzenie może nadejść dwukrotnie. Zapisz identyfikator zdarzenia i zignoruj identyfikator już obsłużony: idempotencja po Twojej stronie odbiorcy jest Twoim obowiązkiem i łatwo ją osiągnąć.
  • Nigdy nie ufaj kwotom z ładunku, aby cokolwiek zaksięgować po swojej stronie. Odczytaj zamówienie ponownie przez API: ładunek mówi, że coś się stało, API mówi dokładnie co.
  • Po ostatniej próbie zdarzenie jest odrzucane i pozostaje widoczne w dzienniku zdarzeń. Możesz je odtworzyć ręcznie.