Signature approvals and self-managed backups are turned on and off separately. To create the configuration, follow Set up flow control hooks.
Signature approvals used to be the
PRE_SIGN_V1 informational webhook event. Existing PRE_SIGN_V1 subscriptions were moved to flow control automatically. If you were subscribed to PRE_SIGN_V1, your endpoint keeps working as before: Portal still calls the same URL with the same request body, the same X-WEBHOOK-SECRET header, and the same secret.Request headers
Every flow control hook request includes these headers:
All hooks use the same secret, unless you used
PRE_SIGN_V1 before. In that case /sign-approval keeps the secret it had and the backup hooks use a different one, so check each path against its own secret. See Secrets.
Signature approvals
When signature approvals are on, Portal callsPOST [baseUrl]/sign-approval before every signature any of your clients makes, and holds the signature until your server answers.
Request body
- EVM
- Solana
- Tron
- Stellar
Response
Portal only reads the status code. The response body is ignored.
Portal makes one attempt per signature and doesn’t retry. If your server is down, every signature fails until it comes back or you turn signature approvals off.
Self-managed backups
By default, Portal stores the custodian backup share for each of your clients. With self-managed backups, Portal sends that share to your server instead, and asks for it back when a client recovers. Portal only holds the share in memory while a backup or recovery runs. If your environment uses Portal-managed backups, the dashboard hides these hooks and you don’t need to build them.POST [baseUrl]/backup
Portal calls /backup when a client backs up a wallet. The request body has three fields:
Store the share by
clientId and backupMethod, replacing any share you already hold for that pair, then respond with a 2xx status such as 200. Any other response, or no response within 10 seconds, fails the backup.
Right after a successful /backup call, Portal calls /backup/fetch for the same client to check that the share was stored. If the share Portal gets back doesn’t match the one it sent, the backup fails.
POST [baseUrl]/backup/fetch
Portal calls /backup/fetch when a client recovers a wallet, and right after every /backup call. The request body has one field, clientId.
Respond with 200 and every custodian backup share you hold for that client, exactly as you received them in /backup:
backupSharePairId matches the backup the client is recovering from. A single share in a backupShare string field also works, but backupShares lets Portal choose. If neither field is present, or no share matches, the recovery fails.
Example database model
With self-managed backups you store two kinds of share, both unique by client and backup method:- The custodian backup share, which Portal sends to
/backup. - The encrypted client backup share (
cipherText), which your app receives from the SDK’s backup method and sends to your backend. Your app fetches it again before calling the SDK’s recover method.
Example server
This Express server handles all three hooks and checks the secret header on every request:isAllowed with your own approval rules. BACKUP_SHARE_ENCRYPTION_KEY is a base64-encoded 32-byte key. In production, keep it in a key management service rather than an environment variable.
Recognizing test calls
The dashboard can send a test call to each hook. Test calls use the same headers and body shape as real calls, and the request body has no field that marks them as tests. You can recognize them by these values:
Test calls show up in the flow control event log with a Test badge and don’t count toward the 24-hour stats or hook status.
Manage in the dashboard
Open Webhooks > Flow control in the Portal Admin Dashboard. The page shows:- Calls · 24h, Approved, Rejected, and Failed: counts for the last 24 hours. Approved and Rejected only cover signature approvals. Failed includes errors and timeouts.
- Flow control event log: every call Portal made and the exact response your server returned.
- Hooks: each hook with its path, status, number of calls in the last 24 hours, and time of the last call.
- Base URL, your secrets, and the Email alerts setting.
Hook status
A
400 from /sign-approval is a rejection, not a failure.
Turn hooks on or off
Check or uncheck Signature approvals or Self-managed backups in the Hooks list, then click Save changes and confirm. Turning a hook off has these effects:- Signature approvals off: Portal stops calling
/sign-approval, and signatures proceed without your approval. - Self-managed backups off: Portal stops calling
/backupand/backup/fetch, and backups and recoveries fail until you turn them back on.
Test your hooks
Click Test all hooks at the top of the page, or Test on a single hook. Portal sends a test call and shows the status code your server returned, the response time, and the response body. Click Show test request body on a hook to see what Portal sends.Secrets
Click the reveal icon next to a secret to see it. Revealing a secret requires two-factor authentication. When/sign-approval and the backup hooks use different secrets, the page shows two: Sign approval secret for /sign-approval and Backup secret for /backup and /backup/fetch.
Email alerts
Turn on Email alerts to get an email when a hook keeps failing. Portal sends at most one failure email per hook per hour, and a recovery email once the hook works again.Flow control events
Click View flow control events to see every call Portal made to your base URL in the last 30 days. Filter by Hook and by date range with From and To. Each row shows the hook, the status code, the outcome, and when Portal received the response. Expand a row to see the request body and your server’s response. Portal hides backup shares and the secret header in this log.Security
- Base URLs must use HTTPS.
- Check the
X-Webhook-Secretheader on every request. - Only accept requests from Portal’s IP addresses:
35.203.150.117,104.155.171.139, and35.185.20.23.