Embedded Wallet
Embedded Wallet: Webhooks
Receive signed webhooks when users transact via the 1Shot Embedded Wallet. Configure destinationUrl, verify Ed25519 signatures, and track transaction lifecycle.
Overview
Set a webhook callback URL once via configure and the embedded wallet includes it on every transaction submitted through the 1Shot Public Relayer. Your backend receives signed POST requests as the relayer moves each task through pending, submitted, confirmed, rejected, or reverted states.
Prefer webhooks over polling relayer_getStatus in production — they scale better and deliver sub-second status updates without a client-side loop.
This is separate from `proxy.analytics`: analytics events are client-side product telemetry in your Host app; webhooks are server-side transaction lifecycle events from the relayer.
Configure destinationUrl
Pass an HTTPS URL (≤256 characters) as the top-level destinationUrl field on configure. The Branding Layer stores it and attaches it to relayer send params for wallet-submitted transactions.
Pass null or "" to clear a previously configured URL. Omit the field to leave the current value unchanged.
The wallet playground Design mode exposes a Status webhook URL field backed by the same configure payload. The embedded-wallet host test configurator uses the same shape for local development.
Webhook destination
await proxy.rpc("configure", {
destinationUrl: "https://my-app.example.com/relayer-webhook",
});Which transactions trigger webhooks
- In-wallet Send — user-initiated transfers from the wallet UI that route through the relayer.
- Host-driven sends — gas-abstracted
eth_sendTransactionand related EIP-1193 flows that the Branding Layer submits via the relayer. - Signing-only RPCs do not trigger webhooks —
personal_sign,eth_signTypedData_v4, and other non-relayer operations do not POST to your callback. - When unset — if
destinationUrlis not configured, the relayer does not send webhooks. Fall back to pollingrelayer_getStatusor client-sideTransactionSubmittedanalytics events.
Webhook delivery
On each status change, the relayer POSTs Ed25519-signed JSON to your destinationUrl. Delivery is at-least-once — de-duplicate at the application level on (data.id, type).
- Payload shape:
{ type, data: { id, chainId, receipt, hash, memo?, ... }, signature, keyId }. type: 0— confirmed;type: 4— pending (numeric types, not string event names).datamatches the `relayer_getStatus` response for that task at the time of the event.- When the client sent
memoon submit,data.memois echoed on every webhook for that task. - Do not use Dev Platform webhook samples for the permissionless relayer — payload shape and signing differ.
Verify webhook signatures
The permissionless relayer signs webhook events with Ed25519. Fetch JWKS from mainnet or testnet. For example, if you are testing out transactions on Sepolia or Arc Testnet, you'll want to use the JWKS from the testnet relayer. If you're running transactions on Ethereum or Arc Mainnet, you must use the JWKS for the mainnet relayer.
To verify: remove the signature field from the event, serialize the remainder with stable sorted-key JSON, and verify Ed25519 over UTF-8 bytes using the public key matching keyId.
For the full error catalog, multichain notes, and runnable receiver examples, see Public Relayer: Error Handling → Webhook verification and the public-relayer skill.
Node.js verification sketch
import { createPublicKey, verify } from "node:crypto";
function verifyRelayerWebhook(event, publicKeyJwk) {
const { signature, ...payload } = event;
const message = Buffer.from(JSON.stringify(payload), "utf8");
const key = createPublicKey({ key: publicKeyJwk, format: "jwk" });
return verify(null, message, key, Buffer.from(signature, "base64url"));
}Status codes and success boundary
- 100 Pending — task accepted, not yet on chain.
- 110 Submitted — transaction broadcast.
- 200 Confirmed — on-chain success; use
data.receipt.transactionHash(top-leveldata.hashis often empty on confirmed events). - 400 Rejected — relayer rejected the bundle.
- 500 Reverted — transaction reverted on chain.
- Treat Confirmed (200 / webhook
type: 0) as the public boundary for success or paid fulfillment logic.
Test before production
Open the wallet playground, switch to Design mode, and set Status webhook URL to a tunnel or staging endpoint (for example ngrok). Send a test transaction from the playground and confirm your backend receives signed events before shipping to production.