Send Broadcasts
12 endpoints from the published OpenAPI import.
This workspace's consent basis for pasted address lists
Full history, newest first, with the active declaration called out.
Revoked declarations are kept and returned: "you have no basis" and "you revoked your basis last Tuesday" are different facts, and only the second one tells an operator what happened to their composer.
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
Declare (or supersede) the consent basis for pasted address lists
Record what lawful basis this workspace relies on for pasted addresses.
Declaring again supersedes: the previous declaration is revoked in the same transaction, so a workspace has at most one active basis and its history stays readable.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"basis": "express_consent",
"source_description": "string",
"evidence_url": "string"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"basis": "express_consent", "source_description": "string", "evidence_url": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"basis": "express_consent", "source_description": "string", "evidence_url": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"basis": "express_consent", "source_description": "string", "evidence_url": "string"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
201 | Successful Response |
422 | Validation Error |
Revoke the consent basis for pasted address lists
Withdraw the active declaration.
Takes effect at both doors immediately — no new paste broadcast can be composed, and any already-composed paste draft is refused at queue time. Messages already in send_queue are not retracted; that is the same boundary DELETE /{broadcast_id} draws.
Try it
Examples
cURL
curl -X DELETE 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.delete(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent", {
method: "DELETE",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/paste-consent", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
204 | Successful Response |
Resolve an audience query to a deliverable count
Resolve WITHOUT persisting anything.
Always reports the subtractions (suppressed / duplicates / invalid) so a shrinking audience reads as the deliverability guard working rather than as missing data. suppression_checked=false means the count is provisional — the queue path refuses outright in that state.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/audience/preview' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"mode": "crm",
"board_id": "string",
"email_status": "valid",
"require_first_name": false,
"topics": [
"string"
],
"addresses": [
"string"
]
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/audience/preview",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/audience/preview", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/audience/preview", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Render a draft as a recipient will receive it
Server-side on purpose: this uses the SAME markdown renderer as fan-out, so the preview cannot drift from the message that actually goes out.
Since CAN-SPAM.2 it also reads the caller's own brand — the tenant scope is load-bearing here, not merely a permission check, because the footer carries that brand's postal address and a preview rendered under someone else's would be showing an address this send will never carry.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/preview' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"subject_template": "",
"body_md": "",
"sample": {
"email": "string",
"first_name": "string",
"full_name": "string",
"current_company": "string"
}
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/preview",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"subject_template": "", "body_md": "", "sample": {"email": "string", "first_name": "string", "full_name": "string", "current_company": "string"}},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/preview", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"subject_template": "", "body_md": "", "sample": {"email": "string", "first_name": "string", "full_name": "string", "current_company": "string"}})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"subject_template": "", "body_md": "", "sample": {"email": "string", "first_name": "string", "full_name": "string", "current_company": "string"}}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/preview", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Sending capacity and drain estimate for the selected sources
Combined effective (warmup-aware) daily cap, remaining capacity today, and how long the audience takes to drain at that rate.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
mailbox_ids | query | any | false | Comma-separated mailbox ids. Omitted = every source the tenant owns. |
audience_size | query | integer | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/capacity' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/capacity",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/capacity", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/capacity", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
List broadcasts
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | false | |
offset | query | integer | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/send/broadcasts' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/send/broadcasts", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Create a broadcast draft
Creates a draft. Nothing is enqueued and no mail can leave until POST /{id}/queue — mirroring the admin composer's draft→publish split.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/send/broadcasts' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "Untitled broadcast",
"subject_template": "",
"preheader": "string",
"body_md": "",
"from_name": "string",
"reply_to": "string",
"audience": {
"mode": "crm",
"board_id": "string",
"email_status": "valid",
"require_first_name": false,
"topics": [
"string"
],
"addresses": [
"string"
]
},
"source_mailbox_ids": [
0
],
"scheduled_at": "2026-01-01T00:00:00Z"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"name": "Untitled broadcast", "subject_template": "", "preheader": "string", "body_md": "", "from_name": "string", "reply_to": "string", "audience": {"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}, "source_mailbox_ids": [0], "scheduled_at": "2026-01-01T00:00:00Z"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"name": "Untitled broadcast", "subject_template": "", "preheader": "string", "body_md": "", "from_name": "string", "reply_to": "string", "audience": {"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}, "source_mailbox_ids": [0], "scheduled_at": "2026-01-01T00:00:00Z"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"name": "Untitled broadcast", "subject_template": "", "preheader": "string", "body_md": "", "from_name": "string", "reply_to": "string", "audience": {"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}, "source_mailbox_ids": [0], "scheduled_at": "2026-01-01T00:00:00Z"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/send/broadcasts", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
201 | Successful Response |
422 | Validation Error |
Get a broadcast
Includes live delivery progress aggregated from send_queue.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
broadcast_id | path | string | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Update a draft
True PATCH — only the fields present are written. Drafts only: editing a queued broadcast would change what the composer shows without changing a single already-queued message.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
broadcast_id | path | string | true |
Try it
Examples
cURL
curl -X PATCH 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"subject_template": "string",
"preheader": "string",
"body_md": "string",
"from_name": "string",
"reply_to": "string",
"audience": {
"mode": "crm",
"board_id": "string",
"email_status": "valid",
"require_first_name": false,
"topics": [
"string"
],
"addresses": [
"string"
]
},
"source_mailbox_ids": [
0
],
"scheduled_at": "2026-01-01T00:00:00Z"
}'Python
import httpx
resp = httpx.patch(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"name": "string", "subject_template": "string", "preheader": "string", "body_md": "string", "from_name": "string", "reply_to": "string", "audience": {"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}, "source_mailbox_ids": [0], "scheduled_at": "2026-01-01T00:00:00Z"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}", {
method: "PATCH",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"name": "string", "subject_template": "string", "preheader": "string", "body_md": "string", "from_name": "string", "reply_to": "string", "audience": {"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}, "source_mailbox_ids": [0], "scheduled_at": "2026-01-01T00:00:00Z"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"name": "string", "subject_template": "string", "preheader": "string", "body_md": "string", "from_name": "string", "reply_to": "string", "audience": {"mode": "crm", "board_id": "string", "email_status": "valid", "require_first_name": false, "topics": ["string"], "addresses": ["string"]}, "source_mailbox_ids": [0], "scheduled_at": "2026-01-01T00:00:00Z"}`)
req, _ := http.NewRequest("PATCH", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Cancel a broadcast that has not been fanned out
Already-queued rows are deliberately NOT withdrawn — pulling messages out from under the send loop is a different, riskier operation than abandoning a draft.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
broadcast_id | path | string | true |
Try it
Examples
cURL
curl -X DELETE 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.delete(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}", {
method: "DELETE",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
204 | Successful Response |
422 | Validation Error |
Fan a broadcast out into the send queue
202 — the rows are enqueued; the send loop delivers them on its own pace.
already_enqueued > 0 is a RESUMED fan-out, not a failure: the enqueue is idempotent per (broadcast, address), so a retry after an interruption fills only the gaps instead of double-sending.
provider_configured=false means the messages are queued and will HOLD at queued until Mailgun credentials exist. That is a deliberate dormant state, reported honestly rather than surfaced as an error or faked as sent.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
broadcast_id | path | string | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}/queue' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}/queue",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}/queue", {
method: "POST",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/send/broadcasts/{broadcast_id}/queue", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
202 | Successful Response |
422 | Validation Error |