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

# iOS (Swift)

> Official Swift SDK for the Verilock Identity API.

## Requirements

| Requirement | Minimum Version |
| ----------- | --------------- |
| iOS         | 15.0+           |
| macOS       | 13.0+           |
| Swift       | 5.9+            |
| Xcode       | 15.0+           |

## Installation

Add the Verilock SDK via **Swift Package Manager**. In Xcode, go to **File > Add Package Dependencies** and enter:

```
https://github.com/verilock/verilock-swift
```

Or add it to your `Package.swift`:

```swift Package.swift theme={null}
dependencies: [
    .package(url: "https://github.com/verilock/verilock-swift", from: "1.0.0"),
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [
            .product(name: "VerilockSDK", package: "verilock-swift"),
        ]
    ),
]
```

## Configuration

Create a `Verilock` client with your API key. All API calls are made through this instance.

```swift theme={null}
import VerilockSDK

let verilock = Verilock(
    apiKey: "qi_live_..."
)
```

You can customise the client with optional parameters:

```swift theme={null}
let verilock = Verilock(
    apiKey: "qi_live_...",
    baseURL: "https://verilock.io/api/v1",  // default
    timeout: 30,                          // seconds, default
    maxRetries: 2                         // retries on 429/5xx, default
)
```

<Warning>
  **Keep your API key secure.** Never embed production keys in client-side code or commit them to version control.
</Warning>

## Quick Start

Create a KYC session, upload a document and selfie, then submit for verification:

```swift theme={null}
import VerilockSDK

let verilock = Verilock(apiKey: "qi_live_...")

// 1. Create a session
let session = try await verilock.sessions.create(
    CreateSessionParams(
        applicantEmail: "john@example.com",
        redirectUrl: "https://example.com/callback"
    )
)
print(session.sessionUrl) // Redirect user here, or upload docs directly

// 2. Upload document (front)
try await verilock.sessions.uploadDocument(
    UploadDocumentParams(
        sessionId: session.id,
        fileData: frontImageData,
        side: .front,
        documentType: .passport
    )
)

// 3. Upload selfie
try await verilock.sessions.uploadSelfie(
    UploadSelfieParams(
        sessionId: session.id,
        fileData: selfieData
    )
)

// 4. Submit for verification
let result = try await verilock.sessions.submit(session.id)
```

## KYC Sessions

The `sessions` resource manages the full verification lifecycle.

```swift theme={null}
// Create a session
let session = try await verilock.sessions.create(
    CreateSessionParams(
        applicantEmail: "jane@example.com",
        redirectUrl: "https://example.com/done"
    )
)

// List sessions with pagination
let list = try await verilock.sessions.list(
    ListSessionsParams(page: 1, limit: 20)
)

// Retrieve a session by ID
let details = try await verilock.sessions.retrieve("sess_abc123")
print(details.decision) // "approved", "declined", or "review"

// Upload address proof
try await verilock.sessions.uploadAddressProof(
    UploadAddressProofParams(
        sessionId: "sess_abc123",
        fileData: proofData,
        documentType: .utilityBill
    )
)
```

## AML Screening

Screen individuals against global sanctions, PEP, and watchlists.

```swift theme={null}
let screening = try await verilock.aml.screen(
    ScreenPersonParams(name: "John Doe")
)
print(screening.risk)    // risk classification
print(screening.matches) // matched watchlist entries
```

## Transaction Monitoring

Screen transactions for suspicious activity.

```swift theme={null}
let tx = try await verilock.transactions.screen(
    ScreenTransactionParams(
        transactionRef: "TX-001",
        senderName: "Alice",
        receiverName: "Bob",
        amount: 5000,
        currency: "USD"
    )
)
print(tx.risk)
print(tx.flags)
```

## Premium Features

The SDK provides access to premium verification services through dedicated resource properties.

```swift theme={null}
// Biometric face authentication
let biometricResult = try await verilock.biometric.verify(params)

// Government database validation
let dbResult = try await verilock.database.validate(params)

// 1:N face duplicate detection
let searchResult = try await verilock.faceSearch.search(params)

// Crypto wallet compliance screening
let walletResult = try await verilock.wallet.screen(params)

// Reusable KYC credentials
let credential = try await verilock.credentials.create(params)

// Age verification from selfie
let ageResult = try await verilock.ageVerify.check(params)
```

<Info>
  Premium features require an active subscription. See the [Premium Features](/premium-features) docs for details.
</Info>

## Error Handling

All methods are `async throws`. Errors are thrown as `VerilockError`, a Swift enum with associated values for each error type.

```swift theme={null}
do {
    let session = try await verilock.sessions.retrieve("sess_invalid")
} catch let error as VerilockError {
    switch error {
    case .authentication(let message, _):
        print("Auth failed: \(message)")

    case .insufficientBalance(let message, let required, let balance):
        print("Need \(required), have \(balance): \(message)")

    case .notFound(let message):
        print("Not found: \(message)")

    case .validation(let message):
        print("Invalid input: \(message)")

    case .rateLimited(let message, let retryAfter):
        print("Slow down: \(message), retry in \(retryAfter ?? 0)s")

    case .serverError(let statusCode, let message):
        print("Server error \(statusCode): \(message)")

    case .networkError(let underlyingError):
        print("Network issue: \(underlyingError.localizedDescription)")

    case .decodingError(let underlyingError):
        print("Decoding issue: \(underlyingError.localizedDescription)")

    case .apiError(let statusCode, let message, _):
        print("API error \(statusCode): \(message)")
    }
}
```

### Error Reference

| Case                  | HTTP Status | Description                          |
| --------------------- | ----------- | ------------------------------------ |
| `authentication`      | 401         | Invalid or missing API key           |
| `insufficientBalance` | 402         | Account balance too low              |
| `notFound`            | 404         | Resource does not exist              |
| `validation`          | 422         | Request parameters failed validation |
| `rateLimited`         | 429         | Too many requests                    |
| `serverError`         | 5xx         | Server-side error                    |
| `networkError`        | --          | No response received                 |
| `decodingError`       | --          | Response body could not be parsed    |
| `apiError`            | \*          | Catch-all for other HTTP errors      |

<Tip>
  The SDK automatically retries requests on `429` and `5xx` errors up to `maxRetries` times (default: 2) with exponential backoff. You only need to handle errors that persist after retries.
</Tip>
