

# Keycard (RFID)

Add and remove RFID keycards on iglooworks locks.

---

## addKeycard

Opens a BLE registration window and waits for the user to tap a physical keycard on the lock's reader (45-second timeout). Once detected, registers the card on the server.

If server registration fails after the card is enrolled on lock hardware, the SDK automatically removes the card from the lock.

### Signature

```kotlin
suspend fun addKeycard(
    deviceId: String,
    key: String,
    name: String,
    accessToken: String? = null,
): AddKeycardResponse
```

```swift
func addKeycard(
    deviceId: String,
    key: String,
    name: String,
    accessToken token: String
) async throws -> CreateKeycardAccessResponse
```

### Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deviceId` | `String` | Yes | Bluetooth device name of the lock. |
| `key` | `String` | Yes | eKey with `ADD_CARD` permission. |
| `name` | `String` | Yes | User-assigned name for the keycard. |
| `accessToken` | `String?` | OAuth only | OAuth access token for server calls. |

### Return Type

```kotlin
data class AddKeycardResponse(
    val accessId: String,
    val name: String,
    val payload: String,
)
```

```swift
public struct CreateKeycardAccessResponse: Codable, Sendable {
    public let accessId: String
    public let name: String
    public let payload: String
}
```

| Field | Description |
|-------|-------------|
| `accessId` | Server-assigned access ID. |
| `name` | The name assigned to the keycard. |
| `payload` | Base64-encoded card UID. |

### Error Codes

| Exception | Code | Description |
|-----------|------|-------------|
| `BluetoothException` | 708 | Bluetooth is off or unavailable. |
| `ConnectionException` | 12 | Device disconnected during registration. |
| `TimeoutException` | 703 | No card tapped within 45 seconds. |
| `LockStorageFullException` | 912 | No storage for more keycards. |
| `ApiException` | varies | Server registration failed (card rolled back from lock). |

### Example

```kotlin
try {
    showPrompt("Tap your keycard on the lock reader...")
    val result = sdk.addKeycard(
        deviceId = "IGM401abc123",
        key = guestKey,
        name = "Office Badge",
    )
    showSuccess("Keycard registered: ${result.accessId}")
} catch (e: IglooWorksException.TimeoutException) {
    showError("No card detected — try again")
} catch (e: IglooWorksException.LockStorageFullException) {
    showError("Lock is full — delete a keycard first")
} catch (e: IglooWorksException) {
    showError("Failed: ${e.message}")
}
```

```swift
do {
    showPrompt(message: "Tap your keycard on the lock reader...")
    let result = try await sdk.addKeycard(
        deviceId: "IGM401abc123",
        key: guestKey,
        name: "Office Badge",
        accessToken: accessToken)
    showSuccess(message: "Keycard registered: \(result.accessId)")
} catch LockManagerError.LockTimeoutError {
    showError(message: "No card detected — try again")
} catch IglooworksError.lockStorageFull {
    showError(message: "Lock is full — delete a keycard first")
} catch {
    showError(message: "Failed: \(error.localizedDescription)")
}
```

---

## deleteKeycard

Removes a keycard from the lock and deletes the server record.

The SDK fetches the card UID from the server, removes it from lock hardware via BLE, then deletes the server record. If the card is already removed from the lock (BLE error 980), the SDK still deletes the server record.

### Signature

```kotlin
suspend fun deleteKeycard(
    deviceId: String,
    key: String,
    accessId: String,
    accessToken: String? = null,
)
```

```swift
func deleteKeycard(
    deviceId: String,
    key: String,
    accessId: String,
    accessType: AccessType = .rfid,
    accessToken token: String
) async throws
```

### Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deviceId` | `String` | Yes | Bluetooth device name of the lock. |
| `key` | `String` | Yes | eKey with `DELETE_CARD` permission. |
| `accessId` | `String` | Yes | Server-assigned access ID of the keycard to delete. |
| `accessToken` | `String?` | OAuth only | OAuth access token for server calls. |

### Error Codes

| Exception | Code | Description |
|-----------|------|-------------|
| `BluetoothException` | 708 | Bluetooth is off or unavailable. |
| `ConnectionException` | 12 | Device disconnected during deletion. |
| `TimeoutException` | 703 | BLE operation exceeded the timeout. |
| `ApiException` | varies | Server deletion failed. |

### Example

```kotlin
try {
    sdk.deleteKeycard(
        deviceId = "IGM401abc123",
        key = guestKey,
        accessId = "access-456",
    )
    showSuccess("Keycard removed")
} catch (e: IglooWorksException.ConnectionException) {
    showError("unexpected bluetooth connection issue")
} catch (e: IglooWorksException.TimeoutException) {
    showError("Timed out, try again")
} catch (e: IglooWorksException) {
    showError("Delete failed: ${e.message}")
}
```

```swift
do {
    try await sdk.deleteKeycard(
        deviceId: "IGM401abc123",
        key: guestKey,
        accessId: "access-456",
        accessToken: accessToken)
    showSuccess(message: "Keycard removed")
} catch {
    showError(message: "Failed: \(error.localizedDescription)")
}
```

### Notes

- Registration timeout is 45 seconds (hardcoded).
- Server deletion retries up to 3 times with 1-second delays.
- `LockUidNotFoundException` (980, Android) / `IglooworksError.lockUidNotFound` (iOS) during BLE delete is non-fatal — server record is still removed.
- Supported lock types: IWS, IGM3, IGM4, IGR, RG1, MP1F, ML5, RW1.
