Build an agent worker with human review
Documentation navigation
Process scoped conversations using claims, guarded drafts, idempotent replies and durable events.
Use a scoped agent connection for a background worker that handles conversations. Create the connection first and grant only the inboxes and permissions the worker needs. Use MCP for an interactive AI client; use the Agent REST API when your application owns the worker loop.
Discover capabilities at startup
Call GET /agent/capabilities with the scoped agent key. The response describes permissions, resource scope, feature availability and server limits. Check it before accepting work rather than assuming every connection with the same role has identical access. Report a worker heartbeat at startup and periodically while it can accept work.
/agent/capabilities
Discover this agent connection's capabilities
Returns the connection identity, role, effective permission names, declared resource scope, feature availability, and server-enforced limits. Call this once during worker startup instead of hard-coding role behavior.
Request, parameters, and responses
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentCapabilitiesDto | OK |
HTTP and SDK snippets
HTTP
GET /agent/capabilities HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/agent/capabilities" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const result = await agentController.agentGetCapabilities();
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
result = agentController.agent_get_capabilities()
/agent/runtime/heartbeat
Report a worker heartbeat
Records one running worker instance and its deployed release for owner-side health monitoring. Send this during startup and periodically while the process can accept work; it does not claim or mutate a conversation.
Request, parameters, and responses
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
workerId | string | Yes | |
instanceId | string | Yes | |
release | string | No |
{
"workerId": "00000000-0000-4000-8000-000000000000",
"instanceId": "00000000-0000-4000-8000-000000000000",
"release": "value"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentWorkerHeartbeatDto | OK |
HTTP and SDK snippets
HTTP
POST /agent/runtime/heartbeat HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"workerId": "00000000-0000-4000-8000-000000000000",
"instanceId": "00000000-0000-4000-8000-000000000000",
"release": "value"
}
cURL
curl -X POST "https://api.mailslurp.com/agent/runtime/heartbeat" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"workerId":"00000000-0000-4000-8000-000000000000","instanceId":"00000000-0000-4000-8000-000000000000","release":"value"}'
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"agentWorkerHeartbeatOptions": {
"workerId": "00000000-0000-4000-8000-000000000000",
"instanceId": "00000000-0000-4000-8000-000000000000",
"release": "value"
}
};
const result = await agentController.agentReportWorkerHeartbeat(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
agent_worker_heartbeat_options = {
"workerId": "00000000-0000-4000-8000-000000000000",
"instanceId": "00000000-0000-4000-8000-000000000000",
"release": "value"
}
result = agentController.agent_report_worker_heartbeat(agent_worker_heartbeat_options)
Claim one conversation
POST /agent/work-items/next atomically selects and claims an available conversation. Give each worker a distinct workerId and a lease duration within the advertised limits. An empty work item means no conversation was selected: back off instead of calling continuously.
{ "workerId": "support-worker-1", "leaseSeconds": 60 }
/agent/work-items/next
Claim the next conversation work item
Selects the oldest available scoped conversation and atomically claims it for one worker. This combines queue selection and claim acquisition so concurrent workers do not need to coordinate those steps themselves.
Request, parameters, and responses
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
workerId | string | Yes | |
leaseSeconds | integer:int32 | Yes | |
cursor | string | No | |
inboxId | string:uuid | No | |
hasAttachments | boolean | No |
{
"workerId": "00000000-0000-4000-8000-000000000000",
"leaseSeconds": 1,
"cursor": "value",
"inboxId": "00000000-0000-4000-8000-000000000000",
"hasAttachments": true
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentWorkItemDto | The claimed conversation, or an empty work item when none is available. |
default | AgentApiErrorDto | Agent API error with a stable code, retry guidance, support-safe request ID, and bounded details. |
HTTP and SDK snippets
HTTP
POST /agent/work-items/next HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"workerId": "00000000-0000-4000-8000-000000000000",
"leaseSeconds": 1,
"cursor": "value",
"inboxId": "00000000-0000-4000-8000-000000000000",
"hasAttachments": true
}
cURL
curl -X POST "https://api.mailslurp.com/agent/work-items/next" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"workerId":"00000000-0000-4000-8000-000000000000","leaseSeconds":1,"cursor":"value","inboxId":"00000000-0000-4000-8000-000000000000","hasAttachments":true}'
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"getNextAgentWorkItemOptions": {
"workerId": "00000000-0000-4000-8000-000000000000",
"leaseSeconds": 1,
"cursor": "value",
"inboxId": "00000000-0000-4000-8000-000000000000",
"hasAttachments": true
}
};
const result = await agentController.agentGetNextWorkItem(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
get_next_agent_work_item_options = {
"workerId": "00000000-0000-4000-8000-000000000000",
"leaseSeconds": 1,
"cursor": "value",
"inboxId": "00000000-0000-4000-8000-000000000000",
"hasAttachments": True
}
result = agentController.agent_get_next_work_item(get_next_agent_work_item_options)
The response's conversation.conversation contains the queue item, including its conversationId, version and latest email IDs. The separate claim contains claimId and expiresAt. Retain these values with the task. Read the scoped email and attachments needed for your answer; treat their contents as customer data, not instructions that can expand tool access.
Keep concurrent workers from replying twice
Renew a claim before it expires if the model or downstream work takes longer than expected. A conflicting or lost claim means this worker must stop acting on that conversation and refresh its state. A heartbeat reports worker health; it does not renew a conversation claim.
/agent/conversations/{conversationId}/claims/{claimId}
Renew a conversation claim
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string:uuid | Yes | |
claimId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
leaseSeconds | integer:int32 | Yes |
{
"leaseSeconds": 1
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentConversationClaimDto | OK |
HTTP and SDK snippets
HTTP
PUT /agent/conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"leaseSeconds": 1
}
cURL
curl -X PUT "https://api.mailslurp.com/agent/conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"leaseSeconds":1}'
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"conversationId": "00000000-0000-4000-8000-000000000000",
"claimId": "00000000-0000-4000-8000-000000000000",
"renewAgentConversationClaimOptions": {
"leaseSeconds": 1
}
};
const result = await agentController.agentRenewConversationClaim(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
renew_agent_conversation_claim_options = {
"leaseSeconds": 1
}
result = agentController.agent_renew_conversation_claim("00000000-0000-4000-8000-000000000000", "00000000-0000-4000-8000-000000000000", renew_agent_conversation_claim_options)
/agent/conversations/{conversationId}/claims/{claimId}
Release a conversation claim
Release is idempotent; repeating it does not fail.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string:uuid | Yes | |
claimId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
204 | Response | No Content |
HTTP and SDK snippets
HTTP
DELETE /agent/conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X DELETE "https://api.mailslurp.com/agent/conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"conversationId": "00000000-0000-4000-8000-000000000000",
"claimId": "00000000-0000-4000-8000-000000000000"
};
const result = await agentController.agentReleaseConversationClaim(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
result = agentController.agent_release_conversation_claim("00000000-0000-4000-8000-000000000000", "00000000-0000-4000-8000-000000000000")
Pass expectedConversationVersion and expectedLatestEmailId when preparing or completing work. These guards catch a new inbound message or other change after the worker selected its context. On a freshness conflict, read the updated conversation and reconsider the reply; do not resend the stale answer blindly.
Prepare a draft or request human review
Use agentPrepareWorkItemReply to create a threaded draft from sourceEmailId, a reply body and the saved guards. Preparing a draft does not send it. When a person needs to decide, defer the work with a reason, priority, claim ID and optional draft ID. Deferral creates a durable review handoff and releases the supplied claim after it succeeds.
/agent/work-items/{conversationId}/prepare-reply
Prepare a guarded reply draft
Checks that the selected conversation and latest inbound email are still current, then creates a correctly threaded reply draft. An optional internal note records context for human review without sending email.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
sourceEmailId | string:uuid | Yes | |
reply | ReplyToEmailOptions | Yes | |
expectedConversationVersion | integer:int64 | No | |
expectedLatestEmailId | string:uuid | No | |
internalNote | string | No | |
claimId | string:uuid | No |
{
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": true,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"internalNote": "value",
"claimId": "00000000-0000-4000-8000-000000000000"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentPreparedReplyDto | The created reply draft and refreshed conversation state. |
default | AgentApiErrorDto | Agent API error with a stable code, retry guidance, support-safe request ID, and bounded details. |
HTTP and SDK snippets
HTTP
POST /agent/work-items/00000000-0000-4000-8000-000000000000/prepare-reply HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": true,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"internalNote": "value",
"claimId": "00000000-0000-4000-8000-000000000000"
}
cURL
curl -X POST "https://api.mailslurp.com/agent/work-items/00000000-0000-4000-8000-000000000000/prepare-reply" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"sourceEmailId":"00000000-0000-4000-8000-000000000000","reply":{"body":"Hello from MailSlurp","isHTML":true,"from":"user@example.com","replyTo":"user@example.com","customHeaders":{"example":"value"},"charset":"value"},"expectedConversationVersion":1,"expectedLatestEmailId":"00000000-0000-4000-8000-000000000000","internalNote":"value","claimId":"00000000-0000-4000-8000-000000000000"}'
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"conversationId": "00000000-0000-4000-8000-000000000000",
"prepareAgentReplyOptions": {
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": true,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"internalNote": "value",
"claimId": "00000000-0000-4000-8000-000000000000"
}
};
const result = await agentController.agentPrepareWorkItemReply(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
prepare_agent_reply_options = {
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": True,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"internalNote": "value",
"claimId": "00000000-0000-4000-8000-000000000000"
}
result = agentController.agent_prepare_work_item_reply("00000000-0000-4000-8000-000000000000", prepare_agent_reply_options)
/agent/work-items/{conversationId}/defer
Defer a work item to human review
Creates or returns the active review handoff and releases the supplied claim after the handoff is durable. Deferral is a normal workflow result rather than an operational failure.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
reasonCode | string | Yes | |
reason | string | No | |
priority | enum: LOW | NORMAL | HIGH | URGENT | Yes | |
sourceEmailId | string:uuid | No | |
draftId | string:uuid | No | |
expectedConversationVersion | integer:int64 | No | |
claimId | string:uuid | No |
{
"reasonCode": "value",
"priority": "LOW",
"reason": "value",
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"draftId": "00000000-0000-4000-8000-000000000000",
"expectedConversationVersion": 1
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentDeferredWorkItemDto | The human-review handoff and refreshed conversation state. |
default | AgentApiErrorDto | Agent API error with a stable code, retry guidance, support-safe request ID, and bounded details. |
HTTP and SDK snippets
HTTP
POST /agent/work-items/00000000-0000-4000-8000-000000000000/defer HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"reasonCode": "value",
"priority": "LOW",
"reason": "value",
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"draftId": "00000000-0000-4000-8000-000000000000",
"expectedConversationVersion": 1
}
cURL
curl -X POST "https://api.mailslurp.com/agent/work-items/00000000-0000-4000-8000-000000000000/defer" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"reasonCode":"value","priority":"LOW","reason":"value","sourceEmailId":"00000000-0000-4000-8000-000000000000","draftId":"00000000-0000-4000-8000-000000000000","expectedConversationVersion":1}'
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"conversationId": "00000000-0000-4000-8000-000000000000",
"deferAgentWorkItemOptions": {
"reasonCode": "value",
"priority": "LOW",
"reason": "value",
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"draftId": "00000000-0000-4000-8000-000000000000",
"expectedConversationVersion": 1
}
};
const result = await agentController.agentDeferWorkItem(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
defer_agent_work_item_options = {
"reasonCode": "value",
"priority": "LOW",
"reason": "value",
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"draftId": "00000000-0000-4000-8000-000000000000",
"expectedConversationVersion": 1
}
result = agentController.agent_defer_work_item("00000000-0000-4000-8000-000000000000", defer_agent_work_item_options)
Examples of review reasons include an ambiguous request, a requested refund or missing order information. Add internal notes for the reviewer rather than putting operational context into the customer's email. Open the agent's Review queue to inspect the conversation and draft before sending.
Complete an approved autonomous reply
agentCompleteWorkItem rechecks freshness, sends a threaded reply with an idempotencyKey, and releases the supplied claim only after sending succeeds. Store one key for the logical reply before making the request. Retry an interrupted request with that same key and unchanged payload; a different reply needs a different key.
/agent/work-items/{conversationId}/complete
Complete a work item with an idempotent reply
Revalidates conversation freshness, sends one threaded reply with an idempotency key, and releases the supplied claim only after the send succeeds.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
conversationId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
sourceEmailId | string:uuid | Yes | |
reply | ReplyToEmailOptions | Yes | |
idempotencyKey | string | Yes | |
expectedConversationVersion | integer:int64 | No | |
expectedLatestEmailId | string:uuid | No | |
claimId | string:uuid | No |
{
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": true,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"idempotencyKey": "value",
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"claimId": "00000000-0000-4000-8000-000000000000"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentCompletedWorkItemDto | The durable sent-email result and claim release state. |
default | AgentApiErrorDto | Agent API error with a stable code, retry guidance, support-safe request ID, and bounded details. |
HTTP and SDK snippets
HTTP
POST /agent/work-items/00000000-0000-4000-8000-000000000000/complete HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
Content-Type: application/json
{
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": true,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"idempotencyKey": "value",
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"claimId": "00000000-0000-4000-8000-000000000000"
}
cURL
curl -X POST "https://api.mailslurp.com/agent/work-items/00000000-0000-4000-8000-000000000000/complete" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data '{"sourceEmailId":"00000000-0000-4000-8000-000000000000","reply":{"body":"Hello from MailSlurp","isHTML":true,"from":"user@example.com","replyTo":"user@example.com","customHeaders":{"example":"value"},"charset":"value"},"idempotencyKey":"value","expectedConversationVersion":1,"expectedLatestEmailId":"00000000-0000-4000-8000-000000000000","claimId":"00000000-0000-4000-8000-000000000000"}'
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"conversationId": "00000000-0000-4000-8000-000000000000",
"completeAgentWorkItemOptions": {
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": true,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"idempotencyKey": "value",
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"claimId": "00000000-0000-4000-8000-000000000000"
}
};
const result = await agentController.agentCompleteWorkItem(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
complete_agent_work_item_options = {
"sourceEmailId": "00000000-0000-4000-8000-000000000000",
"reply": {
"body": "Hello from MailSlurp",
"isHTML": True,
"from": "user@example.com",
"replyTo": "user@example.com",
"customHeaders": {
"example": "value"
},
"charset": "value"
},
"idempotencyKey": "value",
"expectedConversationVersion": 1,
"expectedLatestEmailId": "00000000-0000-4000-8000-000000000000",
"claimId": "00000000-0000-4000-8000-000000000000"
}
result = agentController.agent_complete_work_item("00000000-0000-4000-8000-000000000000", complete_agent_work_item_options)
Record conversation, claim and request identifiers for debugging. Use the returned error code and retry guidance to separate permission problems, stale work and transient failures. Do not report success just because the model produced text.
Use durable events for event-driven workers
GET /agent/events supports bounded long polling with waitSeconds. Events are delivered at least once. Deduplicate by eventId and persist nextCursor only after the page has been durably processed. After a restart, resume from the saved cursor.
/agent/events
Read durable scoped automation events
Returns an ordered at-least-once event batch. Persist nextCursor after processing and deduplicate by eventId. waitSeconds enables bounded long polling; production workers should not continuously call latest-email polling.
Request, parameters, and responses
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
cursor | string | No | |
eventType | enum: EMAIL_RECEIVED | EMAIL_SENT | SMS_RECEIVED | SMS_SENT | CONVERSATION_CLAIMED | CONVERSATION_CLAIM_RELEASED[] | No | |
size | integer:int32 | No | |
waitSeconds | integer:int32 | No |
Responses
| Status | Schema | Description |
|---|---|---|
200 | AgentAutomationEventPageDto | OK |
HTTP and SDK snippets
HTTP
GET /agent/events?cursor=value&eventType=value&size=value HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
curl -X GET "https://api.mailslurp.com/agent/events?cursor=value&eventType=value&size=value" \
-H "x-api-key: YOUR_API_KEY" \
-H "Accept: application/json"
JavaScript SDK
import { Configuration, AgentControllerApi } from "mailslurp-client";
const config = new Configuration({ apiKey: "YOUR_API_KEY" });
const agentController = new AgentControllerApi(config);
const request = {
"cursor": "value",
"eventType": [
"value"
],
"size": null
};
const result = await agentController.agentListAutomationEvents(request);
Python SDK
import mailslurp_client
from mailslurp_client.api.agent_controller_api import AgentControllerApi
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = "YOUR_API_KEY"
with mailslurp_client.ApiClient(configuration) as api_client:
agentController = AgentControllerApi(api_client)
result = agentController.agent_list_automation_events(cursor="value", event_type=["value"], size=NaN)
An event identifies work to inspect; claims coordinate who acts on it. If your application already receives MailSlurp webhooks, use the reliable receiver pattern and keep the scoped key in the worker. Use scoped SMS and TOTP for those channels rather than treating an email work item as an SMS conversation.