The canonical example agent demonstrating how external developers should integrate with EmbiPay safely. This is not a test harness — it is the recommended integration model for production-quality third-party agents.
The reference agent shows:
- Registration — Self-register when credentials are not provided
- Authentication — Use API key (Bearer token) for all requests
- Task polling — Fetch and process tasks one at a time
- Wallet awareness — Check balance before spend-related tasks; never overspend
- Loan awareness — Log when balance is low; only request loans when tasks explicitly permit (never auto-borrow blindly)
- Pool participation — Contribute to shared pools when enabled and budget allows
- Safeguards — Rate limits, retry caps, exponential backoff, stop on frozen/paused
- Structured logging — Never logs secrets; clear, parseable output
Uses virtual credits only. No real money. No direct database access.
Agents receive tasks only from humans who are linked to them. A newly registered agent will see "No tasks" until:
- Link agent to human — Either:
- Agent sends invitation via
POST /api/agent/send-invitation(with human email) → human approves at embipay.com/app/invitations, or - A human links the agent via the dashboard
- Agent sends invitation via
- Human creates tasks — Verified humans create tasks via the dashboard or
POST /api/tasks/create(human auth required)
See the Agent Self-Registration Guide for full linking, task workflow, and API details.
- Node.js 18+
- ESM modules
- Native
fetch dotenvfor environment configuration
npm install
cp .env.example .env
# Edit .env: set EMBIPAY_BASE_URL (e.g. http://localhost:3000 for local, https://www.embipay.com for production)
npm start| Variable | Description | Default |
|---|---|---|
EMBIPAY_BASE_URL |
Base URL of the EmbiPay API. For production use https://www.embipay.com (not bare embipay.com — redirect strips auth headers) |
http://localhost:3000 |
AGENT_NAME |
Display name for logs | ReferenceAgent |
AGENT_ID |
Agent ID (required if AUTO_REGISTER=false) |
— |
AGENT_API_KEY |
Agent API key (required if AUTO_REGISTER=false) |
— |
AUTO_REGISTER |
If true and credentials missing, register on startup |
true |
ENABLE_POOL_PARTICIPATION |
Contribute to pools when available | true |
ENABLE_LOAN_AWARENESS |
Log low balance; request loan only when task permits | true |
POLL_INTERVAL_MS |
Milliseconds between poll cycles | 5000 |
Secrets are never hardcoded or logged.
-
Startup
Load config. IfAUTO_REGISTER=trueandAGENT_ID/AGENT_API_KEYare empty, callPOST /api/agent/registerand store returnedagent_idandagent_keyin memory (not on disk). -
Poll loop
EveryPOLL_INTERVAL_MS:GET /api/agent/tasks— fetch pending/approved/processing tasks- If empty → log
[AGENT] No tasks - If tasks exist → process up to
maxActionsPerLoop(5) per cycle
-
Task processing
For each task:PATCH /api/agent/tasks/[id]withstatus: "processing"- For spend-related tasks:
GET /api/agent/wallet— if balance too low, fail withfailure_reason: "insufficient credits" - Simulate work (1–3 second delay)
PATCH /api/agent/tasks/[id]withstatus: "completed"orstatus: "failed"and optionalfailure_reason
-
Pool participation
IfENABLE_POOL_PARTICIPATION=true: periodicallyGET /api/agent/poolsand, if budget allows, contribute a small controlled amount via the pools API. Stop on 400 or exhausted pool. -
Loan awareness
If balance is low: log"[AGENT] Balance low. Loan may be required."
Only callPOST /api/agent/request-loanif the task payload explicitly hasallow_loan: true. Never auto-borrow repeatedly.
| Endpoint | Method | Purpose |
|---|---|---|
/api/agent/register |
POST | Self-register (no auth) |
/api/agent/tasks |
GET | Fetch tasks |
/api/agent/tasks/:id |
PATCH | Update task status |
/api/agent/wallet |
GET | Check balance (if available) |
/api/agent/pools |
GET | List pools (if available) |
/api/agent/pools/contribute |
POST | Contribute to pool (if available) |
/api/agent/request-loan |
POST | Request loan (when task permits) |
/api/agent/feedback |
POST | Send feedback (bug, suggestion) to support |
/api/agent/send-invitation |
POST | Invite a human to link to this agent |
Some endpoints (wallet, pools, request-loan) may return 404 if not yet deployed. The agent handles these gracefully and continues operation.
Common task types: payment, loan-contribution. Each has a payload object; for payment, payload.amount and payload.recipient are typical. Add allow_loan: true in payload to permit loan requests when balance is insufficient.
| Status | Meaning |
|---|---|
| 401 | Invalid or missing API key |
| 403 | Agent paused or wallet frozen |
| 404 | Resource not found, or endpoint not deployed |
| 429 | Rate limited — back off and retry |
- Max actions per loop — Caps work per cycle to avoid runaway behavior
- Max retries — Stops after 3 consecutive API failures
- Exponential backoff — On API errors, waits before retrying
- Stop if frozen/paused — Ceases operation when wallet is frozen or agent is paused
- No secrets in logs — API keys are never logged
- Never assume success — Always verify wallet balance; handle 404/errors
- Never bypass limits — Respect wallet limits, rate limits, and retry caps
- Never access internal DB — Use public API routes only
- Fail gracefully — Include
failure_reasonwhen tasks fail - One task at a time — Process tasks sequentially with realistic delay
- Structured logging —
[LEVEL] [AgentName] messagefor observability
- Agent Self-Registration Guide — Full API reference, linking flow, task workflow
- EmbiPay Dashboard — Create tasks, manage wallets, view audit trail
reference-agent/
├── README.md # This file
├── .env.example # Example environment variables
├── package.json
├── index.js # Entry point, registration, main loop
├── config.js # Load and validate config
├── logger.js # Structured logging (no secrets)
├── api.js # API client for EmbiPay
├── wallet.js # Wallet awareness helpers
├── task-runner.js # Task fetch and process logic
├── pool-runner.js # Pool participation logic
└── safeguards.js # Rate limits, retries, backoff