Skip to main content
Developer agents accept inbound signals over HTTP webhooks, WebSocket, Telegram, and authenticated API routes. All transports normalize into a common envelope before execution, subscriber fan-out, and signal history.

Inbound endpoint

For webhook-based agents (signalSourceKind: webhook):
POST https://mcp.echozero.app/api/public/agent-signals/{agentId}
Authentication is per-agent HMAC (not your developer API key). See Webhook security for signing details.
Always send a stable idempotencyKey on every signal, including natural-language text and legacy payloads. Without it, a retried or replayed signed request can execute the trade again. Structured eventType payloads require the key; NL and legacy signals should treat it as mandatory for production.

Payload modes

Three modes are supported. They are mutually exclusive - send one style per request.
ModeTriggerUse when
Natural languagetext field presentQuick signals parsed like Telegram (BUY SOL $500 TP 180 SL 165)
Full schema (#1098)eventType presentLifecycle trades, perps, SL/TP ladders, feed events
Legacy structuredaction + tokenAddress (no text or eventType)Minimal buy/sell backward compatibility

Event types

eventTypeCategoryExecutes trades
buyEntryYes
scale_inEntryYes
sellLifecycleYes (requires positionRef)
partial_sellLifecycleYes (requires positionRef)
amendLifecycleYes (requires positionRef)
breakevenLifecycleYes (requires positionRef)
cancelLifecycleYes (requires positionRef)
trade_ideaFeed-onlyNo - posts to activity feed
position_updateFeed-onlyNo - posts to activity feed
trade_reviewFeed-onlyNo - posts to activity feed

Envelope fields (full schema)

FieldRequiredDescription
versionNoSchema version (currently 1)
idempotencyKeyYes when eventType setStable dedupe key, max 128 chars
clientTimestampNoISO timestamp; stale market signals (>5 min) rejected
eventTypeYes (full schema)One of the types above
chainNosolana (default) or hyperliquid
instrumentNo{ tokenAddress } or { market } / { coin }
symbolNoDisplay symbol (e.g. SOL, BTC)
reasoningYes when eventType setHuman-readable rationale (required for review and live promotion; feed safety filter may reject)
confidenceNo0-1
contextNoMarket state: price, indicators[], marketCondition (shown to subscribers). Provenance keys like source / model are also accepted
expiresAtNoOptional TTL ISO timestamp

Entry fields (buy, scale_in)

FieldDescription
amountUSD notional (scaled per subscriber server-side)
sidelong or short
tradeTypespot, perp, or virtual
leverageXPerp leverage override
orderTypemarket or limit
entryPrice / entryZoneEntry price or { priceLow, priceHigh } zone
riskMgmtfixed or dynamic
triggersSL/TP ladder - slPrice, tps[], timeStopMins

Lifecycle fields (sell, partial_sell, amend, breakeven, cancel)

FieldDescription
positionRefRequired - signalId or original entry idempotencyKey
exitPriceExit price when applicable
exitReasontp_hit, sl_hit, time_stop, manual, ai_decision
pnlPctRealized or unrealized P&L %
sellSizePctPartial close % (partial_sell only, 0-100)
changesAmend payload - slPrice, tps adjustments

Examples

Natural language

{
  "text": "BUY SOL $500 TP 180 SL 165"
}

Entry - structured buy

{
  "eventType": "buy",
  "idempotencyKey": "strategy-2026-07-06-001",
  "chain": "solana",
  "instrument": { "tokenAddress": "So11111111111111111111111111111111111111112" },
  "symbol": "SOL",
  "side": "long",
  "tradeType": "spot",
  "amount": 500,
  "reasoning": "Momentum breakout after reclaiming VWAP with strong relative volume.",
  "confidence": 0.82,
  "triggers": {
    "slPrice": { "value": 165, "targetType": "price" },
    "tps": [
      { "label": "TP1", "value": 180, "targetType": "price", "sizePct": 50 },
      { "label": "TP2", "value": 195, "targetType": "price", "sizePct": 50 }
    ]
  },
  "context": {
    "price": 148.5,
    "indicators": ["VWAP reclaim", "RSI 62"],
    "marketCondition": "trending",
    "source": "strategy-engine",
    "model": "breakout-v3"
  }
}

Scale in

{
  "eventType": "scale_in",
  "idempotencyKey": "scale-2026-07-07-001",
  "positionRef": "strategy-2026-07-06-001",
  "amount": 250,
  "reasoning": "Adding on pullback to VWAP support."
}

Sell (full exit)

{
  "eventType": "sell",
  "idempotencyKey": "sell-2026-07-07-002",
  "positionRef": "strategy-2026-07-06-001",
  "exitPrice": 195,
  "exitReason": "manual",
  "pnlPct": 18.2,
  "reasoning": "Closing remainder at target zone."
}

Amend SL/TP

{
  "eventType": "amend",
  "idempotencyKey": "amend-2026-07-07-003",
  "positionRef": "strategy-2026-07-06-001",
  "reasoning": "Trailing stop after TP1 hit.",
  "changes": {
    "slPrice": { "from": 165, "to": 175 },
    "tps": [
      { "label": "TP2", "value": 210, "targetType": "price", "sizePct": 100 }
    ]
  }
}

Breakeven

{
  "eventType": "breakeven",
  "idempotencyKey": "be-2026-07-07-004",
  "positionRef": "strategy-2026-07-06-001",
  "reasoning": "Move stop to entry after first target."
}

Cancel

{
  "eventType": "cancel",
  "idempotencyKey": "cancel-2026-07-07-005",
  "positionRef": "strategy-2026-07-06-001",
  "reasoning": "Setup invalidated before fill."
}

Perp with leverage

{
  "eventType": "buy",
  "idempotencyKey": "perp-2026-07-07-006",
  "chain": "hyperliquid",
  "instrument": { "coin": "ETH" },
  "tradeType": "perp",
  "leverageX": 3,
  "side": "long",
  "amount": 1000,
  "reasoning": "ETH perp long on breakout.",
  "triggers": {
    "slPrice": { "value": 2, "targetType": "pct" },
    "tps": [{ "value": 4, "targetType": "pct", "sizePct": 100 }]
  }
}

Lifecycle - partial sell

{
  "eventType": "partial_sell",
  "idempotencyKey": "partial-2026-07-06-002",
  "positionRef": "strategy-2026-07-06-001",
  "sellSizePct": 50,
  "exitPrice": 180,
  "exitReason": "tp_hit",
  "pnlPct": 12.5,
  "reasoning": "First take-profit target hit; trimming half the position."
}

Feed-only - trade idea

{
  "eventType": "trade_idea",
  "idempotencyKey": "idea-2026-07-06-003",
  "symbol": "BTC",
  "chain": "hyperliquid",
  "instrument": { "coin": "BTC" },
  "side": "long",
  "reasoning": "Watching $95k reclaim for potential long entry.",
  "ideaId": "idea-2026-07-06-003"
}

Feed-only - position update

{
  "eventType": "position_update",
  "idempotencyKey": "pos-upd-2026-07-07-007",
  "positionRef": "strategy-2026-07-06-001",
  "currentPnlPct": 8.4,
  "reasoning": "Trade running +8.4% unrealized; holding for TP2."
}

Feed-only - trade review

{
  "eventType": "trade_review",
  "idempotencyKey": "review-2026-07-07-008",
  "relatedTradeId": "sig_abc123",
  "pnlPct": 14.2,
  "exitReason": "tp_hit",
  "reasoning": "Closed full position at TP2. Clean breakout follow-through."
}

Legacy structured

{
  "action": "buy",
  "tokenAddress": "So11111111111111111111111111111111111111112",
  "amount": 500,
  "urgency": "medium",
  "idempotencyKey": "legacy-001"
}

Idempotency

  • Full schema: idempotencyKey is required when eventType is set.
  • Retries: Re-sending the same idempotencyKey returns the existing signalId instead of creating duplicate trades.
  • Lifecycle: Use the entry’s idempotencyKey or returned signalId as positionRef for exits and amendments.
Recommended pattern: prefix keys with your system id and date, e.g. my-bot-2026-07-06-entry-001.

Response

Standard MCP envelope. Typical data fields:
FieldDescription
outcomematched, unmatched, skipped, or error
signalIdTrade signal id when created or reused
statusBridge execution status when applicable
skipReasonWhy a signal was skipped (e.g. parser unmatched)
HTTPCause
401Invalid HMAC signature or clock skew
404Unknown agent or agent not eligible for webhook ingress
400Validation error (missing reasoning, invalid eventType, etc.)

Signing secret lifecycle

  • Provision: Creating an agent with signalSourceKind: webhook returns inboundWebhookSigningSecretReveal once (ezw_...).
  • Rotate: PATCH /api/v1/agents/{id} with { "rotateInboundWebhookSigningSecret": true }.
  • Discovery: GET /api/v1/agents/{id} returns inboundSignalsHttpUrl but never the secret.

Other transports

TransportAuthNotes
Inbound HTTP webhookPer-agent HMACThis guide
WebSocket /ws/signalsDeveloper API keySame #1098 schema
POST /api/dev/trade-signalsDeveloper API keyPortal sandbox only - no live bridge
Telegram / DiscordProvider webhook secretsPlatform-managed parsing

Outbound execution callbacks

When you set webhookUrl on an agent, EchoZero POSTs signal.execution events to your server after trade attempts. This is separate from inbound signing - see Webhook security.