Sim IDX provides a complete serverless API development environment with built-in database connectivity, automatic scaling, and edge deployment. Whether you’re building simple data endpoints or advanced features, the platform handles infrastructure concerns so you can focus on your business logic. This guide walks you through the complete API development lifecycle on the platform.

Infrastructure & Scalability

Your API runs on Cloudflare Workers with the Hono framework. Anything you can do in Hono will also work here. Your data is stored, by default in a Neon Postgres database accessed through Cloudflare Hyperdrive.
As an alternative, you can also set up Kafka sinks to stream your indexed blockchain data in real-time to external data sinks like Confluent Cloud or Redpanda Cloud, in addition to the default Postgres database.
Requests execute at the edge close to users, and database connections are pooled automatically, so you don’t have to manage servers or connection limits.
The setup scales with your traffic, but there are sensible platform limits. If you anticipate sustained very high volume, please contact us.

Local Development Setup

Building APIs on Sim IDX follows a streamlined workflow. You develop locally, write endpoints to query your indexed data, and deploy with a simple git push. The boilerplate API in the apis/ directory gives you a starting point with common patterns for querying your indexed blockchain data and serving it through HTTP endpoints. Before deploying, you can run and test your API locally.
1

Navigate to the API directory

cd apis
2

Set Up Environment Variable

Create a file named .dev.vars in the apis/ directory. Add the database connection string, which you can find on the App Page after deploying your app for the first time.
```plaintext .dev.vars
DB_CONNECTION_STRING="your_database_connection_string_from_app_page"
```
3

Install Dependencies

npm install
4

Start the Development Server

npm run dev
Your API is now running locally at `http://localhost:8787`.

Understand the API Code

The boilerplate API in apis/src/index.ts is a TypeScript application that runs on Cloudflare Workers. It connects to your indexed database and exposes HTTP endpoints to query your data. Let’s understand how this works.

Framework Setup

The API uses the @duneanalytics/sim-idx helper library, which wraps Hono and Drizzle to simplify setup:
import { App, db, types } from "@duneanalytics/sim-idx";
import { eq, sql } from "drizzle-orm";
import { poolCreated, ownerChanged } from "./db/schema/Listener";
Hono handles HTTP requests and routing, while Drizzle provides a type-safe way to query your PostgreSQL database.

Environment Configuration

@duneanalytics/sim-idx automatically handles credentials in production. For local development, place DB_CONNECTION_STRING in .dev.vars as shown above if you need to supply your own connection string.

Application Instance

Create the web application with a single call:
const app = App.create();

Database Connection Management

Instead of managing your own connection pool, call db.client(c) inside a request handler to reuse the shared Drizzle client:
const rows = await db.client(c)
  .select()
  .from(poolCreated)
  .limit(10);

Add a New Endpoint

Let’s build three endpoints to serve our indexed data: /api/pools to get recent Uniswap V3 pools, /api/owner-changed to get recent owner changed events, and /api/pools/count to get the total number of pools.

Creating the Pools Endpoint

Create an endpoint to fetch the 10 most recent Uniswap V3 pools. This endpoint queries the pool_created table from your listener.
// Endpoint to get the 10 most recent Uniswap V3 pools
app.get("/api/pools", async (c) => {
  try {
    const rows = await db.client(c)
      .select()
      .from(poolCreated)
      .limit(10);

    return Response.json({ data: rows });
  } catch (e) {
    console.error("Database operation failed:", e);
    return Response.json({ error: (e as Error).message }, { status: 500 });
  }
});
This endpoint uses a simple SQL query to fetch the most recent pools. The LIMIT 10 clause keeps the response small. In a production environment, consider adding pagination and filtering.

Adding the Owner Changed Endpoint

Before continuing, make sure you’ve added support for the OwnerChanged event in your listener contract by following the “Triggering more functions and events” section of the Listener guide and then running:
sim build
Running sim build regenerates apis/src/db/schema/Listener.ts with a new ownerChanged table binding that we import below.
Add an endpoint to fetch the 10 most recent owner changed events. This endpoint queries the owner_changed table.
// Endpoint to get the 10 most recent owner changed events
app.get("/api/owner-changed", async (c) => {
  try {
    const rows = await db.client(c)
      .select()
      .from(ownerChanged)
      .limit(10);

    return Response.json({ data: rows });
  } catch (e) {
    console.error("Database operation failed:", e);
    return Response.json({ error: (e as Error).message }, { status: 500 });
  }
});

Creating the Pool Count Endpoint

Finally, add an endpoint to get the total number of pools. This is useful for pagination and analytics.
// Endpoint to get the total number of pools
app.get("/api/pools/count", async (c) => {
  try {
    const [{ total }] = await db.client(c)
      .select({ total: sql<number>`COUNT(*)` })
      .from(poolCreated);

    return Response.json({ data: total });
  } catch (e) {
    console.error("Database operation failed:", e);
    return Response.json({ error: (e as Error).message }, { status: 500 });
  }
});
This endpoint uses an aggregate query to count pools without fetching every row.

Testing Your Endpoints

After adding all three endpoints, you can test them locally at http://localhost:8787/api/pools, http://localhost:8787/api/owner-changed, and http://localhost:8787/api/pools/count.

Authenticate API Endpoints

Sim IDX provides built-in authentication middleware that integrates seamlessly with your app and the platform. When deployed to production, the authentication middleware requires a valid Sim IDX App Endpoints API key to be passed with each request. Sim’s infrastructure validates the key and, if successful, allows the request to proceed. Unauthenticated requests return a 401 Unauthorized error. During local development, the authentication middleware automatically disables authentication checks when your API is running locally. This occurs when NODE_ENV is not production. This allows you to test endpoints without managing keys.

Create a Sim IDX App Endpoints API Key

Your API will need a Sim IDX App Endpoints API key to access your authenticated endpoints. You can generate a new key from the Sim dashboard.

To generate a new API key, visit the Keys page and click the New button.

When creating the key, its purpose should be set to Sim IDX App Endpoints. Keep this key secure and do not expose it in client-side code.

Understanding the Authentication Middleware

The authentication middleware is enabled by default in your API. When you create a new Sim IDX app, the boilerplate code in apis/src/index.ts already includes the necessary authentication setup:
apis/src/index.ts
import { App, db, types, middlewares } from "@duneanalytics/sim-idx";
import { eq, sql } from "drizzle-orm";
import { poolCreated, ownerChanged } from "./db/schema/Listener";

const app = App.create();

// Authentication middleware is applied to all routes by default
app.use("*", middlewares.authentication);

// Your endpoints...
app.get("/api/pools", async (c) => {
  // ...
});

export default app;
The middlewares.authentication is applied to all routes using the app.use("*", middlewares.authentication) line. This ensures that every endpoint in your API requires authentication when deployed.

Calling Your Authenticated API

Once your API is deployed, you must include your Sim IDX App Endpoints API key in the Authorization header with every request. Here is an example using cURL.
curl --request GET \
  --url https://<your-api-url>/api/pools \
  --header 'Authorization: Bearer YOUR_SIM_IDX_APP_ENDPOINTS_API_KEY'
Replace <your-api-url> with your deployment’s base URL and YOUR_SIM_IDX_APP_ENDPOINTS_API_KEY with a valid Sim IDX App Endpoints API key.

Wrangler Configuration

Your API uses a wrangler.jsonc file in the apis/ directory for local tooling and build metadata. This file is already created when you initialize a new project. Sim IDX reads a minimal set of fields from this file during deployment. Other fields in this file are not used by the Sim IDX deployment flow.
Sim IDX deploys only the code that is reachable from your entrypoint during the build. Static files and local state are not packaged. Files on disk such as images, CSV or JSON blobs, or a local Wrangler state directory are not uploaded.
The existing apis/wrangler.jsonc contains:
{
  "name": "sim-apis-sample-app",
  "compatibility_date": "2025-05-28", // Update this date to the current date
  "main": "src/index.ts",
  "compatibility_flags": ["nodejs_compat"]
}
If you add additional keys to this file, the Sim IDX deployment will not use them. Some keys may appear harmless in local development, but they will not change how your production Cloudflare worker runs.

Local vs Deploy

Local development tools can sometimes access files on your machine. The deployed worker does not have a filesystem. Do not read from disk in your request handlers. If you need small reference data then embed it at build time as a TypeScript module import. If you need larger assets then host them behind HTTPS and fetch them at runtime.
CapabilityLocal dev (npm run dev)Deployed on Sim IDXWhat to do
Read ./file.jsonMay appear to workNot availableEmbed at build time or fetch remotely
Serve files from assets/ or public/May serve locallyNot packagedHost externally and fetch
Extra fields in wrangler.jsoncMay work locallyNot usedKeep only name, main, compatibility_date, compatibility_flags

Deploy Your API

Once your repository is connected, shipping updates is as simple as pushing code. Push commits to the main branch to roll out a new production deployment. Push to any other branch to spin up a preview deployment with its own URL. This is useful for staging and pull-request reviews. Sim IDX automatically builds your Cloudflare Worker and updates the deployment status in the dashboard. No CLI command is required.
Before pushing, review your wrangler.jsonc and remove fields that are not name, main, or compatibility_date. Also make sure your handlers do not read from the filesystem. If you need data, either embed it at build time or fetch it from a remote source.