Get outreach sending capacity
curl --request GET \
--url https://api.snowseo.com/v3/outreach/outbox/status \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.snowseo.com/v3/outreach/outbox/status"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.snowseo.com/v3/outreach/outbox/status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.snowseo.com/v3/outreach/outbox/status",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/outreach/outbox/status"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.snowseo.com/v3/outreach/outbox/status")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/outreach/outbox/status")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"account": {
"id": "<string>",
"email": "<string>",
"displayName": "<string>",
"provider": "<string>",
"dailyLimit": 123,
"canReceiveReplies": true,
"lastError": "<string>"
},
"dailyLimit": 123,
"sentLast24h": 123,
"mailboxCount": 123,
"warmingCount": 123,
"fullPaceLimit": 123,
"fullPaceAt": "<string>",
"pausedCount": 123,
"heldCount": 123,
"unauthenticatedCount": 123,
"mailboxes": [
{
"id": "<string>",
"email": "<string>",
"provider": "<string>",
"limit": 123,
"sentToday": 123,
"remaining": 123,
"isWarming": true,
"fullPaceLimit": 123,
"fullPaceAt": "<string>",
"hold": "<string>",
"bounceRate": 123
}
],
"queuedCount": 123,
"sentCount": 123,
"repliedCount": 123,
"failedCount": 123,
"bouncedCount": 123,
"linkedCount": 123
}Backlink Outreach
Email Sending
Templates, drafts, the send queue, replies, mailboxes, and automatic link re-checking.
GET
/
v3
/
outreach
/
outbox
/
status
Get outreach sending capacity
curl --request GET \
--url https://api.snowseo.com/v3/outreach/outbox/status \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.snowseo.com/v3/outreach/outbox/status"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.snowseo.com/v3/outreach/outbox/status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.snowseo.com/v3/outreach/outbox/status",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/outreach/outbox/status"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.snowseo.com/v3/outreach/outbox/status")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/outreach/outbox/status")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"account": {
"id": "<string>",
"email": "<string>",
"displayName": "<string>",
"provider": "<string>",
"dailyLimit": 123,
"canReceiveReplies": true,
"lastError": "<string>"
},
"dailyLimit": 123,
"sentLast24h": 123,
"mailboxCount": 123,
"warmingCount": 123,
"fullPaceLimit": 123,
"fullPaceAt": "<string>",
"pausedCount": 123,
"heldCount": 123,
"unauthenticatedCount": 123,
"mailboxes": [
{
"id": "<string>",
"email": "<string>",
"provider": "<string>",
"limit": 123,
"sentToday": 123,
"remaining": 123,
"isWarming": true,
"fullPaceLimit": 123,
"fullPaceAt": "<string>",
"hold": "<string>",
"bounceRate": 123
}
],
"queuedCount": 123,
"sentCount": 123,
"repliedCount": 123,
"failedCount": 123,
"bouncedCount": 123,
"linkedCount": 123
}Everything from writing the pitch to reading the reply. Outreach sends from your own mailbox, at a pace that keeps the mail deliverable, so a queued batch drains over hours rather than seconds.
Unknown variables collapse to an empty string rather than leaking braces into a real email.
Returns a
Write the subject and body yourself, one per contact, personalised to the page named on the prospect.
Each page re-read uses one page crawl. If the allowance runs out mid-sweep, the run reads what it can and picks up the rest next time. Pages checked more recently than the cadence are skipped, so a page is never fetched twice in one cycle.
The endpoints on this page send real email to real people. Once a message leaves the mailbox it cannot be recalled. Anything still queued can be pulled back.
Sending capacity
GET /outreach/outbox/status
How much sending headroom the brand has right now. Check this before queueing a batch - mail beyond the daily cap waits for the next day rather than going out.
Query parameters: sendingAccountId to narrow to one mailbox.
| Field | Description |
|---|---|
dailyLimit | Recipients the connected mailboxes may take in the next 24 hours |
sentLast24h | How much of that is used |
mailboxCount | Mailboxes the total is spread across |
warmingCount / fullPaceLimit / fullPaceAt | How many mailboxes are still ramping up, what the total becomes when they finish, and when |
pausedCount | Mailboxes stopped because their delivery has gone bad |
heldCount | Mailboxes still sending but not allowed to send more yet |
unauthenticatedCount | Mailboxes held at the starting volume because their sending domain is not set up for email authentication |
mailboxes[] | Per-mailbox limit, sentToday, remaining, warmup state and hold reason |
queuedCount, sentCount, repliedCount, failedCount, bouncedCount, linkedCount | The funnel across every conversation |
A mailbox tops out at 30 recipients a day, and a newly connected one starts well below that and climbs to full pace over roughly four weeks. This is a deliverability ceiling, not a plan limit - the way to send more is another mailbox, not a bigger number on this one.
Templates
A template is a reusable subject and body. A draft copies the template when it is composed, so editing one later never rewrites mail already queued or sent.List templates
GET /outreach/templates
The brand’s templates, most recently updated first. Read these before drafting so an existing template is reused rather than reinvented.
Create a template
POST /outreach/templates
Body: name (unique within the brand), subject, body (Markdown). A brand may hold up to 100 templates.
Update a template
PATCH /outreach/templates/{id}
Only the fields you send are touched.
Delete a template
DELETE /outreach/templates/{id}
Merge variables
Subjects and bodies may contain these, substituted per recipient when a draft is composed:| Variable | Fills in with |
|---|---|
{{first_name}} | The contact’s first name |
{{name}} | Their full name |
{{role}} | Their job title |
{{site_name}} | The site being written to |
{{domain}} | Its domain |
{{source_url}} | The exact page being pitched |
{{matched_query}} | The search that surfaced that page |
{{your_name}} | The display name of the sending mailbox |
Draft a pitch
POST /outreach/prospects/{id}/draft
Open the request and response reference.
Writes a pitch for one prospect, personalised to the page it was found on - what the page is, whether it mentioned you, whether it named competitors and how many, and when it was last updated.
Body
| Field | Description |
|---|---|
emailId | Which contact to write to, from the prospect’s addresses. Defaults to the primary address |
useMergeVars | Leave merge variables unresolved in the returned copy instead of substituting them |
subject and body and sends nothing. Pass them to Queue pitches once the wording has been approved.
Costs 1 AI credit.
Save an unsent draft
GET /outreach/drafts lists saved drafts. PUT /outreach/drafts/{prospectId} saves or replaces a prospect’s subject, body, and optional prospectEmailId without sending anything. An empty subject and body clear the draft. DELETE /outreach/drafts/{prospectId} discards it.
Queue pitches
POST /outreach/outbox/queue
Open the request and response reference.
Queues one pitch per contact. By default they are paced across each mailbox’s daily allowance; with sendNow they go out immediately.
Body
| Field | Description |
|---|---|
items | One entry per recipient, up to 200 |
items[].prospectEmailId | Contact address ID, from List a prospect’s addresses. An address not belonging to one of this brand’s prospects is rejected |
items[].subject | Subject for this recipient |
items[].body | Body for this recipient. Markdown is rendered and newlines are kept as written |
sendNow | Send immediately instead of pacing. Leave false unless asked for |
sendingAccountId | Send from one specific mailbox. Omit to rotate across all connected mailboxes |
Items missing a subject, a body or a valid contact are skipped rather than failing the batch, and the call only errors when nothing at all could be queued - so compare the returned count against what you sent. Queueing the same contact twice is a no-op, so a retry cannot double-send.
List queued pitches
GET /outreach/outbox/queued
Pitches waiting to be sent, with the recipient and the page each is about.
List scheduled mail
GET /outreach/inbox/scheduled
The same queue with the time each message is due. Check this before queueing more so a prospect is not written to twice.
Unqueue a recipient
DELETE /outreach/outbox/queued/{id}
Pulls a message back out of the queue. The recipient row is deleted, which puts the prospect back into the ready list - so the pipeline stage stops reading as “contacted”.
Mark prospects do-not-contact
POST /outreach/outbox/skip
Body: prospectIds, and doNotContact (defaults to true).
Keeps the prospect on the list but takes it out of the send queue. To stop a site being discovered again at all, use Block prospects instead.
Conversations
List conversations
GET /outreach/inbox/threads
Every pitch conversation with its messages, so replies can be read and answered. The conversation id here is what Reply takes.
Reply in a conversation
POST /outreach/inbox/threads/{id}/reply
Sends a real email immediately to the person on the other end, threaded onto the last message. There is no draft step and it cannot be undone.
Body: body - Markdown is rendered and newlines are kept as written. The subject and threading headers come from the conversation, so do not restate them.
Read the thread first so the reply answers what was actually said. To start a new pitch to someone not yet contacted, use Queue pitches instead.
POST /outreach/inbox/threads/{id}/draft-reply generates an unsent reply from the conversation for 1 AI credit. Review its returned body before calling the sending endpoint above.
Mark a conversation read
POST /outreach/inbox/threads/{id}/read
List individual messages
GET /outreach/outbox/messages
Every message sent and received, one row each, newest first. This is the message-level view; the conversation list above groups the same data and is usually the better read. Cap with limit.
Inbound mail only exists for mailboxes connected with reading settings. Mailboxes connected through an OAuth provider are send-only, so an empty reply list is not necessarily a bug.
Mailboxes
GET /outreach/sending-accounts
The mailboxes outreach can send from, with each one’s daily limit, warmup state, whether it can receive replies, and the last connection error. Passwords are never returned.
Outreach cannot send at all until at least one mailbox is connected, so check here first when queueing fails.
Connect a mailbox
POST /outreach/sending-accounts/smtp
Connects a mailbox by its mail-server settings. POST /outreach/sending-accounts/smtp/test and POST /outreach/sending-accounts/imap/test verify the credentials without saving them.
The reading settings are optional. Without them the mailbox sends normally but replies never come back into SnowSEO.
These endpoints take mailbox passwords, so they are not exposed as MCP tools - connecting a mailbox is not something an AI assistant should do on your behalf. Connect mailboxes from Settings → Integrations → Sending accounts in the dashboard.
Update a mailbox
PATCH /outreach/sending-accounts/{id}
Body: dailyLimit (clamped to the deliverability ceiling), isActive, displayName, warmupEnabled.
Check for replies now
POST /outreach/sending-accounts/{id}/sync
Reads the mailbox immediately instead of waiting for the next scheduled check. Runs in the background - poll the mailbox’s syncStatus from GET /outreach/sending-accounts until it is idle. Check imapLastError for a read failure. Only available for mailboxes connected with reading settings.
Disconnect a mailbox
DELETE /outreach/sending-accounts/{id}
Outreach automation
GET /outreach/automation
Whether earned links are re-checked automatically and how often. Read this before changing the cadence so the current value is known.
PATCH /outreach/automation
Body
| Field | Description |
|---|---|
autoRecheckLinks | Turn scheduled re-checking on or off |
recheckFrequency | everyday, every-3-days, every-7-days (default), every-14-days, or monthly |
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Query Parameters
Narrow to one mailbox. Omit for every mailbox on the team.
Response
200 - application/json
Default Response
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Was this page helpful?

