2xx and Portal marks the event as delivered.
Each environment has one informational webhook. It sends every event you subscribe to to a single endpoint URL.
- To create the webhook, follow Set up informational webhooks.
- For what each event means and its payload, see Informational webhook events.
How delivery works
Portal sends each event as aPOST request with a JSON body:
typeis the event type. Use it to route every event from one handler.dataholds the event itself. Its shape depends ontype.metadataalways includesenvironmentId. Every event except the Solana events also includescustodianId.
Headers
Responses and retries
Return a2xx within 10 seconds. Portal only reads the status code and ignores the response body.
If your server returns anything else, or doesn’t respond in time, Portal retries the event with exponential backoff. Once the retries run out, the event is marked FAILED and you can resend it.
Wallet ejected events are the exception: Portal makes one attempt and doesn’t retry them automatically. Resend them from the event log if your server missed one.
Respond first and process the event afterwards. If your processing takes longer than 10 seconds, Portal counts the delivery as failed and sends the event again. Portal doesn’t guarantee that events arrive in the order they happened.
Delivery statuses
Portal records every event it sends as a delivery event, with one of these statuses:
A resend is a single attempt with no automatic retries after it. If you resend an event that is still
PENDING, Portal stops its automatic retries, and the resend becomes the event’s last attempt.
Avoid processing an event twice
Your server can receive the same event more than once:- Retries and resends send the original payload again, unchanged.
- An EVM transaction arrives first with
confirmed: falseand again withconfirmed: true.
For account abstraction wallets, prefer
userOperationHash. A bundler can put several user operations in one transaction, so the transaction hash alone isn’t unique. userOperationHash is the hash that broadcast a user operation returns, and it’s null for transactions that aren’t user operations. A batched user operation produces several data[] items with the same userOperationHash, so keep to and tokenAddress in the key.
For EVM events, treat the confirmed: true event as a status update to the confirmed: false event with the same key.
To process a transaction once instead of once per wallet, drop triggeredBy from the key. See the next section.
Transfers between your own wallets
When both the sender and the receiver are addresses Portal watches for you, such as two of your clients or a client and one of your external addresses, one transfer produces two events:- An
OUTBOUNDevent for the sender. - An
INBOUNDevent for the receiver.
from and to are the same in both events, because they describe the on-chain transfer. Use direction and triggeredBy to tell the events apart. triggeredBy is the watched address the event was sent for: data[].metadata.triggeredBy on EVM events, and data.rawEvents[].triggeredBy on Solana events.
To match the two events, use data[].metadata.transactionHash and data[].metadata.blockNumber on EVM, or data.rawEvents[].signature on Solana.
If only one side of the transfer is watched, you get one event. The same rule applies to token approvals, revocations, and delegated transfers.
The example below shows one 1 USDC transfer on Ethereum Sepolia between two watched addresses. Only direction and triggeredBy differ.
- OUTBOUND (sender)
- INBOUND (receiver)
External addresses
Portal watches every address of your clients by default. Add an external address to also get transaction events for an address Portal doesn’t manage, such as a treasury wallet or an exchange deposit address.External addresses currently support Solana only. EVM support is coming soon.
- Open Webhooks > Informational in the Portal Admin Dashboard.
- Under External addresses, click Add +.
- Enter the Solana address and click Add.

GET /custodians/me/alerts/webhooks/external-addressesPOST /custodians/me/alerts/webhooks/external-addressesDELETE /custodians/me/alerts/webhooks/external-addresses/{externalAddressId}
Tunnel URLs
If your endpoint URL points to a tunneling service such as ngrok, trycloudflare, or webhook.site, Portal turns the webhook off when deliveries keep failing: right away if the domain no longer resolves, or after 10 failed deliveries in a row. While it’s off, Portal marks new events asFAILED without sending them, and resends are rejected.
To turn it back on, change the endpoint to a URL that works. Then resend the events you missed.
Recognizing test events
The dashboard can send a test event of any type you’re subscribed to. Test events go through the same delivery queue as real ones, with the same headers and body shape, and the request body has no field that marks them as tests. You can recognize them by these values:
Test events show up in the event log with a Test badge and don’t count toward the 24-hour failure totals.
Manage in the dashboard
Open Webhooks > Informational in the Portal Admin Dashboard.
- Endpoint and Secret header.
- Event log: how many events Portal sent in the last 24 hours and how many failed.
- Subscribed events: the events you receive, grouped as they are in Informational webhook events.
- Test Informational Event: send a sample of any subscribed event.
- External addresses.
Edit the endpoint
Click the pencil icon next to Endpoint, enter the new URL, and click Save endpoint. The URL must start withhttps://. Events sent after you save go to the new URL.
Change subscribed events
Check or uncheck events under Subscribed events. Changes show a Will be added or Will be removed badge until you click Save changes.- Solana token approvals, token revocations, and delegated transfers require Wallet transactions in the same group. They’re disabled until it’s checked.
- If you uncheck every event, Portal stops sending you informational events.
- If you subscribe to both the current and the archived Solana events, each Solana transaction sends events for both versions.
Rotate the secret
Click Rotate next to Secret header, type a new secret or click Generate, and click Save secret. Secrets must be 32 to 256 printable ASCII characters with no whitespace. Revealing the secret requires two-factor authentication.Send a test event
Under Test Informational Event, pick a subscribed event and click Send test event. The page shows the body Portal sends. Delivery happens in the background, so check the event log or your server’s logs for the result.Event log
Click View events → to see every event Portal sent to your endpoint in the last 30 days.
Resend an event
Click Resend on a failed event and confirm. Portal sends the stored event to your endpoint again with the same payload.Custodian API
You can read your webhook and its delivery events, and resend events, with the Custodian API:GET /custodians/me/alerts/webhookslists your webhook, including whether it’s turned off and why.GET /custodians/me/alerts/webhooks/{alertWebhookId}/delivery-eventslists delivery events. Filter withstatuses=FAILEDto find events that need a resend.POST /custodians/me/alerts/webhooks/{alertWebhookId}/delivery-events/{deliveryEventId}/retriesresends one event. It returns429when 3 resends are already in progress, and409when the webhook is turned off.
Security
- Endpoint 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.