curl --request POST \
--url https://app.manypi.com/api/leads/import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"duplicates": "merge",
"declare_fields": [
{
"label": "Ecommerce platform",
"type": "text"
}
],
"rows": [
{
"company": "Acme GmbH",
"full_name": "Lena Roth",
"title": "Head of Growth",
"email": "lena@acme.de",
"domain": "acme.de",
"custom": {
"ecommerce_platform": "Shopify"
}
}
]
}
'import requests
url = "https://app.manypi.com/api/leads/import"
payload = {
"duplicates": "merge",
"declare_fields": [
{
"label": "Ecommerce platform",
"type": "text"
}
],
"rows": [
{
"company": "Acme GmbH",
"full_name": "Lena Roth",
"title": "Head of Growth",
"email": "lena@acme.de",
"domain": "acme.de",
"custom": { "ecommerce_platform": "Shopify" }
}
]
}
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({
duplicates: 'merge',
declare_fields: [{label: 'Ecommerce platform', type: 'text'}],
rows: [
{
company: 'Acme GmbH',
full_name: 'Lena Roth',
title: 'Head of Growth',
email: 'lena@acme.de',
domain: 'acme.de',
custom: {ecommerce_platform: 'Shopify'}
}
]
})
};
fetch('https://app.manypi.com/api/leads/import', 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/leads/import",
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([
'duplicates' => 'merge',
'declare_fields' => [
[
'label' => 'Ecommerce platform',
'type' => 'text'
]
],
'rows' => [
[
'company' => 'Acme GmbH',
'full_name' => 'Lena Roth',
'title' => 'Head of Growth',
'email' => 'lena@acme.de',
'domain' => 'acme.de',
'custom' => [
'ecommerce_platform' => 'Shopify'
]
]
]
]),
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/leads/import"
payload := strings.NewReader("{\n \"duplicates\": \"merge\",\n \"declare_fields\": [\n {\n \"label\": \"Ecommerce platform\",\n \"type\": \"text\"\n }\n ],\n \"rows\": [\n {\n \"company\": \"Acme GmbH\",\n \"full_name\": \"Lena Roth\",\n \"title\": \"Head of Growth\",\n \"email\": \"lena@acme.de\",\n \"domain\": \"acme.de\",\n \"custom\": {\n \"ecommerce_platform\": \"Shopify\"\n }\n }\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/leads/import")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"duplicates\": \"merge\",\n \"declare_fields\": [\n {\n \"label\": \"Ecommerce platform\",\n \"type\": \"text\"\n }\n ],\n \"rows\": [\n {\n \"company\": \"Acme GmbH\",\n \"full_name\": \"Lena Roth\",\n \"title\": \"Head of Growth\",\n \"email\": \"lena@acme.de\",\n \"domain\": \"acme.de\",\n \"custom\": {\n \"ecommerce_platform\": \"Shopify\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.manypi.com/api/leads/import")
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 \"duplicates\": \"merge\",\n \"declare_fields\": [\n {\n \"label\": \"Ecommerce platform\",\n \"type\": \"text\"\n }\n ],\n \"rows\": [\n {\n \"company\": \"Acme GmbH\",\n \"full_name\": \"Lena Roth\",\n \"title\": \"Head of Growth\",\n \"email\": \"lena@acme.de\",\n \"domain\": \"acme.de\",\n \"custom\": {\n \"ecommerce_platform\": \"Shopify\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"created": 123,
"updated": 123,
"skippedDuplicate": 123,
"skippedNoIdentity": 123,
"skippedOverLimit": 123,
"skippedOtherWorkspace": 123,
"failed": [
{
"index": 123,
"error": "<string>"
}
],
"remaining": 123,
"declared": [
"<string>"
],
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}Import leads
Write a batch of leads. Up to 100 rows per request — chunk larger files client-side so a big import cannot outlive the request timeout and so progress is real.
declare_fields lets the same request that carries the first chunk also declare the custom columns those rows write into. It is idempotent, so resending the declarations with every chunk is harmless.
A full workspace still returns 200 — the rows that fitted were written — with code: "lead_limit" in the body.
Requires the write permission.
curl --request POST \
--url https://app.manypi.com/api/leads/import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"duplicates": "merge",
"declare_fields": [
{
"label": "Ecommerce platform",
"type": "text"
}
],
"rows": [
{
"company": "Acme GmbH",
"full_name": "Lena Roth",
"title": "Head of Growth",
"email": "lena@acme.de",
"domain": "acme.de",
"custom": {
"ecommerce_platform": "Shopify"
}
}
]
}
'import requests
url = "https://app.manypi.com/api/leads/import"
payload = {
"duplicates": "merge",
"declare_fields": [
{
"label": "Ecommerce platform",
"type": "text"
}
],
"rows": [
{
"company": "Acme GmbH",
"full_name": "Lena Roth",
"title": "Head of Growth",
"email": "lena@acme.de",
"domain": "acme.de",
"custom": { "ecommerce_platform": "Shopify" }
}
]
}
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({
duplicates: 'merge',
declare_fields: [{label: 'Ecommerce platform', type: 'text'}],
rows: [
{
company: 'Acme GmbH',
full_name: 'Lena Roth',
title: 'Head of Growth',
email: 'lena@acme.de',
domain: 'acme.de',
custom: {ecommerce_platform: 'Shopify'}
}
]
})
};
fetch('https://app.manypi.com/api/leads/import', 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/leads/import",
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([
'duplicates' => 'merge',
'declare_fields' => [
[
'label' => 'Ecommerce platform',
'type' => 'text'
]
],
'rows' => [
[
'company' => 'Acme GmbH',
'full_name' => 'Lena Roth',
'title' => 'Head of Growth',
'email' => 'lena@acme.de',
'domain' => 'acme.de',
'custom' => [
'ecommerce_platform' => 'Shopify'
]
]
]
]),
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/leads/import"
payload := strings.NewReader("{\n \"duplicates\": \"merge\",\n \"declare_fields\": [\n {\n \"label\": \"Ecommerce platform\",\n \"type\": \"text\"\n }\n ],\n \"rows\": [\n {\n \"company\": \"Acme GmbH\",\n \"full_name\": \"Lena Roth\",\n \"title\": \"Head of Growth\",\n \"email\": \"lena@acme.de\",\n \"domain\": \"acme.de\",\n \"custom\": {\n \"ecommerce_platform\": \"Shopify\"\n }\n }\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/leads/import")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"duplicates\": \"merge\",\n \"declare_fields\": [\n {\n \"label\": \"Ecommerce platform\",\n \"type\": \"text\"\n }\n ],\n \"rows\": [\n {\n \"company\": \"Acme GmbH\",\n \"full_name\": \"Lena Roth\",\n \"title\": \"Head of Growth\",\n \"email\": \"lena@acme.de\",\n \"domain\": \"acme.de\",\n \"custom\": {\n \"ecommerce_platform\": \"Shopify\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.manypi.com/api/leads/import")
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 \"duplicates\": \"merge\",\n \"declare_fields\": [\n {\n \"label\": \"Ecommerce platform\",\n \"type\": \"text\"\n }\n ],\n \"rows\": [\n {\n \"company\": \"Acme GmbH\",\n \"full_name\": \"Lena Roth\",\n \"title\": \"Head of Growth\",\n \"email\": \"lena@acme.de\",\n \"domain\": \"acme.de\",\n \"custom\": {\n \"ecommerce_platform\": \"Shopify\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"created": 123,
"updated": 123,
"skippedDuplicate": 123,
"skippedNoIdentity": 123,
"skippedOverLimit": 123,
"skippedOtherWorkspace": 123,
"failed": [
{
"index": 123,
"error": "<string>"
}
],
"remaining": 123,
"declared": [
"<string>"
],
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}{
"error": "<string>",
"code": "<string>"
}Authorizations
A ManyPI API key (mpi_...) from Settings → API keys, or an OAuth 2.1 access token obtained through the MCP consent flow.
Body
1 - 100 elementsShow child attributes
Show child attributes
merge fills blanks on the existing lead; overwrite lets incoming values win; skip leaves it untouched.
merge, overwrite, skip 60Show child attributes
Show child attributes
Response
Per-row outcome for the chunk.
No email and no domain-plus-name, so there is nothing to file the row under.
Show child attributes
Show child attributes
Lead slots left after this batch.
lead_limit when the plan filled up mid-import.
