curl --request POST \
--url https://app.manypi.com/api/integrations/migrations/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"options": {
"campaigns": [
"c1f0a2b3-instantly-campaign-id"
],
"recreateCampaigns": true,
"importLeads": true,
"doNotContact": true,
"enrollNotContacted": true,
"duplicates": "merge"
}
}
'import requests
url = "https://app.manypi.com/api/integrations/migrations/{id}"
payload = { "options": {
"campaigns": ["c1f0a2b3-instantly-campaign-id"],
"recreateCampaigns": True,
"importLeads": True,
"doNotContact": True,
"enrollNotContacted": True,
"duplicates": "merge"
} }
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({
options: {
campaigns: ['c1f0a2b3-instantly-campaign-id'],
recreateCampaigns: true,
importLeads: true,
doNotContact: true,
enrollNotContacted: true,
duplicates: 'merge'
}
})
};
fetch('https://app.manypi.com/api/integrations/migrations/{id}', 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://app.manypi.com/api/integrations/migrations/{id}",
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([
'options' => [
'campaigns' => [
'c1f0a2b3-instantly-campaign-id'
],
'recreateCampaigns' => true,
'importLeads' => true,
'doNotContact' => true,
'enrollNotContacted' => true,
'duplicates' => 'merge'
]
]),
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://app.manypi.com/api/integrations/migrations/{id}"
payload := strings.NewReader("{\n \"options\": {\n \"campaigns\": [\n \"c1f0a2b3-instantly-campaign-id\"\n ],\n \"recreateCampaigns\": true,\n \"importLeads\": true,\n \"doNotContact\": true,\n \"enrollNotContacted\": true,\n \"duplicates\": \"merge\"\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://app.manypi.com/api/integrations/migrations/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"options\": {\n \"campaigns\": [\n \"c1f0a2b3-instantly-campaign-id\"\n ],\n \"recreateCampaigns\": true,\n \"importLeads\": true,\n \"doNotContact\": true,\n \"enrollNotContacted\": true,\n \"duplicates\": \"merge\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.manypi.com/api/integrations/migrations/{id}")
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 \"options\": {\n \"campaigns\": [\n \"c1f0a2b3-instantly-campaign-id\"\n ],\n \"recreateCampaigns\": true,\n \"importLeads\": true,\n \"doNotContact\": true,\n \"enrollNotContacted\": true,\n \"duplicates\": \"merge\"\n }\n}"
response = http.request(request)
puts response.read_body{
"job": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"provider": "<string>",
"account_label": "<string>",
"status": "scanned",
"scan": {
"label": "<string>",
"campaigns": [
{
"id": "<string>",
"name": "<string>",
"status": "<string>",
"emailSteps": 123,
"leads": 123
}
],
"leadsTotal": 123,
"blocklistTotal": 123,
"accounts": [
{
"email": "<string>",
"provider": "google",
"name": "<string>"
}
],
"notes": [
"<string>"
]
},
"options": {
"campaigns": [],
"recreateCampaigns": true,
"importLeads": true,
"doNotContact": true,
"enrollNotContacted": true,
"duplicates": "merge",
"asCustomers": false
},
"progress": {
"phase": "blocklist",
"campaignIndex": 123,
"campaignMap": {},
"counts": {
"suppressed": 123,
"campaigns": 123,
"steps": 123,
"created": 123,
"updated": 123,
"skipped": 123,
"overLimit": 123,
"failed": 123,
"enrolled": 123,
"customFields": 123
},
"warnings": [
"<string>"
],
"skippedSteps": {},
"leadsSeen": 123
},
"result": {},
"error": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"finished_at": "2023-11-07T05:31:56Z"
}
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}Start an import
Say what to bring and start. The order is fixed: the do-not-contact list first, so nothing that arrives later is queued before its opt-out is known; then the chosen campaigns, recreated as draft campaigns with their email steps; then their leads, with custom variables as lead fields.
Nothing is sent. The campaigns stay drafts with no inbox until you launch them in ManyPI. With enrollNotContacted, leads the old tool never emailed are queued in their new campaign, so the sequence carries on once it is launched. Leads that replied, bounced or unsubscribed are never queued.
The first slice runs inside this request, so the response already shows progress. After that the import runs in slices: call POST /api/integrations/migrations/{id}/advance until status is done. An import nobody advances is picked up by ManyPI’s scheduler, a few seconds every five minutes, so it finishes either way.
Only campaign ids the scan found are used; others are dropped. Calling this on an import that is not scanned returns it unchanged.
At most 100,000 leads per import, and the plan’s lead allowance applies (leads over it are counted in overLimit). Custom fields need the Starter plan and queuing leads needs a paid plan; without them the import still runs and says what stayed behind in warnings.
Requires the write permission.
curl --request POST \
--url https://app.manypi.com/api/integrations/migrations/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"options": {
"campaigns": [
"c1f0a2b3-instantly-campaign-id"
],
"recreateCampaigns": true,
"importLeads": true,
"doNotContact": true,
"enrollNotContacted": true,
"duplicates": "merge"
}
}
'import requests
url = "https://app.manypi.com/api/integrations/migrations/{id}"
payload = { "options": {
"campaigns": ["c1f0a2b3-instantly-campaign-id"],
"recreateCampaigns": True,
"importLeads": True,
"doNotContact": True,
"enrollNotContacted": True,
"duplicates": "merge"
} }
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({
options: {
campaigns: ['c1f0a2b3-instantly-campaign-id'],
recreateCampaigns: true,
importLeads: true,
doNotContact: true,
enrollNotContacted: true,
duplicates: 'merge'
}
})
};
fetch('https://app.manypi.com/api/integrations/migrations/{id}', 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://app.manypi.com/api/integrations/migrations/{id}",
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([
'options' => [
'campaigns' => [
'c1f0a2b3-instantly-campaign-id'
],
'recreateCampaigns' => true,
'importLeads' => true,
'doNotContact' => true,
'enrollNotContacted' => true,
'duplicates' => 'merge'
]
]),
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://app.manypi.com/api/integrations/migrations/{id}"
payload := strings.NewReader("{\n \"options\": {\n \"campaigns\": [\n \"c1f0a2b3-instantly-campaign-id\"\n ],\n \"recreateCampaigns\": true,\n \"importLeads\": true,\n \"doNotContact\": true,\n \"enrollNotContacted\": true,\n \"duplicates\": \"merge\"\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://app.manypi.com/api/integrations/migrations/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"options\": {\n \"campaigns\": [\n \"c1f0a2b3-instantly-campaign-id\"\n ],\n \"recreateCampaigns\": true,\n \"importLeads\": true,\n \"doNotContact\": true,\n \"enrollNotContacted\": true,\n \"duplicates\": \"merge\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.manypi.com/api/integrations/migrations/{id}")
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 \"options\": {\n \"campaigns\": [\n \"c1f0a2b3-instantly-campaign-id\"\n ],\n \"recreateCampaigns\": true,\n \"importLeads\": true,\n \"doNotContact\": true,\n \"enrollNotContacted\": true,\n \"duplicates\": \"merge\"\n }\n}"
response = http.request(request)
puts response.read_body{
"job": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"provider": "<string>",
"account_label": "<string>",
"status": "scanned",
"scan": {
"label": "<string>",
"campaigns": [
{
"id": "<string>",
"name": "<string>",
"status": "<string>",
"emailSteps": 123,
"leads": 123
}
],
"leadsTotal": 123,
"blocklistTotal": 123,
"accounts": [
{
"email": "<string>",
"provider": "google",
"name": "<string>"
}
],
"notes": [
"<string>"
]
},
"options": {
"campaigns": [],
"recreateCampaigns": true,
"importLeads": true,
"doNotContact": true,
"enrollNotContacted": true,
"duplicates": "merge",
"asCustomers": false
},
"progress": {
"phase": "blocklist",
"campaignIndex": 123,
"campaignMap": {},
"counts": {
"suppressed": 123,
"campaigns": 123,
"steps": 123,
"created": 123,
"updated": 123,
"skipped": 123,
"overLimit": 123,
"failed": 123,
"enrolled": 123,
"customFields": 123
},
"warnings": [
"<string>"
],
"skippedSteps": {},
"leadsSeen": 123
},
"result": {},
"error": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"finished_at": "2023-11-07T05:31:56Z"
}
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}{
"error": "<string>",
"code": "<string>",
"details": "<unknown>"
}Authorizations
A ManyPI API key (mpi_...) from the profile menu → API Access in the dashboard, or an OAuth 2.1 access token obtained through the MCP consent flow.
Path Parameters
The import id, from POST /api/integrations/migrations.
Body
Show child attributes
Show child attributes
Response
The import, now running (or already done for a small account).
Show child attributes
Show child attributes
