Docs Navigation

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_sendTransaction and related EIP-1193 flows that the Branding Layer submits via the relayer.
  • Signing-only RPCs do not trigger webhookspersonal_sign, eth_signTypedData_v4, and other non-relayer operations do not POST to your callback.
  • When unset — if destinationUrl is not configured, the relayer does not send webhooks. Fall back to polling relayer_getStatus or client-side TransactionSubmitted analytics 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).
  • data matches the `relayer_getStatus` response for that task at the time of the event.
  • When the client sent memo on submit, data.memo is 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-level data.hash is 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.