sendraven-ai · Schema
Broadcast
A campaign. Every field is always present, null when it has no value (or [] for variants and warnings), so a created campaign and a fetched one have exactly the same keys.
CompanyEmailAIInfrastructureAPI
Properties
| Name | Type | Description |
|---|---|---|
| id | string | |
| audience_id | string | The audience it mails. |
| identity_id | string | The marketing sending domain it goes out on. |
| name | string | |
| subject | string | An A/B variant can override it. |
| html | string | |
| from_name | stringnull | Display name on the From header. null when never set. |
| view_in_browser | boolean | Whether each message opens with a "View this email in your browser" link to web_version_url. |
| web_version_url | stringnull | A public page showing the campaign's HTML, on the sending domain's tracking domain. One URL per campaign, without any recipient's unsubscribe link, so it can be shared. Works whether or not view_in_br |
| segment | objectnull | The inline engagement and tag filter, or null when none was given. A day rule not given is null, a tag list not given is []. |
| segment_id | stringnull | The saved segment it targets. Wins over segment when both are set. |
| topic_key | stringnull | The topic it is sent under. |
| status | string | draft: editable, nothing sent. scheduled: waiting for scheduled_at (a send-time test also returns here between its variants). sending: a run is mailing the frozen audience. paused: stopped with addres |
| scheduled_at | stringnull | When it is due to start. null until scheduled, and again when unscheduled. |
| started_at | stringnull | When a run last claimed it. Rewritten by every run, including each resume. null before the first. |
| completed_at | stringnull | When it finished as sent or failed; null before that. |
| pause_reason | stringnull | Set only while paused: why, in words you can act on (warm-up limit, 24-hour quota, throttling, no postal address, suspension, an interrupted run). null otherwise; cleared when a run picks it up. |
| resume_after | stringnull | Set while paused on the sending domain's warm-up allowance: when it renews (the next 00:00 UTC). The worker resumes the campaign on its own after that, and POST /v1/broadcasts/{id}/resume answers 409 |
| failure_reason | stringnull | Why it failed. Set on every failed campaign, null on every other. |
| total_recipients | integer | Size of the frozen audience after suppressions and topic opt-outs. 0 until the first run freezes it. |
| sent_count | integer | Messages accepted for delivery so far. |
| failed_count | integer | Messages the provider refused. Throttled messages and ones held back by a suspension or a missing postal address are not counted: they go back to pending and the campaign pauses. |
| created_at | string | |
| variants | array | The arms of an A/B test; [] on a campaign that is not a test. |
| ab_test | object | A/B tests only; null otherwise. |
| progress | object | While sending, paused or testing (not on create or update); null otherwise. |
| warnings | array | Settings that will not do what they say yet (today, metric 'click' without click tracking). Derived from the stored campaign, so create, update, list and retrieve say the same thing; [] when there is |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/sendraven-ai/json-schema/sendraven-ai-broadcast-schema.json",
"title": "Broadcast",
"description": "A campaign. Every field is always present, null when it has no value (or [] for variants and warnings), so a created campaign and a fetched one have exactly the same keys.",
"x-generated": "2026-10-31",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/sendraven-ai-api-openapi.json#/components/schemas/Broadcast",
"type": "object",
"required": [
"id",
"audience_id",
"identity_id",
"name",
"subject",
"html",
"from_name",
"view_in_browser",
"web_version_url",
"segment",
"segment_id",
"topic_key",
"status",
"scheduled_at",
"started_at",
"completed_at",
"pause_reason",
"resume_after",
"failure_reason",
"total_recipients",
"sent_count",
"failed_count",
"created_at",
"variants",
"ab_test",
"progress",
"warnings"
],
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"audience_id": {
"type": "string",
"description": "The audience it mails."
},
"identity_id": {
"type": "string",
"description": "The marketing sending domain it goes out on."
},
"name": {
"type": "string"
},
"subject": {
"type": "string",
"description": "An A/B variant can override it."
},
"html": {
"type": "string"
},
"from_name": {
"type": [
"string",
"null"
],
"description": "Display name on the From header. null when never set."
},
"view_in_browser": {
"type": "boolean",
"description": "Whether each message opens with a \"View this email in your browser\" link to web_version_url."
},
"web_version_url": {
"type": [
"string",
"null"
],
"format": "uri",
"description": "A public page showing the campaign's HTML, on the sending domain's tracking domain. One URL per campaign, without any recipient's unsubscribe link, so it can be shared. Works whether or not view_in_browser is set. null while the sending domain has no live tracking domain."
},
"segment": {
"type": [
"object",
"null"
],
"description": "The inline engagement and tag filter, or null when none was given. A day rule not given is null, a tag list not given is [].",
"required": [
"opened_within_days",
"clicked_within_days",
"exclude_unengaged_days",
"engaged_within_days",
"tags",
"exclude_tags",
"date_conditions"
],
"properties": {
"opened_within_days": {
"type": [
"integer",
"null"
]
},
"clicked_within_days": {
"type": [
"integer",
"null"
]
},
"exclude_unengaged_days": {
"type": [
"integer",
"null"
]
},
"engaged_within_days": {
"type": [
"integer",
"null"
]
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Contacts must carry all of these. Normalised."
},
"exclude_tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Contacts carrying any of these are left out. Normalised."
},
"date_conditions": {
"type": "array",
"items": {
"$ref": "#/$defs/SegmentDateCondition"
},
"description": "Relative-date rules; [] when none."
}
}
},
"segment_id": {
"type": [
"string",
"null"
],
"description": "The saved segment it targets. Wins over segment when both are set."
},
"topic_key": {
"type": [
"string",
"null"
],
"description": "The topic it is sent under."
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"sending",
"paused",
"testing",
"sent",
"failed"
],
"description": "draft: editable, nothing sent. scheduled: waiting for scheduled_at (a send-time test also returns here between its variants). sending: a run is mailing the frozen audience. paused: stopped with addresses still pending; pause_reason says why and what continues it. testing: an A/B sample is out and the winner is not yet decided or not yet handed on. sent: every address dealt with. failed: refused before sending (reputation gate, plan allowance, A/B sample too small, sending domain not verified or not marketing) or stopped by an unexpected error; see failure_reason. There is no canceled status."
},
"scheduled_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When it is due to start. null until scheduled, and again when unscheduled."
},
"started_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When a run last claimed it. Rewritten by every run, including each resume. null before the first."
},
"completed_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When it finished as sent or failed; null before that."
},
"pause_reason": {
"type": [
"string",
"null"
],
"description": "Set only while paused: why, in words you can act on (warm-up limit, 24-hour quota, throttling, no postal address, suspension, an interrupted run). null otherwise; cleared when a run picks it up."
},
"resume_after": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "Set while paused on the sending domain's warm-up allowance: when it renews (the next 00:00 UTC). The worker resumes the campaign on its own after that, and POST /v1/broadcasts/{id}/resume answers 409 before it. A warm-up pause is the protection working, not a failure. null otherwise."
},
"failure_reason": {
"type": [
"string",
"null"
],
"description": "Why it failed. Set on every failed campaign, null on every other."
},
"total_recipients": {
"type": "integer",
"description": "Size of the frozen audience after suppressions and topic opt-outs. 0 until the first run freezes it."
},
"sent_count": {
"type": "integer",
"description": "Messages accepted for delivery so far."
},
"failed_count": {
"type": "integer",
"description": "Messages the provider refused. Throttled messages and ones held back by a suspension or a missing postal address are not counted: they go back to pending and the campaign pauses."
},
"created_at": {
"type": "string",
"format": "date-time"
},
"variants": {
"type": "array",
"items": {
"$ref": "#/$defs/BroadcastVariantRecord"
},
"description": "The arms of an A/B test; [] on a campaign that is not a test."
},
"ab_test": {
"description": "A/B tests only; null otherwise.",
"anyOf": [
{
"allOf": [
{
"$ref": "#/$defs/BroadcastAbTestState"
}
]
},
{
"type": "null"
}
]
},
"progress": {
"description": "While sending, paused or testing (not on create or update); null otherwise.",
"anyOf": [
{
"allOf": [
{
"$ref": "#/$defs/BroadcastProgress"
}
]
},
{
"type": "null"
}
]
},
"warnings": {
"type": "array",
"items": {
"type": "string"
},
"description": "Settings that will not do what they say yet (today, metric 'click' without click tracking). Derived from the stored campaign, so create, update, list and retrieve say the same thing; [] when there is nothing to say."
}
},
"$defs": {
"BroadcastAbTestState": {
"type": "object",
"description": "The A/B block on a campaign. null on a campaign without variants.",
"required": [
"metric",
"goal_id",
"sample_share",
"decide_after_minutes",
"sample_completed_at",
"decide_at",
"winner",
"decided_by",
"decided_at",
"results"
],
"properties": {
"metric": {
"type": "string",
"enum": [
"open",
"click",
"conversion"
]
},
"goal_id": {
"type": [
"string",
"null"
],
"description": "The conversion goal a conversion test decides on; null for any goal, and for open and click tests."
},
"sample_share": {
"type": "number",
"description": "0.05 to 1. Always 1 for a send-time test."
},
"decide_after_minutes": {
"type": "integer"
},
"sample_completed_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When the run that finished sending the sample ended. Set once."
},
"decide_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When the worker decides on its own: sample_completed_at plus decide_after_minutes."
},
"winner": {
"type": [
"string",
"null"
],
"description": "The winning variant's key."
},
"decided_by": {
"type": [
"string",
"null"
],
"enum": [
"auto",
"manual",
null
],
"description": "'auto' for the worker, 'manual' for POST /v1/broadcasts/{id}/winner."
},
"decided_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"results": {
"type": "array",
"items": {
"$ref": "#/$defs/VariantResult"
},
"description": "Computed live once the campaign has left draft, by retrieve, the list and the send, resume and winner actions. Create and update return the snapshot taken when the winner was decided, which is an empty array before that."
}
}
},
"BroadcastProgress": {
"type": "object",
"description": "Counted from the frozen audience. Set while the campaign is sending, paused or testing, on retrieve, the list and the send, resume and winner actions; null on create and update and in every other status. All counts are 0 in the moment between a run claiming the campaign and freezing its audience.",
"required": [
"pending",
"sent",
"failed",
"skipped",
"by_variant"
],
"properties": {
"pending": {
"type": "integer",
"description": "Addresses not yet dealt with, including any a run has claimed and not finished."
},
"sent": {
"type": "integer",
"description": "Addresses whose message the provider accepted."
},
"failed": {
"type": "integer",
"description": "Addresses whose message the provider refused. Throttled addresses, and addresses held back by a suspension or a missing postal address, stay in pending."
},
"skipped": {
"type": "integer",
"description": "Addresses suppressed or opted out of the topic between the freeze and their turn, or on a domain that cannot receive mail. They have no message, so they never appear in /recipients."
},
"by_variant": {
"type": [
"array",
"null"
],
"description": "A/B tests only; null otherwise. One row per variant in the campaign's order, then one last row with key null for the addresses outside the sample still waiting for the winner. A list rather than an object keyed by variant, so no field name depends on your variant keys.",
"items": {
"type": "object",
"required": [
"key",
"pending",
"sent",
"failed",
"skipped"
],
"properties": {
"key": {
"type": [
"string",
"null"
],
"description": "The variant's key; null on the row for the addresses waiting for the winner."
},
"pending": {
"type": "integer",
"description": "Addresses not yet dealt with, including any a run has claimed and not finished."
},
"sent": {
"type": "integer",
"description": "Addresses whose message the provider accepted."
},
"failed": {
"type": "integer",
"description": "Addresses whose message the provider refused. Throttled addresses, and addresses held back by a suspension or a missing postal address, stay in pending."
},
"skipped": {
"type": "integer",
"description": "Addresses suppressed or opted out of the topic between the freeze and their turn, or on a domain that cannot receive mail. They have no message, so they never appear in /recipients."
}
}
}
}
}
},
"BroadcastVariantRecord": {
"type": "object",
"description": "One arm of an A/B test as a campaign returns it. Unset overrides are null, not absent.",
"required": [
"key",
"subject",
"from_name",
"send_at"
],
"properties": {
"key": {
"type": "string"
},
"subject": {
"type": [
"string",
"null"
],
"description": "null when the variant uses the campaign's subject."
},
"from_name": {
"type": [
"string",
"null"
],
"description": "null when the variant uses the campaign's from_name."
},
"send_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "Set on every variant of a send-time test, null on every variant otherwise."
}
}
},
"SegmentDateCondition": {
"type": "object",
"description": "A date compared with now, in UTC, each time the segment is counted, listed or sent. A contact with no value for the field never matches, under any op: someone who never opened has not opened more than 30 days ago. A campaign's audience is fixed when it starts, so a send that resumes later does not re-evaluate it.",
"required": [
"field",
"op",
"days"
],
"properties": {
"field": {
"type": "string",
"pattern": "^(created_at|last_opened_at|last_clicked_at|last_active_at|attributes\\.(?!\\$)[^.\\u0000]+)$",
"description": "created_at (when the contact was added to the workspace), last_opened_at, last_clicked_at, last_active_at, or attributes.<key> for a date-valued attribute such as attributes.trial_ends_at. An attribute is read as an ISO 8601 string (\"2026-11-04\" is midnight UTC; an offset such as +02:00 is honoured) or a stored date. A value that does not parse as a date, a number or a boolean does not match. Anything else is 422 invalid_request."
},
"op": {
"type": "string",
"enum": [
"older_than_days",
"within_last_days",
"within_next_days",
"after_next_days"
],
"description": "older_than_days: before now minus days (more than N days ago). within_last_days: from now minus days up to now. within_next_days: from now up to now plus days. after_next_days: after now plus days (more than N days from now)."
},
"days": {
"type": "integer",
"minimum": 1,
"maximum": 3650
}
}
},
"VariantResult": {
"type": "object",
"description": "Per-variant figures. opened and clicked count unique recipients, not events.",
"required": [
"key",
"sent",
"opened",
"clicked",
"converted",
"open_rate",
"click_rate",
"conversion_rate"
],
"properties": {
"key": {
"type": "string"
},
"sent": {
"type": "integer",
"description": "Messages the provider accepted for this variant."
},
"opened": {
"type": "integer",
"description": "Unique recipients who opened, not open events."
},
"clicked": {
"type": "integer",
"description": "Unique recipients who clicked, not click events."
},
"open_rate": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "opened / sent; 0 when nothing was sent."
},
"click_rate": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "clicked / sent; 0 when nothing was sent."
},
"converted": {
"type": "integer",
"description": "Unique people with a conversion attributed to this variant, for the test's goal_id when it has one. Counted for every test, not only a conversion one."
},
"conversion_rate": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "converted / sent; 0 when nothing was sent."
}
}
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/sendraven-ai-broadcast"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.