from __future__ import annotations from datetime import datetime from typing import Any, Literal from pydantic import BaseModel, ConfigDict, Field, SecretStr AddressBookScope = Literal["user", "group", "tenant", "system"] AddressSyncDirection = Literal["read_only", "import", "export", "two_way"] AddressSyncStatus = Literal["idle", "running", "succeeded", "failed", "conflict", "disabled"] AddressSyncDiagnosticSeverity = Literal["debug", "info", "warning", "error"] AddressSyncConflictStatus = Literal["open", "resolved", "ignored"] AddressSyncConflictResolution = Literal["keep_local", "use_remote", "merge", "manual", "ignored"] AddressCardDavAuthType = Literal["none", "basic", "bearer"] AddressSyncPlanAction = Literal["create", "update", "delete", "remote_create", "remote_update", "remote_delete", "conflict", "unchanged", "error"] AddressDistributionChannel = Literal["email", "postal", "internal_mail", "portal"] AddressContactPointChannel = Literal[ "email", "phone", "postal", "internal_mail", "portal", ] AddressChannelDecision = Literal[ "allowed", "opted_in", "preferred", "opted_out", "suppressed", "invalid", "returned", "temporarily_unavailable", ] AddressDistributionOutcome = Literal[ "usable", "unresolved", "invalid", "suppressed", "ambiguous", "duplicate", "policy_blocked", "provider_unavailable", "stale", ] AddressContactPointFallbackRule = Literal["none", "primary", "any"] AddressPostalFormat = Literal["domestic", "international"] ContactPointQualityState = Literal[ "valid", "invalid", "returned", "stale", "undeliverable", ] class ContactEmailPayload(BaseModel): label: str | None = Field(default=None, max_length=80) email: str = Field(max_length=320) is_primary: bool = False class ContactPhonePayload(BaseModel): label: str | None = Field(default=None, max_length=80) phone: str = Field(max_length=100) is_primary: bool = False class ContactPostalAddressPayload(BaseModel): label: str | None = Field(default=None, max_length=80) street: str | None = Field(default=None, max_length=500) postal_code: str | None = Field(default=None, max_length=40) locality: str | None = Field(default=None, max_length=255) region: str | None = Field(default=None, max_length=255) country: str | None = Field(default=None, max_length=255) is_primary: bool = False class AddressBookCreateRequest(BaseModel): scope_type: AddressBookScope = "user" group_id: str | None = Field(default=None, max_length=36) name: str = Field(min_length=1, max_length=255) description: str | None = None class AddressBookUpdateRequest(BaseModel): name: str | None = Field(default=None, min_length=1, max_length=255) description: str | None = None class AddressBookResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None scope_type: AddressBookScope scope_id: str | None = None name: str description: str | None = None source_kind: str source_ref: str | None = None read_only: bool sync_status: str | None = None sync_error: str | None = None contact_count: int = 0 deleted_at: datetime | None = None created_at: datetime updated_at: datetime class AddressBookListResponse(BaseModel): address_books: list[AddressBookResponse] class AddressListCreateRequest(BaseModel): name: str = Field(min_length=1, max_length=255) description: str | None = None class AddressListUpdateRequest(BaseModel): name: str | None = Field(default=None, min_length=1, max_length=255) description: str | None = None class AddressListEntryCreateRequest(BaseModel): contact_id: str = Field(max_length=36) contact_email_id: str | None = Field(default=None, max_length=36) contact_postal_address_id: str | None = Field(default=None, max_length=36) label: str | None = Field(default=None, max_length=255) class AddressListResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None address_book_id: str name: str description: str | None = None source_kind: str source_ref: str | None = None read_only: bool entry_count: int = 0 deleted_at: datetime | None = None created_at: datetime updated_at: datetime class AddressListListResponse(BaseModel): address_lists: list[AddressListResponse] class AddressListEntryResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str address_list_id: str contact_id: str contact_email_id: str | None = None contact_postal_address_id: str | None = None target_kind: str label: str | None = None order_index: int contact_display_name: str email: str | None = None postal_address: str | None = None created_at: datetime updated_at: datetime class AddressListEntryListResponse(BaseModel): entries: list[AddressListEntryResponse] class ContactCreateRequest(BaseModel): display_name: str | None = Field(default=None, max_length=255) given_name: str | None = Field(default=None, max_length=255) family_name: str | None = Field(default=None, max_length=255) organization: str | None = Field(default=None, max_length=255) role_title: str | None = Field(default=None, max_length=255) note: str | None = None tags: list[str] = Field(default_factory=list) emails: list[ContactEmailPayload] = Field(default_factory=list) phones: list[ContactPhonePayload] = Field(default_factory=list) postal_addresses: list[ContactPostalAddressPayload] = Field(default_factory=list) provenance: dict[str, Any] = Field(default_factory=dict) class ContactUpdateRequest(BaseModel): display_name: str | None = Field(default=None, max_length=255) given_name: str | None = Field(default=None, max_length=255) family_name: str | None = Field(default=None, max_length=255) organization: str | None = Field(default=None, max_length=255) role_title: str | None = Field(default=None, max_length=255) note: str | None = None tags: list[str] | None = None emails: list[ContactEmailPayload] | None = None phones: list[ContactPhonePayload] | None = None postal_addresses: list[ContactPostalAddressPayload] | None = None provenance: dict[str, Any] | None = None class ContactFieldProvenanceResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str contact_id: str field_path: str value: Any = None source_kind: str source_ref: str | None = None source_revision: str | None = None precedence: int selected: bool reason_code: str explanation: str | None = None visibility: str merge_record_id: str | None = None created_by_account_id: str | None = None metadata: dict[str, Any] = Field(default_factory=dict, validation_alias="metadata_") created_at: datetime class ContactPointQualityDecisionCreateRequest(BaseModel): model_config = ConfigDict(extra="forbid") channel: AddressContactPointChannel contact_point_id: str | None = Field(default=None, max_length=36) state: ContactPointQualityState reason_code: str | None = Field(default=None, max_length=120) reason: str | None = None evidence_ref: str | None = Field(default=None, max_length=1000) effective_from: datetime | None = None metadata: dict[str, Any] = Field(default_factory=dict) class ContactPointQualityDecisionResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None contact_id: str channel: AddressContactPointChannel contact_point_id: str | None = None state: ContactPointQualityState reason_code: str reason: str | None = None evidence_ref: str | None = None effective_from: datetime effective_until: datetime | None = None created_by_account_id: str | None = None metadata: dict[str, Any] = Field(default_factory=dict, validation_alias="metadata_") created_at: datetime updated_at: datetime class ContactPointQualityDecisionListResponse(BaseModel): decisions: list[ContactPointQualityDecisionResponse] = Field(default_factory=list) class ContactEmailResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str label: str | None = None email: str original_email: str = "" normalized_email: str = "" provenance: dict[str, Any] = Field(default_factory=dict) quality_state: ContactPointQualityState = "valid" quality_reason_code: str | None = None is_primary: bool class ContactPhoneResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str label: str | None = None phone: str original_phone: str = "" normalized_phone: str = "" provenance: dict[str, Any] = Field(default_factory=dict) quality_state: ContactPointQualityState = "valid" quality_reason_code: str | None = None is_primary: bool class ContactPostalAddressResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str label: str | None = None street: str | None = None postal_code: str | None = None locality: str | None = None region: str | None = None country: str | None = None original_value: dict[str, Any] = Field(default_factory=dict) normalized_value: dict[str, Any] = Field(default_factory=dict) provenance: dict[str, Any] = Field(default_factory=dict) quality_state: ContactPointQualityState = "valid" quality_reason_code: str | None = None is_primary: bool class ContactResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None address_book_id: str display_name: str given_name: str | None = None family_name: str | None = None organization: str | None = None role_title: str | None = None note: str | None = None tags: list[str] source_kind: str source_ref: str | None = None source_payload_kind: str | None = None source_revision: str | None = None provenance: dict[str, Any] emails: list[ContactEmailResponse] phones: list[ContactPhoneResponse] postal_addresses: list[ContactPostalAddressResponse] field_provenance: list[ContactFieldProvenanceResponse] = Field(default_factory=list) deleted_at: datetime | None = None created_at: datetime updated_at: datetime class ContactListResponse(BaseModel): contacts: list[ContactResponse] total: int offset: int limit: int has_more: bool class ContactDuplicateFeatureResponse(BaseModel): code: str label: str weight: int value: str class ContactDuplicateSuggestionResponse(BaseModel): left: ContactResponse right: ContactResponse score: int confidence: Literal["possible", "likely", "strong"] features: list[ContactDuplicateFeatureResponse] class ContactDuplicateSuggestionListResponse(BaseModel): suggestions: list[ContactDuplicateSuggestionResponse] = Field(default_factory=list) scanned_contacts: int candidate_pairs: int truncated: bool class ContactMergeRequest(BaseModel): model_config = ConfigDict(extra="forbid") winner_contact_id: str = Field(max_length=36) duplicate_contact_ids: list[str] = Field(min_length=1, max_length=20) reason: str = Field(min_length=3) field_sources: dict[str, str] = Field(default_factory=dict) contact_point_strategy: Literal["union", "winner_only"] = "union" source_precedence: list[str] = Field(default_factory=list, max_length=20) class ContactMergeRecoveryRequest(BaseModel): model_config = ConfigDict(extra="forbid") reason: str = Field(min_length=3) expected_after_hash: str = Field(min_length=64, max_length=64) class ContactMergeRecordResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None address_book_id: str winner_contact_id: str loser_contact_ids: list[str] status: str reason: str survivorship: dict[str, Any] decisions: list[dict[str, Any]] before_hash: str after_hash: str created_by_account_id: str | None = None recovered_at: datetime | None = None recovered_by_account_id: str | None = None recovery_action: str | None = None recovery_reason: str | None = None provenance: dict[str, Any] created_at: datetime updated_at: datetime class ContactMergeRecordListResponse(BaseModel): merges: list[ContactMergeRecordResponse] = Field(default_factory=list) class ContactRedirectResponse(BaseModel): requested_contact_id: str resolved_contact_id: str redirected: bool redirect_chain: list[str] = Field(default_factory=list) merge_record_ids: list[str] = Field(default_factory=list) class AddressQualityCorrectionResponse(BaseModel): contact_id: str display_name: str channel: AddressContactPointChannel contact_point_id: str | None = None state: ContactPointQualityState reason_code: str reason: str | None = None effective_from: datetime class AddressQualitySummaryResponse(BaseModel): contact_count: int contact_point_count: int quality_counts: dict[str, int] = Field(default_factory=dict) duplicate_suggestion_count: int correction_count: int corrections: list[AddressQualityCorrectionResponse] = Field(default_factory=list) truncated: bool = False class ContactChannelRuleCreateRequest(BaseModel): model_config = ConfigDict(extra="forbid") channel: AddressDistributionChannel purpose: str | None = Field(default=None, max_length=120) contact_point_id: str | None = Field(default=None, max_length=36) decision: AddressChannelDecision legal_basis: str | None = Field(default=None, max_length=255) evidence_ref: str | None = Field(default=None, max_length=1000) reason: str | None = None preference_rank: int | None = Field(default=None, ge=0, le=10000) locale: str | None = Field(default=None, max_length=20) effective_from: datetime | None = None effective_until: datetime | None = None metadata: dict[str, Any] = Field(default_factory=dict) class ContactChannelRuleResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None contact_id: str channel: AddressDistributionChannel purpose: str | None = None contact_point_id: str | None = None decision: AddressChannelDecision legal_basis: str | None = None evidence_ref: str | None = None reason: str | None = None preference_rank: int | None = None locale: str | None = None effective_from: datetime | None = None effective_until: datetime | None = None metadata: dict[str, Any] = Field(default_factory=dict, validation_alias="metadata_") created_by_account_id: str | None = None created_at: datetime updated_at: datetime class ContactChannelRuleListResponse(BaseModel): rules: list[ContactChannelRuleResponse] = Field(default_factory=list) class AddressSourceReferencePayload(BaseModel): provider: str = Field(min_length=1, max_length=120) resource_type: str = Field(min_length=1, max_length=120) resource_id: str = Field(min_length=1, max_length=1000) revision: str | None = Field(default=None, max_length=1000) fingerprint: str | None = Field(default=None, max_length=255) label: str | None = Field(default=None, max_length=500) metadata: dict[str, Any] = Field(default_factory=dict) class ContactPointResolveRequest(BaseModel): model_config = ConfigDict(extra="forbid") subject: AddressSourceReferencePayload effective_at: datetime purpose: str | None = Field(default=None, max_length=120) requested_channels: list[AddressDistributionChannel] = Field(default_factory=list) address_purpose: str | None = Field(default=None, max_length=80) fallback_rule: AddressContactPointFallbackRule = "primary" locale: str | None = Field(default=None, max_length=20) postal_format: AddressPostalFormat = "domestic" context: dict[str, Any] = Field(default_factory=dict) class ContactPointSourceRequestPayload(BaseModel): model_config = ConfigDict(extra="forbid") source_id: str = Field(min_length=1, max_length=1000) effective_at: datetime purpose: str | None = Field(default=None, max_length=120) requested_channels: list[AddressDistributionChannel] = Field(default_factory=list) address_purpose: str | None = Field(default=None, max_length=80) fallback_rule: AddressContactPointFallbackRule = "primary" locale: str | None = Field(default=None, max_length=20) postal_format: AddressPostalFormat = "domestic" max_items: int = Field(default=5000, ge=1, le=20000) context: dict[str, Any] = Field(default_factory=dict) class ContactPointSourceRequestResponse(ContactPointSourceRequestPayload): tenant_id: str class ContactPointCandidateResponse(BaseModel): channel: AddressDistributionChannel target: str target_key: str status: AddressDistributionOutcome contact_point_id: str | None = None address_purpose: str | None = None locale: str | None = None preferred: bool = False preference_rank: int | None = None reason_code: str | None = None explanation: str | None = None source: AddressSourceReferencePayload | None = None source_revision: str | None = None preference_revision: str | None = None consent_revision: str | None = None value: dict[str, Any] = Field(default_factory=dict) provenance: dict[str, Any] = Field(default_factory=dict) class DistributionExplanationResponse(BaseModel): code: str message: str severity: Literal["info", "warning", "error"] provider: str | None = None source: AddressSourceReferencePayload | None = None provenance: dict[str, Any] = Field(default_factory=dict) class ContactPointResolutionResponse(BaseModel): contract_version: str subject: AddressSourceReferencePayload status: AddressDistributionOutcome contact_id: str | None = None display_name: str | None = None candidates: list[ContactPointCandidateResponse] = Field(default_factory=list) excluded: list[ContactPointCandidateResponse] = Field(default_factory=list) explanations: list[DistributionExplanationResponse] = Field(default_factory=list) source_revision: str | None = None source_fingerprint: str | None = None provenance: dict[str, Any] = Field(default_factory=dict) class ContactPointSourcePreviewResponse(BaseModel): contract_version: str source: AddressSourceReferencePayload request: ContactPointSourceRequestResponse resolutions: list[ContactPointResolutionResponse] total_count: int usable_count: int excluded_count: int offset: int limit: int has_more: bool source_revision: str source_fingerprint: str generated_at: datetime provenance: dict[str, Any] = Field(default_factory=dict) class ContactPointSnapshotResponse(BaseModel): id: str tenant_id: str contract_version: str source: AddressSourceReferencePayload request: ContactPointSourceRequestResponse resolutions: list[ContactPointResolutionResponse] recipient_count: int excluded_count: int source_revision: str source_fingerprint: str snapshot_hash: str generated_at: datetime provenance: dict[str, Any] = Field(default_factory=dict) class AddressLookupResponse(BaseModel): contacts: list[ContactResponse] class AddressBookWriteDecisionResponse(BaseModel): address_book_id: str address_book_label: str | None = None operation: str allowed: bool reason: str message: str scope_type: AddressBookScope | None = None scope_id: str | None = None tenant_id: str | None = None source_kind: str | None = None read_only: bool = False required_scopes: list[str] = Field(default_factory=list) provenance: dict[str, Any] = Field(default_factory=dict) class AddressBookWriteTargetsResponse(BaseModel): targets: list[AddressBookWriteDecisionResponse] = Field(default_factory=list) class AddressSyncSourceCreateRequest(BaseModel): connector_type: str = Field(min_length=1, max_length=60) display_name: str = Field(min_length=1, max_length=255) external_account_ref: str | None = Field(default=None, max_length=1000) external_address_book_ref: str | None = Field(default=None, max_length=1000) sync_direction: AddressSyncDirection = "read_only" read_only: bool | None = None enabled: bool = True sync_token: str | None = None etag: str | None = Field(default=None, max_length=1000) remote_revision: str | None = Field(default=None, max_length=1000) metadata: dict[str, Any] = Field(default_factory=dict) class AddressSyncSourceUpdateRequest(BaseModel): display_name: str | None = Field(default=None, min_length=1, max_length=255) external_account_ref: str | None = Field(default=None, max_length=1000) external_address_book_ref: str | None = Field(default=None, max_length=1000) sync_direction: AddressSyncDirection | None = None read_only: bool | None = None enabled: bool | None = None sync_token: str | None = None etag: str | None = Field(default=None, max_length=1000) remote_revision: str | None = Field(default=None, max_length=1000) metadata: dict[str, Any] | None = None class AddressSyncAttemptFinishRequest(BaseModel): status: Literal["succeeded", "failed", "conflict"] sync_token: str | None = None etag: str | None = Field(default=None, max_length=1000) remote_revision: str | None = Field(default=None, max_length=1000) error: str | None = None diagnostic: dict[str, Any] | None = None class AddressSyncSourceResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None address_book_id: str connector_type: str display_name: str external_account_ref: str | None = None external_address_book_ref: str | None = None sync_direction: str read_only: bool enabled: bool status: str sync_token: str | None = None etag: str | None = None remote_revision: str | None = None last_attempted_at: datetime | None = None last_success_at: datetime | None = None last_error: str | None = None last_diagnostic: dict[str, Any] | None = None metadata: dict[str, Any] = Field(default_factory=dict) created_at: datetime updated_at: datetime class AddressSyncSourceListResponse(BaseModel): sync_sources: list[AddressSyncSourceResponse] class AddressSyncDiagnosticCreateRequest(BaseModel): severity: AddressSyncDiagnosticSeverity = "info" code: str = Field(min_length=1, max_length=120) message: str = Field(min_length=1) details: dict[str, Any] = Field(default_factory=dict) class AddressSyncDiagnosticResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None sync_source_id: str severity: str code: str message: str details: dict[str, Any] = Field(default_factory=dict) created_at: datetime updated_at: datetime class AddressSyncDiagnosticListResponse(BaseModel): diagnostics: list[AddressSyncDiagnosticResponse] class AddressSyncTombstoneCreateRequest(BaseModel): contact_id: str | None = Field(default=None, max_length=36) remote_uid: str | None = Field(default=None, max_length=1000) resource_href: str | None = Field(default=None, max_length=1000) local_deleted_at: datetime | None = None remote_deleted_at: datetime | None = None synced_at: datetime | None = None metadata: dict[str, Any] = Field(default_factory=dict) class AddressSyncTombstoneResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None sync_source_id: str address_book_id: str contact_id: str | None = None remote_uid: str | None = None resource_href: str | None = None local_deleted_at: datetime | None = None remote_deleted_at: datetime | None = None synced_at: datetime | None = None metadata: dict[str, Any] = Field(default_factory=dict) created_at: datetime updated_at: datetime class AddressSyncTombstoneListResponse(BaseModel): tombstones: list[AddressSyncTombstoneResponse] class AddressSyncConflictCreateRequest(BaseModel): contact_id: str | None = Field(default=None, max_length=36) remote_uid: str | None = Field(default=None, max_length=1000) resource_href: str | None = Field(default=None, max_length=1000) field_path: str = Field(min_length=1, max_length=500) local_value: dict[str, Any] | None = None remote_value: dict[str, Any] | None = None local_updated_at: datetime | None = None remote_updated_at: datetime | None = None metadata: dict[str, Any] = Field(default_factory=dict) class AddressSyncConflictResolveRequest(BaseModel): resolution: AddressSyncConflictResolution status: Literal["resolved", "ignored"] = "resolved" merged_payload: ContactCreateRequest | None = None class AddressSyncConflictResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: str tenant_id: str | None = None sync_source_id: str address_book_id: str contact_id: str | None = None remote_uid: str | None = None resource_href: str | None = None field_path: str local_value: dict[str, Any] | None = None remote_value: dict[str, Any] | None = None local_updated_at: datetime | None = None remote_updated_at: datetime | None = None status: str resolution: str | None = None resolved_at: datetime | None = None resolved_by_account_id: str | None = None metadata: dict[str, Any] = Field(default_factory=dict) created_at: datetime updated_at: datetime class AddressSyncConflictListResponse(BaseModel): conflicts: list[AddressSyncConflictResponse] class AddressCardDavDiscoveryRequest(BaseModel): url: str = Field(min_length=1, max_length=2000) auth_type: AddressCardDavAuthType = "none" username: str | None = Field(default=None, max_length=320) password: SecretStr | None = None bearer_token: SecretStr | None = None credential_ref: str | None = Field(default=None, max_length=1000) source_id: str | None = Field(default=None, max_length=36) class AddressCardDavAddressBookResponse(BaseModel): collection_url: str href: str display_name: str | None = None description: str | None = None ctag: str | None = None sync_token: str | None = None class AddressCardDavDiscoveryResponse(BaseModel): address_books: list[AddressCardDavAddressBookResponse] class AddressCredentialEnvelopeResponse(BaseModel): id: str scope_type: str scope_id: str | None = None name: str description: str | None = None credential_kind: str public_data: dict[str, Any] = Field(default_factory=dict) secret_keys: list[str] = Field(default_factory=list) secret_configured: bool = False allowed_modules: list[str] = Field(default_factory=list) inherit_to_lower_scopes: bool = False is_active: bool = True revision: str class AddressCredentialEnvelopeListResponse(BaseModel): credentials: list[AddressCredentialEnvelopeResponse] = Field(default_factory=list) class AddressCardDavSourceCreateRequest(BaseModel): collection_url: str = Field(min_length=1, max_length=2000) display_name: str | None = Field(default=None, max_length=255) auth_type: AddressCardDavAuthType = "none" username: str | None = Field(default=None, max_length=320) password: SecretStr | None = None bearer_token: SecretStr | None = None credential_ref: str | None = Field(default=None, max_length=1000) sync_direction: AddressSyncDirection = "read_only" read_only: bool | None = None sync_token: str | None = None etag: str | None = Field(default=None, max_length=1000) remote_revision: str | None = Field(default=None, max_length=1000) class AddressSyncRunRequest(BaseModel): force_full: bool = False password: SecretStr | None = None bearer_token: SecretStr | None = None class AddressSyncPlanStats(BaseModel): created: int = 0 updated: int = 0 deleted: int = 0 conflicts: int = 0 unchanged: int = 0 errors: int = 0 fetched: int = 0 full_sync: bool = False used_sync_token: bool = False sync_token: str | None = None etag: str | None = None remote_revision: str | None = None class AddressSyncPlanItemResponse(BaseModel): action: AddressSyncPlanAction href: str | None = None remote_uid: str | None = None contact_id: str | None = None display_name: str | None = None etag: str | None = None message: str | None = None class AddressSyncPlanResponse(BaseModel): sync_source: AddressSyncSourceResponse stats: AddressSyncPlanStats items: list[AddressSyncPlanItemResponse] class VCardImportRequest(BaseModel): content: str = Field(min_length=1) class VCardImportIssue(BaseModel): index: int message: str severity: Literal["warning", "error"] = "error" field: str | None = None line: int | None = None class VCardImportResponse(BaseModel): imported: int skipped: int contacts: list[ContactResponse] issues: list[VCardImportIssue] = Field(default_factory=list)