Getting Started
Engine is self-hosted with minimal configuration.
Setup
Requirements
- Docker
- A thirdweb secret key from the API Keys page
Start the database
A Postgres DB instance is required to run Engine. AWS RDS or Google Cloud SQL are recommended for production use.
Or run Postgres locally to get started quickly:
docker run -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres
This step provides a local Postgres DB URL for the next step:
POSTGRES_CONNECTION_URL="postgresql://postgres:postgres@host.docker.internal:5432/postgres?sslmode=disable"
Start the Engine server
Download and run the Docker container:
docker run \
-e THIRDWEB_API_SECRET_KEY="<thirdweb_secret_key>" \
-e ADMIN_WALLET_ADDRESS="<admin_wallet_address>" \
-e POSTGRES_CONNECTION_URL="<postgres_connection_url>" \
-e ENABLE_HTTPS=true \
-p 3005:3005 \
--pull=always \
--cpus="0.5" \
thirdweb/engine:latest
Provide the following environment variables:
Variable | Description |
---|---|
THIRDWEB_SECRET_KEY | A thirdweb secret key created on the API Keys page. |
ADMIN_WALLET_ADDRESS | The wallet address that will configure Engine from the thirdweb dashboard. |
POSTGRES_CONNECTION_URL | Postgres connection string: postgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...] |
ENABLE_HTTPS | Self-sign a certificate to serve API requests on HTTPS. Set to true if running Engine locally to manage it from the thirdweb dashboard. (Default: false ) |
Your server is running when this log line appears:
Server listening on: 0.0.0.0:3005
Here's a few pointers:
ENABLE_HTTPS=true
is only required when running Engine locally. Remove this line for production use.- Make sure your Engine instance port (default:
3005
) is publicly accessible. All configuration and API requests require authentication.
Dashboard management
Manage your Engine instance from the thirdweb dashboard:
Navigate to https://localhost:3005/json.
- The "Your connection is not private" page will appear.
- Select Show advanced and select Proceed to localhost (unsafe).
- A JSON file will be rendered. This one-time step is required to allow your browser to connect to your local Engine instance.
Navigate to the Engine dashboard page.
Sign in with the
<admin_wallet_address>
wallet.Select Set Engine instance URL to get started..
Add your publicly accessible Engine URL.
- If Engine is running locally, provide the URL
https://localhost:3005
.
- If Engine is running locally, provide the URL
The dashboard is organized in tabs:
- Overview: Manage backend wallets and transactions.
- Explorer: Interactively call API methods.
- Configuration: Manage backend wallet and webhook settings.
- Permissions: Manage admins and access tokens.
Using Engine
Create an access token
The Engine API requires a access token to authenticate requests. To create an access token:
- Navigate to the Engine dashboard page.
- Select the Permissions tab.
- Under Access Tokens, select Create Access Token.
- Provide an access token in the
Authorization
header when calling the Engine API:Authorization: Bearer <access_token>
See Authentication for advanced configuration.
Add a backend wallet
Engine uses your backend wallets to interact with the blockchain. To create a backend wallet:
- Navigate to the Engine dashboard page.
- Navigate to the Overview tab.
- Under Backend Wallets, select Create.
A local wallet is generated, and the encrypted private key is stored in your database.
See Backend Wallets for details on other wallet configuration or importing wallets.
Send gas funds to this backend wallet in order to call contract write methods.
Send blockchain transactions
Call the blockchain with a backend wallet with one API call. Here are some examples.
Get a wallet's balance
const resp = await fetch(
"<engine_url>/backend-wallet/<chain>/<backend_wallet_address>/get-balance",
{
headers: {
Authorization: "Bearer <access_token>",
},
},
);
const { result } = await resp.json();
console.log("Balance:", result.value);
Call a contract read method
This code example does not require gas funds and returns the function result.
const resp = await fetch(
"<engine_url>/contract/<chain>/<contract_address>/read?function_name=balanceOf&args=0x3EcDBF3B911d0e9052b64850693888b008e18373",
{
headers: {
Authorization: "Bearer <access_token>",
},
},
);
const { result } = await resp.json();
console.log("ERC-20 balance:", result);
Call a contract write method
This code example calls a write method on a contract. It requires gas funds and returns a queueId
to query for the result.
const resp = await fetch(
"<engine_url>/contract/<chain>/<contract_address>/write",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer <access_token>",
"x-backend-wallet-address": "<backend_wallet_address>",
},
body: JSON.stringify({
function_name: "transferFrom",
args: [
"0x1946267d81Fb8aDeeEa28e6B98bcD446c8248473",
"0x3EcDBF3B911d0e9052b64850693888b008e18373",
"0",
],
}),
},
);
const { result } = await resp.json();
// queueId is a reference to the transaction queued by Engine.
console.log("Queue ID:", result.queueId);
Deploy a contract
This code example deploys a thirdweb NFT drop contract. It requires gas funds and returns a queueId
to query for the result.
const resp = await fetch("<engine_url>/deploy/<chain>/prebuilts/nft-drop", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer <access_token>",
"x-backend-wallet-address": "<backend_wallet_address>",
},
body: JSON.stringify({
contractMetadata: {
name: "thirdweb Engine example",
symbol: "eng",
primary_sale_recipient: "0x3EcDBF3B911d0e9052b64850693888b008e18373",
},
}),
});
const { result } = await resp.json();
// queueId is a reference to the transaction queued by Engine.
console.log("Queue ID:", result.queueId);
Engine can enable your application to airdrop NFTs, send funds between wallets, update on-chain game state, and more.
Wait for a transaction to complete
Trigger an action when transactions complete by configuring webhooks to call your backend server.
Alternatively, query or poll the transaction/status/<queue_id>
endpoint:
const resp = await fetch("<engine_url>/transaction/status/<queue_id>", {
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
},
});
const { result } = await resp.json();
// status can be: processed, queued, sent, errored, mined, cancelled, retried
const isComplete = ["mined", "errored", "cancelled"].includes(result.status);