A 202 from the send endpoint confirms queueing only. Delivery then runs asynchronously. Use this endpoint to check the state of a message, including per-recipient progress for multi-recipient sends.
Endpoint and headers
GET https://email.useinsider.com/mail/v2/messages/{message_id}
Header | Value | Purpose |
|---|---|---|
X-INS-AUTH-KEY | API token, in INS.{id}.{secret} format | Authentication. The partner is implicit; a message_id belonging to another partner returns 404. |
Request parameter
Below are the parameters required for the request.
Parameter | Description | Data type | Required |
|---|---|---|---|
message_id | The ID returned by the send endpoint. | String (UUID) | Yes |
Code samples
These samples are provided as is, as a starting point for your integration. Insider One does not guarantee that they work in every environment, so test them in your own environment before you use them in production.
Each sample polls one message every 5 seconds and prints the aggregate status and summary until completed_at is set.
Set your API key in the INSIDER_API_KEY environment variable.
Copy the sample for your language into a file named get_message_status.py or get_message_status.mjs.
Run the file with a message_id. Each poll prints a line such as partial: {pending: 1, sent: 2, dropped: 0}, and the sample stops when the message is complete.
Python
Requires Python 3.8 or later and the requests package (pip install requests). Run python get_message_status.py 550e8400-e29b-41d4-a716-446655440000.
"""Poll a message's delivery status with GET /mail/v2/messages/{message_id}.
Sample code, provided as is. Test it in your own environment before you use it in production.
Requires Python 3.8+ and the requests package: pip install requests
"""
import os
import sys
import time
import requests
URL = "https://email.useinsider.com/mail/v2/messages/{message_id}"
# OAuth 2.0: call https://gw.useinsider.com/api/em/v2/tx/messages/{message_id} with "Authorization: Bearer {token}" instead.
HEADERS = {"X-INS-AUTH-KEY": os.environ["INSIDER_API_KEY"], "Content-Type": "application/json"}
def call(method, url, payload=None, retries=3):
"""Send the request. On 429 or 5xx, wait and retry up to `retries` times."""
for attempt in range(retries + 1):
response = requests.request(method, url, json=payload, headers=HEADERS, timeout=30)
if (response.status_code != 429 and response.status_code < 500) or attempt == retries:
return response
wait = float(response.headers.get("Retry-After", 2 ** attempt)) # 1, 2, 4 s without Retry-After
print(f"HTTP {response.status_code}: retrying in {wait:.0f}s")
time.sleep(wait)
message_id = sys.argv[1] # The message_id returned by POST /mail/v2/send
while True:
response = call("GET", URL.format(message_id=message_id))
if response.status_code == 404:
raise SystemExit("Unknown message_id, or the send is older than 2 days.")
if response.status_code != 200:
raise SystemExit(f"Status request failed ({response.status_code}): {response.text[:300]}")
status = response.json()
print(f"{status['status']}: {status['summary']}")
if status["completed_at"] is not None: # Every recipient has reached a final state
break
time.sleep(5)Node.js
Requires Node.js 18 or later. No packages are needed. Run node get_message_status.mjs 550e8400-e29b-41d4-a716-446655440000.
// Poll a message's delivery status with GET /mail/v2/messages/{message_id}.
// Sample code, provided as is. Test it in your own environment before you use it in production.
// Requires Node.js 18+ (built-in fetch). No dependencies.
const URL = "https://email.useinsider.com/mail/v2/messages/{message_id}";
// OAuth 2.0: call https://gw.useinsider.com/api/em/v2/tx/messages/{message_id} with "Authorization: Bearer {token}" instead.
const HEADERS = { "X-INS-AUTH-KEY": process.env.INSIDER_API_KEY, "Content-Type": "application/json" };
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Send the request. On 429 or 5xx, wait and retry up to `retries` times.
async function call(method, url, payload, retries = 3) {
for (let attempt = 0; ; attempt++) {
const response = await fetch(url, {
method,
headers: HEADERS,
body: payload === undefined ? undefined : JSON.stringify(payload),
signal: AbortSignal.timeout(30000),
});
if ((response.status !== 429 && response.status < 500) || attempt === retries) return response;
const wait = Number(response.headers.get("Retry-After") ?? 2 ** attempt); // 1, 2, 4 s without Retry-After
console.warn(`HTTP ${response.status}: retrying in ${wait}s`);
await sleep(wait * 1000);
}
}
const messageId = process.argv[2]; // The message_id returned by POST /mail/v2/send
for (;;) {
const response = await call("GET", URL.replace("{message_id}", messageId));
if (response.status === 404) throw new Error("Unknown message_id, or the send is older than 2 days.");
if (response.status !== 200) {
throw new Error(`Status request failed (${response.status}): ${(await response.text()).slice(0, 300)}`);
}
const status = await response.json();
console.log(`${status.status}:`, status.summary);
if (status.completed_at !== null) break; // Every recipient has reached a final state
await sleep(5000);
}Sample responses
The aggregate status is pending (all recipients pending), partial (some sent), or sent (all sent). Per-recipient status is pending or sent; the email is omitted when the recipient was sent by UUID only.
Mid-delivery, some delivered
{
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "partial",
"submitted_at": 1700000000,
"completed_at": null,
"recipient_count": 3,
"summary": {
"pending": 1,
"sent": 2,
"dropped": 0
},
"recipients": [
{
"email": "alice@example.com",
"status": "sent",
"last_updated": 1700000100
},
{
"email": "bob@example.com",
"status": "sent",
"last_updated": 1700000105
},
{
"status": "pending",
"last_updated": 1700000000
}
]
}Finished, all delivered
{
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "sent",
"submitted_at": 1700000000,
"completed_at": 1700000160,
"recipient_count": 3,
"summary": {
"pending": 0,
"sent": 3,
"dropped": 0
}
}Keep in mind
Poll periodically until the status is sent or completed_at is set. Timestamps are Unix seconds; completed_at stays null until every recipient reaches a terminal state.
Status is available for 2 days after submission; older IDs return 404.
The rate limit is 1000 requests per minute per partner.
For status codes, refer to the Error Codes.