Changelog

Firekeeper

Solana just joined the list of supported networks for x402 payments. That means you can now gate, verify, and settle Solana transactions through your own facilitator wallets — fully end-to-end.

This release adds everything you need to spin up your own server wallet, prepare payment payloads, and handle verification + settlement directly on Solana (devnet or mainnet). No middle layers. No bloat.


What’s new

  • Solana facilitator flow — create or register a Solana server wallet, quote pricing with /v1/payments/x402/accepts, and settle signed transactions with /v1/payments/x402/settle.
  • Unified verify path/v1/payments/x402/verify now validates Solana payloads the same way it does for EVM, so you can reuse your middleware checks across chains.
  • End-to-end examples — refreshed snippets for Node environments that show the exact headers, payloads, and success envelopes you should expect in production.

Fast start guide

Create a facilitator wallet

const response = await fetch(
"https://api.thirdweb.com/v1/solana/wallets",
{
method: "POST",
headers: {
"x-secret-key": "YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
label: "my-solana-facilitator",
}),
},
);
const wallet = await response.json();
console.log(wallet.result.address);

The returned address is the server-side payer for settles, so double-check that it appears in your project’s server wallet list.

Fund the wallet: Top up SOL for fees on the target cluster (devnet or mainnet-beta).

Settle on-chain with your facilitator wallet

const settleResponse = await fetch(
"https://api.thirdweb.com/v1/payments/x402/settle",
{
method: "POST",
headers: {
"x-secret-key": "YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
paymentPayload: SIGNED_PAYMENT_PAYLOAD,
paymentRequirements,
waitUntil: "submitted",
}),
},
);
const settleData = await settleResponse.json();
console.log(settleData.transaction);

Use waitUntil: "confirmed" if you need finality before responding to the client.

Verify before you settle

const verifyResponse = await fetch(
"https://api.thirdweb.com/v1/payments/x402/verify",
{
method: "POST",
headers: {
"x-secret-key": "YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
paymentPayload: SIGNED_PAYMENT_PAYLOAD,
paymentRequirements,
}),
},
);
const verifyData = await verifyResponse.json();
console.log(verifyData.isValid);

A truthy isValid means the signatures, blockhash, and amounts all check out.

Let payers fetch protected resources. If the client hits the protected endpoint first, have it replay the request through /v1/payments/x402/fetch. The api will answer with the payload you need for verification and settlement.

const fetchResponse = await fetch(
"https://api.thirdweb.com/v1/payments/x402/fetch?" +
new URLSearchParams({
url: "https://example.com/solana-protected",
from: "PAYER_SOLANA_ADDRESS",
chainId: "solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K",
}),
{
method: "POST",
headers: {
"x-secret-key": "YOUR_SECRET_KEY",
},
},
);
const fetchData = await fetchResponse.json();

Quote access with /v1/payments/x402/accepts

const acceptsResponse = await fetch(
"https://api.thirdweb.com/v1/payments/x402/accepts",
{
method: "POST",
headers: {
"x-secret-key": "YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
resourceUrl: "https://example.com/solana-protected",
method: "POST",
network: "solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K",
price: {
amount: "0",
asset: {
address: "So11111111111111111111111111111111111111112",
decimals: 9,
tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
},
},
serverWalletAddress: "YOUR_SOLANA_FACILITATOR_ADDRESS",
}),
},
);
const { accepts } = await acceptsResponse.json();
const paymentRequirements = accepts[0];

Keep paymentRequirements around—clients will sign against it, and the facilitator will reuse it when settling.

Watch your server wallet dashboard or any Solana explorer for the transaction signature the settle endpoint returns.

Firekeeper

We've made some major UI changes and grouped the core wallet and transaction functionality into a single Wallets sidebar section in your Project view, with easier access to related functionality for each, let's dive in.

User Wallets

Overview

The first section is for your user wallets, previously in-app wallets, attached to authenticated users on your frontend. It contains general analytics as well as a searchable list of users.

Configuration

The configuration section contains your User Wallet configurable options such as custom authentication and branding for OTP emails.

Server Wallets

Overview

Similarly to User Wallets, you can view analytics about transactions made from your backend as well as the EVM and Solana server wallets you have configured. This was previously all of the UI from the Transactions tab.

Configuration

The Vault section has moved here, it is what powers Server Wallets and you can manage it there. By default, no action is needed and it is managed automatically, but you can choose to eject from it and pass extra x-vault-access-token to our APIs and SDKs to interact with your server wallets if you do so.

Gas Sponsorship

Overview

This section shows you your gas sponsorship usage regardless of the interface (or EIP/execution mode) used to sponsor said gas. You can track your usage here easily.

Configuration

You can configure your sponsorship policies granularly here.

Notes

No functionally relevant pages have been removed, they're at most been moved to the new sections that hopefully feel more natural now.

Various bug fixes were integrated as part of this change, as well as link fixes.

You may still access some of these configurations from the project settings, which will redirect to the new pages as needed.

If you have any questions or need support, please reach out to our support team.

Yash Kumar

We have added support for creating and deploying modular contracts with Stylus. Users can now install rust based modules into the original solidity based modular contracts as described in the main design doc.

This plug-n-play model also allows users to write their own custom minting logic in rust, taking advantage of Stylus' interoperability and gas savings. These modules work with existing router contracts and modules written in solidity.

What's new?

| Learn how to deploy and interact with Stylus contracts through thirdweb documentation.

Deploy through dashboard

Here's a quick overview of how to deploy and setup your modular contracts via thirdweb dashboard.

  • Navigate to thirdweb explore page and select one of the core contracts to use. For e.g. Modular NFT Collection:
  • Once you have deployed one of these contracts, the modules come pre-installed, both solidity and rust ones.
  • If you wish to install / uninstall, navigate to modules tab on your contract page:

In addition, you can also write your own modules in rust and deploy / publish those using thirdweb CLI.

Additional Resources

Support

Need help? Please reach out to our support team

Firekeeper

What's New

GET /v1/solana/swap - Get Swap Quote

Get a quote for swapping Solana tokens without executing the transaction. See the expected output amount, USD values, and slippage before committing.

Example: Get quote to swap 0.1 SOL for USDC

curl -X GET "https://api.thirdweb.com/v1/solana/swap?address=YOUR_WALLET_ADDRESS&tokenIn=So11111111111111111111111111111111111111112&tokenOut=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&amount=100000000&chainId=solana:mainnet" \
-H "x-secret-key: YOUR_SECRET_KEY"

Response:

{
"result": {
"inputMint": "So11111111111111111111111111111111111111112",
"outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"inputAmount": "100000000",
"outputAmount": "15423156",
"inputUsdValue": 15.45,
"outputUsdValue": 15.42,
"slippageBps": 34,
"requestId": "019a5f00-fab2-747d-bba2-b77f993314a0"
}
}

POST /v1/solana/swap - Execute Swap

Execute a complete token swap with automatic signing, execution, and on-chain confirmation. The swap is confirmed on Solana within 30 seconds or returns a timeout error.

Example: Swap 0.1 SOL for USDC

curl -X POST "https://api.thirdweb.com/v1/solana/swap" \
-H "Content-Type: application/json" \
-H "x-secret-key: YOUR_SECRET_KEY" \
-d '{
"address": "YOUR_WALLET_ADDRESS",
"tokenIn": "So11111111111111111111111111111111111111112",
"tokenOut": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "100000000",
"chainId": "solana:mainnet"
}'

Response:

{
"result": {
"signature": "5ttCNobho7nk5F1Hh4pU4d9T2o1yAFn3p1w8z8jk2jKd9KWCKN6dzyuT5xP1ny4wz9f5xCLjAF6Y9s9EoTW4aE1X",
"inputMint": "So11111111111111111111111111111111111111112",
"outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"inputAmount": "100000000",
"outputAmount": "15423156",
"inputUsdValue": 15.45,
"outputUsdValue": 15.42,
"requestId": "019a5f00-fab2-747d-bba2-b77f993314a0"
}
}

View transaction: https://solscan.io/tx/5ttCNobho7nk5F1Hh4pU4d9T2o1yAFn3p1w8z8jk2jKd9KWCKN6dzyuT5xP1ny4wz9f5xCLjAF6Y9s9EoTW4aE1X

Key Features

Aggregated Liquidity - Best prices across multiple DEXs and liquidity sources
💰 USD Value Display - See real-time USD values for input and output amounts
Automatic Execution - No need to manually sign or submit transactions
🔒 Confirmed Results - Returns only after transaction is confirmed on-chain
🌐 Mainnet Only - Swaps available on Solana mainnet (solana:mainnet)
💸 Gasless Support - Qualifying swaps ($10+ with <0.01 SOL) may be gasless

Common Token Addresses

TokenMint Address
SOLSo11111111111111111111111111111111111111112
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB

Request Parameters

ParameterTypeRequiredDescription
addressstringYesWallet address executing the swap
tokenInstringYesInput token mint address (token being sold)
tokenOutstringYesOutput token mint address (token being bought)
amountstringYesAmount in smallest unit (e.g., lamports for SOL)
chainIdstringYesMust be solana:mainnet

Response Fields

FieldTypeDescription
signaturestringTransaction signature (POST only)
inputMintstringInput token mint address
outputMintstringOutput token mint address
inputAmountstringAmount of input token swapped
outputAmountstringAmount of output token received
inputUsdValuenumberUSD value of input amount
outputUsdValuenumberUSD value of output amount
slippageBpsnumberSlippage tolerance in basis points
requestIdstringUnique request identifier

Amount Formatting

Amounts must be in the token's smallest unit (before decimals):

  • SOL (9 decimals): 1 SOL = 1000000000 lamports = "1000000000"
  • USDC (6 decimals): 1 USDC = 1000000 = "1000000"
  • 0.1 SOL: "100000000" (100 million lamports)
  • 10 USDC: "10000000" (10 million)

Error Handling

The API returns detailed error messages for common issues:

Insufficient Balance:

{
"error": {
"message": "Insufficient funds",
"statusCode": 400
}
}

Minimum Swap Amount ($10+ for gasless):

{
"error": {
"message": "Minimum $10 for gasless",
"statusCode": 400
}
}

Transaction Timeout:

{
"error": {
"message": "Swap transaction was not confirmed within timeout period",
"statusCode": 504
}
}

Ready to start swapping? Check out the full API documentation for more details.

Firekeeper

New Endpoints

🔐 Sign Transaction (POST /v1/solana/sign-transaction)

Sign a Solana transaction without broadcasting it. Perfect for workflows where you need to inspect, store, or conditionally broadcast transactions.

Features:

  • Sign serialized transactions or assemble from instructions
  • Configure priority fees and compute limits
  • Returns both signature and signed transaction payload

Example - Sign from instructions:

curl -X POST https://api.thirdweb.com/v1/solana/sign-transaction \
-H "Content-Type: application/json" \
-H "x-secret-key: YOUR_SECRET_KEY" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"chainId": "solana:devnet",
"instructions": [
{
"programId": "11111111111111111111111111111111",
"accounts": [
{
"address": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"isSigner": true,
"isWritable": true
},
{
"address": "FhtwVYF1wKAm7fWmE2N5P2eCv13wt2aT8W4Q9NQ9YcJH",
"isSigner": false,
"isWritable": true
}
],
"data": "02000000e803000000000000",
"encoding": "hex"
}
],
"priorityFee": {
"type": "manual",
"microLamportsPerUnit": 1000
}
}'

Response:

{
"result": {
"signature": "3TZx4Ev7fWN7jk7CHTrxmsf9cXB1LQjs44aYGuC9kPYcyJ8D1V8efFgAfL9QGmxZXZMpDnwhzUbBeAf7dByoDwyx",
"signedTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIAAQIDBAUGBwgJ..."
}
}

📡 Broadcast Transaction (POST /v1/solana/broadcast-transaction)

Broadcast a previously signed transaction and wait for confirmation. The endpoint polls the network until the transaction is confirmed or times out after 30 seconds.

Features:

  • Broadcasts signed transactions to Solana
  • Waits for confirmation before returning
  • Detailed error messages for failed transactions
  • Returns signature (Solana's equivalent of transaction hash)

Example:

curl -X POST https://api.thirdweb.com/v1/solana/broadcast-transaction \
-H "Content-Type: application/json" \
-H "x-secret-key: YOUR_SECRET_KEY" \
-d '{
"chainId": "solana:devnet",
"signedTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIAAQIDBAUGBwgJ..."
}'

Success Response:

{
"result": {
"signature": "5ttCNobho7nk5F1Hh4pU4d9T2o1yAFn3p1w8z8jk2jKd9KWCKN6dzyuT5xP1ny4wz9f5xCLjAF6Y9s9EoTW4aE1X"
}
}

Error Response (Transaction Failed):

{
"message": "Transaction failed at instruction 0",
"error": {
"transactionError": {
"InstructionError": [
0,
"InsufficientFunds"
]
},
"instructionIndex": 0,
"instructionError": "InsufficientFunds",
"signature": "5ttCNobho7nk5F1Hh4pU4d9T2o1yAFn3p1w8z8jk2jKd9KWCKN6dzyuT5xP1ny4wz9f5xCLjAF6Y9s9EoTW4aE1X"
}
}

Complete Workflow Example

Sign a transaction, then broadcast it:

# Step 1: Sign the transaction
SIGNED_TX=$(curl -X POST https://api.thirdweb.com/v1/solana/sign-transaction \
-H "Content-Type: application/json" \
-H "x-secret-key: YOUR_SECRET_KEY" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"chainId": "solana:devnet",
"instructions": [...]
}' | jq -r '.result.signedTransaction')
# Step 2: Broadcast the signed transaction
curl -X POST https://api.thirdweb.com/v1/solana/broadcast-transaction \
-H "Content-Type: application/json" \
-H "x-secret-key: YOUR_SECRET_KEY" \
-d "{
\"chainId\": \"solana:devnet\",
\"signedTransaction\": \"$SIGNED_TX\"
}"

Error Handling

The broadcast endpoint provides detailed error information:

  • 400: Transaction failed (simulation or on-chain) - includes error details, instruction index, and signature
  • 504: Transaction timeout - not confirmed within 30 seconds
  • 500: Server error during broadcast

All errors include the transaction signature when available, allowing you to look up the transaction on Solana explorers for debugging.

Notes

  • Signature = Transaction Hash: In Solana, the "signature" is equivalent to an EVM transaction hash - use it to look up transactions on explorers
  • Confirmation: The broadcast endpoint waits for "confirmed" status before returning (typically 1-2 seconds on Solana)
  • Timeout: 30-second maximum wait time for confirmation
  • Preflight Checks: Failed transactions are caught during simulation before being sent to the network when possible
Firekeeper

Arc Testnet is now supported by both of thirdweb's Account Abstraction solutions, EIP-4337 Smart Wallets and EIP-7702 stack - you can now use our sponsored execution features across all our interfaces. x402 via Nexus soon as well.

Support in API

curl https://api.thirdweb.com/v1/transactions \
--request POST \
--header 'Content-Type: application/json' \
--header 'x-secret-key: nnD...LafQ' \
--data '{
"chainId": 5042002,
"transactions": [
{
"data": "0x",
"to": "vitalik.eth",
"value": "0"
}
]
}'

Support in Typescript/React

const wallet = inAppWallet({
executionMode: {
mode: "EIP7702",
sponsorGas: true,
},
});

Support in .NET/Unity

var wallet = await InAppWallet.Create(
client: myThirdwebClient,
authProvider: AuthProvider.Guest,
executionMode: ExecutionMode.EIP7702Sponsored
);

Documentation for sponsoring transactions available here.

Firekeeper

Etherlink Testnet and Etherlink Mainnet are now supported by thirdweb's EIP-7702 stack - you can now use our sponsored 7702 execution mode via all our interfaces.

Support in API

curl https://api.thirdweb.com/v1/transactions \
--request POST \
--header 'Content-Type: application/json' \
--header 'x-secret-key: nnD...LafQ' \
--data '{
"chainId": 128123,
"transactions": [
{
"data": "0x",
"to": "vitalik.eth",
"value": "0"
}
]
}'

Support in Typescript/React

const wallet = inAppWallet({
executionMode: {
mode: "EIP7702",
sponsorGas: true,
},
});

Support in .NET/Unity

var wallet = await InAppWallet.Create(
client: myThirdwebClient,
authProvider: AuthProvider.Guest,
executionMode: ExecutionMode.EIP7702Sponsored
);

Documentation for sponsoring transactions available here.

Firekeeper

Sei Testnet and Sei Mainnet are now supported by thirdweb's EIP-7702 stack - you can now use our sponsored 7702 execution mode via all our interfaces.

Support in API

curl https://api.thirdweb.com/v1/transactions \
--request POST \
--header 'Content-Type: application/json' \
--header 'x-secret-key: nnD...LafQ' \
--data '{
"chainId": 1329,
"transactions": [
{
"data": "0x",
"to": "vitalik.eth",
"value": "0"
}
]
}'

Support in Typescript/React

const wallet = inAppWallet({
executionMode: {
mode: "EIP7702",
sponsorGas: true,
},
});

Support in .NET/Unity

var wallet = await InAppWallet.Create(
client: myThirdwebClient,
authProvider: AuthProvider.Guest,
executionMode: ExecutionMode.EIP7702Sponsored
);

Documentation for sponsoring transactions available here.

Firekeeper

What's Changed

  • Added Login With Siwe node that works similarly to Login With OAuth, allowing you to either Sign In with an External Wallet or Link an External Wallet to an existing In-App/Ecosystem Wallet.
image
  • Improved authentication session cleanup and lifecycle handling.
  • Enhanced thread-safety for authentication callbacks.
  • Fixed various flows that might lead to a crash.

Links

Github | Fab Marketplace (2.4.0 will be approved on Fab in a few days)

Firekeeper

Celo is now supported by thirdweb's EIP-7702 stack - you can now use our sponsored 7702 execution mode in the SDK (or implicitly, send transactions via the thirdweb API)

const wallet = inAppWallet({
// enable gasless transactions for the wallet
executionMode: {
mode: "EIP7702",
sponsorGas: true,
},
});

Documentation for sponsoring transactions available here.

Firekeeper

Hyperliquid is now supported by thirdweb's ERC-4337 stack - you can now use Smart Wallets on Hyperliquid Testnet & Mainnet.

const wallet = inAppWallet({
executionMode: {
mode: "EIP4337",
smartAccount: {
chain: defineChain(998),
sponsorGas: true,
},
},
});

We hope to integrate EIP-7702 relaying as well once the HyperEVM supports it.

Documentation for sponsoring transactions available here.

Prithvish Baidya

Following our recent announcement of Solana API support, we're excited to bring Solana server wallet management directly into the thirdweb dashboard. You can now create, manage, and test Solana wallets through an intuitive interface, no code required.

What's New

Dashboard Support for Solana Server Wallets

The Vault in your project dashboard now supports Solana! Upgrade your vault to unlock the ability to create and manage Solana server wallets directly from the UI. Every wallet you create is immediately available for use with the Solana API we announced previously.

Key Features

Create Solana Server Wallets

Navigate to Transactions in your project sidebar and locate the Server Wallets card. If you're on an existing project, you'll be prompted to upgrade your vault to enable Solana support. New projects have this enabled by default. Just click "Create Wallet", select Solana as your chain, give it a label, and your wallet is provisioned instantly. No keypair management, no security headaches.

Each wallet gets:

  • A unique Solana address (mainnet and devnet supported)
  • Automatic secure key management
  • Immediate API access via your project's secret key
  • Full transaction history and monitoring

Send Test Transactions

Before going live, test your setup directly in the dashboard. The built-in transaction interface lets you send a 0 SOL transaction and view transaction status in real-time.

Perfect for testing integrations, verifying wallet balances, or running through your transaction flows before deployment.

Seamless API Integration

Every dashboard-created wallet works immediately with the Solana API endpoints:

  • Use POST /v1/solana/send to transfer tokens programmatically
  • Submit custom transactions with POST /v1/solana/transactions
  • Sign messages with POST /v1/solana/sign-message
  • List all your wallets with GET /v1/solana/wallets

Your wallet's label and address are available in both the dashboard UI and via API, making it easy to manage wallets across your team and your applications.

Getting Started

  1. Navigate to Transactions
    From your project dashboard, click "Transactions" in the sidebar.
  2. Upgrade Vault (Existing Projects Only)
    In the Server Wallets card, click "Enable Solana" if prompted. New projects can skip this step, Solana support is already enabled.
  3. Create Your First Wallet
    Click "Create Wallet", select "Solana" as the chain, choose mainnet or devnet, and give it a descriptive label like "my-treasury-wallet".
  4. Send a Test Transaction
    Click into your new wallet and use the "Send" interface to transfer some SOL. Watch the transaction confirm in real-time.
  5. Use with API
    Copy your wallet address and start using it with the Solana API endpoints. Authenticate with your project's secret key via the x-secret-key header.

Transaction Details

Click on any transaction to view comprehensive information including signature, signer address, slot number, confirmation time, block time, and instruction-level details. The detailed view breaks down each instruction with program IDs, account metadata, and raw transaction data. Perfect for debugging and understanding exactly what happened on-chain.

Firekeeper

Introduces a new GET /v1/bridge/routes endpoint to list supported bridge routes with pagination and optional filters for source/destination chains and tokens.

Added

  • GET /v1/bridge/routes — list all supported bridge routes
  • Supports filters:
    • by origin/destination chain
    • by token address
    • by max steps (e.g. single-hop routes)
  • Pagination with limit, page, and hasMore

Examples

# Basic
curl -X GET "https://api.thirdweb.com/v1/bridge/routes?limit=10&page=1" \
-H "x-secret-key: YOUR_SECRET_KEY"
# From Ethereum → Base
curl -X GET "https://api.thirdweb.com/v1/bridge/routes?originChainId=1&destinationChainId=8453" \
-H "x-secret-key: YOUR_SECRET_KEY"
# Single-hop
curl -X GET "https://api.thirdweb.com/v1/bridge/routes?maxSteps=1" \
-H "x-secret-key: YOUR_SECRET_KEY"
# Filter by token
curl -X GET "https://api.thirdweb.com/v1/bridge/routes?originChainId=1&originTokenAddress=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" \
-H "x-secret-key: YOUR_SECRET_KEY"
# Combined filters
curl -X GET "https://api.thirdweb.com/v1/bridge/routes?originChainId=1&destinationChainId=8453&originTokenAddress=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&maxSteps=2" \
-H "x-secret-key: YOUR_SECRET_KEY"

Response Format

{
"result": {
"routes": [
{
"originToken": {
"chainId": 1,
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6,
"iconUri": "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694"
},
"destinationToken": {
"chainId": 8453,
"address": "0xfA980cEd6895AC314E7dE34Ef1bFAE90a5AdD21b",
"symbol": "PRIME",
"name": "Prime",
"decimals": 18,
"iconUri": "https://coin-images.coingecko.com/coins/images/29053/large/prime-logo-small-border_%282%29.png?1696528020"
}
}
],
"pagination": {
"limit": 1,
"page": 1,
"hasMore": true
}
}
}
Manan Tank

Improved Transaction Details page - now with Bridge Status and a cleaner, explorer-style design

Bridge Status

Transactions that are part of a bridge now display a dedicated Bridge section showing cross-chain details, token amounts, and status.

Example: https://thirdweb.com/polygon/tx/0x28486b565957a64eec8e408f149e796d455537f360b23442e51cbec812df233f

Transaction Details with Bridge Status

UI Improvements

The general transaction details layout has been updated to align with the standard design used in most chain explorers, making it more user-friendly

Manan Tank

We’ve added a new Webhook Events view for Bridge webhooks to help monitor and debug webhook deliveries more easily.

You can now:

  • View all delivery attempts - see every webhook event sent to your endpoint, along with status codes, timestamps, and payload details.
  • Inspect payloads and responses - review the exact JSON payload and the response returned by your endpoint.
  • Resend webhooks - trigger a webhook delivery again with the same payload, which is useful for testing or retrying failed events.
Webhook Events
Firekeeper

We're proud to announce initial support for Solana via the thirdweb API. This is the first of many releases making Solana more accessible to Ethereum developers.

Note: For the time being, you must create a new project from the thirdweb dashboard and use its secret key (server-side) to authenticate to the Solana APIs via the x-secret-key header.

Getting Started

All Solana endpoints are available at https://api.thirdweb.com/v1/solana/* and require authentication via the x-secret-key header:

x-secret-key: YOUR_SECRET_KEY

The API supports both Solana Mainnet (solana:mainnet) and Solana Devnet (solana:devnet) networks.


Create a Solana Wallet

Create or retrieve a managed Solana wallet using a unique label. If a wallet with the given label already exists, it will be returned instead of creating a new one.

Endpoint: POST https://api.thirdweb.com/v1/solana/wallets

Example Request:

curl -X POST https://api.thirdweb.com/v1/solana/wallets \
-H "x-secret-key: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "my-treasury-wallet"
}'

Example Response:

{
"result": {
"address": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"label": "my-treasury-wallet",
"createdAt": "2025-10-11T14:22:11.000Z",
"updatedAt": "2025-10-11T14:22:11.000Z"
}
}

The wallet is securely stored and can be used for signing transactions and messages.


List Solana Wallets

Retrieve all Solana wallets created for your project with pagination support.

Endpoint: GET https://api.thirdweb.com/v1/solana/wallets

Query Parameters:

  • page (optional): Page number, defaults to 1
  • limit (optional): Number of wallets per page (1-500), defaults to 100

Example Request:

curl -X GET "https://api.thirdweb.com/v1/solana/wallets?page=1&limit=50" \
-H "x-secret-key: YOUR_SECRET_KEY"

Example Response:

{
"result": {
"wallets": [
{
"address": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"label": "my-treasury-wallet",
"createdAt": "2025-10-11T14:22:11.000Z",
"updatedAt": "2025-10-11T14:22:11.000Z"
}
],
"pagination": {
"totalCount": 125,
"page": 1,
"limit": 50
}
}
}

Send Tokens

Transfer native SOL or SPL tokens with a single API call. The API automatically handles SPL token account creation if needed.

Endpoint: POST https://api.thirdweb.com/v1/solana/send

Send Native SOL

Example Request:

curl -X POST https://api.thirdweb.com/v1/solana/send \
-H "x-secret-key: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"to": "FhtwVYF1wKAm7fWmE2N5P2eCv13wt2aT8W4Q9NQ9YcJH",
"amount": "1000000",
"chainId": "solana:devnet"
}'
Note: Amounts are specified in lamports (1 SOL = 1,000,000,000 lamports)

Send SPL Tokens (Like USDC)

Example Request:

curl -X POST https://api.thirdweb.com/v1/solana/send \
-H "x-secret-key: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"to": "FhtwVYF1wKAm7fWmE2N5P2eCv13wt2aT8W4Q9NQ9YcJH",
"amount": "1000000",
"chainId": "solana:devnet",
"tokenAddress": "HZW5eXoaZySUdkGFwmkpfMoP1jmvYzu3PV6PvUCa3y7F"
}'

Example Response:

{
"result": {
"transactionId": "solana-tx-queue-id-abc123"
}
}

Transactions are queued and processed asynchronously. Use the returned transactionId to poll for status.


Send Transaction

For advanced use cases, submit custom Solana transactions with one or more instructions. This gives you full control over program interactions.

Endpoint: POST https://api.thirdweb.com/v1/solana/transactions

Example Request (SOL Transfer):

curl -X POST https://api.thirdweb.com/v1/solana/transactions \
-H "x-secret-key: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"chainId": "solana:devnet",
"transactions": [
{
"programId": "11111111111111111111111111111111",
"accounts": [
{
"address": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"isSigner": true,
"isWritable": true
},
{
"address": "FhtwVYF1wKAm7fWmE2N5P2eCv13wt2aT8W4Q9NQ9YcJH",
"isSigner": false,
"isWritable": true
}
],
"data": "02000000e888b30000000000",
"encoding": "hex"
}
]
}'

Instruction Fields:

  • programId: The Solana program to invoke
  • accounts: Array of account metadata (address, isSigner, isWritable)
  • data: Instruction data in hex or base64 encoding
  • encoding: Either "hex" or "base64" (defaults to "base64")

Example Response:

{
"result": {
"transactionId": "solana-tx-queue-id-xyz789"
}
}

Get Transaction

Check the status of any queued transaction using its transaction ID.

Endpoint: GET https://api.thirdweb.com/v1/solana/transactions/{transactionId}

Example Request:

curl -X GET https://api.thirdweb.com/v1/solana/transactions/solana-tx-queue-id-abc123 \
-H "x-secret-key: YOUR_SECRET_KEY"

Example Response:

{
"result": {
"id": "solana-tx-queue-id-abc123",
"chainId": "solana:devnet",
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"signature": "5j8k9L4mN3pQ2rS7tU6vW8xY9zA1bC2dE3fG4hH5iJ6kK7lL8mM9nN0oO1pP2qQ3rR4sS5tT6uU7vV8wW9xX0yY",
"status": "CONFIRMED",
"confirmedAt": "2025-10-11T14:23:45.000Z",
"confirmedAtSlot": "123456789",
"blockTime": 1728654225,
"createdAt": "2025-10-11T14:23:11.000Z",
"errorMessage": null,
"clientId": "your-client-id"
}
}

Transaction Statuses:

  • QUEUED: Transaction is waiting to be submitted
  • SUBMITTED: Transaction has been submitted to the network
  • CONFIRMED: Transaction is confirmed on-chain
  • FAILED: Transaction failed (check errorMessage for details)

Sign Message

Sign arbitrary messages with your Solana wallet. Supports both plain text and hexadecimal formats with automatic detection.

Endpoint: POST https://api.thirdweb.com/v1/solana/sign-message

Example Request (Plain Text):

curl -X POST https://api.thirdweb.com/v1/solana/sign-message \
-H "x-secret-key: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"message": "Welcome to my dApp!"
}'

Example Request (Hex Format):

curl -X POST https://api.thirdweb.com/v1/solana/sign-message \
-H "x-secret-key: YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "8JBLmveV4YF5AQ7EVnKJgyj6etGgVkPp3tYqQMTu3p5B",
"message": "0x48656c6c6f20536f6c616e61"
}'

Example Response:

{
"result": {
"signature": "5Nftk1W4nN6Xr2y4griH4sHqY2cD3rPrXg5BDJ9Y6hHSF3oURaUz6VXo4Qzv6TQ2Jj3MdE4Y5nVkq"
}
}

The signature is returned in Base58 format and can be used for authentication and verification.


Coming Soon

We're actively working on expanding our Solana support. Here's what's coming next:

Official thirdweb Solana RPCs

High-performance, globally distributed RPC endpoints optimized for Solana applications.

Solana Swap API

Seamlessly swap tokens on Solana with the best rates from top DEXs like Jupiter and Raydium.

Solana Token Deployment API

Deploy your own SPL tokens with a single API call, including support for Token-2022 program features.


Need Help?

We can't wait to see what you build with Solana on thirdweb! 🚀

Yash Kumar

We have added support for creating and deploying ZK Proof based token contracts with Stylus. The templates provide you with Stylus contracts, ZK circuit files, and a ready-to-deploy Next.js app + API for proof generation and minting.

This guide walks you through building a privacy-preserving ERC721 token system using Zero-Knowledge proofs on Arbitrum Stylus. Users can mint tokens by proving they own a minimum amount of ETH without revealing their exact balance.

What You'll Build

  • ZK Circuit: Proves token ownership without revealing exact balances
  • Stylus Contract: Rust-based ERC721 contract that verifies ZK proofs
  • Frontend: Next.js app for generating proofs and minting tokens
  • Oracle System: Secure balance verification mechanism

Prerequisites

Step 1: Project Setup

Using thirdweb CLI

npx thirdweb create-stylus

Select "Stylus ZK ERC721" from the dropdown menu. This will:

  • Clone the repository to your machine
  • Set up the project structure
  • Install basic dependencies

Manual Setup (Alternative)

git clone https://github.com/thirdweb-example/stylus-zk-erc721.git
cd stylus-zk-erc721

Step 2: Install Dependencies

Install dependencies for all components:

# Install root dependencies
pnpm install
# Install circuit dependencies
cd circuits
pnpm install
cd ..
# Install frontend dependencies
cd app
pnpm install
cd ..

Step 3: Generate Cryptographic Keys

Run the setup script to generate oracle keys and build the ZK circuit:

chmod +x setup.sh
./setup.sh

This script will:

  • Generate a random oracle secret key
  • Inject the secret into the ZK circuit
  • Compile the circuit with circom
  • Generate proving and verification keys
  • Create the trusted setup for Groth16

⚠️ Important: The oracle secret is critical for security. Keep it private!

Step 4: Deploy the Contract

Using thirdweb CLI

cd contracts
npx thirdweb@latest deploy-stylus -k <THIRDWEB_SECRET_KEY>

Using Stylus CLI (Alternative)

cd contracts
cargo stylus deploy --endpoint arbitrum-sepolia

Copy the deployed contract address - you'll need it for the frontend.

Step 5: Configure the Frontend

Update the contract address in your frontend:

cd app
# Edit pages/index.tsx or lib/config.ts
# Update ZK_MINT_CONTRACT_ADDRESS with your deployed address

Create environment file:

# app/.env.local
RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
ORACLE_SECRET_KEY=<your_oracle_secret_from_setup>

Step 6: Run the Application

cd app
pnpm dev
# Visit http://localhost:3000

Step 7: Test the System

  1. Connect Wallet: Connect to Arbitrum Sepolia testnet
  2. Generate Proof: Click "Generate ZK Proof" - this proves you have sufficient balance
  3. Mint Tokens: Use the proof to mint ERC721 tokens

Customizing the ZK Logic

Understanding the Circuit

The core circuit (circuits/token_ownership.circom) has these components:

template TokenOwnership(oracle_secret) {
// Private inputs (hidden from public)
signal input actual_balance; // Real balance from oracle
signal input salt; // Randomness for uniqueness
// Public inputs (visible on-chain)
signal input min_required_balance; // Minimum threshold
signal input token_contract_hash; // Which token to check
signal input user_address_hash; // User's address hash
signal input timestamp; // When oracle signed data
signal input oracle_commitment; // Oracle's commitment
// Output
signal output nullifier; // Prevents replay attacks
}

Customization Examples

1. Change Balance Threshold Logic

Replace the balance check with custom logic:

// Original: Simple greater-than check
component gte = GreaterEqThan(64);
gte.in[0] <== actual_balance;
gte.in[1] <== min_required_balance;
gte.out === 1;
// Custom: Logarithmic scaling
component log_check = LogarithmicCheck();
log_check.balance <== actual_balance;
log_check.threshold <== min_required_balance;
log_check.out === 1;

2. Add Multiple Token Support

Extend the circuit to verify multiple token balances:

template MultiTokenOwnership(oracle_secret, num_tokens) {
signal input actual_balances[num_tokens];
signal input min_required_balances[num_tokens];
signal input token_addresses[num_tokens];
// Verify each token separately
component checks[num_tokens];
for (var i = 0; i < num_tokens; i++) {
checks[i] = GreaterEqThan(64);
checks[i].in[0] <== actual_balances[i];
checks[i].in[1] <== min_required_balances[i];
checks[i].out === 1;
}
}

3. Add Time-Based Constraints

Add expiration logic to proofs:

// Add time validation
component time_check = LessThan(64);
time_check.in[0] <== timestamp;
time_check.in[1] <== max_timestamp; // New public input
time_check.out === 1;

Rebuilding After Changes

After modifying the circuit:

cd circuits
pnpm run build
# Re-inject verification keys
cd ..
node scripts/inject-vk.js
# Recompile contract
cd contracts
cargo build

Additional Resources

Support

Need help? Please reach out to our support team.

Manan Tank

We’ve made several updates to the BuyWidget component to make it more flexible, interactive, and user-friendly - giving users more control while simplifying integration.

New BuyWidget UI

Token and Chain selection can now be changed in the widget UI

Clicking on the selected token opens a Modal that allows changing the selected chain and token. chain, and amount props are now optional

Both fiat and token amounts are editable

Both the fiat and token amount fields can be edited, making it easier to input custom fiat amounts beyond just selecting the suggested fiat amounts.

The wallet's current balance is also shown in the bottom-right corner which helps in choosing the buy amount

Connected wallet displayed

A button is added on the top-right corner that shows the connected wallet, Clicking on it opens the Wallet Details modal, which allows switching the active wallet or disconnecting the wallet

Try it out

Try out the new and improved BuyWidget in playground

Firekeeper

TLDR: The thirdweb API from fields when transacting are now optional - this is powered by the newly launched Project Wallets - go set one up!

What’s new

When you’re orchestrating transactions from your backend, repeating the same sender address in every payload is the definition of busywork. Starting today, you can skip it. Authenticate with your project’s secret key, leave off the from field, and we’ll launch those transactions straight from your project wallet.

  • Automatic sender fallback for server-side flows that use your project secret key.
  • Works everywhere you submit encoded calls, trigger wallet actions, deploy or write contracts, mint tokens, process payments, or swap via the bridge API.
  • Still honors explicit from values when you need to override the default.

Why you’ll love it

Removing boilerplate means less room for typos, quicker prototyping, and cleaner shared helpers. Your integrations stay lean while every transaction still resolves to the right wallet.

Try it now

curl https://api.thirdweb.com/v1/transactions \
-H "Content-Type: application/json" \
-H "x-secret-key: <your-secret-key>" \
-d '{
"chainId": 421614,
"transactions": [
{
"data": "0x",
"to": "vitalik.eth",
"value": "0"
}
]
}'

No from required—just the secret key that unlocks your project wallet.