{"openapi":"3.0.0","paths":{"/notifications/send":{"post":{"description":"Publishes a notification payload to the RabbitMQ priority queue. Accepts a JSON body with notification details including user ID, priority, channels, and optional scheduled time.","operationId":"NotificationController_send","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendNotificationDto"}}}},"responses":{"202":{"description":"Notification successfully validated and queued for delivery.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Notification successfully queued for delivery"},"timestamp":{"type":"string","format":"date-time","example":"2026-08-06T09:00:37.636Z"}}}}}},"400":{"description":"Invalid input payload (e.g., malformed UUID, missing priority, or invalid nested channels array)."},"500":{"description":"Internal server error (e.g., Message queue connection failure)"}},"summary":"Send a notification to a specific user","tags":["Notifications"]}},"/in-app":{"get":{"operationId":"InAppController_getUserNotifications","parameters":[{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of records per page","schema":{"default":20,"type":"number"}},{"name":"isRead","required":false,"in":"query","description":"Filter by unread status","schema":{"type":"boolean"}},{"name":"title","required":false,"in":"query","description":"Filter by title keyword","schema":{"type":"string"}},{"name":"fromDate","required":false,"in":"query","description":"Filter by date range (ISO format, e.g. 2024-01-01T00:00:00Z)","schema":{"type":"string"}},{"name":"toDate","required":false,"in":"query","description":"Filter by date range (ISO format, e.g. 2024-01-31T23:59:59Z)","schema":{"type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"User notifications retrieved successfully"},"400":{"description":"Valid user context is required to fetch messages."}},"summary":"Get all notifications for the authenticated user","tags":["In-App"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/in-app/{messageId}/read":{"patch":{"operationId":"InAppController_markAsRead","parameters":[{"name":"messageId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Notification marked as read successfully"},"400":{"description":"Invalid UUID format or missing user context"},"404":{"description":"Message not found"}},"summary":"Mark a specific notification as read","tags":["In-App"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/in-app/read-all":{"patch":{"operationId":"InAppController_markAllAsRead","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"All user notifications marked as read successfully"},"400":{"description":"Valid user context is required."}},"summary":"Mark all notifications as read for the authenticated user","tags":["In-App"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/provider-configs":{"post":{"operationId":"ProviderConfigController_create","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderConfigDto"}}}},"responses":{"201":{"description":"Provider configuration created successfully"},"400":{"description":"Invalid input data"}},"security":[{"bearer":[]}],"summary":"Create a new provider configuration (e.g., add SendGrid API keys)","tags":["Provider Configurations"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-required-permissions":["notification_admin"],"x-zudoku-badges":[{"label":"Protected","color":"blue"},{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}],"description":"### Permissions required\n- `notification_admin`"},"get":{"operationId":"ProviderConfigController_findAll","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"List of provider configurations retrieved successfully"}},"security":[{"bearer":[]}],"summary":"List all provider configurations","tags":["Provider Configurations"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-required-permissions":["notification_admin"],"x-zudoku-badges":[{"label":"Protected","color":"blue"},{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}],"description":"### Permissions required\n- `notification_admin`"}},"/provider-configs/{id}":{"get":{"operationId":"ProviderConfigController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Provider configuration retrieved successfully"},"400":{"description":"Invalid UUID format"},"404":{"description":"Provider configuration not found"}},"security":[{"bearer":[]}],"summary":"Get a specific provider configuration by ID","tags":["Provider Configurations"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-required-permissions":["notification_admin"],"x-zudoku-badges":[{"label":"Protected","color":"blue"},{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}],"description":"### Permissions required\n- `notification_admin`"},"patch":{"operationId":"ProviderConfigController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderConfigDto"}}}},"responses":{"200":{"description":"Provider configuration updated successfully"},"400":{"description":"Invalid input data or UUID format"},"404":{"description":"Provider configuration not found"}},"security":[{"bearer":[]}],"summary":"Update a provider configuration (e.g., rotate API keys or toggle isActive)","tags":["Provider Configurations"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-required-permissions":["notification_admin"],"x-zudoku-badges":[{"label":"Protected","color":"blue"},{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}],"description":"### Permissions required\n- `notification_admin`"},"delete":{"operationId":"ProviderConfigController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Provider configuration deleted successfully"},"400":{"description":"Invalid UUID format"},"404":{"description":"Provider configuration not found"}},"security":[{"bearer":[]}],"summary":"Delete a provider configuration","tags":["Provider Configurations"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-required-permissions":["notification_admin"],"x-zudoku-badges":[{"label":"Protected","color":"blue"},{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}],"description":"### Permissions required\n- `notification_admin`"}},"/audit-logs":{"get":{"description":"Use query parameters to filter by user, channel, status, or date range. Perfect for customer support dashboards.","operationId":"NotificationLogController_getLogs","parameters":[{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of records per page","schema":{"default":20,"type":"number"}},{"name":"userId","required":false,"in":"query","description":"Filter by specific User UUID","schema":{"type":"string"}},{"name":"channel","required":false,"in":"query","description":"Filter by channel (e.g., push, email)","schema":{"type":"string","enum":["email","sms","push","in-app"]}},{"name":"status","required":false,"in":"query","description":"Filter by status (SUCCESS or FAILED)","schema":{"type":"string","enum":["SUCCESS","FAILED","PENDING_TEMPLATE","READY_TO_SEND"]}},{"name":"startDate","required":false,"in":"query","description":"Filter logs from this date (ISO string)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Filter logs up to this date (ISO string)","schema":{"type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Paginated list of notification logs retrieved successfully"},"400":{"description":"Invalid query parameters"}},"summary":"Get paginated and filtered notification audit logs","tags":["Audit Logs"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/audit-logs/{id}":{"get":{"operationId":"NotificationLogController_getLogDetails","parameters":[{"name":"id","required":true,"in":"path","description":"The UUID of the audit log entry","schema":{"format":"uuid","type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Notification log details retrieved successfully"},"400":{"description":"Invalid UUID format"},"404":{"description":"Audit log not found"}},"summary":"Get the exact details of a specific notification attempt","tags":["Audit Logs"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/templates":{"get":{"operationId":"TemplateController_getTemplates","parameters":[{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of records per page","schema":{"default":20,"type":"number"}},{"name":"name","required":false,"in":"query","description":"Filter by template name","schema":{"type":"string"}},{"name":"userId","required":false,"in":"query","description":"Filter by user id","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status of template","schema":{"type":"string","enum":["active","inactive","archived","pending"]}},{"name":"type","required":false,"in":"query","description":"Filter by type of template","schema":{"type":"string","enum":["email","sms","push"]}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Paginated list of templates"},"400":{"description":"Invalid query parameters"}},"summary":"Get templates","tags":["Templates"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]},"post":{"operationId":"TemplateController_createTemplate","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateInputDTO"}}}},"responses":{"201":{"description":"Template created successfully"},"400":{"description":"Invalid input data"},"500":{"description":"Internal server error while syncing with external service"}},"summary":"Create a new template","tags":["Templates"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/templates/{id}":{"get":{"operationId":"TemplateController_getTemplateById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Template details"},"404":{"description":"Template not found"}},"summary":"Get template by ID","tags":["Templates"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]},"patch":{"operationId":"TemplateController_updateTemplate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Template updated successfully"},"400":{"description":"Invalid input data"},"404":{"description":"Template not found"},"500":{"description":"Internal server error while syncing with external service"}},"summary":"Update an existing template","tags":["Templates"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/health":{"get":{"operationId":"HealthController_check","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"Service is healthy"},"503":{"description":"Service is unavailable (e.g., database disconnected)"}},"summary":"Health check endpoint","tags":["Health"],"x-public-access":true,"x-zudoku-badges":[{"label":"Public","color":"blue"}]}},"/users/register":{"post":{"operationId":"UserController_register","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterUserDto"}}}},"responses":{"201":{"description":"User registered/updated successfully"},"400":{"description":"Invalid input data"},"409":{"description":"User registration conflict"}},"summary":"Register user (or update existing) and set FCM token","tags":["Users"],"x-expose-to-gateways":["admin-apigw","borrower-apigw","openapi-apigw"],"x-zudoku-badges":[{"label":"Admin","color":"gray"},{"label":"Borrower","color":"gray"},{"label":"OpenAPI","color":"gray"}]}},"/internal/events/tenants":{"post":{"description":"Consumes an internal event to create or update a tenant record.","operationId":"InternalEventController_handleTenantEvent","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertTenantDto"}}}},"responses":{"202":{"description":"Tenant event processed successfully.","content":{"application/json":{"schema":{"example":{"message":"Tenant event processed"}}}}},"400":{"description":"Invalid payload."}},"summary":"Upsert a Tenant","tags":["InternalEvent"]}},"/internal/events/users":{"post":{"description":"Consumes an internal event to create or update a subscriber record from Keycloak.","operationId":"InternalEventController_handleUserEvent","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSubscriberDto"}}}},"responses":{"202":{"description":"User event processed successfully.","content":{"application/json":{"schema":{"example":{"message":"User event processed"}}}}},"400":{"description":"Invalid payload."}},"summary":"Upsert a Subscriber/User","tags":["InternalEvent"]}},"/api/health/live":{"get":{"operationId":"HealthController_checkLive","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"The Health Check is successful","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"info":{"type":"object","example":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"error":{"type":"object","example":{},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"details":{"type":"object","example":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true}}}}}}},"503":{"description":"The Health Check is not successful","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"error"},"info":{"type":"object","example":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"error":{"type":"object","example":{"redis":{"status":"down","message":"Could not connect"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"details":{"type":"object","example":{"database":{"status":"up"},"redis":{"status":"down","message":"Could not connect"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true}}}}}}}},"tags":["Health"]}},"/api/health/ready":{"get":{"operationId":"HealthController_checkReady","parameters":[{"name":"accept-language","in":"header","required":false,"schema":{"default":"en"}}],"responses":{"200":{"description":"The Health Check is successful","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"info":{"type":"object","example":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"error":{"type":"object","example":{},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"details":{"type":"object","example":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true}}}}}}},"503":{"description":"The Health Check is not successful","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"error"},"info":{"type":"object","example":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"error":{"type":"object","example":{"redis":{"status":"down","message":"Could not connect"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"details":{"type":"object","example":{"database":{"status":"up"},"redis":{"status":"down","message":"Could not connect"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true}}}}}}}},"tags":["Health"]}}},"info":{"title":"notification-service","description":"# Notification Service\n\nDelivers **notifications to customers and staff** across email, push, and in-app channels.\n\n## Overview\nSends messages across channels, keeps a history of in-app notifications, records delivery outcomes, and manages reusable templates and the providers that deliver each channel. Messages are accepted for delivery and sent in the background.\n\n## Why it exists\nMany parts of the lending process need to notify people, and each building its own messaging would be inconsistent and hard to track. Centralizing delivery means every service sends notifications the same way, with shared templates and a single record of what was sent.\n\n## Authentication\nEndpoints require an authenticated request, and access is further restricted per endpoint by permission; administrative actions such as configuring providers require elevated permission.","version":"1.0.0","contact":{}},"tags":[],"servers":[{"url":"http://localhost:3000"},{"url":"https://api-dev.alpha.looms.cloud"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"NotificationChannel":{"type":"object","properties":{"type":{"type":"string","enum":["email","sms","push","in-app"],"example":"email"},"data":{"type":"object","example":{"title":"Deposit Received","message":"$500 credited."}},"templateName":{"type":"string","example":"fintech-alert","description":"The template identifier"},"message":{"type":"string","example":"expire soon"},"title":{"type":"string","example":"Deposit Received","description":"The title of the notification (for logging and mock strategy)"},"link":{"type":"string","example":"https://example.com/deposit-received","description":"Notification link (e.g., URL or deep link). Optional and can be used for logging or mock strategy."}},"required":["type","data","templateName","message","title","link"]},"SendNotificationDto":{"type":"object","properties":{"tenantId":{"type":"string","example":"b1aabc99-9c0b-4ef8-bb6d-6bb9bd380a11","description":"The UUID of the tenant"},"userId":{"type":"string","example":"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11","description":"The UUID of the target user"},"priority":{"type":"number","enum":[10,1],"example":10},"channels":{"example":[{"type":"email","data":{"title":"Deposit Received","message":"$500 credited."},"templateName":"fintech-alert","message":"expire soon"}],"type":"array","items":{"$ref":"#/components/schemas/NotificationChannel"}},"scheduledAt":{"type":"string","description":"ISO Date string. MUST include timezone (Z or offset). E.g., 2026-02-25T11:05:00Z or 2026-02-25T11:05:00+08:00","example":"2026-02-25T11:05:00+08:00"},"metadata":{"type":"object","example":{"title":"Metadata","message":"For internanl use only"}}},"required":["tenantId","userId","priority","channels"]},"CreateProviderConfigDto":{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms","push","in-app"],"example":"email"},"providerId":{"type":"string","example":"sendgrid","description":"Internal identifier for the provider"},"credentials":{"type":"object","example":{"user":"apikey","pass":"SG.12345..."},"description":"JSON object containing the provider API keys/credentials"},"isActive":{"type":"boolean","example":true,"description":"Set to true to make this the active provider for the channel"}},"required":["channel","providerId","credentials","isActive"]},"UpdateProviderConfigDto":{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms","push","in-app"],"example":"email"},"providerId":{"type":"string","example":"sendgrid","description":"Internal identifier for the provider"},"credentials":{"type":"object","example":{"user":"apikey","pass":"SG.12345..."},"description":"JSON object containing the provider API keys/credentials"},"isActive":{"type":"boolean","example":true,"description":"Set to true to make this the active provider for the channel"}}},"CreateTemplateInputDTO":{"type":"object","properties":{"name":{"type":"string","description":"Name of the template"},"content":{"type":"string","description":"Content of the template"},"status":{"type":"string","description":"Status of the template","enum":["active","inactive","archived","pending"],"default":"pending"},"type":{"type":"string","description":"Type of the template","enum":["email","sms","push"]},"projectData":{"type":"object","description":"JSON object of grapejs which contains the project data for the template.","example":{"key1":"value1","key2":"value2"}}},"required":["name","content","status","type"]},"RegisterUserDto":{"type":"object","properties":{"fcmToken":{"type":"string","example":"fcm-token-string"},"email":{"type":"string","example":"user@example.com"},"userId":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"phoneNumber":{"type":"string","example":"99009900"}},"required":["fcmToken","email","userId","phoneNumber"]},"UpsertTenantDto":{"type":"object","properties":{"id":{"type":"number","example":9,"description":"The internal ID of the tenant"},"tenant_id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000","description":"The UUID of the tenant"},"name":{"type":"string","example":"Tenant Name","description":"The name of the tenant"}},"required":["id","tenant_id","name"]},"UpsertSubscriberDto":{"type":"object","properties":{"tenant_id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000","description":"The UUID of the tenant"},"keycloak_uuid":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440001","description":"The UUID of the subscriber in Keycloak"},"email":{"type":"string","example":"user@example.com","description":"The email of the subscriber"},"first_name":{"type":"string","example":"John","description":"The first name of the subscriber"},"last_name":{"type":"string","example":"Doe","description":"The last name of the subscriber"},"phone_number":{"type":"string","example":"+1234567890","description":"The phone number of the subscriber"},"type":{"type":"string","example":"subscriber","description":"The type of the subscriber"},"status":{"type":"string","example":"active","description":"The status of the subscriber"},"__deleted":{"type":"string","example":"false","description":"Indicates if the subscriber is deleted"}},"required":["tenant_id","keycloak_uuid","email","first_name","last_name","phone_number","type","status","__deleted"]}}}}