Herald Quick Start
The echo channel exercises every part of Herald — webhook, routing, Nexus run, outbox,
dispatch — without a provider account. It performs no authentication at all, which is why it
only registers behind --enable-echo and must never reach an internet-facing deployment.
Start Herald
Section titled “Start Herald”Brings up PostgreSQL 17 and Herald with development credentials. The admin token, encryption
key and tenant-1 send key are committed defaults — override them through the environment
anywhere real.
git clone https://github.com/monaccode/astromesh-herald.gitcd astromesh-heralddocker compose -f deploy/docker-compose.yaml up --build
curl localhost:8081/healthzThe compose stack has no Nexus. Point NEXUS_URL at a reachable control plane —
http://host.docker.internal:8080 is the default for a Nexus running on the host.
Requires Go 1.25+ and PostgreSQL 17.
createdb heraldgo build -o bin/herald ./cmd/herald
DATABASE_URL="postgres://localhost/herald?sslmode=disable" \NEXUS_URL="http://localhost:8080" \HERALD_ENC_KEY="$(openssl rand -hex 32)" \HERALD_ADMIN_TOKEN="$(openssl rand -hex 32)" \HERALD_SEND_KEYS="tenant-1:$(openssl rand -hex 16)" \./bin/herald --enable-echoWire a channel and an agent
Section titled “Wire a channel and an agent”-
Create an echo channel account.
Terminal window curl -X POST localhost:8081/admin/accounts \-H "X-Admin-Token: $HERALD_ADMIN_TOKEN" \-H "Content-Type: application/json" \-d '{"tenant_id":"tenant-1","channel":"echo","external_id":"echo-1","credentials":{}}' -
Bind it to an entry agent. The admin plane validates the entry agent against Nexus and rejects an unknown one with
422— a typo fails here, not in front of a customer.Terminal window curl -X POST localhost:8081/admin/bindings \-H "X-Admin-Token: $HERALD_ADMIN_TOKEN" \-H "Content-Type: application/json" \-d '{"tenant_id":"tenant-1","channel":"echo","account_id":"<account id>","entry_agent":"router","fallback_message":"Out of service","config":{"nexus_api_key":"<tenant nexus key>"}}' -
Send an inbound message. This is what a provider’s webhook would deliver.
Terminal window curl -X POST localhost:8081/webhooks/echo \-H "Content-Type: application/json" \-d '{"message_id":"m-1","account_id":"echo-1","sender":"+549110000001","text":"hola"}'The entry agent
routerruns, itsdata.routedecides whether a conversation is persisted, and the reply is queued in the outbox. See inbound routing. -
Send a proactive message, unprompted by anything the person did.
Terminal window curl -X POST localhost:8081/api/v1/messages/send \-H "X-Herald-Key: <tenant-1 key>" \-H "Content-Type: application/json" \-d '{"channel":"echo","recipient":"+549110000001","text":"recordatorio de pago"}'# → 202 {"message_id":"...","status":"pending"} -
Check whether it actually went out.
202meant queued.Terminal window curl localhost:8081/api/v1/messages/<message_id> \-H "X-Herald-Key: <tenant-1 key>"
Open the operator console
Section titled “Open the operator console”http://localhost:8081/ui/Sign in by pasting the admin token. The outbox screen shows each entry’s retry budget, which is where a delivery that is quietly failing becomes visible.
Next steps
Section titled “Next steps”- WhatsApp Setup — replace echo with a real channel
- API Reference — every endpoint, every flag
- Nexus Quick Start — the control plane Herald invokes agents through