v1.1.0
What's Changed
- feat(templates): email templates beta — CRUD + starters + send-by-alias across all surfaces by @jiashuoz in #375
- feat(web): agent-prompt cards on Templates, Inboxes, and Domains by @jiashuoz in #377
- chore(github): PR template — Python SDK rows reflect the async-only /v1 layout by @jiashuoz in #376
- ci: bump actions/checkout from 4 to 7 by @dependabot[bot] in #378
- deps: bump the go-minor-patch group with 5 updates by @dependabot[bot] in #384
- deps: bump @types/node from 25.9.2 to 26.1.0 by @dependabot[bot] in #380
- deps(web): bump @types/node from 25.9.2 to 26.1.0 in /web by @dependabot[bot] in #382
- deps(web): bump the npm-minor-patch group in /web with 6 updates by @dependabot[bot] in #381
- refactor(jobs): shared River composition root + move senderidentity onto it by @jiashuoz in #386
- refactor(webhook): migrate delivery to River — sole engine, at-least-once, three-layer by @jiashuoz in #387
- feat(v1): async-send contract — accepted status, wait param, terminal events + honesty fixes by @jiashuoz in #385
- feat(outbound): at-least-once outbound send on River (QueueOutbound, async) by @jiashuoz in #388
- feat(inbound): at-least-once inbound on River (queue-first, QueueInbound) by @jiashuoz in #391
- feat(hitl): durable approval-notification on River (QueueNotify) by @jiashuoz in #392
- feat(hitl): TTL expiration sweep on River (QueueMaintenance periodic) by @jiashuoz in #393
- feat(janitor): hourly cleanup on River (QueueMaintenance periodic) by @jiashuoz in #394
- feat(hitl): route approve sends onto QueueOutbound in async mode by @jiashuoz in #395
- feat(hitl): deterministic Message-ID on the approval-notification email by @jiashuoz in #396
- perf(janitor): batch the retention DELETEs on prod-sized tables by @jiashuoz in #397
- feat(webhookfanout): migrate webhook fan-out onto River (flag-gated) by @jiashuoz in #399
- docs(design): webhook fan-out → River migration plan by @jiashuoz in #398
- chore(river): modularity + readability cleanup across the River systems by @jiashuoz in #400
- refactor(webhookpub): extract shared fan-out core into fanout_core.go by @jiashuoz in #401
- feat(prober): real outbound-send scenario + agent PATCH + internal-sink deliverer exemption by @jiashuoz in #403
- ci: build & publish the e2a-prober image (co-versioned) by @jiashuoz in #404
- fix(web): single-scroll mobile inbox + conversation view by @jiashuoz in #405
- fix(prober): adopt the server-seeded shared domain in
seedby @jiashuoz in #406 - feat: caller-supplied Reply-To on outbound send/reply/forward by @jiashuoz in #407
- feat(web): unread count badge on Inboxes list + live read-state refresh by @jiashuoz in #410
- feat(ratelimit): exempt system/internal account classes from request limiters by @jiashuoz in #408
- test(conformance): staging seed-conformance + de-drift e2e-prod to current API by @jiashuoz in #409
- fix(httpapi): send-limit 429 now carries the Retry-After header by @jiashuoz in #411
- test(conformance): standard-class quota account + enforcement suite by @jiashuoz in #412
- test(conformance): P1 suites — webhooks/templates/reviews/account/attachments by @jiashuoz in #413
- feat(oauth): grant account scope to https connectors + default consent to account by @jiashuoz in #414
- test(conformance): P2 real-path — webhook-event emission + domain lifecycle by @jiashuoz in #415
- test(conformance): P3a — SDK/CLI parity live tests (staging) by @jiashuoz in #417
- test(conformance): P3b — API-driven seeding runs contract scenarios on staging by @jiashuoz in #419
- test(conformance): P4 — API operationId coverage gate by @jiashuoz in #420
- fix(usage): count only active agents so usage.agents matches /v1/agents by @jiashuoz in #429
- fix(identity): return correct domain_verified from agent create by @jiashuoz in #431
- fix(ws): standard v1 error envelope + close the agent-existence enumeration oracle (not-owned 403→404) by @jiashuoz in #432
- fix(api): return 404 not_found for a missing or non-owned agent by @jiashuoz in #430
- feat(python-sdk): add templates resource at parity with the TS SDK by @jiashuoz in #433
- feat(api): make list pagination consistent + real across the v1 surface by @jiashuoz in #434
- feat(prober): mcp_http_round_trip scenario — gate the deployed HTTP MCP surface by @jiashuoz in #421
- refactor!: standardize every resource's own id on bare
id(BREAKING) by @jiashuoz in #436 - fix!: return 202 Accepted for enqueued async work (redeliver, outbound accepted) (BREAKING) by @jiashuoz in #442
- fix!: verifyDomain returns 200 (branch on .verified), not misused 412 (BREAKING) by @jiashuoz in #441
- fix!: drop redundant agent id from the user-data export (id == email) (BREAKING) by @jiashuoz in #440
- fix!: align 402 limit_exceeded resource tokens to AccountView field stems + type the details (BREAKING) by @jiashuoz in #439
- fix!: unify validation error code (invalid_request) + type error.details (BREAKING) by @jiashuoz in #444
- fix!: require confirm=DELETE uniformly on all delete endpoints (required enum) (BREAKING) by @jiashuoz in #448
- fix!: converge list pagination to one cap AND default = 100 (BREAKING) by @jiashuoz in #445
- fix!: emit all timestamps at RFC3339Nano precision; drop message second-truncation (BREAKING) by @jiashuoz in #446
- feat!: enforce + document attachment limits (10MB/attachment, 10 max, 25MB total) (BREAKING) by @jiashuoz in #447
- refactor!: unify held-message vocabulary on "review" + remove deprecated message-approve endpoints (BREAKING) by @jiashuoz in #443
- docs(security): fix security contact email + enable private vuln reporting by @jiashuoz in #449
- fix!: declare + document the 402 (quota) / 429 (rate-limit) split on write ops (BREAKING) by @jiashuoz in #450
- fix(python-sdk): thread cursors through all list methods + manual page primitive (pagination parity) by @jiashuoz in #452
- feat(mcp): structured error content (code/request_id/retryable) alongside text by @jiashuoz in #453
- fix(spec): declare idempotency 409/422 + reconcile prose-vs-responses + drop phantom octet-stream + publish dedup window by @jiashuoz in #454
- fix(spec)!: open response schemas for additive evolution + x-stability markers + stability policy by @jiashuoz in #455
- fix(export)!: replace webhook_healthy bool with webhook_status enum (BREAKING) by @jiashuoz in #458
- refactor!: reconcile event data fields + version webhook envelope + rename pending_review (BREAKING) by @jiashuoz in #451
- feat(python-sdk)!: rename async client to AsyncE2AClient + ship sync E2AClient facade (BREAKING) by @jiashuoz in #457
- refactor!: typed per-event data payloads + golden fixtures + WS envelope (BREAKING) by @jiashuoz in #456
- fix(mcp): not-found code for resolved/missing pending message + connection-failure test by @jiashuoz in #459
- fix(api)!: uniform DELETE responses — 200 + typed deletion object on all 7 delete ops (BREAKING) by @jiashuoz in #461
- fix(api)!: reconcile + publish the error.code vocabulary (BREAKING where renamed) by @jiashuoz in #460
- fix(ws)!: distinct close codes — 4000 replaced vs 1008 rejection — + documented close-code contract (BREAKING) by @jiashuoz in #464
- feat(mcp): add agent-scoped API key tools by @jiashuoz in #465
- fix(sdk)!: uniform from_ property for the reserved-word 'from' field in both SDKs by @jiashuoz in #462
- fix(export): typed attachments (AttachmentMeta) + documented byte semantics for size_bytes by @jiashuoz in #463
- deps: bump the go-minor-patch group with 6 updates by @dependabot[bot] in #428
- deps(web): Bump the npm-minor-patch group across 1 directory with 3 updates by @dependabot[bot] in #438
- deps: Bump the npm-minor-patch group across 1 directory with 2 updates by @dependabot[bot] in #425
- deps(sdk): bump typescript from 5.9.3 to 7.0.2 in /sdks/typescript by @dependabot[bot] in #422
- deps: bump storybook from 8.6.18 to 10.5.0 by @dependabot[bot] in #426
- deps: bump vite from 6.4.3 to 8.1.4 by @dependabot[bot] in #427
- deps(cli): bump typescript from 5.9.3 to 7.0.2 in /cli by @dependabot[bot] in #423
- fix: reconcile terminal outbound send failures by @jiashuoz in #469
- fix(api): return 202 for async review approval by @jiashuoz in #470
- feat: add soft delete trash for inboxes and messages by @jiashuoz in #466
- fix(sdk+mcp): retry 409 idempotency_in_flight; document accepted status; unify MCP version by @jiashuoz in #471
- feat(outbound): bound outbound request fields for GA (per-field caps + composed-message ceiling) by @jiashuoz in #472
- feat(outbound): enforce composed-message cap on the HITL approve-override path by @jiashuoz in #473
- refactor(api): align DELETE message to 200 OK and make validation fields non-nullable by @jiashuoz in #474
- test(e2e-prod): MCP suites hit the deployed HTTP /mcp, not a local stdio binary by @jiashuoz in #475
- test(e2e-prod): remove dead prober tests by @jiashuoz in #476
- docs(readme): document inbound content screening (prompt-injection + phishing) by @Rodisolomon in #477
- fix(api): allow null raw message before review approval by @jiashuoz in #478
- test(sdk): type-check live request payloads by @jiashuoz in #479
- feat(sdk,mcp): expose trash restore lifecycle by @jiashuoz in #480
- fix(cli): treat async accepted sends as success by @jiashuoz in #481
- fix(sdk+mcp): expose sender filter as from_ by @jiashuoz in #482
- fix(mcp): align delete receipts and semantics with REST by @jiashuoz in #483
- fix(api): unify recipient cap errors by @jiashuoz in #484
- docs(api): publish composed message ceiling by @jiashuoz in #485
- fix(web): show domain deletion errors inline by @jiashuoz in #486
- Stabilize the canonical pre-GA API contract by @jiashuoz in #487
- Freeze event, webhook, and WebSocket contracts for GA by @jiashuoz in #488
- Require async at-least-once outbound delivery by @jiashuoz in #489
- Freeze the canonical error contract for GA by @jiashuoz in #490
- chore: follow the Mnexa-AI -> tokencanopy org rename by @jiashuoz in #491
- Add GA OpenAPI compatibility gate by @jiashuoz in #492
- fix: make self-send contract-equivalent by @jiashuoz in #494
- fix(mcp): normalize success output shapes by @jiashuoz in #499
- fix(api): reject null redelivery webhook id by @jiashuoz in #501
- fix: reject empty webhook URLs by @jiashuoz in #500
- fix(outbound): qualify SES message-id with region domain so replies thread by @mattfili in #498
- fix(api): make createApiKey idempotent via Idempotency-Key by @cyj-git-0825 in #495
- fix(cli): deliver listen --forward as an independent side channel under --json by @cyj-git-0825 in #497
- fix(sdk): webhook-verify (py) + WS listener (ts) no longer crash on crafted/transient input by @XueyanZhang in #467
- fix(sdk-ts): finish WSStream on normal close by @jiashuoz in #502
- fix(cli): isolate listen forward transport failures by @jiashuoz in #503
- fix(api): finish createApiKey idempotency surfaces by @jiashuoz in #504
- feat(identity): add per-agent HITL notification suppression by @Amerxu1002 in #416
- fix: complete notification suppression surfaces by @jiashuoz in #505
- docs(mcp): explain outbound review policy by @jiashuoz in #510
- fix(api): open evolving response vocabularies pre-freeze (keep normalized classifications closed) by @jiashuoz in #506
- fix(api): align permanent message-delete confirm with the declarative guard (422 invalid_request; retire confirmation_required) by @jiashuoz in #507
- feat(api): version the account-export interior by schema_version (stable envelope, beta interiors) by @jiashuoz in #508
- feat(api): promote the trash surface to stable for GA by @jiashuoz in #509
- feat(api): bound remaining GA request fields (names 200, reason 2000, conversation_id 200, addresses 320) by @jiashuoz in #511
- fix(delivery): emit email.failed when SES rejects after acceptance by @jiashuoz in #513
- docs: require per-session test databases for concurrent DB-backed runs by @jiashuoz in #514
- fix(outbound): enforce suppression on every HITL approval path and before provider I/O by @jiashuoz in #515
- feat(api): Idempotency-Key support on createWebhook by @jiashuoz in #516
- docs(api): document the two DNS state axes (persisted vs live probe) and pin their vocabularies by @jiashuoz in #517
- fix(agent): route testAgent through the durable outbound pipeline (platform-originated, msg_ id contract) by @jiashuoz in #518
- refactor(api): rename implementation-leaked public schemas for GA (EventView, SuppressionView, AuthVerdict, AttachmentMetaView) by @jiashuoz in #512
- fix(outbound): provider-evidence correction for false terminal failures (async-send contract §3.1) by @jiashuoz in #519
- docs(protection): gate-vs-scan accuracy — scoped hold claims, direction-aware domain policy by @jiashuoz in #520
- fix: low-risk hardening across API, SDKs, and MCP (tests + fixes) by @XueyanZhang in #468
- refactor(env): rename E2A_BASE_URL to E2A_API_URL; split it from the CLI's E2A_URL by @jiashuoz in #522
- Fix/rest low severity nits 92 by @James-Z-Zhang00 in #199
- docs: refresh CLAUDE.md, CONTRIBUTING.md, README.md to current codebase by @jiashuoz in #525
- feat: render inline (cid:) email images + attachment download chips in the dashboard by @jiashuoz in #524
- fix(deps): bump grpc + OpenTelemetry to patch 4 CVEs (1 critical) by @jiashuoz in #526
- fix(testutil): truncate FK-less tables between tests by @jiashuoz in #523
- chore(dependabot): track Python SDK via uv ecosystem (not pip) by @jiashuoz in #529
- fix(deps): refresh Python SDK uv.lock to patch CVEs by @jiashuoz in #527
- fix(deps): npm audit fix web deps (ws, js-yaml, @babel) by @jiashuoz in #528
- docs(security): route vulnerability reports to security@tokencanopy.com by @jiashuoz in #535
- test(e2e): reconcile conformance suite with the current API contract (13 stale expectations) by @jiashuoz in #537
- test(e2e): remove duplicated HttpMcpClient in the mcp harness by @jiashuoz in #538
- Harden the API for GA launch by @jiashuoz in #539
- test(e2e): read review_rejected event reason from data.reason (#451 rename) by @jiashuoz in #540
- deps(web): bump the npm-minor-patch group in /web with 2 updates by @dependabot[bot] in #530
- ci: bump actions/setup-go from 6 to 7 by @dependabot[bot] in #531
- ci: bump actions/setup-node from 4 to 7 by @dependabot[bot] in #532
- api: freeze stable generated SDK surface by @HongyuanJia8 in #541
- fix(outbound): guard reply/forward against a not-yet-submitted parent by @jiashuoz in #521
- docs: clarify v1 GA timing by @jiashuoz in #544
- feat(auth): add generic OIDC login for existing users by @jiashuoz in #536
- fix(api): retain standalone OpenAPI schemas by @jiashuoz in #543
- feat(agents): allow agent inboxes on subdomains of a verified parent domain by @jiashuoz in #542
- deps: bump the go-minor-patch group across 1 directory with 3 updates by @dependabot[bot] in #534
- test(e2e): pass email to the MCP list_messages call (account-scoped cred) by @jiashuoz in #546
- fix(mcp): emit snake_case tool output for SDK class instances by @jiashuoz in #550
- fix(domains): reject IP literals in domain registration by @jiashuoz in #559
- Add durable per-domain sending ramp by @jiashuoz in #545
- Fix outbound sends after registered-domain rename by @jiashuoz in #563
- test(e2e): accept 202 async send + widen attachment fixture poll window by @jiashuoz in #547
- test(e2e): implement the email.blocked emission test (outbound gate block) by @jiashuoz in #548
- docs: fix stale root-doc claims (openapi serving, exit codes, Node, idempotency) by @jiashuoz in #551
- docs(cli): bring README and CHANGELOG up to date with 1.6.0 by @jiashuoz in #553
- docs(sdk): dedupe split 4.1.0 changelog entry (TS + Python) by @jiashuoz in #554
- docs(sdk-ts): fix stale wiring status in generated/README.md by @jiashuoz in #555
- docs(web): reflect shipped agent-identity surface and hosted MCP server in auth.md by @jiashuoz in #556
- docs(web): fix templates.md syntax/field names and sdk.md pagination examples by @jiashuoz in #557
- docs(mcp): fix stale tool-count references and send_message status wording by @jiashuoz in #558
- docs: fix example SDK version pin and wrong API field name by @jiashuoz in #560
- docs(design): fix dead links in stripe-tier-webhooks historical proposal by @jiashuoz in #561
- test(e2e): harden the conformance-suite documented skips (Tier 3) by @jiashuoz in #562
- fix(python-sdk): surface client-side validation as E2AValidationError by @jiashuoz in #552
- deps: bump typescript from 5.9.3 to 7.0.2 by @dependabot[bot] in #549
- fix(ci): run all integration-tagged tests by @jiashuoz in #564
- feat(reviews): surface hold reason on the review queue by @jiashuoz in #389
- feat(reviews): surface detector rationale + threat categories on hold detail by @jiashuoz in #390
- docs: add AGENTS.md agent guidance by @jiashuoz in #566
- fix(contract): persist inbound event envelope by @jiashuoz in #567
- fix(identity): keep template timestamps monotonic by @jiashuoz in #568
- fix(testutil): use production migration runner by @jiashuoz in #569
- fix(events): stop dropping email.blocked for outbound gate-blocks (message_id FK) by @jiashuoz in #570
- fix(examples): update agent framework integrations by @jiashuoz in #572
- fix(web): simplify agent setup prompts by @jiashuoz in #575
- fix(web): include agent docs in image build by @jiashuoz in #583
- feat: add beta per-agent managed unsubscribe by @jiashuoz in #571
- test(conformance): cover the trash/restore lifecycle (deleteMessage, restoreMessage, restoreAgent) by @jiashuoz in #574
- feat(auth): lazy OIDC issuer discovery with background retry by @jiashuoz in #573
- feat(feedback): fan out submissions to notify email + GitHub App auth by @jiashuoz in #585
- docs: fix stale MCP self-hosting/npm-publish claim in README by @jiashuoz in #576
- docs: document CLI agents/keys/protection commands by @jiashuoz in #577
- docs: fix Python version requirement in CONTRIBUTING.md by @jiashuoz in #578
- docs: fix OAuth session TTL in data-handling.md by @jiashuoz in #579
- docs: document generic OIDC login support in deployment.md by @jiashuoz in #580
- docs: fill in SDK README pagination/upgrade gaps by @jiashuoz in #581
- docs: fix mcp examples README inaccuracies by @jiashuoz in #582
- test(unsubscribe): cover suppression integration seams by @jiashuoz in #584
- fix(api): mark review protection evidence beta by @jiashuoz in #565
- feat(api): raise the per-user poll rate limit from 60/min to 240/min by @jiashuoz in #586
- fix(outbound): map deadline-driven i/o timeout to context.DeadlineExceeded by @jiashuoz in #587
- ci(release): always publish a GitHub Release when a v* tag is pushed by @jiashuoz in #589
- feat(web): add live inbox polling and delivery status by @jiashuoz in #590
- test(e2e-prod): cover agent suppression endpoints (coverage gate) by @jiashuoz in #591
- fix(cli): account-scoped login only, and close silent-failure gaps by @jiashuoz in #592
- Token Canopy branding + agent-native marketing page, plus a review-page crash fix by @jiashuoz in #594
- feat(web): add client-specific agent onboarding by @jiashuoz in #609
- feat(api): publish canonical inbound authentication by @jiashuoz in #607
- feat(sdk): add inbound email facade by @jiashuoz in #593
- docs: fix docker-up description and self-host port list by @jiashuoz in #595
- docs(readme): fix stale e2a login description by @jiashuoz in #596
- docs(sdk): add reviews, templates, and account.apiKeys to Resources by @jiashuoz in #598
- docs(mcp-examples): scope E2A_MCP_URL and shared-invariants claims to non-ADK examples by @jiashuoz in #599
- docs(mcp): document approve_review/reject_review's inbound-release behavior by @jiashuoz in #600
- docs(design-system): fix nonexistent .prompt.md ref and contradictory node_modules path by @jiashuoz in #601
- docs(examples): fix path param name in adk-cloud-webhook README by @jiashuoz in #602
- docs(marketplace): update stale MCP tool count (37 -> 50) by @jiashuoz in #603
- docs(agentify): fix scaffolding table to list all copied scripts by @jiashuoz in #604
- docs(templates): fix stale flat-variables-only claim by @jiashuoz in #605
- docs(events): fix wrong webhook_subscriber_deliveries retention (90 -> 30 days) by @jiashuoz in #606
- docs(cli): document listen's exit-1 behaviors by @jiashuoz in #597
- feat(identity): retain message data indefinitely by @jiashuoz in #610
- docs(plugin): bootstrap e2a MCP setup by @jiashuoz in #611
- fix(e2e-prod): update 18-reviews.test.ts for the header_from/envelope_from rename by @jiashuoz in #612
- feat(prober): assert on authentication evidence in the inbound round-trip by @jiashuoz in #613
- test(e2e-prod): guard loopback null authentication/envelope_from/verified_domain by @jiashuoz in #614
- docs(auth): distinguish DMARC none from fail in verified_domain docs by @jiashuoz in #615
New Contributors
- @Rodisolomon made their first contribution in #477
- @mattfili made their first contribution in #498
- @cyj-git-0825 made their first contribution in #495
- @XueyanZhang made their first contribution in #467
- @Amerxu1002 made their first contribution in #416
Full Changelog: v1.0.10...v1.1.0