Skip to main content

Authentication-Based Recovery API (Email / SMS)

Use this API to register an email address or phone number as a recovery method, then obtain a service-managed guardian's signature after the user verifies a one-time password (OTP).

The signature counts as one guardian approval under the account's recovery threshold. Submit it through the Recovery UX API to continue recovery.

Before You Start​

  • Deploy the Safe account and enable the Social Recovery Module.
  • Request service access to obtain your service URL and Bearer token.
  • Register the recovery method while the user still controls the account. Registrations are specific to an account and chain.

For a TypeScript walkthrough, see Enable Email/SMS Recovery and the Email/SMS Recovery Flow.

Authentication​

Include Authorization: Bearer YOUR_BEARER_TOKEN in every request. Replace https://yourcompany.recovery.candide.dev with your service URL.

Registration, registration lookup, and deletion also require a SIWE message signed by the Safe account. During recovery, the user verifies codes sent to registered channels to authorize the service-managed guardian's signature. See SIWE signing.

Examples use placeholder addresses, IDs, messages, and signatures. Replace them with values from your integration. Expressions such as siwe(...) and sign(message) describe values to generate in your application; they are not literal API inputs.

Integration Workflow​

Set up recovery while the user has account access:

  1. Call /auth/register with a Safe-signed SIWE message to send a verification code.
  2. Submit the code to /auth/submit to receive a registrationId and guardianAddress.
  3. Add that guardian address to the account's Social Recovery Module on-chain. Registration alone does not add the guardian.

Recover the account after access is lost:

  1. Call /auth/signature/request with the proposed new owners and their signing threshold.
  2. Submit verification codes to /auth/signature/submit until the response includes signer and signature.
  3. Use that signature to create a recovery request, or add it to an existing request with the same recovery data. Collect any other required guardian approvals, execute recovery, and finalize after the grace period.

There are three separate thresholds:

ValueWhat it controls
requiredVerificationsHow many channel verifications are needed to obtain the service-managed guardian's signature.
Guardian thresholdHow many guardian approvals the Social Recovery Module requires to execute recovery.
newThresholdHow many of the new Safe owners must sign account transactions after recovery.

Endpoints​

MethodEndpointPurpose
POST/auth/registerRequest registration and send a verification code.
POST/auth/submitVerify the code and return the guardian address.
GET/auth/registrationsList the account's registered methods on a chain.
POST/auth/deleteDelete a registered method.
POST/auth/signature/requestRequest verification codes for a proposed recovery.
POST/auth/signature/submitVerify a code and return a guardian signature once enough verifications are collected.

Register and Manage Recovery Methods​

Register an Email Address or Phone Number​

Send a verification code to the selected email address or phone number. Save the returned challengeId for /auth/submit.

POST /auth/register​

curl -X POST \
https://yourcompany.recovery.candide.dev/auth/register \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"account":"0x...",
"chainId": 1,
"channel":"email",
"target":"user@example.com",
"message": "siwe(chainId, statement(channel, target))",
"signature": "sign(message)"
}'
  • account: The smart account address requesting registration.
  • chainId: The chain where the Safe is deployed. Register separately for each chain.
  • channel: Either "email" or "sms" (defines the authentication type).
  • target: The email or phone number for authentication.
  • signature: A signature valid for the Safe account over the complete SIWE message.
  • message: The complete SIWE message containing this exact statement:
I authorize Safe Recovery Service to sign a recovery request for my account after I authenticate using {{target}} (via {{channel}})

See SIWE signing for the exact statement and signing requirements.

Verify Registration​

Submit the code to confirm ownership of the email address or phone number. The response returns the guardian address to add to the Social Recovery Module on-chain.

POST /auth/submit​

curl -X POST \
https://yourcompany.recovery.candide.dev/auth/submit \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"challengeId":"unique-challenge-id",
"challenge":"123456"
}'

List Registered Recovery Methods​

List the registered recovery methods for the specified Safe account and chain. The response contains an empty array if no methods are registered.

GET /auth/registrations​

curl -G "https://yourcompany.recovery.candide.dev/auth/registrations" \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
--data-urlencode "account=0x..." \
--data-urlencode "chainId=1" \
--data-urlencode "message=siwe(chainId, statement)" \
--data-urlencode "signature=sign(message)"

See SIWE signing for the exact statement and signing requirements.

Delete a Recovery Method​

Delete the registration identified by registrationId, using a SIWE message signed by the Safe account. This removes the service registration; it does not revoke the guardian on-chain.

POST /auth/delete​

curl -X POST \
https://yourcompany.recovery.candide.dev/auth/delete \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"registrationId":"unique-registration-id",
"message": "siwe(chainId, statement(registrationId))",
"signature": "sign(message)"
}'

See SIWE signing for the exact statement and signing requirements.

Obtain a Recovery Signature​

Request Recovery Verification​

Propose new Safe owners and their signing threshold. The service sends verification codes to registered channels and returns a requestId, the required number of verifications, and the available challenges.

POST /auth/signature/request​

curl -X POST \
https://yourcompany.recovery.candide.dev/auth/signature/request \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"account":"0x...",
"newOwners": ["0x...", "0x..."],
"newThreshold": 2,
"chainId": 1
}'

Verify a Code and Collect the Signature​

Submit a code with its challengeId and the shared requestId. Each successful submission verifies one challenge. The response includes signer and signature only after requiredVerifications is met.

POST /auth/signature/submit​

curl -X POST \
https://yourcompany.recovery.candide.dev/auth/signature/submit \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"requestId": "unique-signature-request-id",
"challengeId": "unique-challenge-id",
"challenge": "123456"
}'

If more verifications are needed, a successful submission returns only:

{
"success": true
}

Continue with another challenge from the same request until signer and signature are returned. A guardian signature authorizes recovery; it does not execute a transaction or change ownership by itself.

How to Sign Messages (SIWE EIP-4361)​

SIWE (Sign-In with Ethereum) messages authorize registration and alert-management actions. Submit the complete prepared message in message and its corresponding signature in signature.

Choose the Signing Account​

EndpointsSIWE address and signature
/auth/register, /auth/registrations, /auth/deleteUse the Safe account address as the SIWE address. Produce a Safe-compatible signature that satisfies the account's owner threshold.
/alerts/subscribe, /alerts/subscriptions, /alerts/unsubscribeUse the owner address as the SIWE address. Sign with that owner. Subscription creation checks that this address is an owner of the Safe.

For Safe accounts, follow the registration signing example, which uses the Safe message-signing helpers and formats the owner signatures for verification. For alert subscriptions, follow the Recovery Alerts Guide.

Use the Exact Statement​

The service checks the statement against the requested action. Preserve its wording and punctuation, and substitute the values in braces.

ActionStatement
Register a recovery methodI authorize Safe Recovery Service to sign a recovery request for my account after I authenticate using {{target}} (via {{channel}})
List recovery methodsI request to retrieve all authentication methods currently registered to my account with Safe Recovery Service
Delete a recovery methodI request to remove the authentication method with registration ID {{id}} from my account on Safe Recovery Service

Use the registration ID for {{id}}, the email address or phone number for {{target}}, and email or sms for {{channel}}. The alert endpoints list their own statements.

Prepare and Sign the Message​

  1. Construct a SIWE message with the signing address above, the correct chain ID, the exact statement, a domain and URI, a fresh nonce, and an issued-at timestamp.
  2. Prepare the message with a SIWE library or the Recovery Service SDK.
  3. Sign that complete message using the appropriate signing account and submit both values unchanged.

The statement alone is not the full SIWE message. The chain ID must match the request, or the registration's chain for deletion. Generate a fresh message when retrying an expired authorization.

Error Handling​

Use the HTTP status to determine whether a request succeeded. Service errors contain top-level code and message fields. For example:

{
"code": 404,
"message": "Could not find registration with this id"
}

HTTP Status Codes​

CodeDescription
200Success
400Bad Request - Invalid parameters or missing required fields
401Unauthorized - Invalid or missing Bearer token
403Forbidden - Signature verification failed, challenge invalid or expired, or action not permitted
404Not Found - Resource not found
409Conflict - The recovery method is already registered
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Something went wrong on the server

Troubleshooting​

  • Invalid signature: Check the signing address, chain ID, and exact message or recovery data. SIWE messages must use the statement for the requested action.
  • Invalid or expired code: Verify that the code matches the challenge ID. If it has expired, start a new registration or recovery verification request as appropriate.
  • Missing resource: Use the ID returned by the corresponding creation endpoint.
  • Rate limit: Wait before retrying the request.