Gateway
Open tools at /a/<slug> or /<workspace>/<slug>. The hidden gateway path proxies the deployed tool and signs x-td-user for the app.
Documentation
Build, run, deploy, share, and operate agent-built internal tools. Everything here is public and written for both humans and coding agents: CLI commands, SDK calls, HTTP contracts, and the rules every tool must follow.
Getting started
A tool is a small app deployed behind the ToolDrop gateway. Start from the scaffold, let Claude Code or Codex build inside the contract, then deploy a version the workspace can open.
Install the CLI from your platform and sign in with the browser-approved device flow.
Scaffold a tool. The scaffold ships with the SDK, gateway guard, AGENTS.md, and CLAUDE.md.
Set required env vars, run locally, validate the contract, and deploy a version.
npm install -g https://tooldrop.app/cli.tgz
tooldrop login --url https://tooldrop.app
tooldrop init revenue-dashboard
cd revenue-dashboard
tooldrop env set DATABASE_URL --description "Read replica for reporting" --tag postgres
tooldrop dev
tooldrop validate
tooldrop deploy -m "first version"Getting started
The CLI opens a short-lived browser handoff. The human signs in or creates an account there, approves the connection, and the waiting terminal receives the token without exposing credentials to the agent.
When someone asks a desktop agent to deploy to ToolDrop, explain that the one-time setup installs the CLI and opens ToolDrop in their browser. Ask whether they already have an account so they know which browser choice to use; never ask for their password, verification code, or session token.
Install the platform-served CLI package with npm install -g <platform-url>/cli.tgz. A CLI downloaded from a ToolDrop platform remembers that platform; from a source checkout, pass --url <platform-url> to login.
Run tooldrop login --url <platform-url>. The CLI opens a short-lived authorization page. Existing users sign in; new users choose Create account on that sign-in screen. After signup or sign-in, the browser returns to the same CLI request so the human can choose a workspace and approve it.
Wait for the CLI to report the connected email and workspace, then run tooldrop whoami. The token is returned only to the CLI that started the flow and is stored in the macOS Keychain when available. Continue with init, validation, and deploy only after this succeeds.
npm install -g https://tooldrop.app/cli.tgz
tooldrop login --url https://tooldrop.app
# Existing account: sign in in the opened browser.
# New account: choose Create account, finish signup, then approve the CLI.
tooldrop whoamiGetting started
Six things ToolDrop owns so your agent-built app doesn't have to.
Open tools at /a/<slug> or /<workspace>/<slug>. The hidden gateway path proxies the deployed tool and signs x-td-user for the app.
Workspace builders connect Postgres, MySQL, and HTTP APIs once. Credentials stay encrypted, agents see safe metadata, and every app receives an explicit read or write grant used in both dev and production.
Each tool gets app-owned key/value storage behind td.storage. Team editors can browse and update records. On Pro an app can be upgraded to a managed database — the same protocol with far larger caps plus a provisioned DATABASE_URL for advanced SQL. Managed Postgres apps cannot be downgraded to Tool Storage because SQL tables cannot be preserved there.
Every deploy keeps source, author, status, message, and rollback metadata. Rollback repoints traffic to an existing ready version. On Team and Pro, --staging deploys build without going live so editors can preview (?sbv=N) and promote when ready.
Team and Pro workspaces can declare recurring jobs in tooldrop.json. ToolDrop generates the scheduler wrapper, records runs, and shows logs at the app level.
Team and Pro workspaces can declare public webhook endpoints in tooldrop.json. ToolDrop publishes stable platform URLs, forwards deliveries into app /api/webhooks/* handlers, and records delivery status plus logs.
ToolDrop automatically records app 5xx gateway failures and Team or Pro workspaces can browse/search app log lines written with td.log(), td.warn(), and td.error(). Editors can also read app, cron, and webhook logs through the CLI, HTTP API, or MCP.
A /s/<token> page starts invite-only, then can opt into guest viewer access or source remixing without env values.
The scaffold carries AGENTS.md and CLAUDE.md so coding agents know auth, secrets, storage, UI, and deployment rules.
Convert existing apps
A migration plan for teams bringing an existing page, dashboard, or internal app into ToolDrop without carrying over the old auth, secret, database, scheduler, or shell assumptions.
List framework, routes, auth/session code, env vars, database writes, file/blob storage, cron or queue workers, external APIs, and any pages that recreate workspace chrome.
Convert one useful page or workflow first. Prefer a stable read-only route, then move writes, background jobs, and larger data changes after the ToolDrop contract is passing.
Add tooldrop.json, declare required data resources and env keys, set framework/build/output fields when detection is not enough, and run with tooldrop dev so identity, data grants, base path, and storage match production.
Remove local auth, secret files, deployment dashboards, global nav, account/team settings, and host scheduler config. ToolDrop owns those surfaces; the tool keeps only the app workflow.
Run tooldrop validate, fix every contract failure, use tooldrop deploy --staging for risky changes on Team or Pro, then publish with a human deploy message.
You are converting an existing app into a ToolDrop tool.
First read AGENTS.md or run tooldrop docs.
Then make a narrow conversion plan:
1. Inventory routes, auth, env vars, data writes, crons, and local/global chrome.
2. Convert one page or workflow at a time.
3. Remove app-owned auth and use td.user() / useTDUser().
4. Move secrets to ToolDrop env vars and app-owned state to td.storage.
5. Convert scheduled work to /api/cron/* plus tooldrop.json crons.
6. Convert inbound webhooks to /api/webhooks/* plus tooldrop.json webhooks.
7. Run tooldrop validate before deploy.
Do not deploy until the human has reviewed the converted workflow.Open the converted route through tooldrop dev, not plain framework dev, and verify base-path-safe links, loading, empty, and error states.
Run tooldrop validate before every deploy and fix contract failures instead of bypassing them.
Run a local production build or tooldrop deploy --preflight-build after changing framework config, env use, cron routes, or server-only imports.
Use a staged deploy on Team or Pro for high-risk conversions, then promote only after an editor previews the version.
Write a deploy message that names the converted workflow, for example Converted invoice review to ToolDrop auth and storage.
Convert existing apps
ToolDrop owns sign-in and workspace access. The converted app keeps only workflow-specific permissions.
Delete app-owned login, logout, signup, session-cookie, next-auth, Clerk, Auth0, or custom JWT flows unless the human explicitly needs the tool to administer those systems.
Read the current viewer with server-side td.user() or client-side useTDUser() inside TDProvider; do not infer identity from browser storage or query params.
Move app-specific authorization into small domain checks, for example an allowed email/domain list, a role table read from an external system, or records stored in td.storage.
Keep the scaffold proxy.ts, lib/tooldrop/, and /api/td/* bridge intact. If the source app has middleware, merge only app-specific redirects and leave ToolDrop identity checks in place.
Remove auth screens from the converted page. The viewer reaches the tool through the ToolDrop workspace session and should land directly in the workflow.
Convert existing apps
Secrets become ToolDrop env vars, app-owned state moves to `td.storage`, and existing business systems stay behind server-side drivers or APIs.
Before declaring an env var missing, list accessible workspace-global variables with tooldrop env ls --global or MCP td_list_env with global: true. Match the user's requested integration semantically against key names and descriptions; if a global clearly covers it, declare that exact key in tooldrop.json and continue without asking for or retrieving its value.
Move database and API connections out of .env and code into approved ToolDrop resources; declare each required slug and read/write level under resources in tooldrop.json.
Keep external business systems external. Use td.resources.query() or td.resources.request() from server code so credentials stay encrypted and local development matches production.
Move app-owned preferences, saved filters, drafts, notes, review states, and small CRUD records into td.storage; do not add SQLite, an ORM, or new production tables for that state.
For existing local JSON, SQLite, or browser-local data, write a small import script or route that reads records and calls td.storage.set() / tooldrop db set with namespaced keys.
When the converted app outgrows Tool Storage, upgrade the app to a managed database on Pro before bringing a new provider. The same td.storage calls keep working and a managed DATABASE_URL can support direct SQL.
For existing production databases, start read-only when possible, add LIMITs to exploratory reads, parameterize queries, and confirm static egress or relay setup for IP-allowlisted hosts.
Convert existing apps
Scheduled work should be explicit in `tooldrop.json`, implemented as `/api/cron/*` handlers, and observable from the app's Scheduled jobs page.
Convert host scheduler files, worker entrypoints, and external cron callbacks into Next.js GET route handlers under /api/cron/* when the tool uses the Next scaffold.
Declare each schedule in tooldrop.json with name, path, and cron schedule; deploy live when changing schedules because scheduler config follows the live version.
Cron handlers run without a human viewer. Do not call td.user(); use server-side env vars, external APIs, td.storage, and idempotent job state such as sync:last-run.
Use td.cron.log() for progress lines that should appear on the app's Scheduled jobs page, and return concise JSON or text because the response is saved with the run.
Copy the latest scaffold proxy.ts if validation reports an old cron bypass marker.
{
"slug": "revenue-dashboard",
"name": "Revenue Dashboard",
"crons": [
{
"name": "daily-sync",
"path": "/api/cron/daily-sync",
"schedule": "0 12 * * *"
}
]
}Convert existing apps
Inbound webhook callbacks should be explicit in `tooldrop.json`, implemented as `/api/webhooks/*` handlers, and observable from the app's Webhooks page.
Convert third-party webhook receivers into Next.js route handlers under /api/webhooks/* when the tool uses the Next scaffold.
Declare each public endpoint in tooldrop.json with name, path, and optional methods; live deploys publish stable /webhooks/<deploy-slug>/<endpoint> URLs.
Webhook handlers run without a human viewer. Do not call td.user(); verify provider signatures with server-side env vars before trusting payloads.
Use td.webhook.log() for delivery-visible notes, and return concise JSON or text because the response is saved with the delivery.
Copy the latest scaffold proxy.ts if validation reports an old webhook bypass marker.
{
"slug": "revenue-dashboard",
"name": "Revenue Dashboard",
"webhooks": [
{
"name": "stripe-events",
"path": "/api/webhooks/stripe",
"methods": ["POST"]
}
]
}Reference
Everything builders and agents run day to day. Install once, then work from inside the tool directory.
tooldrop login --url <platform-url>Connect a local machine with the browser-approved device flow. Existing users sign in; new users choose Create account on the same screen, then return to approve the CLI.
tooldrop whoamiVerify the email, role, workspace, and platform connected to this machine before an agent deploys.
tooldrop init <name>Scaffold a new tool with Next.js, the ToolDrop SDK, proxy guard, AGENTS.md, and CLAUDE.md.
tooldrop dev [-p 4711]Run the tool locally behind the same gateway contract used in production.
tooldrop validateCheck tooldrop.json, framework settings, gateway files, SDK files, and obvious secret leaks.
tooldrop deploy -m "what changed"Run the local typecheck when available, package source, create a version, build on ToolDrop hosting, and publish through the workspace gateway.
tooldrop deploy --preflight-buildRun npm run build locally before uploading so build errors fail fast instead of waiting on the remote builder.
tooldrop deploy --stagingBuild a preview version that stays off the live URL. Editors preview it at ?sbv=N and promote it from the app's settings page (Team or Pro).
tooldrop env ls|get|set|pull|rmManage encrypted app env vars and metadata. Values are explicit to retrieve and injected server-side.
tooldrop env ... --globalList accessible workspace-global metadata before treating a requested integration or secret as missing. Match by key and description; declare the exact matching key in tooldrop.json. Writes require admin or Clerk org:env:manage, and app env vars override globals on conflicts.
tooldrop resources ls|add|test|attached|grant|revoke|query|request|rmConnect approved Postgres, MySQL, and HTTP resources; grant an app read or write access; and inspect data without returning credentials.
tooldrop billing [status|plans|preview|subscribe|upgrade|change|cancel]Inspect workspace billing, compare tiers, get a hosted checkout link for a new subscription, or explicitly confirm a plan change with --yes (admin only).
tooldrop db ls|get|set|rm|info|upgrade|downgradeInspect and update an app's database from the CLI, or upgrade its storage tier to a managed database (Pro, editor access required). Downgrade is only for key/value-only managed stores; managed Postgres stays managed.
tooldrop logs [app|errors|cron|webhook|all]Read app logs, gateway/runtime errors, scheduled job run logs, and public webhook delivery logs from the CLI (Team or Pro).
tooldrop apps|versions|rollback|clone|pullDiscover apps, inspect version history, repoint live traffic, download source, or three-way merge the latest live version into an existing project. Pull keeps files changed only locally and stops when the same path changed on both sides; inspect first with --dry-run.
tooldrop source show|unlink [slug]Inspect or remove an app's recorded Git/GitHub source association. Unlinking keeps historical version provenance.
tooldrop share|installTurn on a public share page, opt into guest join/remix access, or remix a shared source bundle from another ToolDrop workspace.
tooldrop docs|mcpPrint the agent guide or expose ToolDrop tools to Claude Code, Codex, and other MCP clients.
Reference
The tool runtime APIs. Server helpers come from @/lib/tooldrop/server, client helpers from @/lib/tooldrop/client.
td.user()serverReturns the signed-in viewer from the gateway JWT: { id, email, name, role }.
td.resources.query() / request()serverQuery an approved Postgres/MySQL resource or call an approved HTTP API. ToolDrop enforces the app grant and keeps connection credentials server-side.
process.env.KEYserverRead encrypted variables for non-resource secrets such as webhook verification keys after declaring them in tooldrop.json.
td.storageserverPer-app key/value storage for preferences, saved views, notes, review states, and records. Backed by Tool Storage on Free, or the app's managed database (far larger caps) on Pro — the same calls either way.
td.cron.log()serverWrite a log line to the current scheduled job run. No-ops outside scheduled job requests.
td.webhook.log()serverWrite a log line to the current public webhook delivery. No-ops outside webhook handler requests.
td.log() / td.warn() / td.error()serverWrite app-level log lines visible from the app Logs page, CLI, API, and MCP. Do not log secrets, payload bodies, or customer data you would not show an editor.
TDProvider + useTDUser()clientExpose the current ToolDrop user to client components through the tool's /api/td/user bridge.
tdStorageclientClient helper for Tool Storage calls through the app's /api/td/* route.
import { td } from "@/lib/tooldrop/server";
const me = await td.user();
await td.storage.set(`prefs:${me.id}`, { density: "compact" });
const prefs = await td.storage.get(`prefs:${me.id}`);
const orders = await td.resources.query(
"customer-data",
"SELECT id, total FROM orders WHERE customer_id = $1 LIMIT 50",
[me.id],
);Reference
Connect approved company databases and APIs once, then grant each app only the read or write access it needs. Credentials stay encrypted and non-retrievable.
Workspace builders add Postgres, MySQL, or HTTP connections in Settings → Data resources or with tooldrop resources add.
ToolDrop exposes safe schema and endpoint metadata to agents, but never returns passwords, tokens, connection URLs with credentials, or configured header values.
Read grants allow only read-only SQL and GET/HEAD requests. Query and response size, duration, and path are bounded; write access must be granted explicitly.
{
"slug": "refund-console",
"name": "Refund Console",
"resources": [
{
"slug": "customer-data",
"access": "read",
"description": "Customer and order lookup"
},
{
"slug": "billing-api",
"access": "write",
"description": "Issue approved refunds"
}
]
}tooldrop resources add customer-data --kind postgres
tooldrop resources test customer-data
tooldrop resources grant customer-data --access read
tooldrop resources attachedconst result = await td.resources.query(
"customer-data",
"SELECT id, email FROM customers WHERE email = $1 LIMIT 20",
[email],
);Reference
Tool Storage is the app-owned database. Team and Pro editors can inspect and update those records from the workspace UI, CLI, MCP, or HTTP API.
Runtime app code should keep using td.storage. The app database surface is for humans and agents operating the records around that app.
Reads and writes require app edit access plus Team or Pro. Listing values, setting keys, and deleting records are all audit logged.
The API lives at /api/apps/:slug/storage. Use values=0 when a list only needs key metadata.
tooldrop db ls --app revenue-dashboard --prefix task:
tooldrop db get task:123 --app revenue-dashboard
tooldrop db set task:123 '{"title":"Review contract","done":false}' --app revenue-dashboard
tooldrop db rm task:123 --app revenue-dashboardReference
Team and Pro workspaces can browse app runtime logs and automatic gateway failures from the app UI, CLI, HTTP API, and MCP.
ToolDrop automatically records app 5xx gateway failures. Server code can add explicit lines with td.log(), td.warn(), and td.error().
CLI and API access use the same app editor permission model. Read app, cron, and webhook logs with tooldrop logs or GET /api/apps/:slug/logs.
Logs store metadata and messages only. Do not log request bodies, webhook payloads, cookies, env values, tokens, or sensitive customer data.
tooldrop logs errors --app revenue-dashboard
tooldrop logs app --level warn --source runtime --app revenue-dashboard
tooldrop logs cron --details --app revenue-dashboard
tooldrop logs webhook --json --app revenue-dashboardimport { td } from "@/lib/tooldrop/server";
export async function GET() {
await td.log("Starting report refresh");
try {
// run app work here
await td.log("Report refresh finished");
return Response.json({ ok: true });
} catch (err) {
await td.error(err instanceof Error ? err.message : "Report refresh failed");
return Response.json({ error: "refresh failed" }, { status: 500 });
}
}Scheduled jobs
Team and Pro workspaces can run recurring work from Next.js tools with platform-owned scheduling, run history, and logs.
Declare each job in tooldrop.json. Live deploys generate the scheduler wrapper and expose runs on the app's Scheduled jobs page.
Job handlers live under /api/cron/*. They run without a human viewer, so use server-side env vars and td.storage instead of td.user().
Use td.cron.log() for messages you want saved with the run.
{
"slug": "revenue-dashboard",
"name": "Revenue Dashboard",
"crons": [
{
"name": "daily-sync",
"path": "/api/cron/daily-sync",
"schedule": "0 12 * * *"
}
]
}import { td } from "@/lib/tooldrop/server";
export async function GET() {
await td.cron.log("Starting daily sync");
// Read secrets from process.env and store lightweight state in td.storage.
const previous = await td.storage.get("sync:last-run");
await td.storage.set("sync:last-run", {
previous,
finishedAt: new Date().toISOString(),
});
await td.cron.log("Daily sync finished");
return Response.json({ ok: true });
}Webhooks
Team and Pro workspaces can publish stable webhook URLs from Next.js tools with platform-owned delivery history and logs.
Declare each endpoint in tooldrop.json. Live deploys publish stable URLs on the app's Webhooks page.
Handlers live under /api/webhooks/*. They run without a human viewer, so verify provider signatures with server-side env vars before trusting payloads.
Use td.webhook.log() for messages you want saved with the delivery.
{
"slug": "revenue-dashboard",
"name": "Revenue Dashboard",
"webhooks": [
{
"name": "stripe-events",
"path": "/api/webhooks/stripe",
"methods": ["POST"]
}
]
}import { td } from "@/lib/tooldrop/server";
export async function POST(request: Request) {
const body = await request.text();
const signature = request.headers.get("stripe-signature");
// Verify provider signatures with a server-side env var before trusting body.
if (!signature || !process.env.STRIPE_WEBHOOK_SECRET) {
await td.webhook.log("Missing Stripe signature", "warn");
return Response.json({ error: "missing signature" }, { status: 400 });
}
await td.webhook.log("Received Stripe event");
await td.storage.set("stripe:last-event", {
bytes: body.length,
receivedAt: new Date().toISOString(),
});
return Response.json({ ok: true });
}Building with agents
The four rules every coding agent must follow inside a tool, plus the MCP server that teaches them automatically.
No Clerk, next-auth, custom login pages, or session cookies inside a tool. Read identity with td.user().
List workspace resources, grant the app read access by default, declare the slug and access in tooldrop.json, and use td.resources from server code. Credentials never belong in source, prompts, logs, or local .env files.
Before coding or calling an env requirement missing, list accessible globals without values. Match the user's requested integration semantically against key names and descriptions. When one clearly fits, declare its exact key in tooldrop.json and continue through deploy; do not ask for a duplicate value or retrieve the secret merely to verify it.
Preferences, workflow state, saved filters, notes, and small records belong in td.storage.
Every deploy becomes version history. Use a short human sentence that says what changed.
When talking to viewers or builders, say ToolDrop hosting, remote build, or deployed runtime; do not name the underlying infrastructure provider.
You are editing a ToolDrop tool.
First read the local AGENTS.md or run:
tooldrop docs
If MCP is available, call td_docs before making changes.
Follow the tool contract:
- no app auth code
- no hardcoded secrets
- app-owned state goes in td.storage
- run tooldrop validate before deployConnect any MCP client to the hosted endpoint with a workspace API key from Settings → API keys:
claude mcp add tooldrop --transport http https://tooldrop.app/api/mcp --header "Authorization: Bearer sbk_your_key"Or, with the CLI installed, run the local server — it adds the filesystem tools (init, validate, deploy, clone, install) and uses your tooldrop login session:
claude mcp add tooldrop -- tooldrop mcptd_docstd_whoamitd_list_appstd_list_resourcestd_list_app_resourcestd_grant_resourcetd_revoke_resourcetd_query_resourcetd_request_resourcetd_logstd_list_envtd_env_settd_database_listtd_database_gettd_database_settd_database_deletetd_database_tiertd_validatetd_deploytd_versionstd_rollbacktd_clonetd_pulltd_sharetd_installBuilding with agents
Tool Storage is the default database for a tool. These rules decide what lives there and when to reach for something bigger.
Tool Storage is the default lightweight database for a tool. It is platform-managed, scoped by tool, and accessed through td.storage.
For shared records, key by record type, for example task:<id>, note:<id>, or approval:<orderId>.
For per-user records, include me.id, for example prefs:<userId> or saved-view:<userId>:<viewId>.
For small collections, store one record per key and discover them with td.storage.list("task:").
Team and Pro editors can inspect and update those records outside the tool with the app database page, tooldrop db, or /api/apps/:slug/storage. Treat those writes like production data changes.
Do not add SQLite, an ORM, or new tables just to save preferences, drafts, notes, review flags, saved filters, or small CRUD records.
Use approved workspace resources for company systems. Declare { slug, access } under resources in tooldrop.json and call td.resources.query() or td.resources.request() from server code.
Read grants block SQL writes and non-GET HTTP methods. Prefer read, parameterize SQL, add LIMITs to exploratory queries, and grant write only for an explicit operational workflow.
Resource credentials stay encrypted and non-retrievable. Builders and agents receive safe host, base URL, header-name, and schema metadata—not passwords, tokens, or configured header values.
Sizing rule of thumb: Tool Storage caps at 5000 keys, 256KB per value, and 50MB per app — preferences, saved views, and small CRUD records. When data outgrows that, is unbounded (event streams, sync pipelines, imported datasets), or needs SQL (joins, rollups, indexes), the first choice on Pro is to upgrade the app to a managed database (app database page, or tooldrop db upgrade): the same td.storage calls keep working with far larger caps, records copy over, and a fully-managed DATABASE_URL is injected for direct SQL. Otherwise bring your own — a free-tier Neon/Supabase Postgres set with tooldrop env set DATABASE_URL.
Managed tier: upgrading an app provisions a database it owns. td.storage transparently uses it with the larger caps, and (where the platform has a database provider configured) process.env.DATABASE_URL points at that same managed Postgres for advanced/relational/chart data — no signup, connection string, or allowlist. Managed Postgres apps stay on the managed tier so SQL tables and deployment database state are not lost.
API reference
Every request authenticates with one of four modes. The tables below note which mode each endpoint expects.
CLI bearer
Stored in ~/.tooldrop.json after login and used by the CLI plus MCP server.
Workspace session
Browser session checked by the platform gateway before a tool is opened.
App token
Runtime token issued to deployed tools or tooldrop dev for storage calls.
Public token
Share-link token embedded in /s/<token>; never grants env values or private app data.
| Method | Endpoint | Auth |
|---|---|---|
| POST | /api/mcpHosted MCP endpoint (Streamable HTTP). Connect any MCP client with a workspace API key as a bearer token. | CLI bearer |
| GET | /api/meReturn the current user and platform URL. | CLI bearer |
| GET | /api/appsList apps visible to the signed-in user. | CLI bearer |
| POST | /api/appsRegister or sync a tool before dev or deploy. | CLI bearer |
| GET | /api/apps/:slugReturn app metadata, env metadata, and recent versions. | CLI bearer |
| POST | /api/apps/:slug/devIssue local dev credentials, env values, and the gateway signing secret. | Builder |
| POST | /api/apps/:slug/deployUpload source files and create a new deploy version. Pass staging: true to build without going live (Team or Pro). | Editor |
| GET | /api/apps/:slug/versionsList version history and the currently served version. | Viewer |
| POST | /api/apps/:slug/rollbackActivate an existing ready version — roll back to an older one or promote a staged one. | Editor |
| GET | /api/apps/:slug/bundleDownload source for clone or handoff. Optional ?version=N. | Builder |
| GET / DELETE | /api/apps/:slug/source-linkInspect the recorded Git source, or unlink it without changing historical version provenance. | Viewer / Editor |
| GET | /api/apps/:slug/logsRead app logs, gateway errors, cron run logs, and webhook delivery logs. Query: ?type=app|errors|cron|webhook|all&level=error&source=gateway&q=text&limit=50. | Editor + Team |
| Method | Endpoint | Auth |
|---|---|---|
| GET | /api/billing/subscriptionReturn the workspace subscription, usage, limits, and the Free, Team, and Pro plan catalog. | Admin session or CLI bearer |
| POST | /api/billing/subscriptionPreview or apply a plan choice. New paid subscriptions return a hosted checkout URL; existing subscription changes require confirm: true. | Admin session or CLI bearer |
| Method | Endpoint | Auth |
|---|---|---|
| GET | /api/apps/:slug/storageList Tool Storage records. Query: ?prefix=task:&limit=100&values=0. Values are included by default unless values=0. | Editor + Team |
| GET | /api/apps/:slug/storage?key=KEYRead one Tool Storage record by key. | Editor + Team |
| POST | /api/apps/:slug/storageCreate or replace one JSON-serializable value: { key, value }. | Editor + Team |
| DELETE | /api/apps/:slug/storageDelete one record: { key }. | Editor + Team |
| GET | /api/apps/:slug/databaseReport the app's storage tier, managed database status, and usage stats. | Editor + Team |
| POST | /api/apps/:slug/databaseUpgrade to a managed database (needs managedDatabase). Provisions it and copies existing records over. | Editor + Pro |
| DELETE | /api/apps/:slug/databaseDowngrade key/value-only managed storage to Tool Storage. Managed Postgres databases are refused because SQL tables cannot be preserved. | Editor + Pro |
| Method | Endpoint | Auth |
|---|---|---|
| GET | /api/resourcesList approved workspace resources with safe metadata and pagination. Credentials are never returned. | Builder |
| POST | /api/resourcesCreate or update an encrypted Postgres, MySQL, or HTTP resource and optionally test it. | Builder |
| POST | /api/resources/:slugTest a resource and refresh safe schema or endpoint metadata. | Builder |
| DELETE | /api/resources/:slugDelete a resource and all app grants. | Builder |
| GET | /api/apps/:slug/resourcesList the app's attached resources and read/write grants. | Editor |
| POST | /api/apps/:slug/resourcesGrant the app read or write access to one approved resource. | Editor |
| DELETE | /api/apps/:slug/resourcesRevoke an app resource grant. | Editor |
| POST | /api/apps/:slug/resources/executeRun a bounded resource query or HTTP request through the same server-side connector used at runtime. | Editor |
| Method | Endpoint | Auth |
|---|---|---|
| GET | /api/apps/:slug/envList env metadata. Add ?values=1 to explicitly include decrypted values. | Editor |
| POST | /api/apps/:slug/envSet or rotate one encrypted env var with description and tags. | Editor |
| DELETE | /api/apps/:slug/envRemove an env var from the vault. | Editor |
| GET | /api/settings/variablesList workspace-global env metadata visible to the caller. Add ?values=1 to include decrypted values the caller can use. | Workspace member |
| POST | /api/settings/variablesSet or rotate one workspace-global env var: { key, value, description, scope, allowedUsers }. | Admin or org:env:manage |
| DELETE | /api/settings/variablesRemove one workspace-global env var: { key }. | Admin or org:env:manage |
| GET | /api/apps/:slug/shareReturn the active share link and stats if one exists. | Viewer |
| POST | /api/apps/:slug/shareCreate, update, or regenerate the public share link. New links default to no guest join and no remix. | Editor |
| DELETE | /api/apps/:slug/shareRevoke the active share link. | Editor |
| Method | Endpoint | Auth |
|---|---|---|
| ANY | /a/:deploySlug/*Gateway proxy that signs x-td-user and serves the current tool version. | Workspace session |
| ANY | /webhooks/:deploySlug/:endpointPublic webhook receiver that records delivery status, forwards to the generated wrapper, and returns the app handler response. | Public endpoint |
| GET | /api/tooldrop-cron/:jobGenerated scheduled-job wrapper that records start, finish, status, and log lines before invoking the tool's /api/cron/* handler. | Host secret |
| ANY | /api/tooldrop-webhook/:endpointGenerated webhook wrapper that forwards public deliveries into the tool's /api/webhooks/* handler. | Platform secret |
| POST | /api/connectorRuntime bridge for Tool Storage operations plus cron, webhook, and app log reporting. Tools call this through the SDK. | App token |
| POST | /api/cli/device/startStart CLI browser login. Returns a short-lived code, a CLI-only device secret, the browser verification URL, expiry, and polling interval. | Public |
| POST | /api/cli/device/pollPoll for browser signup/sign-in approval and atomically return a one-time CLI token only to the desktop that started the flow. | CLI-only device secret in JSON body |
Operations
If DATABASE_URL is correct but every query times out (connect ETIMEDOUT), the database probably only accepts connections from IPs on its allowlist. ToolDrop solves this with one permanent egress IP: the database admin allowlists that single address once, and every tool — local tooldrop dev and deployed — reaches the database through it. Your own machine's IP is never involved.
ToolDrop egress IP
8.235.38.133tooldrop-egressAll ToolDrop database traffic — tooldrop dev on any machine and every deployed tool — reaches your database from one permanent platform IP. Have your database admin add that single address to the allowlist, labeled tooldrop-egress. It never changes, and it is the only entry ToolDrop ever needs. Your own machine's IP is never involved.
DATABASE_URL at the relay addressYour workspace admin registers the database with the ToolDrop egress relay and gives you a relay address (host and port). Use that as the host in DATABASE_URL with your normal database credentials: tooldrop env set DATABASE_URL.
Nothing else changes: server-only code, the usual driver (pg, mysql2, or a provider SDK), parameterized queries, and a read replica with a read-only user when possible. The connection is end-to-end between your driver and the database — the relay only forwards packets, so credentials and TLS still terminate at the database.
Console → SQL → the instance → Connections → Networking → Authorized networks → Add network. Name: tooldrop-egress, Network: the ToolDrop IP as x.x.x.x/32, then Save. Applies in about a minute.
The instance's security group → Edit inbound rules → add a rule for the database port with source x.x.x.x/32, and put tooldrop-egress in the rule's Description.
The server's Networking page → Firewall rules → add a rule named tooldrop-egress.
Operations
Defaults the platform enforces so a quick internal tool never becomes an incident.
Tools never own authentication. Direct deployment URLs are guarded by proxy.ts and should reject requests without x-td-user.
Scheduled jobs enter through a generated wrapper protected by CRON_SECRET. Put job handlers under /api/cron/* and do not expose them to browsers.
Webhooks enter through public /webhooks/<deploy-slug>/<endpoint> URLs, then a generated wrapper protected by TOOLDROP_WEBHOOK_SECRET. Put handlers under /api/webhooks/* and verify provider signatures inside the handler.
App logs capture metadata only: level, source, message, path, method, status, duration, request id, and optional user attribution. Do not log secrets, request bodies, cookies, env values, tokens, or sensitive customer data.
Uploaded bundles exclude .env files, local state, build output, node_modules, and logs. Env values remain on the platform.
Resource credentials are encrypted and never returned. Per-app grants enforce read/write access, HTTP paths stay under the approved base URL, and query/request results are size and time bounded.
Tool Storage is intentionally small: 5000 keys per app, 256KB per value, and 50MB total per app. A Pro app upgraded to a managed database keeps the same protocol with far larger caps.
Public remix links publish source code when enabled. They never publish env values, data, credentials, or member lists.
Something missing? The Markdown docs carry the same content in one file.