Saltar al contenido principal

RGPD / GDPR Compliance

Fyso provides built-in compliance primitives for operating AI agents under GDPR (called RGPD in Spanish/French contexts). This covers three areas: Data Processing Agreement acceptance by the tenant admin, session-level AI consent from end users, and the right to erasure via data suppression.

Data Processing Agreement (DPA)

Before using AI features in production, the tenant's administrator must accept the DPA. This acceptance is recorded with a timestamp and the acting admin's ID.

Accept the DPA

curl -X POST https://api.fyso.dev/api/auth/tenants/<tenantId>/dpa-accept \
-H "Authorization: Bearer <admin-token>"

Response:

{
"success": true,
"data": {
"dpaAcceptedAt": "2026-03-14T10:00:00.000Z",
"dpaAcceptedBy": "admin-user-id"
}
}

Check DPA Status

curl https://api.fyso.dev/api/auth/tenants/<tenantId>/dpa-status \
-H "Authorization: Bearer <admin-token>"

Response:

{
"success": true,
"data": {
"accepted": true,
"acceptedAt": "2026-03-14T10:00:00.000Z",
"acceptedBy": "admin-user-id"
}
}

End users interacting with an agent via any channel can be asked whether they consent to AI data processing. The consent flag is stored on the agent_sessions row.

curl -X POST https://api.fyso.dev/api/rgpd/sessions/<sessionId>/consent \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{ "consent": true }'

Set "consent": false to record a refusal.

What Happens With a Refusal

When ai_consent is false on a session, the agent runner returns a refusal response without making any LLM call. The response text is taken from the agent's fallbackMessages.consent_refused config key, defaulting to:

"I cannot process your request because AI data processing consent has been refused for this session."

ai_consent: null (not yet collected) allows processing — consent collection is the caller's responsibility and does not block the runner.

ai_consent valueRunner behavior
nullAllow — consent not yet collected
trueAllow — user has consented
falseBlock — return refusal, no LLM call

Data Suppression (Right to Erasure)

Delete all AI data associated with an end user across sessions and call logs.

curl -X DELETE \
"https://api.fyso.dev/api/rgpd/users/<externalRef>/ai-data" \
-H "Authorization: Bearer <api-key>"

Optional query parameter external_type filters by channel type if the same externalRef value is used across multiple channels.

curl -X DELETE \
"https://api.fyso.dev/api/rgpd/users/user-123/ai-data?external_type=web" \
-H "Authorization: Bearer <api-key>"

This endpoint requires admin role. It deletes:

  • All agent_sessions rows for the user
  • All ai_call_logs rows for those sessions
  • All _fyso_agent_memory facts for the user (if agent memory is enabled)

The deletion is recorded in the consent audit log.


Every consent and suppression event is recorded in consent_audit_log.

curl "https://api.fyso.dev/api/rgpd/audit-log?limit=50" \
-H "Authorization: Bearer <api-key>"

Query parameters:

ParameterDescription
external_refFilter by end-user identifier
limitMaximum records to return (default 50)

Response:

{
"success": true,
"data": [
{
"id": "uuid",
"event": "consent_given",
"externalRef": "user-123",
"actorId": null,
"metadata": { "consent": true },
"createdAt": "2026-03-14T10:05:00.000Z"
}
]
}

Event types: consent_given, consent_refused, data_suppressed.


Database Migrations

RGPD compliance requires two migrations:

MigrationChanges
0067dpa_accepted_at, dpa_accepted_by on tenants; ai_consent, ai_consent_at on agent_sessions; consent_audit_log table
0068_fyso_agent_memory table (agent memory — separate feature, same release)

Implementation Notes

  • DPA routes (/api/auth/tenants/:id/dpa-*) require admin authentication via requireAuth.
  • Consent and suppression routes (/api/rgpd/*) require tenant context (API key or admin session).
  • Suppression and audit log routes require admin role within the tenant.
  • The web widget and other public-facing channel endpoints do not enforce DPA — that check is the tenant operator's responsibility before deploying a public widget.