Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.relayer.fi/llms.txt

Use this file to discover all available pages before exploring further.

This guide results in real on-chain transactions when using production credentials. Use the sandbox environment (https://testnet.relayer.fi/v1) while testing. Blockchain transactions are irreversible once broadcast.
The Signing Kit uses a prepare → stamp → confirm pattern. Every signing operation (wallet creation, address creation, transaction signing) follows the same three steps:
  1. Prepare — your backend calls the API to get an unsigned activity/transaction
  2. Stamp — the user signs the payload with a passkey (WebAuthn, browser-side)
  3. Confirm — your backend sends the stamped payload back; the enclave validates and processes it
The passkey stamping in step 2 must happen in a browser context that has access to WebAuthn. Server-only flows (cURL) can call prepare and confirm, but the stamping itself requires user interaction.

Prerequisites

  • A Relayer API key with the Signing module enabled (see Authentication)
  • A user with a registered passkey in your workspace (see step 1 below)
export RELAYER_API_KEY="rk_client_key_v1_your_key_here"
export RELAYER_BASE_URL="https://testnet.relayer.fi/v1"  # sandbox; use https://api.relayer.fi/v1 for production

Step 1 — Register a passkey (one-time setup)

The first time a user enrolls in your workspace, they register a passkey. This creates the wallet workspace and binds the user’s WebAuthn credential to it. The full flow happens in the browser via the Relayer dashboard or your own WebAuthn-capable frontend. The API calls involved:
POST /v1/signing/passkeys/challenge   → returns WebAuthn challenge
POST /v1/signing/passkeys/register    → registers the credential and creates the workspace
For end-user onboarding (Embedder integrators), the Widget Kit handles passkey enrollment automatically. See Widget Kit.

Step 2 — Create a wallet

1

Prepare the wallet creation

Your backend asks the API for an unsigned wallet-creation activity.
cURL
curl -X POST $RELAYER_BASE_URL/v1/signing/wallets/prepare \
  -H "Authorization: ApiKey $RELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "My Wallet" }'
The response includes the unsigned activity payload your frontend needs to stamp.
2

User stamps with passkey

Your frontend prompts the user with a WebAuthn biometric challenge (Face ID, fingerprint, security key). The browser produces a stamped activity.
Frontend (browser)
// Pseudo-code — exact stamping API depends on the WebAuthn library
const stamped = await passkey.stamp(unsignedActivity);
3

Confirm the wallet creation

Your backend sends the stamped activity back to the API.
cURL
curl -X POST $RELAYER_BASE_URL/v1/signing/wallets/confirm \
  -H "Authorization: ApiKey $RELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "stampedActivity": "..."
  }'
The response contains the walletId. Save it.

Step 3 — Generate an address

Same prepare/stamp/confirm pattern, this time for CREATE_WALLET_ACCOUNTS:
POST /v1/signing/wallets/accounts/prepare   { walletId, curve, addressFormat }
  → user stamps the returned activity with their passkey
POST /v1/signing/wallets/accounts/confirm   { stampedActivity }
  → returns { address, addressId, walletId }
Use addressFormat: "ADDRESS_FORMAT_ETHEREUM" for all EVM-compatible networks (Ethereum, Polygon, Arbitrum, Base, etc.). Use addressFormat: "ADDRESS_FORMAT_SOLANA" for Solana.

Step 4 — Sign a transaction

1

Prepare the transaction

cURL
curl -X POST $RELAYER_BASE_URL/v1/transactions/prepare \
  -H "Authorization: ApiKey $RELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "walletId": "wallet_abc123",
    "from": "0xYourWalletAddress",
    "to": "0xRecipientAddress",
    "value": "10000000000000000",
    "network": "sepolia"
  }'
The response includes:
  • transactionId — store this for later
  • unsignedTransaction (hex) — pass to the frontend for passkey signing
The transaction is persisted with status awaiting_signature.
2

User signs with passkey

Your frontend signs the unsigned transaction hex with the user’s passkey:
Frontend (browser)
const signedTx = await passkey.signTransaction(unsignedTransaction);
3

Confirm — and broadcast

Send the signed hex to confirm. The API validates the signature against the original unsigned transaction via hash comparison, persists the signed transaction, and broadcasts to the blockchain.
cURL
curl -X POST $RELAYER_BASE_URL/v1/transactions/confirm \
  -H "Authorization: ApiKey $RELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionId": "tx_def456",
    "signedTransaction": "0x..."
  }'
The response contains txHash once the transaction is in the mempool.
4

Check status

Poll the broadcast status to confirm on-chain confirmation.
cURL
curl $RELAYER_BASE_URL/v1/transactions/broadcast/$TRANSACTION_ID \
  -H "Authorization: ApiKey $RELAYER_API_KEY"
Status values: broadcast, confirmed, failed. Once confirmed, the response includes blockNumber.

Separating signing from broadcasting

If you need to gate the broadcast step (multi-step approval, scheduled submission), don’t use confirm-with-broadcast. Instead:
  1. POST /v1/transactions/prepare → unsigned tx
  2. User stamps with passkey on the frontend
  3. POST /v1/transactions/confirm → signs and persists (no broadcast yet) — TODO: confirm whether your tenant supports this gated mode
  4. POST /v1/transactions/broadcast/{transactionId} later, when conditions are met
Alternatively, sign externally and submit raw:
cURL
curl -X POST $RELAYER_BASE_URL/v1/transactions/broadcast/raw \
  -H "Authorization: ApiKey $RELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "rawSignedTransaction": "0x...", "network": "mainnet" }'

Cancelling before broadcast

A transaction in awaiting_signature status can be cancelled:
cURL
curl -X DELETE $RELAYER_BASE_URL/v1/transactions/sign/$TRANSACTION_ID \
  -H "Authorization: ApiKey $RELAYER_API_KEY"
Once POST /v1/transactions/confirm has broadcast the transaction, cancellation is no longer possible. The transaction is in the mempool.

Approval gate (high-value transactions)

If your workspace has approval enabled and the transaction value exceeds the threshold, POST /v1/transactions/confirm returns HTTP 202 with { approvalId } instead of broadcasting. The transaction stays pending until an authorized team member stamps approval:
GET  /v1/signing/approvals                              — Approver lists pending requests
POST /v1/signing/approvals/{id}/approve-with-passkey    — Approver stamps approval
Once approved, the transaction is broadcast automatically.

Next Steps

Endpoints

Full endpoint reference for wallets, transactions, passkeys, recovery, policies, and approvals.

API Reference

Interactive schemas and try-it playground.

Glossary

Wallet, passkey, policy, and other domain terms.

Error Reference

API error codes and handling patterns.