Integrations

Event Ingestion API

Connected applications can send normalized security and application events to FrameRadar. The first API version is intentionally small: one endpoint, one bearer token, and a JSON event payload.

Signal specification

FrameRadar events should use stable, framework-agnostic signal names. The first signal specification defines recommended categories, names, severity guidance, and payload fields.

Connector specification

Future framework connectors should translate framework-specific events into FrameRadar signals, report connector metadata, and use safe retry behavior without ingesting raw logs.

Endpoint and authorization

Event endpoint
POST https://www.passon-app.de/api/v1/events
Heartbeat endpoint
POST https://www.passon-app.de/api/v1/heartbeat
Authorization header
Authorization: Bearer {application.api_key}

Event JSON format

{
  "type": "auth.login_failed",
  "severity": "low",
  "source": "laravel",
  "payload": {
    "ip": "203.0.113.10",
    "path": "/login"
  }
}

Severity values are info, low, medium, high, and critical. If severity is omitted for a known signal, FrameRadar uses the registry default. Custom signal types must start with custom. and default to info.

Supported signal types

auth

  • auth.login_failed / default low
  • auth.login_succeeded_from_new_location / default low
  • auth.password_reset_requested / default info
  • auth.mfa_challenge_failed / default low

security

  • security.permission_denied / default low
  • security.suspicious_request_blocked / default medium
  • security.csrf_validation_failed / default low
  • security.rate_limit_exceeded / default low

application

  • application.error_rate_increased / default medium
  • application.background_job_failed / default low
  • application.deployment_completed / default info
  • application.feature_flag_changed / default info

configuration

  • configuration.debug_mode_enabled / default medium
  • configuration.security_header_missing / default low
  • configuration.secret_rotation_due / default info
  • configuration.integration_disconnected / default low

system

  • system.health_check_failed / default low
  • system.resource_usage_high / default medium
  • system.clock_drift_detected / default low
  • system.queue_backlog_high / default medium
  • system.connector_offline / default high

curl example

curl -X POST https://www.passon-app.de/api/v1/events \
  -H "Authorization: Bearer YOUR_APPLICATION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"auth.login_failed","severity":"low","source":"laravel","payload":{"path":"/login","account_identifier":"user@example.com","reason":"invalid_password"}}'

Heartbeat endpoint

Connected applications can send a lightweight heartbeat to update connector status and version information. This is useful for confirming that an application is still connected even when it has not sent recent events.

Connector offline detection depends on the Laravel scheduler running regularly. If the scheduler is not running, offline detections will not be evaluated until it resumes.

curl -X POST https://www.passon-app.de/api/v1/heartbeat \
  -H "Authorization: Bearer YOUR_APPLICATION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"connector_name":"laravel","connector_version":"0.1.0"}'

Laravel example

use Illuminate\Support\Facades\Http;

Http::withToken(config('services.frameradar.api_key'))
    ->post('https://www.passon-app.de/api/v1/events', [
        'type' => 'auth.login_failed',
        'severity' => 'low',
        'source' => 'laravel',
        'payload' => [
            'account_identifier' => optional(request()->user())->email,
            'reason' => 'invalid_password',
            'path' => request()->path(),
            'ip' => request()->ip(),
        ],
    ]);

JavaScript fetch example

await fetch('https://www.passon-app.de/api/v1/events', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_APPLICATION_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    type: 'custom.client_error',
    severity: 'medium',
    source: 'browser',
    payload: {
      message: 'Unhandled client error'
    }
  })
});