Run402 gives an agent a full Postgres database, REST API, user auth, content-addressed file storage, static site hosting, serverless functions, and image generation — provisioned with one call, paid with x402 USDC on Base (or Stripe credits). The prototype tier is free on testnet.
This monorepo ships every surface an agent can pick up:
| Package | Use when… |
|---|---|
@run402/sdk |
Calling Run402 from TypeScript — typed kernel, isomorphic (Node 22 / Deno / Bun / V8 isolates) with a Node entry that auto-loads the local keystore + allowance + x402 fetch |
run402 CLI |
Terminal, scripts, CI, agent-controlled shells — JSON in, JSON out, exit code on failure |
run402-mcp |
Claude Desktop, Cursor, Cline, Claude Code — core Run402 operations as MCP tools |
| OpenClaw skill | OpenClaw agents (no MCP server required) |
@run402/functions |
Imported inside deployed functions (db(req?), adminDb(), auth.user(), email, ai, assets) and for TypeScript autocomplete in your editor. Source lives in the private gateway monorepo (it's bundled into your function zip at deploy time, so it co-evolves with the gateway). |
All five interfaces share a single typed kernel where appropriate: @run402/sdk. MCP tools, CLI subcommands, and OpenClaw scripts are thin shims over SDK calls. @run402/functions is the in-function helper that runs inside deployed code; the npm package on the registry stays in lockstep with what the gateway bundles, even though its source ships from the private monorepo. Pick whichever interface fits your runtime.
npm install -g run402
run402 init # creates allowance, requests testnet faucet
run402 tier set prototype # free on testnet (verifies x402 setup)
run402 projects provision --name my-app # → anon_key, service_key, project_id
run402 sites deploy-dir ./dist # incremental deploy of a directory → live URL
run402 subdomains claim my-app # → https://my-app.run402.comThat's a real Postgres database + a deployed static site, paid for autonomously with testnet USDC.
assets.put() returns an AssetRef whose scriptTag() / linkTag() / imgTag() emitters produce HTML with the URL, the SRI integrity hash, and modern best-practice attributes (defer, loading="lazy", decoding="async", crossorigin) already wired. The URL is content-addressed (pr-<public_id>.run402.com/_blob/<key>-<8hex>.<ext>), served through the v1.33 CDN, and never needs invalidation:
import { run402 } from "@run402/sdk/node";
const r = run402();
const p = await r.project(projectId);
const logo = await p.assets.put("logo.png", { bytes: pngBytes });
const app = await p.assets.put("app.js", { content: jsSource });
const style = await p.assets.put("app.css", { content: css });
const html = `
<!doctype html>
<html>
<head>${style.linkTag()}${app.scriptTag({ type: "module" })}</head>
<body>${logo.imgTag("Company logo")}</body>
</html>
`;immutable: true is the default — the SDK computes the SHA-256 client-side, the gateway returns a content-hashed URL, and the browser refuses execution on byte mismatch. No cache-invalidation choreography, no waiting, no integrity-attribute construction.
Tables you create are unreachable via /rest/v1/* until you declare them in a manifest. That closes the "agent created a table, forgot to set RLS, data leaked" footgun. The manifest is convergent — applying it twice is a no-op; items removed between applies have their policies, grants, triggers, and views dropped.
cat > manifest.json <<'EOF'
{
"$schema": "https://run402.com/schemas/manifest.v1.json",
"version": "1",
"tables": [
{ "name": "items", "expose": true, "policy": "user_owns_rows",
"owner_column": "user_id", "force_owner_on_insert": true },
{ "name": "audit", "expose": false }
],
"views": [
{ "name": "leaderboard", "base": "items", "select": ["user_id", "score"], "expose": true }
],
"rpcs": [
{ "name": "compute_streak", "signature": "(user_id uuid)", "grant_to": ["authenticated"] }
]
}
EOF
run402 projects validate-expose <project_id> --file manifest.json
run402 projects apply-expose <project_id> --file manifest.json
run402 projects get-expose <project_id>Built-in policies: user_owns_rows (rows where owner_column = auth.uid(); with force_owner_on_insert: true a BEFORE INSERT trigger sets it), public_read_authenticated_write (anyone reads, any authenticated user writes), public_read_write_UNRESTRICTED (fully open; requires i_understand_this_is_unrestricted: true), and custom (escape hatch — your own CREATE POLICY SQL).
Use run402 projects validate-expose or the MCP validate_manifest tool for a non-mutating feedback loop before applying. Optional migration SQL is used only to check manifest references; it is not executed as a PostgreSQL dry run, and this does not validate deploy manifests.
Auth-as-SDLC: put the same JSON under database.expose in your v2 ReleaseSpec. The gateway validates it against your migration SQL during deploy and rejects mismatches with a structured errors array listing every violation.
deployDir walks a local directory, hashes every file client-side, asks the gateway which bytes it doesn't already have, and PUTs only those. Re-deploying an unchanged tree returns immediately with bytes_uploaded: 0.
import { run402 } from "@run402/sdk/node";
const r = run402();
const { url, bytes_uploaded, bytes_total } = await r.sites.deployDir({
project: projectId,
dir: "./dist",
onEvent: (e) => process.stderr.write(JSON.stringify(e) + "\n"),
});Progress events stream over onEvent (or stderr from the CLI) as unified
DeployEvent JSON objects from the v2 deploy primitive.
CLI:
run402 sites deploy-dir ./dist --project prj_… > result.json 2> events.logDeploy-v2 routes and static public paths are release resources: they activate atomically with the site, functions, migrations, secrets, and subdomains in the same deploy apply. Release static asset paths such as events.html are distinct from browser-visible public static paths such as /events. Use site.public_paths for ordinary clean static URLs; keep routes for function ingress and exact, method-aware static aliases.
{
"project_id": "prj_...",
"site": {
"replace": {
"index.html": { "data": "<!doctype html><main id='app'></main><script>fetch('/api/hello')</script>" },
"events.html": { "data": "<!doctype html><h1>Events</h1>" }
},
"public_paths": {
"mode": "explicit",
"replace": {
"/events": { "asset": "events.html", "cache_class": "html" }
}
}
},
"functions": {
"replace": {
"api": {
"runtime": "node22",
"source": {
"data": "export default async function handler(req) { const url = new URL(req.url); return Response.json({ ok: true, path: url.pathname }); }"
}
},
"login": {
"runtime": "node22",
"source": { "data": "export default async function handler(req) { return Response.json({ ok: true }); }" }
}
}
},
"routes": {
"replace": [
{ "pattern": "/api/*", "methods": ["GET", "POST", "OPTIONS"], "target": { "type": "function", "name": "api" } },
{ "pattern": "/login", "methods": ["POST"], "target": { "type": "function", "name": "login" } }
]
}
}site.public_paths.mode: "explicit" means only the complete public_paths.replace table is directly reachable as static URLs. In the example, /events serves the release asset events.html, while /events.html is not public unless separately declared. mode: "implicit" restores filename-derived public reachability and can widen access, so review gateway warnings before confirming it.
Omit routes or pass routes: null to carry forward base routes. Use routes: { "replace": [] } to clear the route table. Route entries are an ordered replace list, not a path-keyed map. Function targets use { "type": "function", "name": "<materialized function name>" }. Static route targets use exact patterns only, methods ["GET"] or ["GET","HEAD"], and { "pattern": "/events", "methods": ["GET","HEAD"], "target": { "type": "static", "file": "events.html" } } where file is a release static asset path, not a public path, URL, CAS hash, rewrite, or redirect. Use static route targets for method-aware aliases such as static GET /login plus function POST /login; in explicit public path mode the backing asset can stay private by filename. Direct /functions/v1/:name calls remain API-key protected; browser-routed paths are public same-origin ingress.
Matching is exact or final-prefix-wildcard only. /admin and /admin/ are exact trailing-slash equivalents; /admin/* matches children but not /admin, /admin/, /admin.css, or /administrator, so deploy both /admin and /admin/* for a routed section root. Query strings are ignored for matching and preserved in the handler's full public req.url. Exact routes beat prefix routes; longest prefix wins; method-compatible dynamic routes beat static assets. A POST /login route can coexist with static GET /login HTML. Unsafe method mismatch returns 405, and matched dynamic route failures fail closed instead of falling back to static files.
Routed functions use the Node 22 Fetch Request -> Response contract: export default async function handler(req) { ... }. req.method is the browser method, and req.url is the full public URL on managed subdomains, deployment hosts, and verified custom domains. Derive OAuth callbacks from it, for example new URL("/admin/oauth/google/callback", new URL(req.url).origin). Append multiple cookies with headers.append("Set-Cookie", value); redirects, cookies, and query strings are preserved. The raw run402.routed_http.v1 envelope is internal; do not write route handlers against it.
Avoid routing every static file, broad method lists by default, wildcard static route targets, leading-slash static files, directory shorthand, and one-static-route-target-per-page tables that exhaust route limits. Also watch wildcard function routes that shadow direct public static paths. Warning codes to handle include STATIC_ALIAS_SHADOWS_STATIC_PATH, STATIC_ALIAS_RELATIVE_ASSET_RISK, STATIC_ALIAS_DUPLICATE_CANONICAL_URL, STATIC_ALIAS_EXTENSIONLESS_NON_HTML, and STATIC_ALIAS_TABLE_NEAR_LIMIT; inspect active routes, static_public_paths, and resolve diagnostics to distinguish the route pattern from the backing asset_path.
Diagnose public URLs with the URL-first CLI or MCP/SDK equivalents:
run402 deploy diagnose --project prj_123 https://example.com/events --method GET
run402 deploy resolve --project prj_123 --url https://example.com/events?utm=x#hero --method GET
run402 deploy resolve --project prj_123 --host example.com --path /events --method GETdeploy_diagnose_url and r.project(id).deploy.resolve({ url, method: "GET" }) return would_serve, diagnostic_status, match, normalized request data, warnings, full resolution JSON, and next steps. When returned, asset_path, reachability_authority, and direct explain which release asset backs the public URL and whether reachability came from implicit file-path mode, explicit site.public_paths, or a route-only static alias. Stable-host diagnostics may also include authorization_result, cas_object (sha256, exists, expected_size, actual_size), hostname-specific response_variant, and route/static fields such as allow, route_pattern, target_type, target_name, and target_file. Known match literals are host_missing, manifest_missing, active_release_missing, unsupported_manifest_version, path_error, none, static_exact, static_index, spa_fallback, spa_fallback_missing, route_function, route_static_alias, and route_method_miss; preserve unknown future strings. Known authorization_result values include authorized, not_public, not_applicable, manifest_missing, target_missing, active_release_missing, unsupported_manifest_version, path_error, missing_cas_object, unfinalized_or_deleting_cas_object, size_mismatch, and unauthorized_cas_object. Known fallback_state values include active_release_missing, unsupported_manifest_version, and negative_cache_hit; preserve unknown future strings. result is the diagnostic body status, not the HTTP status of the SDK call, so host misses can still be successful CLI/MCP/SDK calls with would_serve: false. Do not treat resolve/diagnose as a fetch, cache purge, or cache-policy oracle; route method misses should inspect allow, and CAS authorization/health failures should inspect or redeploy the affected static asset. Branch on structured JSON fields such as cache_class and preserve unknown cache classes.
Release observability exposes stable asset identity and public reachability. Inventories include release_generation, static_manifest_sha256, nullable static_manifest_metadata (file_count, total_bytes, cache_classes, cache_class_sources, spa_fallback), and static_public_paths[] when returned. site.paths lists release static assets; static_public_paths[] lists browser-visible public paths with public_path, asset_path, reachability_authority, direct, cache class, and content type. Plan and release diffs expose static_assets counters: unchanged/changed/added/removed, newly_uploaded_cas_bytes, reused_cas_bytes, deployment_copy_bytes_eliminated, legacy_immutable_warnings, previous_immutable_failures, and cas_authorization_failures.
Runtime route failure codes to branch on: ROUTE_MANIFEST_LOAD_FAILED (manifest/propagation), ROUTED_INVOKE_WORKER_SECRET_MISSING (custom-domain Worker secret), ROUTED_INVOKE_AUTH_FAILED (internal invoke signature), ROUTED_ROUTE_STALE (selected route failed release revalidation), ROUTE_METHOD_NOT_ALLOWED (method mismatch), and ROUTED_RESPONSE_TOO_LARGE (body over 6 MiB).
For repo-driven deploys, Run402 does not need service keys or allowance files in GitHub secrets. Run a local link command once:
run402 ci link github --project prj_... --manifest run402.deploy.json
# Optional route authority for CI route declarations:
run402 ci link github --project prj_... --manifest run402.deploy.json --route-scope /admin --route-scope /api/*That creates a deploy-scoped /ci/v1/* binding and writes a workflow that grants id-token: write, checks out the repo, and runs the existing deploy primitive:
permissions:
contents: read
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to run402
run: npx --yes run402@1.60.0 deploy apply --manifest 'run402.deploy.json' --project 'prj_...'CI deploys are intentionally narrow: site, functions, database, absent/current base, and route declarations only when the binding has covering --route-scope patterns. Without route scopes, CI cannot ship routes. Keep secrets, domains, subdomains, checks, non-current base, and broader trust changes in a local allowance-backed deploy. If the gateway returns CI_ROUTE_SCOPE_DENIED, re-link with exact scopes like /admin or final-wildcard scopes like /api/*, or deploy locally. Manage bindings with run402 ci list and run402 ci revoke.
Inside a deployed function, import from @run402/functions. Two distinct DB clients keep RLS clean:
import { db, adminDb, auth, email, ai } from "@run402/functions";
export default async (req: Request) => {
const user = await auth.requireUser();
// Caller-context — db() mints a 60s actor JWT so run402.current_user_id() resolves in RLS.
// No .eq("user_id", user.id) needed — RLS already binds the visitor's rows; the redundant
// filter is a deploy-fail (R402_AUTH_REDUNDANT_USER_FILTER) under @run402/functions v3.0+.
const mine = await db().from("items").select("*");
// BYPASSRLS — for platform-authored writes (audit logs, cron cleanup, webhook handlers).
await adminDb().from("audit").insert({ event: "items_read", user_id: user.id });
// Send mail from the project's mailbox — discovers it automatically.
if (mine.length === 0) {
await email.send({ to: user.email, subject: "Welcome", html: "<h1>hi</h1>" });
}
return Response.json(mine);
};adminDb().sql(query, params?) runs raw parameterized SQL and always bypasses RLS. It returns a flat Promise<Record<string, unknown>[]> (just the rows — no envelope):
import { adminDb, auth } from "@run402/functions";
export default async (req: Request) => {
const user = await auth.requireUser();
const rows = await adminDb().sql(
"SELECT count(*)::int AS n FROM items WHERE user_id = $1",
[user.id],
);
const n = (rows[0]?.n as number | undefined) ?? 0;
return Response.json({ count: n });
};@run402/functions is auto-bundled into deployed code; install it in your editor for full TypeScript autocomplete (also works at build time for static-site generation with RUN402_SERVICE_KEY + RUN402_PROJECT_ID set).
ai.generateImage({ prompt, aspect? }) is available inside deployed functions for live app flows such as generated avatars or OG images. It calls the project runtime image endpoint with RUN402_SERVICE_KEY, so deployed functions do not need allowance wallets or x402 signing code. Aspects are square, landscape, and portrait; the result is { image, content_type, aspect } with base64 image bytes. Runtime image generation is billed, rate-limited, and spend-capped against the project billing account; public routed functions should authenticate/rate-limit their users before calling it.
assets.put(key, source, opts?) uploads bytes from inside a deployed function through the same CAS-backed apply substrate as deploy-time assets. It uses RUN402_SERVICE_KEY, accepts a string, Uint8Array, or { content | bytes }, and returns an SDK-compatible AssetRef with mutable and immutable URLs.
Calling from outside a function entirely (raw curl/fetch from CI scripts, bash bootstrappers, non-TS runtimes) — service-key writes go to /admin/v1/rest/<table>, not /rest/v1/*. The gateway 403s service-role tokens on /rest/v1/* so a leaked key can't silently bypass RLS, which means curl ... > /dev/null against the wrong path looks like success but writes nothing. SQL-shaped admin work uses POST /projects/v1/admin/:id/sql (or run402 projects sql).
curl -X POST https://api.run402.com/admin/v1/rest/audit \
-H "Authorization: Bearer $RUN402_SERVICE_KEY" \
-H "Content-Type: application/json" \
-d '{"event":"seed","ts":"2026-04-30"}'npm install @run402/sdkTwo entry points:
@run402/sdk— isomorphic. Bring your ownCredentialsProvider(a session-token shim, a remote vault, anything that resolves project keys + auth headers). Works in Node 22, Deno, Bun, V8 isolates.@run402/sdk/node— Node-only convenience. Reads~/.config/run402/projects.json, signs x402 payments from the local allowance, exposessites.deployDir(...),fileSetFromDir(...), and typed deploy-manifest helpers (loadDeployManifest,normalizeDeployManifest).
import { run402 } from "@run402/sdk/node";
const r = run402();
const project = await r.projects.provision({ tier: "prototype" });
const p = await r.project(project.project_id);
await p.assets.put("hello.txt", { content: "hi" });The SDK is organised as 22 namespaces: projects, assets, cache, ci, sites, functions, jobs, secrets, subdomains, domains, email (+ webhooks), senderDomain, auth, apps, tier, billing, contracts, ai, allowance, service, admin, plus the r.project(id).apply hero for atomic mixed writes (release slices + assets slice via /apply/v1/*). Every operation throws a typed Run402Error subclass on failure: PaymentRequired, ProjectNotFound, Unauthorized, ApiError, NetworkError, LocalError, Run402DeployError. apply() automatically re-plans safe current-base BASE_RELEASE_CONFLICT races and emits apply.retry progress events. See sdk/README.md.
Astro SSR + ISR cache (v1.52+). For Astro apps, use @run402/astro 1.0+ — export default run402(); in astro.config.mjs returns an AstroUserConfig composing the SSR adapter (Lambda + SnapStart + ISR cache + AsyncLocalStorage request-context), image integration, and build-time detectors. Functions opt into the SSR class via FunctionSpec.class: "ssr" in ReleaseSpec; the gateway provisions SnapStart and caches HTML responses keyed by (host, path, search, method, locale, release_id). Cache is bypass-by-default (no-store unless Cache-Control explicitly allows it AND no Set-Cookie AND no auth-taint flag from auth.* helpers / payment primitives). Invalidate from in-function code or out-of-band: r.cache.invalidate(url) / r.cache.invalidatePrefix({ host, prefix }) / r.cache.invalidateAll({ host }) (SDK), run402 cache invalidate <url> (CLI). Inspect cached state with r.cache.inspect(url) / run402 cache inspect <url>. Agent DX helpers also in the CLI: run402 doctor (5 health checks), run402 dev (Astro dev with .env.local), run402 logs --request-id req_... (correlate across functions). Full reference at astro/README.md and cli/llms-cli.txt (R402_* SSR Runtime Error Codes section).
npm install -g run402Every subcommand prints JSON to stdout, JSON errors to stderr, exits 0 on success and 1 on failure — designed for an agent shell, not a human. Full reference: cli/llms-cli.txt (also at https://run402.com/llms-cli.txt).
run402 init # one-shot allowance + faucet + tier check
run402 status # account snapshot (allowance, balance, tier, projects)
run402 projects provision --name my-app
run402 projects sql <id> "CREATE TABLE …"
run402 projects validate-expose <id> --file manifest.json
run402 projects apply-expose <id> --file manifest.json
run402 sites deploy-dir ./dist
run402 deploy release active --project <id> # inspect current-live release inventory
run402 deploy diagnose --project <id> https://example.com/events --method GET
run402 functions deploy <id> <name> --file fn.ts
run402 ci link github --project <id> # GitHub Actions OIDC deploy binding (--route-scope for CI routes)
run402 assets put ./asset.png --immutable
run402 assets diagnose <url> # inspect live CDN state for a public URL
run402 cdn wait-fresh <url> --sha <hex> # poll until a mutable URL serves the new SHAThe active project is sticky: run402 projects use <id> makes <id> the default for every subsequent <id>-taking subcommand, so most commands work without it.
npx -y run402-mcp # standalone testAdd to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
}
}Add to .cursor/mcp.json:
{
"mcpServers": {
"run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
}
}Add to your Cline MCP settings:
{
"mcpServers": {
"run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
}
}claude mcp add run402 -- npx -y run402-mcpcp -r openclaw ~/.openclaw/skills/run402
cd ~/.openclaw/skills/run402/scripts && npm installEach script re-exports from cli/lib/*.mjs — the OpenClaw command surface is identical to the CLI command surface by construction. See openclaw/README.md.
The full MCP surface — every tool is a thin shim over an SDK call.
| Tool | Description |
|---|---|
provision_postgres_project |
Provision a new database. Auto-handles x402 payment. |
run_sql |
Execute SQL (DDL or queries). Returns a markdown table. |
rest_query |
Query/mutate via PostgREST. |
apply_expose |
Apply the declarative authorization manifest (tables, views, RPCs). Convergent — drops items removed between applies. |
validate_manifest |
Validate the auth/expose manifest without applying it. Accepts manifest object/string, optional migration_sql, optional project_id. |
get_expose |
Return the current manifest. source is either applied (from the tracking table) or introspected (regenerated from live DB state). |
get_schema |
Introspect tables, columns, types, constraints, RLS policies. |
get_usage |
Per-project usage report (API calls, storage, lease expiry). |
promote_user / demote_user |
Manage project_admin role on a project user. |
delete_project |
Cascade purge — schema, Lambdas, S3 site files, deployments, secrets, published versions. Irreversible. |
| Tool | Description |
|---|---|
assets_put |
Upload an asset (any size, up to 5 TiB) via direct-to-S3 presigned URLs. Returns an AssetRef with scriptTag() / linkTag() / imgTag() emitters. |
assets_get |
Download an asset to a local file. |
assets_ls |
Keyset-paginated list with prefix filter. |
assets_rm |
Delete an asset. |
assets_sign |
Time-boxed presigned GET URL for a private asset. |
diagnose_public_url |
Live CDN state for a public URL — expected vs observed SHA, cache headers, invalidation status. |
wait_for_cdn_freshness |
Poll a mutable URL until it serves the expected SHA-256. |
| Tool | Description |
|---|---|
deploy_site |
Deploy a static site from inline file bytes. |
deploy_site_dir |
Deploy a static site from a local directory. Routes through the unified deploy primitive (CAS-backed) — only uploads bytes the gateway doesn't have. |
claim_subdomain |
Claim <name>.run402.com (idempotent; reassigns to latest deployment on subsequent deploys). |
list_subdomains / delete_subdomain |
Manage subdomains. |
add_custom_domain / list_custom_domains / check_domain_status / remove_custom_domain |
Point your own domain at a Run402 subdomain. |
deploy / deploy_resume / deploy_list / deploy_events |
Apply, resume, list, and inspect deploy operations. |
deploy_release_get / deploy_release_active / deploy_release_diff |
Inspect release inventory and release-to-release diffs without starting a new deploy mutation. |
deploy_diagnose_url |
URL-first deploy resolver diagnostics. Params: project_id, either url or host/path, optional method; returns would_serve, diagnostic_status, match, warnings, next steps, and fenced JSON. |
| Tool | Description |
|---|---|
ci_create_binding |
Create a GitHub Actions CI deploy binding from a locally signed delegation. Optional route_scopes delegate exact paths like /admin or final wildcards like /api/*; omitted means no CI route authority. |
ci_list_bindings / ci_get_binding / ci_revoke_binding |
Inspect and revoke CI bindings, including returned route_scopes. |
| Tool | Description |
|---|---|
deploy_function |
Deploy a Node 22 serverless function. Cron-schedulable. |
invoke_function |
Invoke a deployed function over the direct API-key-protected test path. |
get_function_logs |
Recent logs (CloudWatch), filterable by since and routed request_id. |
update_function |
Update schedule / timeout / memory without redeploying code. |
list_functions / delete_function |
List / remove functions. |
set_secret / list_secrets / delete_secret |
Manage process.env secrets injected into all functions. Values are write-only; list returns keys and timestamps only. |
jobs_submit / jobs_get / jobs_logs / jobs_cancel |
Submit and inspect fixed platform-managed jobs. Requests use the gateway jobs shape; the SDK supplies the required idempotency header. |
| Tool | Description |
|---|---|
request_magic_link |
Send a passwordless login email. |
verify_magic_link |
Exchange the magic link token for access_token + refresh_token. |
create_auth_user / invite_auth_user |
Create/update auth users and send trusted service-key invites. |
set_user_password |
Change, reset, or set a user's password. |
auth_settings |
Configure password set, preferred sign-in method, public signup policy, and project-admin passkey enforcement. |
passkey_register_options / passkey_register_verify |
Create and verify WebAuthn passkey registration ceremonies. |
passkey_login_options / passkey_login_verify |
Create and verify WebAuthn passkey login ceremonies. |
list_passkeys / delete_passkey |
List or delete the authenticated user's passkeys. |
create_mailbox / get_mailbox / delete_mailbox |
Per-project mailbox at <slug>@mail.run402.com. |
send_email |
Template (project_invite, magic_link, notification) or raw HTML. Single recipient. |
list_emails / get_email / get_email_raw |
Read messages. get_email_raw returns RFC-822 bytes for DKIM / zk-email verification. |
register_mailbox_webhook / list_mailbox_webhooks / get_mailbox_webhook / update_mailbox_webhook / delete_mailbox_webhook |
Email-event webhooks (delivery, bounced, complained, reply_received). |
register_sender_domain / sender_domain_status / remove_sender_domain |
Send from your own domain (DKIM verified). |
enable_sender_domain_inbound / disable_sender_domain_inbound |
Receive replies on your custom sender domain. |
| Tool | Description |
|---|---|
generate_image |
Text-to-PNG via x402 ($0.03 / image). |
ai_translate |
Translate text. Metered per project. |
ai_moderate |
Moderate text (free). |
ai_usage |
Translation quota (used / included / remaining). |
| Tool | Description |
|---|---|
browse_apps |
Browse public forkable apps. |
get_app |
Inspect an app, including expected bootstrap_variables. |
fork_app |
Clone schema + site + functions into a new project. Runs the app's bootstrap function with provided variables. |
publish_app |
Publish a project as a forkable app. |
list_versions / update_version / delete_version |
Manage published versions. |
| Tool | Description |
|---|---|
set_tier |
Subscribe / renew / upgrade a tier (auto-detects action). x402 payment. |
tier_status |
Current tier, lease expiry, usage, and function authoring caps when returned. |
get_quote |
Tier pricing (free, no auth). |
tier_checkout |
Stripe checkout for a tier (alternative to x402). |
create_email_billing_account / link_wallet_to_account |
Email-based billing accounts; hybrid Stripe + x402. |
billing_history |
Ledger history. |
buy_email_pack |
$5 for 10,000 emails (never expire). |
set_auto_recharge |
Auto-buy email packs when credits run low. |
| Tool | Description |
|---|---|
provision_contract_wallet |
AWS KMS-backed Ethereum wallet. $0.04/day rental + $0.000005 per call. Private keys never leave KMS. |
get_contract_wallet / list_contract_wallets |
Metadata + live native balance. |
set_recovery_address / set_low_balance_alert |
Optional safety nets. |
contract_call |
Submit a write call (chain gas at-cost + KMS sign fee). |
contract_read |
Read-only call (free). |
get_contract_call_status |
Lifecycle, gas, receipt. |
drain_contract_wallet |
Drain native balance (works on suspended wallets — the safety valve). |
delete_contract_wallet |
Schedule KMS key deletion (refused if balance ≥ dust). |
| Tool | Description |
|---|---|
init |
One-shot setup: allowance + faucet + tier check + project list. |
status |
Full account snapshot (allowance, balance, tier, projects). |
allowance_status / allowance_create / allowance_export |
Local allowance management. |
request_faucet |
Request testnet USDC. |
check_balance |
USDC balance for an allowance address. |
list_projects |
Active projects for a wallet. |
pin_project |
Pin a project (admin only — uses the configured admin allowance wallet). |
project_info / project_keys / project_use |
Inspect / set the active project. |
create_checkout |
Stripe checkout to add cash credit. |
send_message |
Send feedback to the Run402 team. |
set_agent_contact / get_agent_contact_status / verify_agent_contact_email |
Register agent contact info, read assurance status, and start the operator email reply challenge. |
start_operator_passkey_enrollment |
Email a Run402 operator passkey enrollment link to the verified contact email. |
get_operator_status |
Compact operator-health snapshot — contact assurance state, critical items, skipped notifications, billing accounts, projects, active thresholds. Read via run402 doctor or directly. |
get_notification_preferences / set_notification_preferences |
Read/update operator notification preferences (cadence, channels, per-class toggles, locale, timezone). Cross-wallet effects require email_verified; webhook URL changes require operator_passkey. |
list_notifications |
Per-delivery-attempt audit log. Paginated, filterable by event_type / since. |
test_notification |
Fire a real test notification through the full worker pipeline. Audit row marked is_test=true. Rate-limited per wallet at 1/min. |
rotate_webhook_secret |
Generate a new HMAC signing secret for the operator webhook (returned exactly once). Previous secret remains valid for 24h. Requires operator_passkey. |
| Tool | Description |
|---|---|
service_status |
Public availability report — 24h/7d/30d uptime per capability, operator, deployment topology. |
service_health |
Liveness probe with per-dependency results. |
| Variable | Default | Purpose |
|---|---|---|
RUN402_API_BASE |
https://api.run402.com |
API base URL (override for staging) |
RUN402_CONFIG_DIR |
~/.config/run402 |
Local credential storage directory |
RUN402_ALLOWANCE_PATH |
{config_dir}/allowance.json |
Custom allowance file path |
Local state lives at:
~/.config/run402/projects.json(0600) —{ projects: { <id>: { anon_key, service_key, tier, lease_expires_at } } }~/.config/run402/allowance.json(0600) — wallet for x402 signing
anon_key and service_key have no expiry — lease enforcement happens server-side. Rotate them by deleting the project and re-provisioning.
npm run build # builds core/, sdk/, then the MCP server
npm test # SKILL + sync + unit tests
npm run test:e2e # 47 CLI end-to-end tests
npm run test:sync # checks MCP/CLI/OpenClaw/SDK stay in sync
npm run test:skill # validates SKILL.md frontmatter + bodyArchitecture: every tool / subcommand / skill script is a thin shim over an @run402/sdk call. core/ holds Node-only filesystem primitives (keystore, allowance, SIWE signing) wrapped by the SDK's Node provider. See CLAUDE.md for the full layout.
- Web: https://run402.com
- API docs (HTTP): https://run402.com/llms.txt · https://run402.com/openapi.json
- CLI docs: https://run402.com/llms-cli.txt
- Status: https://api.run402.com/status
- Health: https://api.run402.com/health
MIT