### Install and start Warmbly to claim the instance Source: https://docs.warmbly.com/development/first-run The installer starts the stack and prints the claim link when it finishes. From a clone it is the same two steps and a build. Both print a single-use link when they finish. ```shell curl -fsSL https://warmbly.com/install.sh | sh ``` ```shell git clone https://github.com/warmbly/warmbly && cd warmbly make up ``` -------------------------------- ### Retrieve the setup link from the backend log Source: https://docs.warmbly.com/development/bare-metal Use journalctl to grep the backend log for the one-time setup URL. Install the token and open it during the first boot when the users table is empty. ```bash sudo journalctl -u warmbly-backend | grep -o 'http[^ ]*/setup?token=[a-f0-9]*' | tail -1 ``` -------------------------------- ### Quickstart: warmbly-js, warmbly-py, warmbly-go Source: https://docs.warmbly.com/api/sdks Quickstart examples for each official SDK. They require a WARMBLY_API_KEY environment variable (or explicit API key) and demonstrate listing campaigns (JS/Go) or API keys (Python) with auto-pagination. ```javascript import { Warmbly } from "warmbly"; const warmbly = new Warmbly({ apiKey: process.env.WARMBLY_API_KEY }); // List campaigns (auto-paginated) for await (const campaign of await warmbly.campaigns.list()) { console.log(campaign.id, campaign.name); } ``` ```python import os from warmbly import Warmbly client = Warmbly(api_key=os.environ["WARMBLY_API_KEY"]) for key in client.api_keys.list(): print(key.name, key.status) ``` ```go package main import ( "context" "fmt" "log" "github.com/warmbly/warmbly-go" ) func main() { client, err := warmbly.New(warmbly.WithAPIKey("wmbly_...")) if err != nil { log.Fatal(err) } ctx := context.Background() page, err := client.Campaigns.List(ctx, nil) if err != nil { log.Fatal(err) } for campaign, err := range page.All(ctx) { if err != nil { log.Fatal(err) } fmt.Println(campaign.Name) } } ``` -------------------------------- ### GET /plans response example Source: https://docs.warmbly.com/api/reference/account-org Example JSON response from the GET /plans endpoint, showing a list of public subscription plans with fields like id, name, price, duration, and public. ```json { "plans": [ { "id": "plan_pro...", "name": "Pro", "price": 99, "duration": "month", "public": true } ] } ``` -------------------------------- ### Install Warmbly with default installer Source: https://docs.warmbly.com/development/install Runs the official installer script from warmbly.com. The script checks Docker, creates one directory, generates secrets, pulls pinned release images, starts the stack, and prints the link to claim the instance. On a clean box with Docker already installed, it finishes in under two minutes. ```shell curl -fsSL https://warmbly.com/install.sh | sh ``` -------------------------------- ### warmbly CLI examples Source: https://docs.warmbly.com/api/cli A set of example commands covering campaign creation and starting, mailbox health checks, inbox operations, and contact management. Use these as a quick reference for common workflows. ```shell # Create a campaign, add a step, check it, start it warmbly campaign create --name "Q3 outbound" --daily-limit 40 warmbly campaign add-step CAMPAIGN_ID --subject "Quick question" --wait-after 0 warmbly campaign preflight CAMPAIGN_ID warmbly campaign start CAMPAIGN_ID # Mailbox health across the workspace warmbly mailbox list warmbly mailbox check MAILBOX_ID warmbly mailbox edit MAILBOX_ID --daily-limit 40 # The inbox warmbly inbox list --unseen --limit 20 warmbly inbox thread --email-id EMAIL_ID # Contacts in and out warmbly contact create --email jane@example.com --first-name Jane --company Acme warmbly contact list --all --json > contacts.json ``` -------------------------------- ### GET /v1/campaigns Source: https://docs.warmbly.com/api Lists campaigns. This endpoint is used in the quickstart example to demonstrate authentication and the base URL. ```APIDOC ## GET /v1/campaigns ### Description Lists campaigns. This endpoint is used in the quickstart example to demonstrate authentication and the base URL. ### Method GET ### Endpoint https://api.warmbly.com/v1/campaigns ### Authentication Bearer token (API key) required. Pass as `Authorization: Bearer wmbly_your_api_key_here`. ### Request Example ``` curl -X GET "https://api.warmbly.com/v1/campaigns" \ -H "Authorization: Bearer wmbly_your_api_key_here" \ -H "Content-Type: application/json" ``` ### Response #### Success Response (200) - **data** (array) - List of campaigns. - **pagination** (object) - Pagination information with `has_more` and `next_cursor` fields. #### Response Example ``` { "data": [], "pagination": { "has_more": false, "next_cursor": null } } ``` ``` -------------------------------- ### GET /suppressions response example Source: https://docs.warmbly.com/api/reference/deliverability-ops Example JSON response from the GET /suppressions endpoint, showing suppression entries for an email and a domain, along with pagination metadata. ```json { "data": [ { "id": "5a0c...", "organization_id": "9b1e...", "email": "dana@acme.com", "kind": "email", "reason": "clicked the unsubscribe link", "source": "unsubscribe", "campaign_id": "c1...", "metadata": { "via": "link" }, "created_at": "2026-09-01T10:12:00Z", "updated_at": "2026-09-01T10:12:00Z" }, { "id": "7d2f...", "organization_id": "9b1e...", "email": "competitor.io", "kind": "domain", "reason": "Competitor", "source": "manual", "metadata": { "added_by": "4e5f..." }, "created_at": "2026-08-20T09:00:00Z", "updated_at": "2026-08-20T09:00:00Z" } ], "pagination": { "next_cursor": null, "has_more": false } } ``` -------------------------------- ### Get A/B analysis response example Source: https://docs.warmbly.com/api/reference/campaigns Example response body for GET /campaigns/:id/ab-analysis. Shows per-variant engagement stats and the computed winner, including winning_rule and confidence. ```json { "campaign_id": "8f1d6b2e-2b7a-4c9e-9a1f-0e6d4c3b2a10", "variants": [ { "variant_id": "c1a2...", "variant_name": "Subject A", "total_sent": 120, "opened": 78, "clicked": 21, "replied": 9, "bounced": 2, "open_rate": 65.0, "click_rate": 17.5, "reply_rate": 7.5, "bounce_rate": 1.7 } ], "winner_id": "c1a2...", "winner_name": "Subject A", "winning_rule": "reply_rate", "confidence": "low" } ``` -------------------------------- ### make targets quick reference Source: https://docs.warmbly.com/development/deployment-guide Quick reference for the most common make targets. Use `make up` to build and start the platform, `make claim` to check instance state, `make doctor` to run health checks (non-zero exit on error), and `make cli status` to run any warmblyctl command inside the backend container. `make reset` tears down containers and volumes, destroying data and encryption keys. `make gen-key` prints a fresh KMS_LOCAL_MASTER_KEY, and `make grant-admin EMAIL=you@example.com` promotes an existing account to platform admin. ```makefile make up # build and start the platform, then print the claim link make claim # check instance state and print the claim link or the next command make doctor # run every instance health check (non-zero exit on an error) make cli status # any warmblyctl command inside the backend container make seed-demo # load the showcase workspace make status # docker compose ps make logs # follow logs (make logs backend for one service) make stop # stop everything, keep data make down # stop and remove containers, keep data make reset # tear down including volumes (destroys data and the encryption keys) make gen-key # print a fresh KMS_LOCAL_MASTER_KEY make grant-admin EMAIL=you@example.com # promote an existing account to platform admin make dev # local development stack instead (native Go, hot reload) make sandbox # live end-to-end demo ``` -------------------------------- ### Run Warmbly installer in demo mode Source: https://docs.warmbly.com/development/install Runs the installer in demo mode, simulating the wizard and review without making changes. It writes no files, pulls no images, creates no containers, and requires no Docker. Takes about half a minute; set WARMBLY_DEMO_FAST=1 to collapse to under ten seconds. ```shell curl -fsSL https://warmbly.com/install.sh | sh -s -- --demo ``` -------------------------------- ### Set up environment and run basic warmblyctl commands Source: https://docs.warmbly.com/development/warmblyctl Export the API key and optional API URL, then run commands like 'warmblyctl me' and 'warmblyctl campaign list'. The API key is obtained from Settings > API keys. Omit WARMBLY_API_URL for the hosted service. ```bash export WARMBLY_API_KEY=wmbly_... # Settings > API keys export WARMBLY_API_URL=https://api.your-instance.com # omit for the hosted service warmblyctl me # who the key is, and its scopes warmblyctl campaign list warmblyctl campaign start --id ``` -------------------------------- ### GET /unibox/thread/labels response Source: https://docs.warmbly.com/api/reference/unibox Example response from the GET endpoint. The labels are wrapped in a data array, each with id, title, and color. ```json { "data": [ { "id": "c0ffee00-0000-4000-8000-000000000001", "title": "Interested", "color": "#16a34a" } ] } ``` -------------------------------- ### Setup Bus and Cache Services Source: https://docs.warmbly.com/development/split-deployment Downloads and executes the setup script to configure Docker, certbot, NATS, and Redis on the bus machine. ```bash curl -fsSLO https://raw.githubusercontent.com/warmbly/warmbly/main/deploy/split-cloud/bus/setup.sh sh setup.sh --domain bus.example.com ``` -------------------------------- ### Get pipeline response Source: https://docs.warmbly.com/api/reference/crm Example response from GET /crm/pipelines/:id. Returns the pipeline object with empty stages array. ```json { "id": "5d8a2b1e-0c4f-4a9b-9f2e-1a2b3c4d5e6f", "organization_id": "0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9", "name": "Sales", "position": 0, "stages": [], "created_at": "2026-05-01T09:00:00Z", "updated_at": "2026-05-01T09:00:00Z" } ``` -------------------------------- ### Get outreach settings response example Source: https://docs.warmbly.com/api/reference/deliverability-ops Example response for GET /outreach/settings, returning the AdvancedOutreachSettings object directly. Shows the bounce pipeline, task reliability, A/B testing, reply-intent, send-time optimization, preflight, dashboard, unsubscribe, and custom configuration blocks. ```json { "bounce_pipeline": { "enabled": true, "auto_suppress_on_bounce": true, "auto_suppress_on_complaint": true, "auto_suppress_on_unsubscribe": true, "auto_pause_campaign_on_spike": true, "pause_bounce_rate_threshold": 8, "pause_complaint_rate_threshold": 1.5 }, "task_reliability": { "enabled": true, "dlq_enabled": true, "max_attempts": 5, "execution_window_seconds": 300 }, "ab_testing": { "enabled": true, "default_winning_rule": "reply_rate", "auto_promote_winner": false, "min_sample_size": 30 }, "reply_intent": { "enabled": true, "positive_keywords": ["interested", "demo", "pricing"], "negative_keywords": ["not interested", "unsubscribe", "stop"], "out_of_office_keywords": ["out of office", "ooo", "vacation"], "question_keywords": ["?", "how", "price"], "auto_create_crm_task": true, "auto_pause_on_negative": false, "auto_suppress_on_unsubscribe_keyword": true }, "send_time_optimization": { "enabled": false, "use_contact_timezone": true, "default_contact_timezone": "UTC", "preferred_hours": [9, 10, 11, 14, 15, 16], "weekend_weight_multiplier": 0.5 }, "preflight": { "enabled": true, "check_tracking_domain": true, "check_unsubscribe_header": true, "check_ab_variant_configured": false, "check_daily_limit": true, "check_schedule_window": true, "check_content_score": true, "min_content_score": 60 }, "dashboard": { "enabled": true, "show_suppression_log": true, "show_intent_summary": true, "show_dlq_stats": true }, "unsubscribe": { "mode": "text", "text": "If this isn't relevant, just reply and let me know and I won't email you again.", "link_intro": "Not the right person, or not interested?", "link_text": "Unsubscribe" }, "custom": {} } ``` -------------------------------- ### Build and install Go services Source: https://docs.warmbly.com/development/bare-metal Builds the six Go binaries statically (CGO_ENABLED=0) and installs them. The default build has no Kafka support; add -tags kafka only if pointing at an existing Kafka cluster. ```bash cd /opt/warmbly/src export CGO_ENABLED=0 for cmd in backend forms consumer worker migrate warmblyctl; do go build -ldflags="-s -w" -o "out/$cmd" "./cmd/$cmd" done sudo install -m 0755 out/backend out/forms out/consumer out/worker out/migrate out/warmblyctl /opt/warmbly/bin/ sudo ln -sf /opt/warmbly/bin/warmblyctl /usr/local/bin/warmblyctl ``` -------------------------------- ### List campaigns response example Source: https://docs.warmbly.com/api/reference/campaigns Example JSON response from GET /campaigns. Shows the data and pagination envelope with campaign fields and pagination metadata. ```json { "data": [ { "id": "8f1d6b2e-2b7a-4c9e-9a1f-0e6d4c3b2a10", "user_id": "a2c4...", "organization_id": "11111111-2222-3333-4444-555555555555", "name": "Q3 outbound", "description": "", "status": "active", "kind": "sequence", "stop_on_reply": true, "open_tracking": true, "link_tracking": true, "text_only": false, "daily_limit": 50, "unsubscribe_header": true, "risky_emails": false, "cc": [], "bcc": [], "start_date": null, "end_date": null, "timezone": "UTC", "days": 62, "start_time": "09:00", "end_time": "17:00", "schedule_windows": [[],[{"start":540,"end":1020}],[],[],[],[],[]], "email_tags": ["sales"], "folders": [], "contact_order_by": "created_at", "contact_order_dir": "asc", "sender_strategy": "tags", "rotation_mode": "round_robin", "ramp_enabled": false, "ramp_start": 0, "ramp_increment": 0, "ramp_ceiling": 0, "ramp_level": 0, "esp_match_mode": "off", "max_new_leads_per_day": 0, "prioritize_new_leads": false, "entry_delay_minutes": 0, "continuous": false, "idle_since": null, "tracking_domain": "", "tracking_domain_verified": false, "utm_tracking": true, "utm_source": "", "utm_medium": "", "utm_campaign": "", "updated_at": "2026-06-10T12:00:00Z", "created_at": "2026-06-01T09:00:00Z" } ], "pagination": { "total": 12, "next_cursor": "c1_b3BhcXVlLWN1cnNvcg", "has_more": true } } ``` -------------------------------- ### Begin enrollment - Response Source: https://docs.warmbly.com/api/reference/account-org Example response for POST /auth/2fa/enroll/start. Contains the TOTP secret and the otpauth:// provisioning URI, returned once. ```json { "secret": "JBSWY3DPEHPK3PXP", "otpauth_uri": "otpauth://totp/Warmbly:alex@acme.com?secret=JBSWY3DPEHPK3PXP&issuer=Warmbly" } ``` -------------------------------- ### Get connection webhook secret response Source: https://docs.warmbly.com/api/reference/integrations Example response for GET /integrations/connections/:id/webhook-secret. Returns the HMAC signing secret, the signature header name, and the signing scheme. ```json { "signing_secret": "whsec_live_...", "signature_header": "X-Warmbly-Signature", "scheme": "HMAC-SHA256 of \"{t}.{body}\", sent as t=,v1=" } ``` -------------------------------- ### Start the backend first Source: https://docs.warmbly.com/development/bare-metal Starts the backend and follows its logs. The backend applies migrations on boot; wait for them to finish and for /health to return 200. A prod boot refuses development secrets, so a message naming a variable means a placeholder remains in the env file. ```bash sudo systemctl enable --now warmbly-backend sudo journalctl -u warmbly-backend -f ``` -------------------------------- ### GET /contacts/:id/campaigns response example Source: https://docs.warmbly.com/api/reference/contacts Example JSON response showing campaign state for a contact, including steps, lead status, and next action details. ```json { "data": [ { "campaign_id": "c1...", "campaign_name": "Q3 Outbound", "campaign_status": "active", "lead_status": "active", "sender_id": "m1...", "sender_email": "alex@acme.com", "steps": [ { "id": "s1...", "label": "Email 1", "kind": "email", "position": 0, "subject": "Quick question", "sent_at": "2026-06-09T08:00:00Z", "opened_at": "2026-06-09T08:14:00Z" }, { "id": "s2...", "label": "Email 2", "kind": "email", "position": 1, "subject": "Following up" } ], "completed_steps": 1, "total_steps": 2, "current_step": { "id": "s1...", "label": "Email 1", "kind": "email", "position": 0, "subject": "Quick question", "sent_at": "2026-06-09T08:00:00Z", "opened_at": "2026-06-09T08:14:00Z" }, "last_action": "Opened", "last_action_at": "2026-06-09T08:14:00Z", "next": { "step_id": "s2...", "step_label": "Email 2", "kind": "email", "subject": "Following up", "state": "waiting", "not_before": "2026-06-12T08:00:00Z", "constraint": "Waiting 3 days after Email 1" } } ] } ``` -------------------------------- ### Make targets for day-one setup Source: https://docs.warmbly.com/development/local-development Day-one Make targets for the warmbly project. `make dev` runs the full stack; `make infra` starts stateful services (postgres, redis, nats, mailpit) and leaves them running; `make run` starts the app natively after infra; `make up` runs the whole stack in Docker; `make gen-key` prints a KMS_LOCAL_MASTER_KEY; `make seed` loads fixtures; `make sandbox` sets up a demo environment; `make reset` removes everything including volumes. ```makefile make dev # one command: infra + migrations + seed + backend/forms/consumer/worker + realtime + tracking + dashboard + admin make infra # postgres, redis, nats, mailpit (leave running) make run # backend + forms + consumer + worker (native, after make infra) make up # the whole no-cloud stack in Docker (docker compose up --build) make gen-key # print a KMS_LOCAL_MASTER_KEY for a real deployment make seed # load rich fixtures (3 orgs, 6 mailboxes, a campaign) make sandbox # fully working demo environment (see /development/sandbox/) make reset # nuke everything including volumes, start over ``` -------------------------------- ### PATCH /api-keys/:id response example Source: https://docs.warmbly.com/api/reference/api-keys Example response after updating an API key. Returns the updated key object with the same shape as get, including unchanged fields. ```json { "id": "0b2d5e7a-1c3f-4a9b-8c2d-1e2f3a4b5c6d", "name": "Zapier production", "description": "Lead sync, now read-only", "permissions": 4329731, "rate_limit_per_minute": 60, "status": "active", "updated_at": "2026-06-11T19:30:00Z" // ... remaining key fields unchanged } ``` -------------------------------- ### Build and install dashboard, admin, and forms apps Source: https://docs.warmbly.com/development/bare-metal Builds the three static Vite apps (web, admin, forms) and installs their dist folders. No URL is baked in at build time; the dashboard and admin read config.js at runtime, and the forms app is served by the forms binary from forms/dist. ```bash cd /opt/warmbly/src/web && pnpm install --frozen-lockfile && pnpm build cd /opt/warmbly/src/admin && pnpm install --frozen-lockfile && pnpm build cd /opt/warmbly/src/forms && pnpm install --frozen-lockfile && pnpm build sudo rm -rf /opt/warmbly/web /opt/warmbly/admin /opt/warmbly/forms sudo cp -r /opt/warmbly/src/web/dist /opt/warmbly/web sudo cp -r /opt/warmbly/src/admin/dist /opt/warmbly/admin sudo install -d /opt/warmbly/forms sudo cp -r /opt/warmbly/src/forms/dist /opt/warmbly/forms/dist ``` -------------------------------- ### Build and install tracking service (Rust) Source: https://docs.warmbly.com/development/bare-metal Builds the Rust tracking service in release mode and installs the binary. The tracking snippet in static/ is compiled into the binary, so nothing else needs copying. ```bash cd /opt/warmbly/src/tracking cargo build --release sudo install -m 0755 target/release/tracking /opt/warmbly/bin/tracking ``` -------------------------------- ### Reveal Webhook Secret Response Source: https://docs.warmbly.com/api/oauth Example response from the GET /oauth/applications/{id}/webhook-secret endpoint. ```json { "webhook_secret": "whsec_9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0" } ``` -------------------------------- ### Download, verify, and run the install script Source: https://docs.warmbly.com/development/install The install script can be verified by checking its SHA256 checksum before running. It is designed to be executed directly, not piped to a shell, and will request elevation only for specific steps. ```bash curl -fsSLO https://warmbly.com/install.sh curl -fsSLO https://warmbly.com/install.sh.sha256 sha256sum -c install.sh.sha256 less install.sh sh install.sh ``` -------------------------------- ### GET /integrations/connections response example Source: https://docs.warmbly.com/api/reference/integrations Example JSON response for listing connections. Returns a connections array of IntegrationConnection objects. Secrets are never serialized. Requires scope INTEGRATIONS or org permission manage_settings or use_integrations. ```json { "connections": [ { "id": "9b2c1f7e-4d6a-4f2b-bb11-9d0e2a7c5f33", "organization_id": "1a2b3c4d-0000-0000-0000-000000000001", "provider": "hubspot", "label": "HubSpot (Sales)", "status": "connected", "auth_method": "oauth", "display_fields": {}, "sync_direction": "push", "external_account_name": "Acme Inc", "granted_scopes": ["crm.objects.contacts.write"], "health": "healthy", "last_synced_at": "2026-06-10T14:03:00Z", "created_at": "2026-05-01T09:00:00Z", "updated_at": "2026-06-10T14:03:00Z" } ] } ``` -------------------------------- ### POST /auth/passkey/register/begin Source: https://docs.warmbly.com/api/reference/account-org Begins passkey registration by returning WebAuthn creation options for the browser's navigator.credentials.create() call. Requires session authentication. ```APIDOC ## POST /auth/passkey/register/begin ### Description Begins passkey registration. Returns the WebAuthn creation options the browser passes to `navigator.credentials.create()`. ### Method POST ### Endpoint /auth/passkey/register/begin ### Authentication Session only (not available to API keys). ### Response #### Success Response (200) - The WebAuthn creation options object (challenge, RP, user, pubkey params). #### Response Example ```json { "challenge": "...", "rp": { "name": "...", "id": "..." }, "user": { "id": "...", "name": "...", "displayName": "..." }, "pubKeyCredParams": [ { "type": "public-key", "alg": -7 } ] } ``` ``` -------------------------------- ### Create user, directories, and clone warmbly Source: https://docs.warmbly.com/development/bare-metal Creates the warmbly system user, directories, and clones the repository. Run as a normal user; cloning with sudo leaves a root-owned tree that builds cannot write to. ```bash sudo useradd --system --home /var/lib/warmbly --create-home --shell /usr/sbin/nologin warmbly sudo mkdir -p /opt/warmbly/bin /etc/warmbly /var/lib/warmbly/blobs sudo chown -R warmbly:warmbly /var/lib/warmbly sudo chmod 0700 /etc/warmbly sudo install -d -o "$USER" -g "$USER" /opt/warmbly/src git clone https://github.com/warmbly/warmbly /opt/warmbly/src ``` -------------------------------- ### GET /webhooks/deliveries response example Source: https://docs.warmbly.com/api/reference/webhooks Example response for listing all deliveries. Uses the standard data + pagination envelope with an opaque cursor. The response includes delivery details such as status, attempt counts, and response status. ```json { "data": [ { "id": "d1e2f3a4-b5c6-7d8e-9f0a-1b2c3d4e5f6a", "endpoint_id": "a3f1c2e4-5b6d-7e8f-9a0b-1c2d3e4f5a6b", "organization_id": "11111111-2222-3333-4444-555555555555", "event_type": "campaign.reply_received", "event_id": "e9f8a7b6-c5d4-3e2f-1a0b-9c8d7e6f5a4b", "status": "delivered", "attempt_count": 1, "max_attempts": 8, "next_attempt_at": null, "last_attempt_at": "2026-06-11T18:02:14Z", "response_status": 200, "response_body_excerpt": "ok", "error_reason": null, "created_at": "2026-06-11T18:02:13Z", "updated_at": "2026-06-11T18:02:14Z" } ], "pagination": { "next_cursor": "eyJpZCI6ImQx...", "has_more": true } } ```