Skip to main content
This guide will walk you through setting up CongregationKit and making your first API call to fetch church member data from Salesforce.

Prerequisites

Before you begin, make sure you have:
  • Installed CongregationKit (see Installation)
  • Salesforce OAuth credentials (client ID and client secret)
  • Salesforce username and password
  • AsyncHTTPClient imported in your project
Keep your Salesforce credentials secure. Never hardcode them in your source code. Use environment variables or secure storage instead.

Step 1: Import Dependencies

First, import the required modules:
import CongregationKit
import AsyncHTTPClient
import Foundation

Step 2: Set Up Credentials

Create your Salesforce credentials. In production, load these from environment variables or secure storage:
let credentials = SalesforceCredentials(
    clientId: "your_client_id",
    clientSecret: "your_client_secret",
    username: "your_salesforce_username",
    password: "your_salesforce_password"
)
Best Practice: Store credentials in environment variables:
let credentials = SalesforceCredentials(
    clientId: ProcessInfo.processInfo.environment["SALESFORCE_CLIENT_ID"] ?? "",
    clientSecret: ProcessInfo.processInfo.environment["SALESFORCE_CLIENT_SECRET"] ?? "",
    username: ProcessInfo.processInfo.environment["SALESFORCE_USERNAME"] ?? "",
    password: ProcessInfo.processInfo.environment["SALESFORCE_PASSWORD"] ?? ""
)

Step 3: Initialize the Client

Create an HTTP client and initialize CongregationKit. The client will automatically authenticate with Salesforce:
let httpClient = HTTPClient.shared

do {
    let congregation = try await CongregationKit(
        httpClient: httpClient,
        credentials: credentials
    )
    print("Successfully authenticated with Salesforce!")
} catch SalesforceAuthError.invalidCredentials {
    print("Invalid credentials. Please check your Salesforce credentials.")
} catch SalesforceAuthError.networkError(let error) {
    print("Network error: \(error.localizedDescription)")
} catch {
    print("Authentication failed: \(error)")
}

Step 4: Fetch Members

Now you can fetch member data. You can choose which information to include using the expanded parameter:
// Fetch first page of members (50 members by default)
let response = try await congregation.members.fetchAll(
    pageNumber: 1,
    pageSize: 50
)

print("Fetched \(response.members.count) members")

for member in response.members {
    print("\(member.memberName ?? "Unknown") - \(member.phone ?? "No phone")")
}

Understanding Field Expansion

When you fetch members, you can choose which parts of their data you want by passing an array of MemberExpand values. This makes API calls faster and keeps your app efficient:
ExpansionProperty on MemberWhat It Includes
.contactInformationmember.contactInformationPhone, email, address, WhatsApp number
.employmentInformationmember.employmentInformationEmployment status, organization, occupation
.maritalInformationmember.maritalInformationMarital status, spouse name, wedding anniversary
.discipleshipInformationmember.discipleshipInformationWater baptism, courses completed, ministry involvement
If you don’t request a field expansion, that property will be nil in the member object. Always check for nil before accessing expanded fields.

Complete Example

Here’s a complete working example:
main.swift
import CongregationKit
import AsyncHTTPClient
import Foundation
import SalesforceClient

@main
struct App {
    static func main() async throws {
        // 1. Set up credentials
        let credentials = SalesforceCredentials(
            clientId: ProcessInfo.processInfo.environment["SALESFORCE_CLIENT_ID"] ?? "",
            clientSecret: ProcessInfo.processInfo.environment["SALESFORCE_CLIENT_SECRET"] ?? "",
            username: ProcessInfo.processInfo.environment["SALESFORCE_USERNAME"] ?? "",
            password: ProcessInfo.processInfo.environment["SALESFORCE_PASSWORD"] ?? ""
        )
        
        // 2. Create HTTP client
        let httpClient = HTTPClient.shared
        
        do {
            // 3. Initialize CongregationKit
            let congregation = try await CongregationKit(
                httpClient: httpClient,
                credentials: credentials
            )
            
            // 4. Fetch members with expanded fields
            let response = try await congregation.members.fetchAll(
                pageNumber: 1,
                pageSize: 10,
                expanded: [
                    .contactInformation,
                    .discipleshipInformation
                ]
            )
            
            // 5. Process the results
            print("Successfully fetched \(response.members.count) members\n")
            
            for member in response.members {
                print("Name: \(member.memberName ?? "Unknown")")
                print("Phone: \(member.contactInformation?.phoneNumber ?? "N/A")")
                print("Email: \(member.contactInformation?.email ?? "N/A")")
                
                if let baptism = member.discipleshipInformation?.waterBaptism {
                    print("Baptized: \(baptism.received ? "Yes" : "No")")
                }
                
                print("---")
            }
            
            // 6. Handle pagination if needed
            if let nextPageToken = response.metadata?.nextPageToken {
                print("\nMore members available. Next page token: \(nextPageToken)")
            }
            
        } catch SalesforceAuthError.invalidCredentials {
            print("Error: Invalid Salesforce credentials")
        } catch SalesforceAuthError.networkError(let error) {
            print("Network error: \(error.localizedDescription)")
        } catch MemberError.memberNotFound {
            print("Error: Member not found")
        } catch MemberError.fetchFailed(let error) {
            print("Failed to fetch members: \(error.localizedDescription)")
        } catch {
            print("Unexpected error: \(error)")
        }
    }
}

Error Handling

Always handle errors appropriately when working with the API:

Authentication Errors

do {
    let congregation = try await CongregationKit(
        httpClient: httpClient,
        credentials: credentials
    )
} catch SalesforceAuthError.invalidCredentials {
    print("Invalid credentials. Please check your Salesforce credentials.")
} catch SalesforceAuthError.networkError(let error) {
    print("Network error: \(error.localizedDescription)")
} catch SalesforceAuthError.rateLimitExceeded {
    print("Rate limit exceeded. Please wait before retrying.")
} catch SalesforceAuthError.serverError(let message) {
    print("Salesforce server error: \(message)")
} catch {
    print("Authentication failed: \(error)")
}

Member Fetch Errors

do {
    let member = try await congregation.members.fetch(id: memberId)
} catch MemberError.memberNotFound {
    print("Member not found")
} catch MemberError.invalidMemberID {
    print("Invalid member ID format (must start with TKT)")
} catch MemberError.fetchFailed(let error) {
    print("Failed to fetch member: \(error.localizedDescription)")
} catch {
    print("Unexpected error: \(error)")
}

Type Safety with MemberID

CongregationKit uses a type-safe MemberID struct to ensure member IDs are valid:
import Congregation

// Using the throwing initializer
do {
    let memberId = try MemberID(validating: "TKT123456")
    let member = try await congregation.members.fetch(id: memberId)
} catch MemberError.invalidMemberID {
    print("Member ID must start with 'TKT'")
}

// Using the failable initializer
if let memberId = MemberID(rawValue: "tkt123456") {
    // memberId.rawValue is automatically normalized to "TKT123456"
    let member = try await congregation.members.fetch(id: memberId)
}
Member IDs are automatically normalized to uppercase (e.g., “tkt123” becomes “TKT123”).

Next Steps

Working with Members

Learn about all member operations and data types

Fetching Members

Handle large datasets with pagination

Authentication

Advanced authentication patterns

Error Handling

Comprehensive error handling guide

Build docs developers (and LLMs) love