v1.7.0
Backward compatible with 1.6.0 on the wire — nothing in this release removes an
operation, field, or enum value, and every API addition is additive or opt-in.
Two behavior changes are deliberate and customer-visible, and one of them
changes an email address your filters may match on — read "Behavior changes"
before upgrading. Three migrations: two metadata-only ALTER TABLEs with NULL
defaults and one CREATE INDEX — see "Upgrading".
Behavior changes
Each of these changes an outcome that 1.6.0 produced.
-
Operational email now comes from
approvals@andwebhooks@, not
hitl-noreply@. HITL approval notifications previously sent from
hitl-noreply@<your from_domain>; they now send fromapprovals@, and the
new webhook health mail sends fromwebhooks@. If you filter, route, or
allowlist on the old address — including bounce rules and mail-server
allowlists — those rules stop matching. The senders are deliberately distinct
so a time-boxed approval stays filterable apart from routine webhook mail;
settingnotifications.from_addresscollapses both into one identity. -
Operational email now carries a working
Reply-To. Previously HITL
approval mail setReply-Toto its own sender on the platform relay domain,
which has no mailbox — a reply went nowhere. Whennotifications.reply_tois
configured, both notification kinds now direct replies to that address; unset
preserves the previous behavior exactly, so a deployment that configures
nothing is unchanged. -
e2a now emails webhook owners when their endpoint is failing. Two new
emails: an early warning when deliveries start failing, and a notice
when e2a auto-disables an endpoint. Accounts with webhooks will receive mail
they have not received before. The auto-disable thresholds themselves are
unchanged (10 terminal failures in 72h with none succeeding); the warning is
new and fires on attempt-level failures within minutes, long before the
breaker can see them. -
Deliveries parked against a disabled webhook now terminate. Previously a
delivery whose webhook was disabled snoozed hourly with no ceiling, sitting in
pendinguntil its 90-day expiry. It is now capped at 24 snoozes (~24h) and
then written terminal withlast_error = "webhook disabled". Re-enabling
within that window still drains the queue as before; after it, events remain
replayable viaPOST /v1/events/{id}/redeliverfor the 30-day retention.
New
-
Message filtering —
filteronlistMessages(beta). A boolean
expression language derived from AIP-160 overlabel,from,subjectand
created. Operators: = != < <= > >=withAND/OR/NOTand
parentheses; whitespace is an implicitANDand binds looser thanOR.
It composes with (ANDs) the existing flat filters rather than replacing
them, sodirection,labels,sinceand friends keep working alongside it.
Capped at 500 characters. Pagination is cursor-stable under a filter.
Available across the API, both SDKs, the CLI and MCP. The parameter is
filter, notq— it was renamed during development and some intermediate
commit messages still sayq. Unknown fields and malformed expressions return
400 invalid_filterwith the column position of the error. -
Delivery metrics (beta).
GET /v1/metricsand
GET /v1/agents/{email}/metrics, aggregated from the message lifecycle
ledger, plus a/metricsdashboard page,e2a metricsin the CLI, and
get_agent_metrics/get_account_metricsin MCP. No migration — the
aggregate rides existing indexes. Three semantics worth knowing before you
build on it: messages join a window by their owncreated_at(so recent days
keep settling for up to 72h as feedback arrives), headline numbers use message
grain rather than observation grain, and a rate with a zero denominator is
null— never0, which would be indistinguishable from total failure. -
Webhook enable/disable in the dashboard. The webhooks list and detail
pages can now toggle an endpoint, including re-enabling one e2a disabled. The
detail page previously told you to use the API. -
auto_disabled_reasonon the webhook view. The concrete cause e2a
captured when it disabled an endpoint (for exampleHTTP 404), so the reason
is visible without reading delivery history. Additive and optional; treat the
value as an open set.
Fixed
-
MCP
delete_agenthonours permanent purge, matching REST. Previously the
MCP tool could only trash an agent, leaving message bodies stored and counting
againstusage.storage_bytesuntil the retention window elapsed. (#847) -
The webhook breaker no longer counts e2a's own failures. Terminal errors
attributable to e2a (expired before delivery, internal load/resolve errors)
previously counted toward the auto-disable threshold and could be quoted back
to the customer as the reason their endpoint was disabled. They are now
excluded from the breaker, the warning, the captured reason, and the email. -
The auto-disable sweep is now bounded per tick, so a systemic failure on
e2a's side cannot mass-disable and mass-mail the customer base in one pass.
Upgrading
Migrations (three, applied automatically on startup):
096_webhooks_health_notify.sql— two nullable columns onwebhooks
(metadata-only)097_webhooks_reenabled_at.sql— one nullable column onwebhooks
(metadata-only)098_wsd_created_at_idx.sql— an index onwebhook_subscriber_deliveries
supporting the health sweeps
Configuration (all optional; unset preserves 1.6.0 behavior):
notifications.from_address— overrides both notification senders with a
single addressnotifications.reply_to— adds aReply-Toto notification mail. Set this
if yourfrom_domainis relay-only with no mailbox behind it, or replies
from customers will go nowhere.
Client packages — publish in this order, as the CLI depends on the SDK:
@e2a/sdk → e2a (PyPI) → @e2a/cli.
New telemetry: e2a_webhook_notify_total{kind,outcome} counts notification
sends. A sustained outcome="permanent" rate means the path that reports broken
webhooks is itself broken — worth an alert.