Skip to main content

Getting Started

A single-page consolidated reference for getting QTG running, authenticated, and verified. If you want a guided multi-step walkthrough instead, use docs/quickstart/ (4 documents, ~30 minutes end-to-end).

Supported platforms

Toolchain:
  • Python 3.14+
  • uv package manager
  • PostgreSQL (Docker Compose provided)
  • Exchange API keys (live mode only)
  • AWS KMS key (EVM proving lanes) or 1Password CLI (dev quickstart)

Quickstart

Before starting Core, configure the local values, start the Compose PostgreSQL service, wait for it to become healthy, and migrate the global plus the one network bucket selected by MG_NETWORK_MODE. Follow the ordered API-only local setup; running uvicorn before those prerequisites leaves Core without its required schema. The local configuration must supply:
  • MG_DATABASE_URL matching the PostgreSQL password and host connection
  • MG_CALLBACK_HMAC_SECRET replacing the template value
  • MG_CALLBACK_ALLOWED_HOSTS_CSV
  • MG_NETWORK_MODE set to mainnet or testnet

Docker

Name the services you want. qtg-mainnet uses the qtg_v3 database from the Compose defaults. Do not add qtg-testnet to that command: its configured qtg_v3_testnet database needs its own PostgreSQL setup and the testnet migration bucket. The Postgres data volume is external so that docker compose down -v cannot delete it. Compose therefore refuses to start when it is absent, which is the intended signal — see docs/quickstart/01-local-setup.md.

Dashboard

The dashboard provides Gateway balances, CCTP transfer tracking, movement management, and route lookup.

Execution modes

Signer backends

The proving-lane signer is AWS KMS behind the private signer service. For explicit development or evaluation tools without AWS, a local private-key signer provides two key sources:
  • 1Password CLI (recommended for local) — keys fetched on demand from your vault.
  • Plain env var (plain) — development only; plaintext key held in process memory. Do not use for fund movement volume. No sign-without-expose guarantee.
Migrate to AWS KMS (or a future signer backend such as Vault Transit / GCP KMS) before scaling. See docs/reference/signers/local-private-key-signer.md and docs/reference/signers/signer-protocol.md.

Multi-signer bootstrap

qtg.main does not accept in-process local or multi-signer bootstrap. Run a private signer service for the selected KMS key and configure that one remote signer in each Core deployment. MG_EXTRA_SIGNERS_JSON remains available only to reviewed explicit tools; Core rejects it.

CCTP local signer readiness

Activate the EVM / signer section in .env (copied from .env.example). The retained one-shot command is TESTNET-only and can sign and broadcast through AWS KMS. Its presence is not live approval: use it only with a fresh reviewed operator approval for the exact run. Pytest has no CCTP broadcast authority.

Binance and OKX master / sub-account models

Binance sub-account bindings are signed through the master credentials — QTG never holds sub-account trading keys. Declare sub bindings with account_role: "sub" and sub_account_uid, omitting access_key and secret_key. For Binance, sub_account_uid is intentionally the sub-account email (Binance sub-account asset and transfer APIs use email / fromEmail); do not put the numeric subUserId / UID there. Master bindings use account_role: "master" and carry credentials. The Free adapter reads ordinary account balances; QTG Pro registers privileged master-signed sub-account balance reads through /sapi/v3/sub-account/assets, which require the Binance master API key’s Enable Sub-Account Management permission. See .env.example for the full binding JSON shape. OKX uses the same credential boundary: the master binding carries access key, secret, and passphrase; the sub binding carries only the OKX sub-account name in sub_account_uid. OKX capital transfers support only explicit FUNDING and TRADING account types and only master↔sub topologies. A submit response is not completion: QTG keeps the request pending and reconciles the exact request tuple through OKX transfer state before finalizing reservations. QTG Pro is required. New capital-transfer mutation is default-off: explicitly set MG_CAPITAL_TRANSFER_MUTATIONS_ENABLED=true only after installation and operator review. This does not enable the independent follow-up sidecar. Set MG_CAPITAL_TRANSFER_FOLLOWUP_ENABLED=true to run that automatic reconciliation sidecar; otherwise the durable row and source hold remain for manual investigation, with no automatic resubmit. QTG prepares and durably stores the non-secret OKX clientId before HTTP; submit and follow-up reuse that stored identity rather than deriving a second copy after the crash boundary.

CEX logical venue alias

MG_CEX_BINDINGS_JSON maps an alias such as binance_lab to the existing Binance provider. If an alias exists, runtime proving and balance both resolve binding-first. Legacy MG_BINANCE_* settings remain as fallback.

Auth model

Settings.auth_enabled defaults to true, so an environment that omits MG_AUTH_ENABLED requires HMAC signatures for its /v3/** requests except /healthz. The shipped .env.example intentionally sets MG_AUTH_ENABLED=false for the local API-only quickstart; do not carry that value into an operational deployment.

Inbound request HMAC

Required headers:
  • X-QTG-Key-Id
  • X-QTG-Timestamp
  • X-QTG-Nonce
  • X-QTG-Signature
Canonical string:
  • PATH is the routed, percent-decoded path the server dispatches on — no origin, no query string.
  • QUERY is the query exactly as sent: no leading ?, no sorting, empty string if absent. Sorting before signing transmits bytes you did not sign, and every such request 401s.
A working signed-sender example is provided in the repository’s examples/ directory.

RBAC — 3 roles

Each API key is bound to exactly one role, enforced per route by the HMAC auth middleware: All mutating routes are mirrored into an append-only audit_events table. Query via GET /v3/audit/events (canonical, admin + operator) or the legacy GET /v3/registry/audit. For agent-namespace tenant isolation, see docs/reference/api/v3-endpoints.md.

Outbound callback HMAC (v3)

Headers:
  • X-QTG-Callback-Timestamp
  • X-QTG-Callback-Nonce
  • X-QTG-Callback-Signature-Version: v3
  • X-QTG-Callback-Signature
v3 includes nonce-based replay defense. Receiver implementation requirements: docs/callback-verification-contract.md. A working receiver example is provided in the repository’s examples/ directory.

Schema bootstrap

PostgreSQL only since v0.1.0. Auto-creating tables at startup is no longer supported. A fresh DB requires the global Alembic bucket plus exactly one network bucket matching MG_NETWORK_MODE:
Schema changes ship as new migrations in the same chain.
  • Heads are per-bucket — there is no single global “head” revision; upgrade the global bucket and only the selected network bucket to their own @head.
  • Startup validation: on boot the server checks that the schema exists and the alembic head matches before accepting traffic — a drifted or unmigrated DB refuses to boot.
  • Existing databases (schema drift, live deployment): managed by the same alembic_v3/ migration chain.
  • One-off data backfills: scripts/ or explicit operational runbooks.
  • Local and container dependency installation: all aligned on uv.
  • Minimum Python: 3.14 (repo-local default + Docker baseline both aligned).
MG_NETWORK_MODE is required and has no default (mainnet | testnet). The server refuses to boot if it is unset; .env.example ships MG_NETWORK_MODE=mainnet.

Runtime surfaces

QTG runs as a single FastAPI service with a few operator-facing surfaces:
  • REST API — Core mounts its /v3/* movement, template, registry, and signer endpoints, plus /healthz. Optional Pro routes mount only when the commercial package is installed and configured.
  • Dashboard — a React SPA served against the /dashboard/* endpoints (Gateway balances, CCTP transfer tracking, movement management, route lookup). Optional Pro dashboard surfaces likewise depend on the installed Pro package.
  • Runtime workers — when MG_WORKERS_ENABLED=true, 8 always-on workers (dispatcher, observer, recovery, callbacks, expiration, proposal expiry, executor health, audit promotion) run and execute real integrations, plus conditional sidecars behind their own flags.
  • CLI tools — preflight, seed, and import utilities for setup and operations.
The repository also ships examples/ (a callback receiver and a signed sender) and docs/ (design, reference, and operational docs).

Verification commands

Health check — once the server is up, GET /healthz returns:

Important runtime nuances

  • Auto-approve. When MG_AUTO_APPROVE_ENABLED=true and strategy_id is provided, policy-matched requests become APPROVED immediately and manual approval is skipped.
  • Address allowlist. On-chain executors apply the DB-level address guard at dispatch time, not at template registration.
  • Callback v3. Nonce-based replay protection is implemented; receivers must store and reject seen nonces.
  • Signer health. Bootstrap authenticates private signer health and pins the expected EVM address.
  • EVM proving signer. qtg.main uses RemoteSignerProxy; the private signer service owns AWS KMS. Local signer variables are reserved for explicit one-off tools and are rejected by Core.
  • EVM RPC endpoints. Default to PublicNode URLs for ~24 mainnet + testnet chains so the dev quickstart works out of the box. Per-chain overrides in MG_EVM_RPC_ENDPOINTS_JSON always win; set MG_EVM_RPC_USE_DEFAULTS=false to disable the table entirely. Live broadcast tools (*_live_preflight, Stage 3 harness) ignore defaults regardless — see reference/rpc-defaults.md.

Where to go next