Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions .github/workflows/api-changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: API Changelog Automation

on:
pull_request:
paths:
- 'fern/definition/**/*.yml'
workflow_dispatch:

jobs:
generate-diff:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install Fern CLI
run: npm install -g fern-api

- name: Generate current OpenAPI spec
run: |
cd fern && fern export ../current-openapi.json
continue-on-error: true

- name: Generate base OpenAPI spec
run: |
git checkout ${{ github.event.pull_request.base.sha }}
cd fern && fern export ../base-openapi.json || echo '{}' > ../base-openapi.json
git checkout ${{ github.event.pull_request.head.sha }}
continue-on-error: true

- name: Run oasdiff changelog
id: oasdiff
uses: oasdiff/oasdiff-action/changelog@main
with:
base: base-openapi.json
revision: current-openapi.json
format: markdown
fail-on-diff: false
continue-on-error: true

- name: Check if changes detected
id: check_changes
env:
CHANGELOG: ${{ steps.oasdiff.outputs.changelog }}
BREAKING: ${{ steps.oasdiff.outputs.breaking }}
run: |
if [ -n "$CHANGELOG" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "breaking_count=${BREAKING:-0}" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "breaking_count=0" >> $GITHUB_OUTPUT
fi

- name: Write changelog diff for local preview
if: steps.check_changes.outputs.has_changes == 'true'
env:
CHANGELOG_DIFF: ${{ steps.oasdiff.outputs.changelog }}
run: |
node -e "require('fs').writeFileSync('changelog-diff.md', process.env.CHANGELOG_DIFF || '')"

- name: Upload changelog diff for local preview
if: steps.check_changes.outputs.has_changes == 'true'
uses: actions/upload-artifact@v4
with:
name: api-changelog-diff
path: changelog-diff.md
retention-days: 7

- name: Comment on PR with diff
if: steps.check_changes.outputs.has_changes == 'true'
env:
CHANGELOG_DIFF: ${{ steps.oasdiff.outputs.changelog }}
BREAKING_COUNT: ${{ steps.check_changes.outputs.breaking_count || 0 }}
uses: actions/github-script@v7
with:
script: |
const diff = process.env.CHANGELOG_DIFF || '';
const breaking = (Number(process.env.BREAKING_COUNT) || 0) > 0;
const safeDiff = diff.replace(/\`\`\`/g, '\\`\\`\\`');
const body = `## ${breaking ? '🚨 Breaking' : '✨'} API Changes\n\n\`\`\`markdown\n${safeDiff}\n\`\`\`\n\n💡 Download \`api-changelog-diff\` artifact or tag @Fern Writer in #github-prs for changelog.`;
await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body });
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.env
**/.preview/
**/generated/
.DS_Store
*-openapi.json
49 changes: 49 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# AgentMail Changelog Guidelines

Instructions for creating changelog entries (e.g. when asked in #github-prs with a PR link or writing manually). One source of truth for process and style.

## When you're invoked

- **API changes:** A PR that touches `fern/definition/**` triggers a GitHub Action. It posts an oasdiff (technical diff) on the PR and uploads it as the `api-changelog-diff` artifact. Someone may tag you with that PR or paste the diff.
- **Manual:** For non-API changes, create `fern/changelog/YYYY-MM-DD.mdx` and follow the structure below. Use `fern/changelog/TEMPLATE.mdx` as reference.
- **Output:** Create or edit files in `fern/changelog/`. File name: `YYYY-MM-DD.mdx` (same day = add suffix e.g. `2026-01-30-metrics.mdx`).

## Required structure

1. **Summary** (2–3 sentences): What changed and **user benefit**. Not "New GET /foo" — e.g. "Monitor X in real-time so agents can…"
2. **What's new?** Bullets: new endpoints, features, or capabilities (with paths/params).
3. **Breaking changes** (if any): ⚠️ header, clear explanation, before/after code, timeline if deprecated.
4. **Use cases** (2–4): "Build agents that…" — what users can do with this.
5. **SDK Updates:** Links to Python and Node SDK releases (include when documenting an SDK release).
6. **Code block:** When it helps (bar is low), include **both Python and TypeScript** in a single toggle. Use `<CodeBlocks>` (plural) with two fenced blocks: ` ```python title="Python" ` and ` ```typescript title="TypeScript" `. When included: runnable (imports + client), &lt; 15 lines per language. Use realistic IDs. **Code comments: use lowercase** (e.g. `# create a draft` not `# Create a draft`).
7. **Note:** One call-to-action link to API reference or a guide.

## Voice and terms

- User-focused, action-oriented, specific. Use "agents" (not "bots"), "inboxes" (not "mailboxes"), "deliverability", "bounce rate."
- Tags: 2–4 total. API area: `inboxes-api`, `messages-api`, `drafts-api`, `domains-api`, `webhooks`, `websockets`, `pods-api`, `metrics-api`, etc. Change type: `new-feature`, `breaking-change`, `enhancement`, `bug-fix`. Deliverable: `sdk`, `docs`.

## Format (for predictable output)

- **Frontmatter:** Exactly `---` then `tags: ["tag1", "tag2", ...]` then `---`. Tags are a YAML array of strings.
- **Section headers:** Use `## Summary`, `### What's new?`, `### Use cases`. Add `### Breaking changes` only when needed.
- **Components:** Use `<CodeBlocks>` (plural) with two fenced blocks: ` ```python title="Python" ` … ` ``` ` and ` ```typescript title="TypeScript" ` … ` ``` ` so readers get a Python | TypeScript tab toggle. Use `<Note>` with a single paragraph and optional link inside. No other custom components.
- **Links:** Use `https://docs.agentmail.to/...` (e.g. `/api-reference/metrics`, `/core-concepts/pods`, `/webhooks/webhooks-overview`). No relative links.
- **Date:** Use today's date for new entries (`YYYY-MM-DD.mdx`) unless the user specifies a date.
- **Don't:** Invent endpoints or params — only document what's in the diff/API. Avoid raw `<` in prose (e.g. write "under 100ms" not "<100ms") so MDX doesn't break.

## Minimal example (mirror this structure)

- Frontmatter: `---` then `tags: ["webhooks", "new-feature", "sdk"]` then `---`
- Sections in order: `## Summary` → `### What's new?` → `### Use cases` → `<CodeBlocks>` with ` ```python title="Python" ` and ` ```typescript title="TypeScript" ` (same example in both; runnable, imports + client) → `<Note>` with one sentence and link to `https://docs.agentmail.to/...`
- Add `### Breaking changes` only when applicable (⚠️ + before/after code). Add SDK Updates section when documenting an SDK release.

## Checklist before finalizing

- Summary states user benefit. Code is runnable. Links valid. Breaking changes have before/after. Tags accurate. Technical accuracy matches API definition.

## Triggering Fern Writer (API changelog)

The workflow does **not** post to Slack. It comments on the PR with the diff and uploads the `api-changelog-diff` artifact. To get a changelog draft:

- In **#github-prs** (or wherever @Fern Writer is), post or reply with the PR link and **@Fern Writer produce a changelog for this** (or "for PR <url> per AGENTS.md"). Fern Writer uses the PR link as context and can read the diff from the PR comment or artifact.
84 changes: 84 additions & 0 deletions fern/changelog/2025-06-15.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
tags: ["pods-api", "new-feature", "sdk", "collaboration"]
---

## Summary

Introducing **Pods** - team collaboration spaces for AgentMail. Share inboxes, domains, and resources across your organization while maintaining granular control. Perfect for teams building multi-agent email systems that need organized resource management.

### What's new?

**New endpoints:**
- `POST /pods` - Create a new pod (team workspace)
- `GET /pods` - List all pods in your organization
- `GET /pods/{pod_id}` - Get pod details
- `DELETE /pods/{pod_id}` - Delete a pod
- `POST /pods/{pod_id}/inboxes` - Create inbox within a pod
- `POST /pods/{pod_id}/domains` - Add custom domain to a pod
- `GET /pods/{pod_id}/threads` - List threads within a pod
- `GET /pods/{pod_id}/metrics` - Get metrics for a pod

**Pod features:**
- Shared inbox access across team members
- Per-pod domain configuration
- Isolated metrics and analytics per pod
- Organized resource hierarchy

### Use cases

Build systems where:
- Multiple agents share email infrastructure
- Different teams manage their own inboxes independently
- Resources are organized by department or project
- Analytics are tracked per team workspace
- Billing and usage can be attributed to specific teams

<CodeBlocks>
```python title="Python"
from agentmail import AgentMail

client = AgentMail(api_key="your-api-key")

# create a pod for your sales team
pod = client.pods.create(
name="Sales Team",
description="Shared resources for sales agents"
)

# create an inbox in the pod
inbox = client.pods.inboxes.create(
pod_id=pod.pod_id,
inbox_id="sales@example.com"
)

# list all pods
pods = client.pods.list()
for pod in pods.pods:
print(f"Pod: {pod.name} ({len(pod.inbox_ids)} inboxes)")
```

```typescript title="TypeScript"
import { AgentMail } from "agentmail";

const client = new AgentMail({ apiKey: "your-api-key" });

// create a pod for your sales team
const pod = await client.pods.create({
name: "Sales Team",
description: "Shared resources for sales agents",
});

// create an inbox in the pod
await client.pods.inboxes.create(pod.podId, "sales@example.com");

// list all pods
const { pods } = await client.pods.list();
for (const p of pods) {
console.log(`Pod: ${p.name} (${p.inboxIds?.length ?? 0} inboxes)`);
}
```
</CodeBlocks>

<Note>
Learn more about organizing teams with [Pods](https://docs.agentmail.to/core-concepts/pods) in our documentation.
</Note>
76 changes: 76 additions & 0 deletions fern/changelog/2025-07-20.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
tags: ["websockets", "new-feature", "sdk"]
---

## Summary

Introducing **WebSocket Streaming** - receive email events in real-time as they happen. Build reactive agents that respond instantly to new messages, deliveries, and bounces without polling. Perfect for building interactive, event-driven email experiences.

### What's new?

**WebSocket endpoint:**
- `wss://ws.agentmail.to/v0` - Real-time event streaming

**Events streamed:**
- `message.received` - New inbound email detected
- `message.sent` - Outbound email sent successfully
- `message.delivered` - Delivery confirmed by recipient server
- `message.bounced` - Bounce detected (permanent or temporary)
- `message.complained` - Spam complaint received

**Connection features:**
- JWT-based authentication for secure connections
- Automatic reconnection with exponential backoff
- Event filtering by inbox for targeted subscriptions
- Low-latency delivery (typically under 100ms)
- Support for thousands of concurrent connections

### Use cases

Build agents that:
- Respond to emails within seconds of receipt
- Monitor deliverability in real-time across all inboxes
- Trigger workflows instantly on specific events
- Build interactive conversational email experiences
- Scale to handle high-volume email operations
- React to bounces and complaints immediately

<CodeBlocks>
```python title="Python"
from agentmail import AgentMail

client = AgentMail(api_key="your-api-key")

# subscribe to events for an inbox
async with client.websockets.subscribe(
inbox_id="support@example.com"
) as ws:
async for event in ws:
if event.type == "message.received":
print(f"New email from: {event.data.from_}")
response = await generate_response(event.data.text)
await client.messages.reply(
message_id=event.data.message_id,
text=response
)
```

```typescript title="TypeScript"
import { AgentMail } from "agentmail";

const client = new AgentMail({ apiKey: "your-api-key" });

// subscribe to events for an inbox
for await (const event of client.websockets.subscribe("support@example.com")) {
if (event.type === "message.received") {
console.log("New email from:", event.data.from);
const response = await generateResponse(event.data.text);
await client.messages.reply(event.data.messageId, response);
}
}
```
</CodeBlocks>

<Note>
Get started with [WebSocket Streaming](https://docs.agentmail.to/websockets) to build real-time email agents.
</Note>
27 changes: 20 additions & 7 deletions fern/changelog/2025-08-13.mdx
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
---
tags: ["metrics-api", "new-feature", "sdk"]
---

## Summary

We're excited to introduce **Metrics Endpoints** - two new powerful endpoints that give you deep insights into your email deliverability and agent performance. Track critical events like bounces, deliveries, rejections, and complaints with detailed timestamps.
We're excited to introduce **Metrics Endpoints** - two new powerful endpoints that give you deep insights into your email deliverability and agent performance. Track critical events like bounces, deliveries, rejections, and complaints with detailed timestamps to build smarter, self-optimizing email agents.

### What's new?

New endpoints:

**New endpoints:**
- `GET /metrics` - Get comprehensive metrics across all your inboxes
- `GET /inboxes/{inbox_id}/metrics` - Get metrics for a specific inbox

Build smarter agents that monitor their own bounce rates, optimize send timing, and automatically adjust behavior based on deliverability metrics. This unlocks exciting possibilities for self-optimizing agents that can pause campaigns when performance drops or implement intelligent retry strategies.
**Metrics tracked:**
- Delivery events: sent, delivered, bounced, rejected
- Error tracking: complaints, spam reports
- Time-series data with detailed timestamps

### Use cases

Build agents that:
- Monitor their own bounce rates in real-time
- Optimize send timing based on historical performance
- Automatically adjust behavior based on deliverability metrics
- Pause campaigns when performance drops below thresholds
- Implement intelligent retry strategies for better inbox placement

<Note>
Ready to build smarter agents? Check out our [metrics
documentation](https://docs.agentmail.to/api-reference/metrics) to get
started.
Ready to build smarter agents? Check out our [Metrics API documentation](https://docs.agentmail.to/api-reference/metrics) to get started.
</Note>
Loading
Loading