One API Call: Send, Check, Deliver, Track
2026-04-17
The interface that an agent uses to send email through Molted is a single HTTP call:
POST /v1/agent/request-send
Authorization: Bearer mm_live_...
Content-Type: application/json
{
"tenantId": "your-tenant-id",
"mailboxId": "mbx_abc123",
"recipientEmail": "alice@example.com",
"templateId": "onboarding-welcome",
"dedupeKey": "onboarding-alice-step1",
"payload": { "firstName": "Alice", "trialDays": 14 },
"sendReason": "onboarding sequence step 1"
}
That's it from the agent's side. One call. No separate policy check, no template rendering step, no delivery configuration. The response tells the agent whether the send was allowed, and if so, whether it was queued or delivered.
What happens between the request arriving and the response going back is the point of this post.
What the agent gets back
A successful response looks like this:
{
"requestId": "req_abc123",
"status": "queued",
"policyTrace": {
"decision": { "allow": true },
"auditEvents": [
{ "rule": "deduplication", "passed": true },
{ "rule": "suppression", "passed": true },
{ "rule": "cooldown", "passed": true },
{ "rule": "rate_limit_hourly", "passed": true },
{ "rule": "rate_limit_daily", "passed": true },
{ "rule": "consent", "passed": true }
]
}
}
If the send is blocked by policy, the response is still HTTP 200 - not a 4xx error. The status field changes to blocked and the trace explains which rule failed:
{
"requestId": "req_abc124",
"status": "blocked",
"reason": "cooldown",
"policyTrace": {
"decision": { "allow": false, "reason": "cooldown" },
"cooldownExpiresAt": "2026-04-17T14:32:00Z",
"auditEvents": [
{ "rule": "deduplication", "passed": true },
{ "rule": "suppression", "passed": true },
{ "rule": "cooldown", "passed": false, "detail": "contact in cooldown window" }
]
}
}
Policy blocks are not errors. They're information. The agent knows exactly why the send didn't go out and when it can try again. No exception handling required - just branch on status.
If the send requires human approval (based on the mailbox's autonomy level), the status comes back as pending_approval:
{
"requestId": "req_abc125",
"status": "pending_approval",
"approvalQueueId": "apq_xyz789"
}
The send sits in the approval queue until a human approves or rejects it. The agent can poll the request ID to check current status, or listen for the approval event.
The pipeline inside that one call
When the request arrives, it passes through several stages before a response is returned.
1. Authentication and scope validation
The Bearer token is validated against the API. If the token is scoped to a specific mailbox, the requested mailboxId is checked against the allowed scope. A key scoped to mailbox A cannot send from mailbox B - the request is rejected before any further processing.
2. Deduplication check
The dedupeKey is checked against recent sends. If the same key has been used in the deduplication window, the send is marked as a duplicate and returns status: "duplicate" without touching any other policy rules. This is the first check because it's the cheapest - a cache lookup that prevents redundant work downstream.
Deduplication is why you can safely retry on network errors. If your agent's POST to /request-send times out and you retry, the deduplication check ensures the second attempt doesn't send a second email even if the first actually succeeded before the timeout.
3. Policy evaluation
After deduplication, the request runs through the policy engine. The rules evaluated depend on your mailbox configuration, but a standard evaluation includes:
- Suppression check - is this recipient on a suppression list? Global suppressions (bounces, complaints), tenant-level suppressions (manual do-not-contact), and campaign-level suppressions are all checked.
- Consent validation - does a consent record exist for this recipient? If your mailbox requires explicit consent and none is recorded, the send is blocked.
- Cooldown - has this recipient received an email from this mailbox within the configured cooldown window? The cooldown is per-contact, not per-template, so overlapping sequences from different agent workflows don't pile up.
- Rate limits - hourly, daily, and monthly limits are checked at the mailbox level. Molted enforces triple-window rate limiting: a spike that stays under the daily limit can still hit the hourly ceiling.
- Risk budget - if the mailbox has accumulated too many bounces or complaints relative to its risk budget, new sends are blocked until the budget resets.
Each rule that runs generates an audit event in the decision trace. If the send is blocked, the trace shows which rule failed first. If it's allowed, the trace shows that all rules passed.
4. Autonomy check
Before dispatching, the mailbox's autonomy level is evaluated. A mailbox configured for human-in-the-loop (HITL) review routes the send to the approval queue instead of delivering immediately. The agent gets status: "pending_approval" and the send waits.
A mailbox configured for full autonomy skips the approval step and proceeds directly to delivery. The autonomy level is set per mailbox, not per send, so the agent doesn't need to reason about whether this particular send needs approval.
5. Template rendering
If the send is allowed and not pending approval, the template is fetched and rendered. The payload from the request is substituted into the template variables. If the mailbox has the humanizer enabled, the rendered content passes through AI-assisted rewriting that adjusts tone and phrasing to sound less templated - useful when agents are sending at scale and you want each email to feel individual.
The rendered output is validated: if the template references a variable that isn't in the payload, the render fails and the request returns an error before anything is sent.
6. Delivery
The rendered email is handed to the delivery layer. The failover router selects a delivery provider based on weight and current health - if the primary provider is having issues, the router tries the next one transparently. The agent doesn't see which provider handled the delivery.
Once the provider accepts the message, the send status updates to delivered or queued depending on whether the provider confirmed immediate acceptance or queued it for delivery.
7. Decision trace storage
The full audit trail - policy evaluation results, provider routing, delivery status - is stored as an immutable decision trace linked to the requestId. This trace is accessible via the portal or the API. If a question arises later ("did this email go out? why was it blocked?"), the trace answers it without requiring you to piece together logs from multiple systems.
What you don't have to build
The pipeline above replaces a significant amount of infrastructure that teams typically build themselves:
- A deduplication store (usually Redis) with per-key TTL management
- A rate limiting layer with per-contact, per-mailbox, and per-window counters
- A suppression list that's checked before every send
- A consent management system for GDPR/CCPA compliance
- A template engine that renders payloads safely (no XSS, no injection)
- A delivery abstraction that handles provider failover
- An audit logging system that ties policy decisions to individual sends
Each of those is infrastructure that has to be designed, implemented, tested, and maintained. None of them are the product you're building. They're the plumbing that has to work before the product can.
The point of routing agent sends through a single API call is that this plumbing lives at the infrastructure layer - enforced regardless of what the agent does or how it's configured - rather than in your application code where it has to be maintained alongside every other business logic change.
Simulating before sending
If you want to preview the policy decision without actually sending, there's a dry-run endpoint:
POST /v1/agent/simulate-send
Authorization: Bearer mm_live_...
{
"tenantId": "your-tenant-id",
"mailboxId": "mbx_abc123",
"recipientEmail": "alice@example.com",
"templateId": "onboarding-welcome",
"dedupeKey": "onboarding-alice-step1"
}
The response is identical in structure to a real send response, but "simulation": true is set and nothing is actually delivered. Useful for testing policy behavior in staging, or for agents that want to check before committing to a high-stakes send.
If you're building an agent that sends email and want the full pipeline - policy, deduplication, delivery, tracing - handled at the infrastructure layer, get started with Molted or read the full API docs.
For a step-by-step walkthrough of sending your first email through the API, Send Your First Policy-Checked Email covers the setup from domain verification to a working send.