MailSlurp logo

Scoped SMS and TOTP for agents

Documentation navigation
Search documentation

Assign phone numbers and authenticator devices to agent workflows with separate read, send and management permissions.

An agent connection can use the phone numbers and TOTP devices allowed by its permissions and resource scope. The operator provisions and assigns resources; the running agent discovers what it can access with agentGetCapabilities and the channel-specific listing operations.

Assign phone numbers before the agent runs

Provision numbers through the dashboard or account API and assign the intended numbers to the agent connection. A scoped agent's phone listing returns only active assigned numbers. Phone provisioning is an operator action, separate from an agent reading or replying to SMS.

GET /agent/phone-numbers

List assigned phone numbers

Returns only active phone numbers explicitly assigned to this agent connection.

Request, parameters, and responses

Query parameters

NameTypeRequiredDescription
pageinteger:int32No
sizeinteger:int32No
sortenum: ASC | DESCNoValues: ASC, DESC
searchstringNo

Responses

StatusSchemaDescription
200PageAgentPhoneNumberOK
HTTP examples

HTTP

HTTP
GET /agent/phone-numbers HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
  --request GET \
  --url 'https://api.mailslurp.com/agent/phone-numbers' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}')
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const response = await fetch("https://api.mailslurp.com/agent/phone-numbers", {
  method: "GET",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
  },
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/phone-numbers")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("GET", path, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
GET /agent/phone-numbers/{phoneNumberId}/sms

List received SMS for an assigned phone number

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
phoneNumberIdstring:uuidYes

Query parameters

NameTypeRequiredDescription
pageinteger:int32No
sizeinteger:int32No
sortenum: ASC | DESCNoValues: ASC, DESC
sincestring:date-timeNo
beforestring:date-timeNo
searchstringNo
favouritebooleanNo

Responses

StatusSchemaDescription
200PageSmsProjectionOK
HTTP examples

HTTP

HTTP
GET /agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
  --request GET \
  --url 'https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}')
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const response = await fetch("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms", {
  method: "GET",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
  },
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("GET", path, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()

Keep SMS read/history permissions separate from SMS send permission. Replying requires both because the agent reads an inbound message before sending its response. An email role or inbox assignment alone should not be assumed to grant phone access; check capabilities and the assigned resources.

Read and reply within scope

  1. List the assigned phones and select the intended phone ID.
  2. List its received SMS or message threads, using a time boundary when following a new action.
  3. Retrieve the selected message and verify that it belongs to the intended workflow.
  4. Reply only when the connection has the required permission and the application authorizes the response.
  5. Inspect sent history and activity to confirm the outcome.
GET /agent/phone-numbers/{phoneNumberId}/message-threads

List SMS threads

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
phoneNumberIdstring:uuidYes

Query parameters

NameTypeRequiredDescription
pageinteger:int32No
sizeinteger:int32No

Responses

StatusSchemaDescription
200PagePhoneMessageThreadProjectionOK
HTTP examples

HTTP

HTTP
GET /agent/phone-numbers/00000000-0000-4000-8000-000000000000/message-threads HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
  --request GET \
  --url 'https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/message-threads' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}')
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const response = await fetch("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/message-threads", {
  method: "GET",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
  },
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/message-threads")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("GET", path, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
POST /agent/phone-numbers/{phoneNumberId}/sms/{smsId}/reply

Reply to received SMS

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
phoneNumberIdstring:uuidYes
smsIdstring:uuidYes

Query parameters

NameTypeRequiredDescription
expectedConversationVersioninteger:int64No
expectedLatestMessageIdstring:uuidNo

Header parameters

NameTypeRequiredDescription
Idempotency-KeystringNo

Request body (required)

SmsReplyOptions application/json
FieldTypeRequiredDescription
bodystringYes
Request example
{
  "body": "Hello from MailSlurp"
}

Responses

StatusSchemaDescription
201SentSmsDtoCreated
HTTP examples

HTTP

HTTP
POST /agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms/00000000-0000-4000-8000-000000000000/reply HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*

{
  "body": "value"
}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{\0012  "body": "value"\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request POST \
  --url 'https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms/00000000-0000-4000-8000-000000000000/reply' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{\n  \"body\": \"value\"\n}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms/00000000-0000-4000-8000-000000000000/reply", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms/00000000-0000-4000-8000-000000000000/reply")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{\n  \"body\": \"value\"\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("POST", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
POST /agent/phone-numbers/{phoneNumberId}/sms

Send SMS from an assigned phone number

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
phoneNumberIdstring:uuidYes

Query parameters

NameTypeRequiredDescription
expectedConversationVersioninteger:int64No
expectedLatestMessageIdstring:uuidNo

Header parameters

NameTypeRequiredDescription
Idempotency-KeystringNo

Request body (required)

SmsSendOptions application/json
FieldTypeRequiredDescription
tostringYes
bodystringYes
Request example
{
  "to": "+15551234567",
  "body": "Hello from MailSlurp"
}

Responses

StatusSchemaDescription
201SentSmsDtoCreated
HTTP examples

HTTP

HTTP
POST /agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*

{
  "to": "user@example.com",
  "body": "value"
}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{\0012  "to": "user@example.com",\0012  "body": "value"\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request POST \
  --url 'https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{\n  \"to\": \"user@example.com\",\n  \"body\": \"value\"\n}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/phone-numbers/00000000-0000-4000-8000-000000000000/sms")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{\n  \"to\": \"user@example.com\",\n  \"body\": \"value\"\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("POST", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()

For supervised SMS conversations, use the SMS claim, renewal and handoff operations. Do not reuse email conversation IDs or assume an email claim also reserves a phone.

POST /agent/sms-conversations/{conversationId}/claims

Acquire an SMS conversation claim

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
conversationIdstring:uuidYes

Request body (required)

FieldTypeRequiredDescription
workerIdstringYes
leaseSecondsinteger:int32Yes
expectedVersioninteger:int64No
Request example
{
  "workerId": "00000000-0000-4000-8000-000000000000",
  "leaseSeconds": 1,
  "expectedVersion": 1
}

Responses

StatusSchemaDescription
201AgentConversationClaimDtoCreated
HTTP examples

HTTP

HTTP
POST /agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*

{
  "workerId": "value",
  "leaseSeconds": 5
}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{\0012  "workerId": "value",\0012  "leaseSeconds": 5\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request POST \
  --url 'https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{\n  \"workerId\": \"value\",\n  \"leaseSeconds\": 5\n}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{\n  \"workerId\": \"value\",\n  \"leaseSeconds\": 5\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("POST", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
PUT /agent/sms-conversations/{conversationId}/claims/{claimId}

Renew an SMS conversation claim

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
conversationIdstring:uuidYes
claimIdstring:uuidYes

Request body (required)

FieldTypeRequiredDescription
leaseSecondsinteger:int32Yes
Request example
{
  "leaseSeconds": 1
}

Responses

StatusSchemaDescription
200AgentConversationClaimDtoOK
HTTP examples

HTTP

HTTP
PUT /agent/sms-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
Content-Type: application/json
Accept: */*

{
  "leaseSeconds": 5
}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{\0012  "leaseSeconds": 5\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request PUT \
  --url 'https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{\n  \"leaseSeconds\": 5\n}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000", {
  method: "PUT",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/claims/00000000-0000-4000-8000-000000000000")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{\n  \"leaseSeconds\": 5\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("PUT", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
POST /agent/sms-conversations/{conversationId}/handoffs

Request human review for an SMS conversation

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
conversationIdstring:uuidYes

Request body (required)

FieldTypeRequiredDescription
reasonCodestringYes
reasonstringNo
priorityenum: LOW | NORMAL | HIGH | URGENTYesValues: LOW, NORMAL, HIGH, URGENT
sourceSmsIdstring:uuidNo
expectedVersioninteger:int64No
Request example
{
  "reasonCode": "value",
  "priority": "LOW",
  "reason": "value",
  "sourceSmsId": "00000000-0000-4000-8000-000000000000",
  "expectedVersion": 1
}

Responses

StatusSchemaDescription
201AgentConversationHandoffDtoCreated
HTTP examples

HTTP

HTTP
POST /agent/sms-conversations/00000000-0000-4000-8000-000000000000/handoffs HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*

{
  "reasonCode": "value",
  "priority": "LOW"
}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{\0012  "reasonCode": "value",\0012  "priority": "LOW"\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request POST \
  --url 'https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/handoffs' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{\n  \"reasonCode\": \"value\",\n  \"priority\": \"LOW\"\n}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/handoffs", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/sms-conversations/00000000-0000-4000-8000-000000000000/handoffs")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{\n  \"reasonCode\": \"value\",\n  \"priority\": \"LOW\"\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("POST", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()

Use an authenticator device

For applications using TOTP, list or find an agent-accessible device, then generate a code for the authorized authentication step. With the appropriate permissions, agent-managed devices can be created from a base32 secret or an otpauth URL.

GET /agent/totp/devices

List agent-accessible TOTP devices

Request, parameters, and responses

Query parameters

NameTypeRequiredDescription
pageinteger:int32No
sizeinteger:int32No
sortenum: ASC | DESCNoValues: ASC, DESC
issuerstringNo
usernamestringNo

Responses

StatusSchemaDescription
200PageTotpDeviceProjectionOK
HTTP examples

HTTP

HTTP
GET /agent/totp/devices HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
  --request GET \
  --url 'https://api.mailslurp.com/agent/totp/devices' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}')
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const response = await fetch("https://api.mailslurp.com/agent/totp/devices", {
  method: "GET",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
  },
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/totp/devices")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("GET", path, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
POST /agent/totp/devices/otp-auth-url

Create an agent-managed TOTP device from an OTP Auth URL

Request, parameters, and responses

Request body (required)

FieldTypeRequiredDescription
otpAuthUrlstringYesOTP Auth URI for connecting a TOTP device.
namestringNoName for labeling the TOTP device
usernamestringNoOptional username for the TOTP device
issuerstringNoOptional issuer override for the TOTP device
digitsinteger:int32NoOptional number of digits in TOTP code
periodinteger:int32NoOptional period in seconds for TOTP code expiration
algorithmstringNoOptional algorithm override
Request example
{
  "otpAuthUrl": "otpauth://totp/your-app:contact%40mailslurp.dev?secret=LJCTOYKGGBAWCMSHJRZGITCVLIXCG4JY&issuer=your-app&algorithm=SHA1&digits=6&period=30",
  "name": "Example name",
  "username": "Example name",
  "issuer": "value",
  "digits": 6,
  "period": 30
}

Responses

StatusSchemaDescription
201TotpDeviceDtoCreated
HTTP examples

HTTP

HTTP
POST /agent/totp/devices/otp-auth-url HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*

{
  "otpAuthUrl": "otpauth://totp/your-app:contact%40mailslurp.dev?secret=LJCTOYKGGBAWCMSHJRZGITCVLIXCG4JY&issuer=your-app&algorithm=SHA1&digits=6&period=30",
  "digits": 6,
  "period": 30
}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{\0012  "otpAuthUrl": "otpauth://totp/your-app:contact%40mailslurp.dev?secret=LJCTOYKGGBAWCMSHJRZGITCVLIXCG4JY&issuer=your-app&algorithm=SHA1&digits=6&period=30",\0012  "digits": 6,\0012  "period": 30\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request POST \
  --url 'https://api.mailslurp.com/agent/totp/devices/otp-auth-url' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{\n  \"otpAuthUrl\": \"otpauth://totp/your-app:contact%40mailslurp.dev?secret=LJCTOYKGGBAWCMSHJRZGITCVLIXCG4JY&issuer=your-app&algorithm=SHA1&digits=6&period=30\",\n  \"digits\": 6,\n  \"period\": 30\n}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/agent/totp/devices/otp-auth-url", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/totp/devices/otp-auth-url")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{\n  \"otpAuthUrl\": \"otpauth://totp/your-app:contact%40mailslurp.dev?secret=LJCTOYKGGBAWCMSHJRZGITCVLIXCG4JY&issuer=your-app&algorithm=SHA1&digits=6&period=30\",\n  \"digits\": 6,\n  \"period\": 30\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("POST", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()
GET /agent/totp/devices/{id}/code

Generate a code for an agent-managed TOTP device

Request, parameters, and responses

Path parameters

NameTypeRequiredDescription
idstring:uuidYes

Query parameters

NameTypeRequiredDescription
atstring:date-timeNo
minSecondsUntilExpireinteger:int32NoMinimum remaining code lifetime. The request may wait for the next period when needed.

Responses

StatusSchemaDescription
200TotpDeviceCodeDtoOK
HTTP examples

HTTP

HTTP
GET /agent/totp/devices/00000000-0000-4000-8000-000000000000/code HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
  --request GET \
  --url 'https://api.mailslurp.com/agent/totp/devices/00000000-0000-4000-8000-000000000000/code' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}')
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const response = await fetch("https://api.mailslurp.com/agent/totp/devices/00000000-0000-4000-8000-000000000000/code", {
  method: "GET",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
  },
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/agent/totp/devices/00000000-0000-4000-8000-000000000000/code")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("GET", path, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()

Treat the enrollment secret and generated code as credentials. Keep them out of shared logs, generate a fresh code near the submission step and verify the application's authenticated state. See TOTP testing for the enrollment and verification flow.

Choose the correct credential

Use a scoped agent key for the operations documented here. An account key belongs in a separate provisioning service when account-level setup is required. For browser-test suites using ordinary account APIs, see SMS waits and phone pool leases. Check the connected MCP client's available tool list before assuming every REST operation is exposed as an MCP tool.