Security events
Observe abuse and probing on your payment surface with onSecurityEvent and the built-in notifiers.
payfyio runs inside your server and never phones home. To help you catch a problem before it affects your customers, it surfaces security-relevant signals — a 3D Secure callback that fails verification (a likely forgery attempt), repeated provider errors, a misconfiguration — through a hook you provide. You decide what to do with them: log, alert, email, or forward to your monitoring.
Events never contain card numbers, CVV, expiry, or secret keys. Keep it that way if you emit your own events via payment.emitSecurityEvent(...).
Event types
| Type | Default severity | Meaning |
|---|---|---|
callback_verification_failed | critical | A 3DS callback failed signature/hash verification — someone may be forging a "paid" result. |
provider_http_error | warn / info | A provider call returned an HTTP error or failed. A burst suggests probing or an outage (401/403 → warn). |
config_invalid | warn | A provider was constructed with missing/invalid configuration. |
retry_suppressed | info | A non-idempotent request timed out and was deliberately not retried (double-charge guard). |
custom | info | Your own signal, raised via emitSecurityEvent. |
Configuration
import { Payfyio, consoleNotifier, webhookNotifier } from '@fyio/payfyio';
const payment = new Payfyio({
providers: { /* … */ },
// Raw hook — called for every event. Best-effort: throwing here can never
// break a payment.
onSecurityEvent: (event) => {
if (event.severity === 'critical') {
myAlerting.page(event); // e.g. someone POSTing forged "paid" callbacks
}
},
// Ready-made handlers, invoked alongside onSecurityEvent.
securityNotifiers: [
consoleNotifier({ minSeverity: 'warn' }),
webhookNotifier({
url: 'https://ops.example.com/payfyio-alerts',
minSeverity: 'critical',
headers: { Authorization: 'Bearer <token>' },
}),
],
});The event shape
interface PayfyioSecurityEvent {
type: SecurityEventType;
severity: 'info' | 'warn' | 'critical';
provider?: string; // e.g. 'paytr'
message: string; // human-readable, safe to log
metadata?: Record<string, unknown>; // small, non-sensitive context
timestamp: string; // ISO
}Built-in notifiers
webhookNotifier(options)
POSTs each event as JSON to your endpoint, so you can fan out to email / Slack / PagerDuty on your own infrastructure — payfyio stays dependency-light (axios only) and never holds your mail credentials.
webhookNotifier({
url: 'https://ops.example.com/payfyio-alerts',
headers?: { /* auth, etc. */ },
minSeverity?: 'warn', // default 'warn'
throttleMs?: 300000, // de-dupe window, default 5 min; 0 disables
timeoutMs?: 5000,
});consoleNotifier(options)
Writes events to the console (console.error for critical, console.warn otherwise). A good floor of visibility in production logs.
consoleNotifier({ minSeverity: 'warn' });throttle(handler, options)
Wrap any handler to drop events below a severity and de-duplicate identical events (by type + provider + severity) within a window — prevents a burst of the same signal from flooding you. The built-in notifiers use it internally.
import { throttle } from '@fyio/payfyio';
const guarded = throttle(myHandler, { minSeverity: 'warn', windowMs: 5 * 60 * 1000 });Emitting your own events
Raise a custom signal from your own callback route or business logic:
payment.emitSecurityEvent({
type: 'custom',
severity: 'warn',
message: 'Checkout attempted with a mismatched order total',
metadata: { orderId },
});Notifiers run best-effort. A handler that throws or rejects is isolated and logged to the console — it can never fail the payment it is observing.