curl --request POST \
--url https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"subject": "Follow up on our conversation",
"message": "Hi {{firstName}}, I wanted to follow up...",
"isEnabled": true,
"attachmentIds": [
101,
102
]
}
'import requests
url = "https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants"
payload = {
"subject": "Follow up on our conversation",
"message": "Hi {{firstName}}, I wanted to follow up...",
"isEnabled": True,
"attachmentIds": [101, 102]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
subject: 'Follow up on our conversation',
message: 'Hi {{firstName}}, I wanted to follow up...',
isEnabled: true,
attachmentIds: [101, 102]
})
};
fetch('https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants', 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.reply.io/v3/sequences/{id}/steps/{step_id}/variants",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'subject' => 'Follow up on our conversation',
'message' => 'Hi {{firstName}}, I wanted to follow up...',
'isEnabled' => true,
'attachmentIds' => [
101,
102
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.reply.io/v3/sequences/{id}/steps/{step_id}/variants"
payload := strings.NewReader("{\n \"subject\": \"Follow up on our conversation\",\n \"message\": \"Hi {{firstName}}, I wanted to follow up...\",\n \"isEnabled\": true,\n \"attachmentIds\": [\n 101,\n 102\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.post("https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"subject\": \"Follow up on our conversation\",\n \"message\": \"Hi {{firstName}}, I wanted to follow up...\",\n \"isEnabled\": true,\n \"attachmentIds\": [\n 101,\n 102\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"subject\": \"Follow up on our conversation\",\n \"message\": \"Hi {{firstName}}, I wanted to follow up...\",\n \"isEnabled\": true,\n \"attachmentIds\": [\n 101,\n 102\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": 1,
"subject": "Follow up on our conversation",
"message": "Hi {{firstName}}, I wanted to follow up...",
"isEnabled": true,
"hasAttachments": false
}Create a step variant
sequences:write scope (or a broader one that includes it).
Add another variant so a step rotates between bodies. Text variants use JSON; LinkedIn voice uses multipart form data.
curl --request POST \
--url https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"subject": "Follow up on our conversation",
"message": "Hi {{firstName}}, I wanted to follow up...",
"isEnabled": true,
"attachmentIds": [
101,
102
]
}
'import requests
url = "https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants"
payload = {
"subject": "Follow up on our conversation",
"message": "Hi {{firstName}}, I wanted to follow up...",
"isEnabled": True,
"attachmentIds": [101, 102]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
subject: 'Follow up on our conversation',
message: 'Hi {{firstName}}, I wanted to follow up...',
isEnabled: true,
attachmentIds: [101, 102]
})
};
fetch('https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants', 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.reply.io/v3/sequences/{id}/steps/{step_id}/variants",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'subject' => 'Follow up on our conversation',
'message' => 'Hi {{firstName}}, I wanted to follow up...',
'isEnabled' => true,
'attachmentIds' => [
101,
102
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.reply.io/v3/sequences/{id}/steps/{step_id}/variants"
payload := strings.NewReader("{\n \"subject\": \"Follow up on our conversation\",\n \"message\": \"Hi {{firstName}}, I wanted to follow up...\",\n \"isEnabled\": true,\n \"attachmentIds\": [\n 101,\n 102\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.post("https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"subject\": \"Follow up on our conversation\",\n \"message\": \"Hi {{firstName}}, I wanted to follow up...\",\n \"isEnabled\": true,\n \"attachmentIds\": [\n 101,\n 102\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/sequences/{id}/steps/{step_id}/variants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"subject\": \"Follow up on our conversation\",\n \"message\": \"Hi {{firstName}}, I wanted to follow up...\",\n \"isEnabled\": true,\n \"attachmentIds\": [\n 101,\n 102\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": 1,
"subject": "Follow up on our conversation",
"message": "Hi {{firstName}}, I wanted to follow up...",
"isEnabled": true,
"hasAttachments": false
}Authorizations
Authenticate every request with a Bearer token. Pass your Reply API key in the
Authorization header:
Authorization: Bearer <your-api-key>
Get your API key from the Reply dashboard: Settings → API Key.
Body
Request body for creating or updating a text variant
Message content of the variant
Subject line of the variant
Whether the variant is enabled
IDs of previously uploaded attachments to attach to this variant. Upload files via POST /v3/attachments first to obtain attachment IDs.
A variant may carry up to 3 attachments. Omit or pass null to leave attachments unchanged on update; pass an empty array to clear existing attachments.
3Response
Variant created successfully
A text variant for a sequence step
Unique identifier for the variant
Subject line of the variant
Message content of the variant
Whether the variant is enabled
Whether the variant has any attachments. To retrieve or modify attachments, use GET /v3/attachments and the attachmentIds field on create/update.