curl --request PATCH \
--url https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"name": "<string>",
"subject": "<string>",
"fromName": "<string>",
"replyTo": "<string>",
"bodyHtml": "<string>",
"bodyDocument": "<string>",
"senderProfileId": "<string>",
"listId": "<string>",
"fieldMappings": {},
"scheduleType": "<string>",
"scheduledAt": "<string>",
"timezone": "<string>"
}
'import requests
url = "https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}"
payload = {
"name": "<string>",
"subject": "<string>",
"fromName": "<string>",
"replyTo": "<string>",
"bodyHtml": "<string>",
"bodyDocument": "<string>",
"senderProfileId": "<string>",
"listId": "<string>",
"fieldMappings": {},
"scheduleType": "<string>",
"scheduledAt": "<string>",
"timezone": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
subject: '<string>',
fromName: '<string>',
replyTo: '<string>',
bodyHtml: '<string>',
bodyDocument: '<string>',
senderProfileId: '<string>',
listId: '<string>',
fieldMappings: {},
scheduleType: '<string>',
scheduledAt: '<string>',
timezone: '<string>'
})
};
fetch('https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}', 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.parallellabs.app/api/v0/marketing-campaigns/{campaignId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'subject' => '<string>',
'fromName' => '<string>',
'replyTo' => '<string>',
'bodyHtml' => '<string>',
'bodyDocument' => '<string>',
'senderProfileId' => '<string>',
'listId' => '<string>',
'fieldMappings' => [
],
'scheduleType' => '<string>',
'scheduledAt' => '<string>',
'timezone' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"subject\": \"<string>\",\n \"fromName\": \"<string>\",\n \"replyTo\": \"<string>\",\n \"bodyHtml\": \"<string>\",\n \"bodyDocument\": \"<string>\",\n \"senderProfileId\": \"<string>\",\n \"listId\": \"<string>\",\n \"fieldMappings\": {},\n \"scheduleType\": \"<string>\",\n \"scheduledAt\": \"<string>\",\n \"timezone\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"subject\": \"<string>\",\n \"fromName\": \"<string>\",\n \"replyTo\": \"<string>\",\n \"bodyHtml\": \"<string>\",\n \"bodyDocument\": \"<string>\",\n \"senderProfileId\": \"<string>\",\n \"listId\": \"<string>\",\n \"fieldMappings\": {},\n \"scheduleType\": \"<string>\",\n \"scheduledAt\": \"<string>\",\n \"timezone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"subject\": \"<string>\",\n \"fromName\": \"<string>\",\n \"replyTo\": \"<string>\",\n \"bodyHtml\": \"<string>\",\n \"bodyDocument\": \"<string>\",\n \"senderProfileId\": \"<string>\",\n \"listId\": \"<string>\",\n \"fieldMappings\": {},\n \"scheduleType\": \"<string>\",\n \"scheduledAt\": \"<string>\",\n \"timezone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"companyId": "<string>",
"uid": "<string>",
"name": "<string>",
"subject": "<string>",
"fromName": "<string>",
"replyTo": "<string>",
"bodyHtml": "<string>",
"bodyDocument": "<string>",
"senderProfileId": "<string>",
"listId": "<string>",
"fieldMappings": {},
"scheduleType": "<string>",
"scheduledAt": "<string>",
"timezone": "<string>",
"status": "<string>",
"sentCount": 123,
"failedCount": 123,
"skippedCount": 123,
"totalRecipients": 123,
"startedAt": "<string>",
"completedAt": "<string>",
"created_date": "<string>",
"updated_date": "<string>",
"smartList": {
"id": "<string>",
"name": "<string>"
},
"senderProfile": {
"id": "<string>",
"name": "<string>",
"email": "<string>",
"integrationId": "<string>"
}
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Update a marketing campaign. Editable only while the campaign is in draft,
scheduled, cancelled, or failed status. Editing a scheduled campaign drops it back to draft until you re-schedule it.
curl --request PATCH \
--url https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"name": "<string>",
"subject": "<string>",
"fromName": "<string>",
"replyTo": "<string>",
"bodyHtml": "<string>",
"bodyDocument": "<string>",
"senderProfileId": "<string>",
"listId": "<string>",
"fieldMappings": {},
"scheduleType": "<string>",
"scheduledAt": "<string>",
"timezone": "<string>"
}
'import requests
url = "https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}"
payload = {
"name": "<string>",
"subject": "<string>",
"fromName": "<string>",
"replyTo": "<string>",
"bodyHtml": "<string>",
"bodyDocument": "<string>",
"senderProfileId": "<string>",
"listId": "<string>",
"fieldMappings": {},
"scheduleType": "<string>",
"scheduledAt": "<string>",
"timezone": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
subject: '<string>',
fromName: '<string>',
replyTo: '<string>',
bodyHtml: '<string>',
bodyDocument: '<string>',
senderProfileId: '<string>',
listId: '<string>',
fieldMappings: {},
scheduleType: '<string>',
scheduledAt: '<string>',
timezone: '<string>'
})
};
fetch('https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}', 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.parallellabs.app/api/v0/marketing-campaigns/{campaignId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'subject' => '<string>',
'fromName' => '<string>',
'replyTo' => '<string>',
'bodyHtml' => '<string>',
'bodyDocument' => '<string>',
'senderProfileId' => '<string>',
'listId' => '<string>',
'fieldMappings' => [
],
'scheduleType' => '<string>',
'scheduledAt' => '<string>',
'timezone' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"subject\": \"<string>\",\n \"fromName\": \"<string>\",\n \"replyTo\": \"<string>\",\n \"bodyHtml\": \"<string>\",\n \"bodyDocument\": \"<string>\",\n \"senderProfileId\": \"<string>\",\n \"listId\": \"<string>\",\n \"fieldMappings\": {},\n \"scheduleType\": \"<string>\",\n \"scheduledAt\": \"<string>\",\n \"timezone\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"subject\": \"<string>\",\n \"fromName\": \"<string>\",\n \"replyTo\": \"<string>\",\n \"bodyHtml\": \"<string>\",\n \"bodyDocument\": \"<string>\",\n \"senderProfileId\": \"<string>\",\n \"listId\": \"<string>\",\n \"fieldMappings\": {},\n \"scheduleType\": \"<string>\",\n \"scheduledAt\": \"<string>\",\n \"timezone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parallellabs.app/api/v0/marketing-campaigns/{campaignId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"subject\": \"<string>\",\n \"fromName\": \"<string>\",\n \"replyTo\": \"<string>\",\n \"bodyHtml\": \"<string>\",\n \"bodyDocument\": \"<string>\",\n \"senderProfileId\": \"<string>\",\n \"listId\": \"<string>\",\n \"fieldMappings\": {},\n \"scheduleType\": \"<string>\",\n \"scheduledAt\": \"<string>\",\n \"timezone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"companyId": "<string>",
"uid": "<string>",
"name": "<string>",
"subject": "<string>",
"fromName": "<string>",
"replyTo": "<string>",
"bodyHtml": "<string>",
"bodyDocument": "<string>",
"senderProfileId": "<string>",
"listId": "<string>",
"fieldMappings": {},
"scheduleType": "<string>",
"scheduledAt": "<string>",
"timezone": "<string>",
"status": "<string>",
"sentCount": 123,
"failedCount": 123,
"skippedCount": 123,
"totalRecipients": 123,
"startedAt": "<string>",
"completedAt": "<string>",
"created_date": "<string>",
"updated_date": "<string>",
"smartList": {
"id": "<string>",
"name": "<string>"
},
"senderProfile": {
"id": "<string>",
"name": "<string>",
"email": "<string>",
"integrationId": "<string>"
}
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Authorizations
Company API key - scoped to a specific company. Generate from the Integrations page in your dashboard.
Path Parameters
Body
Fields to update (include only fields you want to change)
Request body for updating a marketing campaign (only include fields to change). Editable only while the campaign is in draft, scheduled, cancelled, or failed status.
Internal campaign name
Email subject line
Display name shown in the From: header
Optional Reply-To email address. Must be a valid email if provided.
HTML email body. Supply without bodyDocument for HTML-based campaigns. On update, nonblank HTML replaces the previous body and clears the previous visual-builder document. Empty HTML preserves existing content.
Visual-builder JSON document for the email body. When supplied, the server renders bodyHtml from this document and it takes precedence over HTML input. Alternatively, supply bodyHtml without a document. Envelope: {"subject": string, "subTitle": string, "content": }. Every node is {"type": string, "attributes": {MJML attributes as string values, e.g. "padding": "10px 25px 10px 25px", "background-color": "#ffffff", "color": "#333333", "font-size": "16px", "align": "center", "width": "600px", "href", "src"}, "data": {"value": {...}}, "children": [...]}; attribute values must be strings (numbers are dropped). Tree: page -> (wrapper | section) -> section -> column -> content blocks. Content block types: "text" (data.value.content = inline HTML string), "image" (attributes.src, alt, href, width), "button" (data.value.content = label, attributes.href), "divider", "spacer" (attributes.height), "social" (data.value.elements = [{src, href, content, target}]), "navbar" (data.value.links = [{href, content}]), "raw" (data.value.content = raw MJML/HTML), plus "hero", "group", "accordion", "carousel" and "table". Each also has an "advanced_" variant (e.g. "advanced_text"), which is what the builder palette inserts; advanced content blocks placed directly under the page or a wrapper are auto-wrapped in a section/column. Page node: {"type": "page", "attributes": {"background-color": "#efeeea", "width": "600px"}, "data": {"value": {"breakpoint": "480px", "font-family": string, "font-size": "14px", "line-height": "1.7", "font-weight": "400", "text-color": "#000000", "content-background-color": string (optional), "headStyles": [{"content": css, "inline": bool}], "fonts": [{"name", "href"}], "headAttributes": "", "responsive": true}}}. Always set "responsive": true — a missing flag renders a fixed-width layout. Merge tokens pass through rendering untouched: {{content}} inside a text block marks where content-engine output is inserted when content is published as a campaign from this template; {{variableName}} tokens (e.g. {{First Name}}) are replaced per recipient from the smart-list row; {{unsubscribe}} becomes the per-recipient unsubscribe link.
Sender profile ID
Smart list ID whose rows become recipients
Field mapping for resolving recipient email from a list row
Schedule type (one of: now, scheduled)
ISO timestamp at which to send
IANA timezone name
Response
The updated marketing campaign
Marketing campaign object
Campaign ID
Company this campaign belongs to
User ID that created the campaign
Internal campaign name
Email subject line
Display name shown in the From: header
Reply-To email address used on outgoing emails
HTML body of the email; rendered from bodyDocument when a document is supplied
Visual-builder JSON document for the email body. When supplied, the server renders bodyHtml from this document and it takes precedence over HTML input. Alternatively, supply bodyHtml without a document. Envelope: {"subject": string, "subTitle": string, "content": }. Every node is {"type": string, "attributes": {MJML attributes as string values, e.g. "padding": "10px 25px 10px 25px", "background-color": "#ffffff", "color": "#333333", "font-size": "16px", "align": "center", "width": "600px", "href", "src"}, "data": {"value": {...}}, "children": [...]}; attribute values must be strings (numbers are dropped). Tree: page -> (wrapper | section) -> section -> column -> content blocks. Content block types: "text" (data.value.content = inline HTML string), "image" (attributes.src, alt, href, width), "button" (data.value.content = label, attributes.href), "divider", "spacer" (attributes.height), "social" (data.value.elements = [{src, href, content, target}]), "navbar" (data.value.links = [{href, content}]), "raw" (data.value.content = raw MJML/HTML), plus "hero", "group", "accordion", "carousel" and "table". Each also has an "advanced_" variant (e.g. "advanced_text"), which is what the builder palette inserts; advanced content blocks placed directly under the page or a wrapper are auto-wrapped in a section/column. Page node: {"type": "page", "attributes": {"background-color": "#efeeea", "width": "600px"}, "data": {"value": {"breakpoint": "480px", "font-family": string, "font-size": "14px", "line-height": "1.7", "font-weight": "400", "text-color": "#000000", "content-background-color": string (optional), "headStyles": [{"content": css, "inline": bool}], "fonts": [{"name", "href"}], "headAttributes": "", "responsive": true}}}. Always set "responsive": true — a missing flag renders a fixed-width layout. Merge tokens pass through rendering untouched: {{content}} inside a text block marks where content-engine output is inserted when content is published as a campaign from this template; {{variableName}} tokens (e.g. {{First Name}}) are replaced per recipient from the smart-list row; {{unsubscribe}} becomes the per-recipient unsubscribe link.
Sender profile ID
Smart list ID whose rows become recipients
Field mapping for resolving recipient email from a list row
Schedule type (now, scheduled)
ISO timestamp at which sending begins (for scheduled campaigns)
IANA timezone used to interpret scheduledAt
Campaign status (draft, scheduled, sending, sent, failed, cancelled)
Number of recipients the email has been sent to
Number of recipients that failed to send
Number of list rows skipped (missing email, duplicate, etc.)
Total rows in the associated smart list at read time
ISO timestamp when sending started
ISO timestamp when sending completed
ISO timestamp when the campaign was created
ISO timestamp when the campaign was last updated
Summary of the associated smart list
Show child attributes
Show child attributes
Summary of the sender profile
Show child attributes
Show child attributes

