diff --git a/src/LeadProcessor.Domain/Entities/Lead.cs b/src/LeadProcessor.Domain/Entities/Lead.cs
new file mode 100644
index 0000000..d07dcd0
--- /dev/null
+++ b/src/LeadProcessor.Domain/Entities/Lead.cs
@@ -0,0 +1,118 @@
+namespace LeadProcessor.Domain.Entities;
+
+///
+/// Represents a lead entity captured from various sources.
+///
+public record Lead
+{
+ ///
+ /// Gets the unique identifier for the lead.
+ ///
+ public int Id { get; init; }
+
+ ///
+ /// Gets the tenant identifier for multi-tenancy support.
+ ///
+ public required string TenantId { get; init; }
+
+ ///
+ /// Gets the correlation identifier for idempotency and message tracking.
+ ///
+ public required string CorrelationId { get; init; }
+
+ ///
+ /// Gets the email address of the lead.
+ ///
+ public required string Email { get; init; }
+
+ ///
+ /// Gets the first name of the lead.
+ ///
+ public string? FirstName { get; init; }
+
+ ///
+ /// Gets the last name of the lead.
+ ///
+ public string? LastName { get; init; }
+
+ ///
+ /// Gets the phone number of the lead.
+ ///
+ public string? Phone { get; init; }
+
+ ///
+ /// Gets the company name of the lead.
+ ///
+ public string? Company { get; init; }
+
+ ///
+ /// Gets the source from which the lead originated (e.g., website, mobile app, referral).
+ ///
+ public required string Source { get; init; }
+
+ ///
+ /// Gets the metadata as a JSON string containing additional information about the lead.
+ ///
+ public string? Metadata { get; init; }
+
+ ///
+ /// Gets the UTC date and time when the lead was created.
+ ///
+ public DateTimeOffset CreatedAt { get; init; }
+
+ ///
+ /// Gets the UTC date and time when the lead was last updated.
+ ///
+ public DateTimeOffset UpdatedAt { get; init; }
+
+ ///
+ /// Validates that the email format is correct.
+ ///
+ ///
+ /// True if the email is in a valid format according to RFC 5322, otherwise false.
+ /// Returns false if email is null, empty, or whitespace.
+ ///
+ public bool HasValidEmail()
+ {
+ if (string.IsNullOrWhiteSpace(Email))
+ return false;
+
+ try
+ {
+ var addr = new System.Net.Mail.MailAddress(Email);
+ return addr.Address == Email;
+ }
+ catch (FormatException)
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Validates that the correlation ID is in GUID format.
+ ///
+ /// True if the correlation ID can be parsed as a GUID, otherwise false.
+ public bool IsCorrelationIdGuid()
+ {
+ return Guid.TryParse(CorrelationId, out _);
+ }
+
+ ///
+ /// Gets the full name of the lead by combining first and last names.
+ ///
+ /// The full name, or null if both names are empty.
+ public string? GetFullName()
+ {
+ var hasFirst = !string.IsNullOrWhiteSpace(FirstName);
+ var hasLast = !string.IsNullOrWhiteSpace(LastName);
+
+ return (hasFirst, hasLast) switch
+ {
+ (true, true) => $"{FirstName} {LastName}",
+ (true, false) => FirstName,
+ (false, true) => LastName,
+ _ => null
+ };
+ }
+}
+
diff --git a/src/LeadProcessor.Domain/Repositories/ILeadRepository.cs b/src/LeadProcessor.Domain/Repositories/ILeadRepository.cs
new file mode 100644
index 0000000..731b2a8
--- /dev/null
+++ b/src/LeadProcessor.Domain/Repositories/ILeadRepository.cs
@@ -0,0 +1,35 @@
+using LeadProcessor.Domain.Entities;
+
+namespace LeadProcessor.Domain.Repositories;
+
+///
+/// Repository interface for managing lead persistence operations.
+///
+public interface ILeadRepository
+{
+ ///
+ /// Saves a lead to the data store asynchronously.
+ ///
+ /// The lead entity to save.
+ /// Cancellation token to cancel the operation.
+ /// The saved lead entity with updated fields (e.g., Id, timestamps).
+ Task SaveLeadAsync(Lead lead, CancellationToken cancellationToken = default);
+
+ ///
+ /// Checks if a lead with the specified correlation ID already exists.
+ /// This method supports idempotency by allowing duplicate message detection.
+ ///
+ /// The correlation ID to check for.
+ /// Cancellation token to cancel the operation.
+ /// True if a lead with the correlation ID exists, otherwise false.
+ Task ExistsByCorrelationIdAsync(string correlationId, CancellationToken cancellationToken = default);
+
+ ///
+ /// Retrieves a lead by its correlation ID asynchronously.
+ ///
+ /// The correlation ID to search for.
+ /// Cancellation token to cancel the operation.
+ /// The lead entity if found, otherwise null.
+ Task GetByCorrelationIdAsync(string correlationId, CancellationToken cancellationToken = default);
+}
+