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
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}Email sending
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
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}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.
In
Older names (
Returns a
Response
Write the subject and body yourself, one per contact, personalised to the page named on the prospect.
Managing the queue:
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
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 the totals to one mailbox. It does not narrow mailboxes, which always lists every connected mailbox, and the funnel counts are always team-wide.
| Field | Description |
|---|---|
account | The mailbox named by sendingAccountId, or the first active one when it is omitted or unknown; null when none is connected. Has id, email, displayName, provider, dailyLimit, canReceiveReplies and lastError |
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 for complaints. The complaint pause is not live yet, so this is always 0 today |
heldCount | Mailboxes capped at 10 a day because too many of their recent emails bounced |
unauthenticatedCount | Mailboxes capped at 10 a day because their sending domain has no SPF or DMARC record |
mailboxes[] | One entry per mailbox, most room left first: id, email, provider, limit, sentToday, remaining, isWarming, fullPaceLimit, fullPaceAt, bounceRate and hold |
queuedCount, sentCount, repliedCount, failedCount, bouncedCount, linkedCount | The funnel across every conversation |
mailboxes[], bounceRate is the share of recent sends that bounced, or null when there are too few to judge. hold is none, bounces, unauthenticated or complaints-paused (which does not occur today).
A mailbox’s daily cap is the lower of its own
dailyLimit and 30 recipients. 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.A mailbox is held to 10 a day when its bounce rate is 10% or more across at least 50 sends in the last 7 days (bounces), or when its domain has no SPF or DMARC record (unauthenticated). If both apply, unauthenticated is reported. Mailboxes with pacing switched off (warmupEnabled false) skip the ramp and both of these caps.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.Merge variables
Subjects and bodies may contain these, substituted per recipient when a draft is composed and again at send time:| Variable | Fills in with |
|---|---|
{{first_name}} | The contact’s first name |
{{contact_name}} | Their full name |
{{contact_role}} | Their job title |
{{target_site_name}} | The site being written to. Currently the same as its domain |
{{prospect_domain}} | Its domain |
{{target_page_title}} | The pitched page’s title with the site name trimmed off, or its URL when there is no title |
{{target_page_url}} | The exact page being pitched |
{{broken_link_url}} | The dead link to your site on that page. Empty unless the link is broken |
{{anchor_text}} | The text of their existing link to you. Empty when they do not link to you |
{{competitors_on_page}} | Competitors the page names, for example “Ahrefs, Semrush and Moz”. Empty when it names none |
{{display_name}} | The display name of the sending mailbox |
{{your_brand}} | Your brand name |
{{your_domain}} | Your own domain |
{{name}}, {{role}}, {{site_name}}, {{domain}}, {{source_url}}, {{matched_query}}, {{your_name}}) still resolve in saved templates but should not be used in new ones. Unknown variables collapse to an empty string rather than leaking braces into a real email.
Draft a pitch
POST /v3/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. Omitting it does not fall back to the primary address: the draft is then written to the site rather than a named person |
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. A 400 means your brand name is not set in settings.
Save an unsent draft
List saved drafts, save a draft without sending anything, or delete a draft.Queue pitches
POST /v3/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. sendNow sends immediately only when exactly one new recipient is queued; a batch is always paced.
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 skipped |
items[].subject | Subject for this recipient. Truncated past 500 characters |
items[].body | Body for this recipient. Markdown is rendered and newlines are kept as written. Truncated past 50,000 characters |
sendNow | Send immediately instead of pacing, for a single new recipient only. Leave false unless asked for |
sendingAccountId | Send from one specific mailbox. Omit to rotate across all connected mailboxes. An unknown or inactive ID is not an error: the mailbox is silently replaced with the first active one |
| Field | Description |
|---|---|
queued | Newly queued pitches |
queuedConversationIds | Their conversation IDs. Read delivery status for them from GET /v3/outreach/outbox/emails |
updated | Pitches already waiting in the queue whose unsent copy was overwritten |
skipped | Items that were incomplete, not owned, for a do-not-contact prospect, or already sent |
sendNow | true only if the single new pitch went out immediately |
spacingMs | Gap between paced sends |
Items missing a subject, a body or a valid contact are skipped rather than failing the batch, and the call returns
400 when nothing at all could be queued, when items is missing or empty, or when no item has a prospectEmailId - so compare the returned counts against what you sent. Contacts at do-not-contact prospects are skipped and counted in skipped. Queueing a contact whose pitch is still waiting overwrites its unsent copy (counted in updated) and never sends twice; a contact already sent to is left alone. A batch where every contact is already queued returns 200 with queued: 0. A 409 means no active mailbox is connected.- List queued pitches
- List scheduled mail
- Send a queued pitch now
- Unqueue a recipient
- List outreach emails
- Mark prospects do-not-contact
Conversations
Mailboxes
Outreach cannot send at all until at least one mailbox is connected.Outreach automation
Whether earned links are re-checked automatically and how often.Authorizations
bearerAuthapiKey
Your SnowSEO API key (sk_...).
Query Parameters
Narrow to one mailbox. Omit for every mailbox on the team.
Response
Default Response
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Was this page helpful?

