# Recovery Alert Subscription Guide

Set up email and SMS notifications for recovery requests to keep Safe account owners informed of recovery attempts. This security feature provides an essential early warning system during the recovery process.

> To set up the recovery module first, see the [Enable Recovery Module and Add Guardians](https://docs.candide.dev/wallet/plugins/how-to-add-a-guardian.md) guide.

## Overview[​](#overview "Direct link to Overview")

The Recovery Alert system provides:

1. **Instant Notifications**: Immediate email and SMS alerts when recovery requests are initiated
2. **On-Chain Monitoring**: Tracks on-chain recoveries across all supported networks
3. **Grace Period Warnings**: Alerts during the grace period enabling owners to respond to unauthorized attempts
4. **Signature Verification**: Only verified account owners can subscribe to alerts

To learn more, visit the [Safe Recovery Service API](https://docs.candide.dev/wallet/recovery/overview.md) section.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

### Installation[​](#installation "Direct link to Installation")

* npm
* yarn

```
npm i safe-recovery-service-sdk abstractionkit viem
```

```
yarn add safe-recovery-service-sdk abstractionkit viem
```

* `safe-recovery-service-sdk` provides the alert subscription functionality
* `abstractionkit` provides Safe account creation and management
* `viem` is used for message signing and wallet operations

### Environment Setup[​](#environment-setup "Direct link to Environment Setup")

.env

```
# Network Configuration
CHAIN_ID=11155111  # Sepolia testnet chain ID
NODE_URL=https://ethereum-sepolia-rpc.publicnode.com

# Bundler and Paymaster URLs
BUNDLER_URL=https://api.candide.dev/public/v3/11155111
PAYMASTER_URL=https://api.candide.dev/public/v3/11155111

# Recovery Service URL
# Get access here: https://app.formbricks.com/s/brdzlw0t897cz3mxl3ausfb5
RECOVERY_SERVICE_URL=

# Safe Owner
OWNER_PRIVATE_KEY=0x..

# Alert Configuration
USER_EMAIL=owner@example.com
USER_PHONE=+1234567890
```

## Alert Subscription Steps[​](#alert-subscription-steps "Direct link to Alert Subscription Steps")

> Fork the [complete code](https://github.com/candidelabs/safe-recovery-service-sdk/tree/main/examples/02-alerts-setup) to follow along.

### Step 1: Initialize Alert Service[​](#step-1-initialize-alert-service "Direct link to Step 1: Initialize Alert Service")

Set up the recovery service client and account credentials.

initialize-alert-service.ts

```
import { Alerts } from "safe-recovery-service-sdk";
import { SafeAccountV0_3_0 as SafeAccount } from "abstractionkit";
import { privateKeyToAccount } from "viem/accounts";
import * as dotenv from 'dotenv';

dotenv.config();

const recoveryServiceURL = process.env.RECOVERY_SERVICE_URL as string;
const ownerPrivateKey = process.env.OWNER_PRIVATE_KEY as `0x${string}`;
const ownerEmail = process.env.USER_EMAIL as string;
const ownerPhone = process.env.USER_PHONE as string;
const chainId = BigInt(process.env.CHAIN_ID as string);

const ownerAccount = privateKeyToAccount(ownerPrivateKey);
const smartAccount = SafeAccount.initializeNewAccount([ownerAccount.address]);
const safeAccountAddress = smartAccount.accountAddress;

const alertsService = new Alerts(recoveryServiceURL, chainId);
```

### Step 2: Create SIWE Messages[​](#step-2-create-siwe-messages "Direct link to Step 2: Create SIWE Messages")

Generate Sign-in with Ethereum (EIP-4361) messages for subscription verification using the SDK helper methods.

* Email Subscription
* SMS Subscription

create-email-siwe-message.ts

```
const emailSiweMessage = alertsService.createEmailSubscriptionSiweStatementToSign(
  safeAccountAddress,
  ownerAccount.address,
  ownerEmail
);
```

create-sms-siwe-message.ts

```
const smsSiweMessage = alertsService.createSubscriptionSiweStatementToSign(
  safeAccountAddress,
  ownerAccount.address,
  "sms",
  ownerPhone
);
```

### Step 3: Sign Messages and Create Subscriptions[​](#step-3-sign-messages-and-create-subscriptions "Direct link to Step 3: Sign Messages and Create Subscriptions")

Sign the SIWE messages and submit subscription requests for both email and SMS.

* Email Subscription
* SMS Subscription

subscribe-email-alerts.ts

```
const emailSignature = await ownerAccount.signMessage({
  message: emailSiweMessage
});

const emailSubscriptionId = await alertsService.createEmailSubscription(
  safeAccountAddress,
  ownerAccount.address,
  ownerEmail,
  emailSiweMessage,
  emailSignature
);
```

subscribe-sms-alerts.ts

```
const smsSignature = await ownerAccount.signMessage({
  message: smsSiweMessage
});

const smsSubscriptionId = await alertsService.createSubscription(
  safeAccountAddress,
  ownerAccount.address,
  "sms",
  ownerPhone,
  smsSiweMessage,
  smsSignature
);
```

### Step 4: Activate Subscriptions[​](#step-4-activate-subscriptions "Direct link to Step 4: Activate Subscriptions")

Enter the verification codes received via email and SMS to activate both subscriptions.

* Email Activation
* SMS Activation

activate-email-subscription.ts

```
const emailVerificationCode = "123456";

await alertsService.activateSubscription(
  emailSubscriptionId,
  emailVerificationCode
);
```

activate-sms-subscription.ts

```
const smsVerificationCode = "654321";

await alertsService.activateSubscription(
  smsSubscriptionId,
  smsVerificationCode
);
```

### Step 5: Verify Active Subscriptions[​](#step-5-verify-active-subscriptions "Direct link to Step 5: Verify Active Subscriptions")

Check your current active alert subscriptions.

verify-subscriptions.ts

```
const getSubscriptionsSiweMessage = alertsService.getSubscriptionsSiweStatementToSign(
  ownerAccount.address
);

const getSubscriptionsSignature = await ownerAccount.signMessage({
  message: getSubscriptionsSiweMessage
});

const activeSubscriptions = await alertsService.getActiveSubscriptions(
  safeAccountAddress,
  ownerAccount.address,
  getSubscriptionsSiweMessage,
  getSubscriptionsSignature
);
```

## Complete Working Example[​](#complete-working-example "Direct link to Complete Working Example")

Full Alert Subscription Example

examples/02-alerts-setup/index.ts

```
loading...
```

[See full example on GitHub](https://github.com/candidelabs/safe-recovery-service-sdk/blob/main/examples/02-alerts-setup/index.ts)

## What's Next[​](#whats-next "Direct link to What's Next")

* [Enable Email / SMS Recovery](https://docs.candide.dev/wallet/plugins/add-candide-guardian.md): add Candide's managed guardian service so users can recover via email or SMS without managing guardian keys
* [Recovery API Reference](https://docs.candide.dev/wallet/recovery/ux-api.md): explore the full alert and recovery API surface

## Managing Subscriptions[​](#managing-subscriptions "Direct link to Managing Subscriptions")

### Update Contact Information[​](#update-contact-information "Direct link to Update Contact Information")

To change your alert email or phone number:

1. **Unsubscribe from current alerts** for that channel using the unsubscribe method with SIWE authentication
2. **Subscribe with new contact information** using the subscription flow
3. **Verify the new subscription** by entering the OTP code sent to your new contact

### Unsubscribe from Specific Channel[​](#unsubscribe-from-specific-channel "Direct link to Unsubscribe from Specific Channel")

To stop receiving alerts on one channel:

```
// Generate SIWE message for unsubscribing
const unsubscribeSiweMessage = alertsService.unsubscribeSiweStatementToSign(
  ownerAccount.address
);

// Sign the SIWE message
const unsubscribeSignature = await ownerAccount.signMessage({
  message: unsubscribeSiweMessage
});

// Unsubscribe from email only
const emailUnsubscribeSuccess = await alertsService.unsubscribe(
  "your-email-subscription-id",
  ownerAccount.address,
  unsubscribeSiweMessage,
  unsubscribeSignature
);

if (emailUnsubscribeSuccess) {
  console.log("Successfully unsubscribed from email alerts");
  // SMS subscription remains active
}
```

### Unsubscribe from All Channels[​](#unsubscribe-from-all-channels "Direct link to Unsubscribe from All Channels")

To stop all recovery alerts:

```
// Generate SIWE message for unsubscribing
const unsubscribeSiweMessage = alertsService.unsubscribeSiweStatementToSign(
  ownerAccount.address
);

// Sign the SIWE message
const unsubscribeSignature = await ownerAccount.signMessage({
  message: unsubscribeSiweMessage
});

// Unsubscribe from all channels
const emailUnsubscribeSuccess = await alertsService.unsubscribe(
  "email-subscription-id",
  ownerAccount.address,
  unsubscribeSiweMessage,
  unsubscribeSignature
);

const smsUnsubscribeSuccess = await alertsService.unsubscribe(
  "sms-subscription-id",
  ownerAccount.address,
  unsubscribeSiweMessage,
  unsubscribeSignature
);

if (emailUnsubscribeSuccess && smsUnsubscribeSuccess) {
  console.log("Successfully unsubscribed from all alerts");
}
```
