> ## Documentation Index
> Fetch the complete documentation index at: https://docs.contactsmanager.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Inviting Users

> Comprehensive invite system for user acquisition and growth

# Inviting Users

The ContactsManager SDK provides a powerful invite system that enables controlled app growth, user acquisition tracking, and viral loop implementation. The invite service supports multiple distribution methods and provides detailed analytics for measuring growth effectiveness.

## Accessing the Invite Service

The invite service is accessed through the ContactsManager shared instance:

<CodeGroup>
  ```swift Swift theme={null}
  import ContactsManager

  let cm = ContactsService.shared
  let inviteService = cm.invites

  // Access invite properties and methods
  let inviteCode = await inviteService.code
  let inviteLink = await inviteService.link
  let remainingInvites = await inviteService.remaining()
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

## Invite Code Management

### Getting Current Invite Code

Retrieve the user's current invite code, or create one if none exists:

<CodeGroup>
  ```swift Swift theme={null}
  let inviteCode = await cm.invites.code

  if let code = inviteCode {
      print("Your invite code: \(code)")
      // Display code to user for sharing
  } else {
      print("Unable to get invite code")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Getting Invite Link

Retrieve the full invite URL for web-based sharing:

<CodeGroup>
  ```swift Swift theme={null}
  let inviteLink = await cm.invites.link

  if let link = inviteLink {
      print("Share this link: \(link)")
      // Use link for social sharing, email, etc.
  } else {
      print("Unable to get invite link")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Creating New Invites

Manually create a new invite (useful for generating fresh codes):

<CodeGroup>
  ```swift Swift theme={null}
  let newInvite = await cm.invites.createInvite()

  if let invite = newInvite {
      print("New invite code: \(invite.inviteCode)")
      print("New invite URL: \(invite.inviteUrl)")
      print("Expires at: \(invite.expiresAt)")
  } else {
      print("Failed to create new invite")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

## Invite Validation and Redemption

### Validating Invite Codes

Validate an invite code before allowing redemption:

<CodeGroup>
  ```swift Swift theme={null}
  let validation = await cm.invites.validateCode(code: "ABC123")

  if let result = validation {
      if result.valid {
          print("Valid invite from: \(result.inviter?.displayName ?? "Unknown")")
          print("Organization: \(result.organizationName ?? "N/A")")
          print("Remaining invites: \(result.remainingInvites ?? 0)")
      } else {
          print("Invalid invite: \(result.message)")
      }
  } else {
      print("Unable to validate invite code")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Redeeming Invites

Redeem an invite code for a new user:

<CodeGroup>
  ```swift Swift theme={null}
  let success = await cm.invites.redeemInvite(
      code: "ABC123", 
      for: "new_user_id_123"
  )

  if success {
      print("Invite redeemed successfully")
      // Proceed with user onboarding
  } else {
      print("Failed to redeem invite")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Getting Invite Details (Public)

Get detailed invite information for landing pages (doesn't require authentication):

<CodeGroup>
  ```swift Swift theme={null}
  let details = await cm.invites.getInviteDetails(for: "ABC123")

  if let inviteDetails = details {
      if inviteDetails.valid {
          print("Invited by: \(inviteDetails.inviter?.displayName ?? "Someone")")
          print("Join \(inviteDetails.organizationName ?? "this app")")
      } else {
          print("Invite expired or invalid")
      }
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

## Invite Analytics and Tracking

### Checking Remaining Invites

Get the number of invites the current user has left:

<CodeGroup>
  ```swift Swift theme={null}
  let remaining = await cm.invites.remaining()
  print("You have \(remaining) invites remaining")

  // Use this to show invite limits in UI
  if remaining > 0 {
      // Show invite button
  } else {
      // Show "no invites left" message
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Getting Invited Users

Retrieve the list of users invited by the current user:

<CodeGroup>
  ```swift Swift theme={null}
  let invitedUsers = await cm.invites.invited()

  print("You've invited \(invitedUsers.count) users:")
  for user in invitedUsers {
      print("- \(user.displayName ?? "Unknown")")
  }

  // Use for showing invite success and building social proof
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Finding Who Invited You

Get information about who invited the current user:

<CodeGroup>
  ```swift Swift theme={null}
  let inviter = await cm.invites.invitedBy()

  if let whoInvitedMe = inviter {
      print("You were invited by: \(whoInvitedMe.displayName ?? "Unknown")")
      // Show connection to inviter in onboarding
      // Enable features that connect inviter and invitee
  } else {
      print("You joined without an invite")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

## Bulk Email Invitations

### Checking Email Invite Availability

Verify if bulk email invites are available for your organization:

<CodeGroup>
  ```swift Swift theme={null}
  let emailAvailable = await cm.invites.isBulkInviteEmailAvailable()

  if emailAvailable {
      // Show email invite options
      print("Email invites are available")
  } else {
      // Show setup instructions or alternative invite methods
      print("Email invites require domain verification")
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Sending Bulk Email Invites

Send invite emails to multiple contacts at once:

<CodeGroup>
  ```swift Swift theme={null}
  // Get contacts to invite (from recommendations or user selection)
  let contactsToInvite = await cm.people.fetch(
      matching: [.suggestedInvite], 
      limit: 10
  )

  let emailBody = """
  Hi there!

  I've been using this amazing app and thought you'd love it too. 
  It's helped me stay organized and connect with friends.

  Join me and let's explore it together!

  Best,
  [Your name]
  """

  let result = await cm.invites.sendBulkInviteEmails(
      contacts: contactsToInvite,
      emailBody: emailBody
  )

  if let response = result {
      if response.success {
          print("Sent \(response.emailsSent) invites successfully")
          if !response.failedEmails.isEmpty {
              print("Failed to send to: \(response.failedEmails.joined(separator: ", "))")
          }
      } else {
          print("Email invite failed: \(response.message)")
      }
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

## Building Invite Flows

### Basic Invite Sharing

Create a simple invite sharing interface:

<CodeGroup>
  ```swift Swift theme={null}
  struct InviteView: View {
      @State private var inviteCode: String?
      @State private var inviteLink: String?
      @State private var remainingInvites: Int = 0
      @State private var isLoading = true
      
      var body: some View {
          VStack(spacing: 20) {
              if isLoading {
                  ProgressView("Loading invite info...")
              } else {
                  VStack(spacing: 16) {
                      Text("Invite Friends")
                          .font(.title2)
                          .fontWeight(.bold)
                      
                      Text("You have \(remainingInvites) invites remaining")
                          .foregroundColor(.secondary)
                      
                      if let code = inviteCode {
                          VStack {
                              Text("Your Invite Code")
                                  .font(.headline)
                              Text(code)
                                  .font(.title)
                                  .fontWeight(.bold)
                                  .padding()
                                  .background(Color.gray.opacity(0.1))
                                  .cornerRadius(8)
                          }
                      }
                      
                      if let link = inviteLink {
                          ShareLink(
                              item: URL(string: link)!,
                              message: Text("Join me on this amazing app!")
                          ) {
                              Label("Share Invite Link", systemImage: "square.and.arrow.up")
                                  .frame(maxWidth: .infinity)
                                  .padding()
                                  .background(Color.blue)
                                  .foregroundColor(.white)
                                  .cornerRadius(8)
                          }
                      }
                  }
              }
          }
          .padding()
          .onAppear {
              loadInviteInfo()
          }
      }
      
      private func loadInviteInfo() async {
          let cm = ContactsService.shared
          
          async let code = cm.invites.code
          async let link = cm.invites.link
          async let remaining = cm.invites.remaining()
          
          let (inviteCode, inviteLink, remainingCount) = await (code, link, remaining)
          
          DispatchQueue.main.async {
              self.inviteCode = inviteCode
              self.inviteLink = inviteLink
              self.remainingInvites = remainingCount
              self.isLoading = false
          }
      }
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Invite Redemption Flow

Handle invite code redemption during onboarding:

<CodeGroup>
  ```swift Swift theme={null}
  struct InviteRedemptionView: View {
      @State private var inviteCode = ""
      @State private var isValidating = false
      @State private var validationResult: ValidateInviteCodeResponse?
      @State private var showError = false
      
      var body: some View {
          VStack(spacing: 20) {
              Text("Enter Invite Code")
                  .font(.title2)
                  .fontWeight(.bold)
              
              TextField("Invite Code", text: $inviteCode)
                  .textFieldStyle(RoundedBorderTextFieldStyle())
                  .autocapitalization(.allCharacters)
                  .onChange(of: inviteCode) { newValue in
                      if newValue.count == 6 {
                          validateInvite()
                      }
                  }
              
              if isValidating {
                  ProgressView("Validating...")
              }
              
              if let result = validationResult {
                  if result.valid {
                      VStack {
                          Text("✅ Valid Invite")
                              .foregroundColor(.green)
                              .fontWeight(.bold)
                          
                          if let inviter = result.inviter {
                              Text("Invited by: \(inviter.displayName ?? "Unknown")")
                          }
                          
                          if let orgName = result.organizationName {
                              Text("Organization: \(orgName)")
                          }
                          
                          Button("Join App") {
                              redeemInvite()
                          }
                          .buttonStyle(.borderedProminent)
                      }
                  } else {
                      Text("❌ \(result.message)")
                          .foregroundColor(.red)
                  }
              }
          }
          .padding()
          .alert("Error", isPresented: $showError) {
              Button("OK") { }
          } message: {
              Text("Unable to validate invite code")
          }
      }
      
      private func validateInvite() {
          guard inviteCode.count == 6 else { return }
          
          isValidating = true
          
          Task {
              let result = await ContactsService.shared.invites.validateCode(code: inviteCode)
              
              DispatchQueue.main.async {
                  self.isValidating = false
                  self.validationResult = result
                  if result == nil {
                      self.showError = true
                  }
              }
          }
      }
      
      private func redeemInvite() {
          // Implement redemption logic with your user ID
          Task {
              let success = await ContactsService.shared.invites.redeemInvite(
                  code: inviteCode,
                  for: "current_user_id"
              )
              
              if success {
                  // Navigate to main app
              } else {
                  // Show error
              }
          }
      }
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

### Invite Analytics Dashboard

Display invite performance and user relationships:

<CodeGroup>
  ```swift Swift theme={null}
  struct InviteAnalyticsView: View {
      @State private var invitedUsers: [Contact] = []
      @State private var invitedBy: Contact?
      @State private var remainingInvites: Int = 0
      @State private var isLoading = true
      
      var body: some View {
          NavigationView {
              List {
                  Section("Your Invite Status") {
                      HStack {
                          Text("Remaining Invites")
                          Spacer()
                          Text("\(remainingInvites)")
                              .fontWeight(.bold)
                      }
                      
                      if let inviter = invitedBy {
                          HStack {
                              Text("Invited by")
                              Spacer()
                              Text(inviter.displayName ?? "Unknown")
                          }
                      }
                  }
                  
                  if !invitedUsers.isEmpty {
                      Section("People You've Invited (\(invitedUsers.count))") {
                          ForEach(invitedUsers, id: \.contactId) { user in
                              HStack {
                                  VStack(alignment: .leading) {
                                      Text(user.displayName ?? "Unknown")
                                          .fontWeight(.medium)
                                      if let email = user.cmContact?.emailAddresses.first?.value {
                                          Text(email)
                                              .font(.caption)
                                              .foregroundColor(.secondary)
                                      }
                                  }
                                  Spacer()
                                  Image(systemName: "checkmark.circle.fill")
                                      .foregroundColor(.green)
                              }
                          }
                      }
                  }
              }
              .navigationTitle("Invite Analytics")
              .refreshable {
                  await loadAnalytics()
              }
          }
          .onAppear {
              Task {
                  await loadAnalytics()
              }
          }
      }
      
      private func loadAnalytics() async {
          let cm = ContactsService.shared
          
          async let invited = cm.invites.invited()
          async let inviter = cm.invites.invitedBy()
          async let remaining = cm.invites.remaining()
          
          let (invitedList, inviterContact, remainingCount) = await (invited, inviter, remaining)
          
          DispatchQueue.main.async {
              self.invitedUsers = invitedList
              self.invitedBy = inviterContact
              self.remainingInvites = remainingCount
              self.isLoading = false
          }
      }
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

## Best Practices

### Invite Limit Management

* **Start Conservative**: Begin with 3-5 invites per user to create scarcity
* **Reward Quality**: Give additional invites to users whose invitees become active
* **Monitor Growth**: Adjust limits based on server capacity and user acquisition goals

### User Experience

* **Clear Value Proposition**: Explain why users should invite friends
* **Social Proof**: Show mutual connections and successful invitations
* **Immediate Connection**: Help invited users connect with their inviter quickly

### Growth Optimization

* **Track Conversion**: Monitor invite-to-signup and invite-to-active-user rates
* **A/B Test Messages**: Experiment with different invite email templates
* **Analyze Networks**: Identify users who bring high-quality new members

### Privacy Considerations

* **Minimal Exposure**: Invite codes contain no personal information
* **User Control**: Allow users to disable invite notifications
* **Data Retention**: Implement policies for invite relationship data

## Error Handling

Common error scenarios and how to handle them:

<CodeGroup>
  ```swift Swift theme={null}
  // Handle invite validation errors
  let validation = await cm.invites.validateCode(code: userInput)

  if let result = validation {
      if !result.valid {
          switch result.message {
          case "Invalid invite code format":
              // Show format help (6 characters, alphanumeric)
              break
          case "Invite code expired":
              // Suggest requesting new invite
              break
          case "Invite limit reached":
              // Explain invite limits
              break
          default:
              // Generic error message
              break
          }
      }
  } else {
      // Network or service error
      // Show retry option
  }

  // Handle bulk email errors
  let emailResult = await cm.invites.sendBulkInviteEmails(
      contacts: selectedContacts,
      emailBody: customMessage
  )

  if let result = emailResult {
      if !result.success {
          if result.message.contains("verified email sending domain") {
              // Guide user to domain verification
          } else if result.message.contains("Invalid request data") {
              // Check contact data quality
          }
      }
  }
  ```

  ```jsx React Native theme={null}
  // Coming soon
  ```

  ```kotlin Kotlin theme={null}
  // Coming soon
  ```

  ```objectivec Objective-C theme={null}
  // Coming soon
  ```
</CodeGroup>

For more information about implementing invite features in your application, visit [contactsmanager.io](https://contactsmanager.io).
