Remote triggers
Remote triggers let you dispatch signals and broadcasts from any application to a Station server over HTTP. Your application code calls .trigger() as usual, but execution happens on the Station server instead of locally.
How it works
When you call configure() with a remote endpoint, Station creates an HttpTriggerAdapter internally. Every subsequent .trigger() call sends an HTTP POST to the Station server's v1 API instead of writing to a local adapter.
- Client validates input against the signal's Zod schema locally
- Client sends
POST /api/v1/triggerwith the signal name and input - Server authenticates the request via API key, creates a pending run, and returns the run ID
- The signal runner on the server picks up the pending run and executes it
1. Set up the Station server
Your Station server needs an adapter for persistence, auth for API key management, and host: "0.0.0.0" to accept remote connections.
// station.config.tsimport { defineConfig } from "station-kit";import { SqliteAdapter } from "station-adapter-sqlite"; export default defineConfig({ port: 4400, host: "0.0.0.0", signalsDir: "./signals", adapter: new SqliteAdapter({ dbPath: "./.station/data/jobs.db" }), auth: { username: "admin", password: "changeme", },});Start the server with npx station. The dashboard will be available at http://localhost:4400.
2. Create an API key
API keys authenticate remote trigger requests. Create one from the dashboard Settings page, or via the v1 API:
curl -X POST http://localhost:4400/api/v1/keys \ -H "Authorization: Bearer <session-token>" \ -H "Content-Type: application/json" \ -d '{"name": "my-app", "scopes": ["trigger", "read"]}'The response includes the full key (prefixed sk_live_). Store it securely — the key is only shown once.
API keys support scoped access: trigger (dispatch jobs), read (view runs and status), cancel (cancel running jobs), and admin (manage keys).
3. Configure the client
In your application, call configure() once at startup. All subsequent .trigger() calls will go to the remote server.
Option A: Explicit configuration
import { configure } from "station-signal"; configure({ endpoint: "https://station.example.com", apiKey: "sk_live_abc123...",});Option B: Environment variables
Station auto-detects these environment variables. No code changes needed.
STATION_ENDPOINT=https://station.example.comSTATION_API_KEY=sk_live_abc123...4. Trigger signals remotely
Once configured, .trigger() works the same as local triggering. The call returns a run ID immediately.
import { sendEmail } from "./signals/send-email.js"; // This sends an HTTP POST to your Station serverconst runId = await sendEmail.trigger({ to: "user@example.com", subject: "Welcome", body: "Thanks for signing up.",}); console.log("Dispatched run:", runId);Broadcasts work the same way:
import { orderPipeline } from "./broadcasts/order-pipeline.js"; const runId = await orderPipeline.trigger({ orderId: "ord_123", amount: 99.99,});Deployment
Station includes a deploy command that generates deployment files for your server:
npx station deployThis writes a Dockerfile and nixpacks.toml to .station/out/. Copy the appropriate file to your project root and deploy to any container platform (Railway, Render, Fly.io, AWS ECS, etc.).
CLI reference
| Flag | Description |
|---|---|
--port <n> | Override server port (default: 4400) |
--host <s> | Override server host (default: localhost) |
--dir <path> | Set station directory for generated files (default: .station) |
--config <path> | Path to config file (default: station.config.ts) |
--no-open | Don't open browser on start |
--no-runners | Read-only mode — don't execute signals or broadcasts |