Backup + Recover Webhooks
To use backup and recovery, you can configure a webhook with Portal.
Why do I need a webhook?
The raw custodian backup share is stored in your database.
During the backup process, Portal generates the custodian backup share on its servers and then sends it to your API via a webhook endpoint for you to store. After the webhook request completes, the custodian backup share is deleted from the Portal servers. Portal never stores the custodian backup shares in its database -- it is only ever used in memory during the duration of the backup and recover processes.
During the recovery process, Portal will request the custodian backup shares for the user from your API via the POST
/backup/fetch
webhook endpoint. After the wallet successfully recovers, a new set of signing shares are generated, which are then stored on the user's device.
Your Database
Before we dive into the webhook endpoints' implementations, we should go over your database schema. Multi-backup requires storing both custodian and user backup shares by their respective backup method in your own database. We recommend the following database model structure:
We won't go into depth just yet, but it's worth calling out that you can see a couple associations:
A user has many raw custodian backup shares unique by backup method.
A user has many encrypted user backup shares unique by backup method.
The encryption key is stored differently depending on the backup method used.
Perfect, let's dive right into building out the webhook endpoints with this context.
API Endpoints you need to build
There are two webhook endpoints that your API needs to support: POST
/backup
for backup and POST
/backup/fetch
for recover.
POST
/backup
POST
/backup
During the backup process, Portal sends the custodian backup share to your API to store. The request will include a X-Webhook-Secret
header (you can set this in the Portal Admin Dashboard).
The body of this POST
request will contain three fields:
backupMethod
- The backup method used to create the backup share. Example values:"GDRIVE"
,"GDRIVE-SECP256K1"
,"GDRIVE-ED25519"
,"ICLOUD"
,"PASSKEY"
,"PASSWORD"
, etc. This should be stored as a generic string (not an enum) byclientId
. Its value is subject to change in future releases.clientId
- The Portal ID of the user. We recommend keeping track of this.share
- A JSON stringified version of the custodian backup share.
Your webhook server is expected to store the backupMethod
, clientId
, and share
value in a secure database.
Even if you are currently focused on a specific blockchain like Solana or Ethereum, it's essential to store ALL backup shares sent to your webhook. For example, if you're only using Solana and receive backup shares for both "GDRIVE-SECP256K1"
and "GDRIVE-ED25519"
, you need to store both. This ensures that all necessary data is available for wallet recovery, regardless of the blockchain involved.
The backup share
is critical to protecting your users' wallet. It is important to treat the share
value as a sensitive value and handle it accordingly. Do not log the value (or request body), be sure to store the value encrypted at rest, and understand the access control on the database.
It should also return a 200
status code.
Here is a simple example of how to set this up using Node and Express:
When Portal makes a request to your /backup
webhook, another immediate request is made to /backup/fetch
right after in order to validate the custodian backup share was stored successfully. The /backup/fetch
webhook is explained in the "Handling recovery" doc.
Your webhook must respond within 10 seconds. If your webhook has an error or does not respond in time, the propagated error will look something like this:
FAILED_WEBHOOK
: This error occurs when a webhook experiences an error. Unable to send backup share to configured webhook. Check your webhook status in the Portal Admin Dashboard to learn more.
Recovery
During the recovery process, Portal requests the custodian backup share from your API. Portal will request the existing custodian backup shares for a user with a POST
request to [webhookBaseURL]/backup/fetch
. The request will include a X-Webhook-Secret
header (you can set this in the Portal Admin Dashboard).
The request body of this request will contain one field:
clientId
- The Portal Id of the user.
Your webhook server is expected to fetch the custodian backup shares for the given clientId
. It should also return a 200
status code along with the backupShares
in the response body.
Here is a simple example of how to set this up using Node and Express:
Configuration
To configure your webhook go to the Settings Page of the Portal web app. Navigate to the Webhooks section and select the "New +" button. Enter in the base URL for your webhook server and select "Create". A secure, random webhook secret will be automatically generated for you unless you prefer to create your own secret.
Once the webhook base URL has been added. You will be able to view the webhook configuration. See the image below describing the different components of the webhook configuration.
Base URL - This is the URL you've configured.
When Portal runs backup it will send a request to the
[webhookBaseURL]/backup
route to send your server a custodian backup share to save for a client by backup method.When Portal runs recover it will send a request to the
[webhookBaseURL]/backup/fetch
endpoint to request the custodian backup shares for a user from your server.
Webhook Secret - Click the icon to reveal your webhook secret.
Webhook Endpoint - Each endpoint that Portal sends requests to has a status indicator letting you know whether the route is working correctly.
Request Explorer - To view the HTTP requests and responses sent to each route select "View Requests".
Security
To ensure secure transmission of recovery shares via the webhook we follow several security best practices.
Webhook Secret
Including a secret along with each webhook request adds authentication to the requests sent to your webhook server. You should verify that the secret with the request matches the secret configured in Portal.
All of our webhook requests are sent with a secret in the X-Webhook-Secret
header. The secret is securely generated on webhook configuration and can be viewed in the Settings Page of the web app.
IP Allowlist
Restricting requests on your webhook server to only those from Portal's IP addresses protects against requests from other parties. Configure your webhook server to only accept inbound connections from Portal's IP address.
Portal always makes requests from the IP addresses 35.203.150.117
, 104.155.171.139
or 35.185.20.23
.
Last updated