Consent Management
The ConsentController at /api/v1/privacy/consent provides a full consent lifecycle: recording, verification, withdrawal, renewal, and audit. Consent records support GDPR requirements including lawful basis tracking, double opt-in, cross-border transfer documentation, and granular communication preferences.
Consent Lifecycle
RECORD --> ACTIVE (or PENDING_DOUBLE_OPT_IN) --> WITHDRAWN
| ^
v |
EXPIRED ---------> RENEWED ---------------+Recording Consent
public record RecordConsentRequestDTO(
@NotNull UUID subjectId,
String subjectEmail,
String subjectType,
@NotBlank String purpose,
String purposeDescription,
@NotNull ConsentType consentType, // EXPLICIT, IMPLICIT, OPT_IN, OPT_OUT
boolean isGranted,
List<String> dataCategories,
List<String> processingActivities,
List<ThirdPartyRequestDTO> thirdParties,
boolean crossBorderTransfer,
List<String> transferCountries,
LegalBasis legalBasis, // CONSENT, CONTRACT, LEGAL_OBLIGATION, ...
String legalBasisDescription,
String collectionPoint,
String collectionMethod,
String privacyPolicyVersion,
String privacyPolicyUrl,
String termsVersion,
String optInText,
Instant expiresAt,
boolean doubleOptIn,
String sourceIp,
String userAgent,
String deviceId,
String sessionId,
Map<String, Object> geoLocation,
Map<String, Boolean> preferences,
Boolean emailMarketing,
Boolean smsMarketing,
Boolean pushNotifications,
Boolean analyticsTracking,
Boolean personalization,
Map<String, String> labels
) {}curl -X POST http://localhost:8082/api/v1/privacy/consent \
-H "X-Tenant-ID: {tenantId}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subjectId": "a1b2c3d4-...",
"subjectEmail": "user@example.com",
"purpose": "marketing_emails",
"purposeDescription": "Send promotional emails about new features",
"consentType": "EXPLICIT",
"isGranted": true,
"dataCategories": ["email", "name", "preferences"],
"processingActivities": ["email_marketing", "personalization"],
"legalBasis": "CONSENT",
"collectionPoint": "signup_form",
"collectionMethod": "web_form",
"privacyPolicyVersion": "2.1",
"expiresAt": "2027-02-12T00:00:00Z",
"doubleOptIn": true,
"emailMarketing": true,
"analyticsTracking": true,
"personalization": true
}'Response (201 Created): Returns a ConsentResponse with the full consent record including generated consentId.
Retrieving Consent Records
List All Consents
# All consents for the tenant
curl http://localhost:8082/api/v1/privacy/consent \
-H "X-Tenant-ID: {tenantId}"
# Filter by purpose
curl "http://localhost:8082/api/v1/privacy/consent?purpose=marketing_emails" \
-H "X-Tenant-ID: {tenantId}"Get by Subject
# All consents for a subject
curl http://localhost:8082/api/v1/privacy/consent/subject/{subjectId} \
-H "X-Tenant-ID: {tenantId}"
# Active consents only
curl http://localhost:8082/api/v1/privacy/consent/subject/{subjectId}/active \
-H "X-Tenant-ID: {tenantId}"
# By email
curl http://localhost:8082/api/v1/privacy/consent/subject/email/user@example.com \
-H "X-Tenant-ID: {tenantId}"Consent Verification
Check Consent
Quick check if a subject has valid consent for a purpose:
curl "http://localhost:8082/api/v1/privacy/consent/check?subjectId={id}&purpose=marketing_emails" \
-H "X-Tenant-ID: {tenantId}"Response:
{
"subjectId": "a1b2c3d4-...",
"purpose": "marketing_emails",
"hasValidConsent": true
}Verify for Processing
Detailed verification for data processing operations:
curl -X POST http://localhost:8082/api/v1/privacy/consent/verify \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"subjectId": "a1b2c3d4-...",
"purpose": "marketing_emails",
"dataCategories": ["email", "name"],
"processingActivity": "email_marketing"
}'Returns a ConsentVerificationResult with detailed information about consent coverage for each data category and processing activity.
Double Opt-In Confirmation
When consent is recorded with doubleOptIn: true, a verification token is generated. The subject must confirm:
curl -X POST http://localhost:8082/api/v1/privacy/consent/confirm-double-opt-in \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"consentId": "consent-abc123",
"verificationToken": "token-xyz789"
}'Withdrawing Consent
Withdraw Specific Consent
curl -X POST http://localhost:8082/api/v1/privacy/consent/{consentId}/withdraw \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"reason": "Subject requested withdrawal via support ticket"
}'Withdraw by Purpose
curl -X POST http://localhost:8082/api/v1/privacy/consent/subject/{subjectId}/withdraw \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"purpose": "marketing_emails",
"reason": "Unsubscribed from marketing"
}'Withdraw All (for DSR Erasure)
curl -X POST http://localhost:8082/api/v1/privacy/consent/subject/{subjectId}/withdraw-all \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"reason": "Data erasure request DSR-2026-001"
}'Returns a BulkWithdrawResponse with the count of withdrawn consent records.
Renewing Consent
curl -X POST http://localhost:8082/api/v1/privacy/consent/{consentId}/renew \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"newExpiryDate": "2028-02-12T00:00:00Z"
}'Communication Preferences
Update granular communication preferences for a consent record:
curl -X PUT http://localhost:8082/api/v1/privacy/consent/{consentId}/communication-preferences \
-H "X-Tenant-ID: {tenantId}" \
-H "Content-Type: application/json" \
-d '{
"emailMarketing": true,
"smsMarketing": false,
"pushNotifications": true,
"analyticsTracking": true,
"personalization": false
}'Expiring Consents
Monitor consents approaching expiration:
curl "http://localhost:8082/api/v1/privacy/consent/expiring?daysThreshold=30" \
-H "X-Tenant-ID: {tenantId}"Consent Statistics
curl "http://localhost:8082/api/v1/privacy/consent/statistics?daysPeriod=90" \
-H "X-Tenant-ID: {tenantId}"Returns a ConsentStatistics object with total counts, granted/withdrawn ratios, consent by purpose, and trend data.
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
CONSENT_NOT_FOUND | 404 | Consent record does not exist |
INVALID_CONSENT_STATE | 400 | Operation not valid for current consent state |
Source Files
| File | Path |
|---|---|
| Controller | control-plane/tenant-service/src/main/java/com/matih/tenant/privacy/controller/ConsentController.java |
| Service | control-plane/tenant-service/src/main/java/com/matih/tenant/privacy/service/ConsentService.java |
| Entity | control-plane/tenant-service/src/main/java/com/matih/tenant/privacy/ConsentRecord.java |