Self-hosting the agent
The AutoPay Agent process.
The agent is a Nest cron app + BullMQ worker. It runs scheduled jobs (recovery emails, cashflow digests, anomaly detection, monthly reports) and consumes the routing queue for CCTP V2 bridging.
Build
Configuration
What runs when
| Capability | Cron | Notes |
|---|---|---|
recovery | hourly | Idempotent per (subId, attempt) |
cashflow.digest | daily 9am UTC | Idempotent per UTC day |
cashflow.anomaly | hourly | z-score over trailing 30d |
cashflow.yield | daily 9:30am UTC | Recommendation only. No signing. |
commerce | first of each month | Per-month dedup |
pricing_intelligence | first of each month | Per-month dedup |
routing | queue-driven | CCTP V2 attestation polling |
The agent reads AgentMerchantConfig on every tick, so config changes in the dashboard take effect on the next firing.
Single-instance recommendation
Unlike the scheduler, the agent has no built-in multi-instance safety. Two agent instances will fire each cron twice. The dedup logic inside each capability stops the visible side effects from duplicating (the same email won't be sent twice inside the dedup window), but you're burning compute for nothing.
If you need horizontal scale for the routing worker (high CCTP
volume), run one cron instance and several routing-only workers
configured through BullMQ.concurrency.
Observability
/healthz,/readyz- Activity log written to
AgentActivityLogfor every action - AuditLog entries for
cashflow.anomaly_detected,merchant.fee_bps_changed_onchain,fees.accrued
Failure modes
- Resend API outage. Emails fail. The agent retries on the next tick. No state is lost.
- Circle attestation outage. Routing jobs back up in the queue. The agent re-polls until Circle responds.
- Postgres outage. Capabilities skip. The next tick retries.
