payfyio
Guides

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

TypeDefault severityMeaning
callback_verification_failedcriticalA 3DS callback failed signature/hash verification — someone may be forging a "paid" result.
provider_http_errorwarn / infoA provider call returned an HTTP error or failed. A burst suggests probing or an outage (401/403 → warn).
config_invalidwarnA provider was constructed with missing/invalid configuration.
retry_suppressedinfoA non-idempotent request timed out and was deliberately not retried (double-charge guard).
custominfoYour 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.

On this page