curl --request POST \
--url https://api.politicalcomms.com/v1/contact-lists/import \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"source_url": "https://example.com/path/to/list.csv",
"organization_id": "01HX0000000000000000000000",
"brand_id": "01HX0000000000000000000001",
"list_name": "Spring Outreach List",
"phone_column": "phone",
"merge_tags": {
"first_name": "first_name",
"last_name": "last_name",
"address": "street",
"address_line_2": "street2",
"city": "city",
"state": "state",
"zip": "zip",
"custom_fields": [
{
"csv_column": "donor_tier",
"merge_tag": "tier"
}
]
}
}
'import requests
url = "https://api.politicalcomms.com/v1/contact-lists/import"
payload = {
"source_url": "https://example.com/path/to/list.csv",
"organization_id": "01HX0000000000000000000000",
"brand_id": "01HX0000000000000000000001",
"list_name": "Spring Outreach List",
"phone_column": "phone",
"merge_tags": {
"first_name": "first_name",
"last_name": "last_name",
"address": "street",
"address_line_2": "street2",
"city": "city",
"state": "state",
"zip": "zip",
"custom_fields": [
{
"csv_column": "donor_tier",
"merge_tag": "tier"
}
]
}
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source_url: 'https://example.com/path/to/list.csv',
organization_id: '01HX0000000000000000000000',
brand_id: '01HX0000000000000000000001',
list_name: 'Spring Outreach List',
phone_column: 'phone',
merge_tags: {
first_name: 'first_name',
last_name: 'last_name',
address: 'street',
address_line_2: 'street2',
city: 'city',
state: 'state',
zip: 'zip',
custom_fields: [{csv_column: 'donor_tier', merge_tag: 'tier'}]
}
})
};
fetch('https://api.politicalcomms.com/v1/contact-lists/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://api.politicalcomms.com/v1/contact-lists/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([
'source_url' => 'https://example.com/path/to/list.csv',
'organization_id' => '01HX0000000000000000000000',
'brand_id' => '01HX0000000000000000000001',
'list_name' => 'Spring Outreach List',
'phone_column' => 'phone',
'merge_tags' => [
'first_name' => 'first_name',
'last_name' => 'last_name',
'address' => 'street',
'address_line_2' => 'street2',
'city' => 'city',
'state' => 'state',
'zip' => 'zip',
'custom_fields' => [
[
'csv_column' => 'donor_tier',
'merge_tag' => 'tier'
]
]
]
]),
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.politicalcomms.com/v1/contact-lists/import"
payload := strings.NewReader("{\n \"source_url\": \"https://example.com/path/to/list.csv\",\n \"organization_id\": \"01HX0000000000000000000000\",\n \"brand_id\": \"01HX0000000000000000000001\",\n \"list_name\": \"Spring Outreach List\",\n \"phone_column\": \"phone\",\n \"merge_tags\": {\n \"first_name\": \"first_name\",\n \"last_name\": \"last_name\",\n \"address\": \"street\",\n \"address_line_2\": \"street2\",\n \"city\": \"city\",\n \"state\": \"state\",\n \"zip\": \"zip\",\n \"custom_fields\": [\n {\n \"csv_column\": \"donor_tier\",\n \"merge_tag\": \"tier\"\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", 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.post("https://api.politicalcomms.com/v1/contact-lists/import")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source_url\": \"https://example.com/path/to/list.csv\",\n \"organization_id\": \"01HX0000000000000000000000\",\n \"brand_id\": \"01HX0000000000000000000001\",\n \"list_name\": \"Spring Outreach List\",\n \"phone_column\": \"phone\",\n \"merge_tags\": {\n \"first_name\": \"first_name\",\n \"last_name\": \"last_name\",\n \"address\": \"street\",\n \"address_line_2\": \"street2\",\n \"city\": \"city\",\n \"state\": \"state\",\n \"zip\": \"zip\",\n \"custom_fields\": [\n {\n \"csv_column\": \"donor_tier\",\n \"merge_tag\": \"tier\"\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.politicalcomms.com/v1/contact-lists/import")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_url\": \"https://example.com/path/to/list.csv\",\n \"organization_id\": \"01HX0000000000000000000000\",\n \"brand_id\": \"01HX0000000000000000000001\",\n \"list_name\": \"Spring Outreach List\",\n \"phone_column\": \"phone\",\n \"merge_tags\": {\n \"first_name\": \"first_name\",\n \"last_name\": \"last_name\",\n \"address\": \"street\",\n \"address_line_2\": \"street2\",\n \"city\": \"city\",\n \"state\": \"state\",\n \"zip\": \"zip\",\n \"custom_fields\": [\n {\n \"csv_column\": \"donor_tier\",\n \"merge_tag\": \"tier\"\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "cl_abc123",
"list_name": "Spring Outreach List",
"status": "importing",
"created_at": "2025-03-15T10:00:00Z"
}
}{
"success": false,
"error": "Invalid request parameters",
"code": "BAD_REQUEST",
"statusCode": 400
}{
"success": false,
"error": "The provided API key is invalid or has been revoked",
"code": "INVALID_API_KEY",
"statusCode": 401
}{
"success": false,
"error": "API key lacks the permission scope this endpoint requires",
"code": "PERMISSION_DENIED",
"statusCode": 403
}{
"success": false,
"error": "Rate limit exceeded",
"message": "Maximum 100 requests per 60 seconds",
"code": "RATE_LIMIT_EXCEEDED",
"statusCode": 429,
"retryAfter": 12
}{
"success": true,
"error": "<string>",
"code": "<string>",
"statusCode": 123
}Import Contact List
Asynchronous job: import a CSV from a client-supplied presigned S3 or public HTTPS URL. Returns immediately with the created resource; poll GET /contact-lists/{id} until status is ready.
curl --request POST \
--url https://api.politicalcomms.com/v1/contact-lists/import \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"source_url": "https://example.com/path/to/list.csv",
"organization_id": "01HX0000000000000000000000",
"brand_id": "01HX0000000000000000000001",
"list_name": "Spring Outreach List",
"phone_column": "phone",
"merge_tags": {
"first_name": "first_name",
"last_name": "last_name",
"address": "street",
"address_line_2": "street2",
"city": "city",
"state": "state",
"zip": "zip",
"custom_fields": [
{
"csv_column": "donor_tier",
"merge_tag": "tier"
}
]
}
}
'import requests
url = "https://api.politicalcomms.com/v1/contact-lists/import"
payload = {
"source_url": "https://example.com/path/to/list.csv",
"organization_id": "01HX0000000000000000000000",
"brand_id": "01HX0000000000000000000001",
"list_name": "Spring Outreach List",
"phone_column": "phone",
"merge_tags": {
"first_name": "first_name",
"last_name": "last_name",
"address": "street",
"address_line_2": "street2",
"city": "city",
"state": "state",
"zip": "zip",
"custom_fields": [
{
"csv_column": "donor_tier",
"merge_tag": "tier"
}
]
}
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source_url: 'https://example.com/path/to/list.csv',
organization_id: '01HX0000000000000000000000',
brand_id: '01HX0000000000000000000001',
list_name: 'Spring Outreach List',
phone_column: 'phone',
merge_tags: {
first_name: 'first_name',
last_name: 'last_name',
address: 'street',
address_line_2: 'street2',
city: 'city',
state: 'state',
zip: 'zip',
custom_fields: [{csv_column: 'donor_tier', merge_tag: 'tier'}]
}
})
};
fetch('https://api.politicalcomms.com/v1/contact-lists/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://api.politicalcomms.com/v1/contact-lists/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([
'source_url' => 'https://example.com/path/to/list.csv',
'organization_id' => '01HX0000000000000000000000',
'brand_id' => '01HX0000000000000000000001',
'list_name' => 'Spring Outreach List',
'phone_column' => 'phone',
'merge_tags' => [
'first_name' => 'first_name',
'last_name' => 'last_name',
'address' => 'street',
'address_line_2' => 'street2',
'city' => 'city',
'state' => 'state',
'zip' => 'zip',
'custom_fields' => [
[
'csv_column' => 'donor_tier',
'merge_tag' => 'tier'
]
]
]
]),
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.politicalcomms.com/v1/contact-lists/import"
payload := strings.NewReader("{\n \"source_url\": \"https://example.com/path/to/list.csv\",\n \"organization_id\": \"01HX0000000000000000000000\",\n \"brand_id\": \"01HX0000000000000000000001\",\n \"list_name\": \"Spring Outreach List\",\n \"phone_column\": \"phone\",\n \"merge_tags\": {\n \"first_name\": \"first_name\",\n \"last_name\": \"last_name\",\n \"address\": \"street\",\n \"address_line_2\": \"street2\",\n \"city\": \"city\",\n \"state\": \"state\",\n \"zip\": \"zip\",\n \"custom_fields\": [\n {\n \"csv_column\": \"donor_tier\",\n \"merge_tag\": \"tier\"\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", 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.post("https://api.politicalcomms.com/v1/contact-lists/import")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source_url\": \"https://example.com/path/to/list.csv\",\n \"organization_id\": \"01HX0000000000000000000000\",\n \"brand_id\": \"01HX0000000000000000000001\",\n \"list_name\": \"Spring Outreach List\",\n \"phone_column\": \"phone\",\n \"merge_tags\": {\n \"first_name\": \"first_name\",\n \"last_name\": \"last_name\",\n \"address\": \"street\",\n \"address_line_2\": \"street2\",\n \"city\": \"city\",\n \"state\": \"state\",\n \"zip\": \"zip\",\n \"custom_fields\": [\n {\n \"csv_column\": \"donor_tier\",\n \"merge_tag\": \"tier\"\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.politicalcomms.com/v1/contact-lists/import")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_url\": \"https://example.com/path/to/list.csv\",\n \"organization_id\": \"01HX0000000000000000000000\",\n \"brand_id\": \"01HX0000000000000000000001\",\n \"list_name\": \"Spring Outreach List\",\n \"phone_column\": \"phone\",\n \"merge_tags\": {\n \"first_name\": \"first_name\",\n \"last_name\": \"last_name\",\n \"address\": \"street\",\n \"address_line_2\": \"street2\",\n \"city\": \"city\",\n \"state\": \"state\",\n \"zip\": \"zip\",\n \"custom_fields\": [\n {\n \"csv_column\": \"donor_tier\",\n \"merge_tag\": \"tier\"\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "cl_abc123",
"list_name": "Spring Outreach List",
"status": "importing",
"created_at": "2025-03-15T10:00:00Z"
}
}{
"success": false,
"error": "Invalid request parameters",
"code": "BAD_REQUEST",
"statusCode": 400
}{
"success": false,
"error": "The provided API key is invalid or has been revoked",
"code": "INVALID_API_KEY",
"statusCode": 401
}{
"success": false,
"error": "API key lacks the permission scope this endpoint requires",
"code": "PERMISSION_DENIED",
"statusCode": 403
}{
"success": false,
"error": "Rate limit exceeded",
"message": "Maximum 100 requests per 60 seconds",
"code": "RATE_LIMIT_EXCEEDED",
"statusCode": 429,
"retryAfter": 12
}{
"success": true,
"error": "<string>",
"code": "<string>",
"statusCode": 123
}Authorizations
Authenticate every request by passing your API key in the X-API-Key header. Keys are scoped to your organization hierarchy.
Headers
Optional idempotency key: a unique string of 16-200 printable ASCII characters (a UUID is recommended). Retrying the write with the same key within 24 hours returns the stored response of the first call with an X-Idempotent-Replayed: true response header instead of executing it again. Reusing a key with a different request body returns 422 (IDEMPOTENCY_MISMATCH); a duplicate sent while the first call is still running returns 409 with a Retry-After header. Keys are scoped per endpoint and organization.
16 - 200Body
Target organization for the import. Defaults to the organization that owns the API key. Required only when targeting a sub-organization under an agency-tier parent; the API key must have access to the sub-organization (otherwise the request returns 403 ORG_ACCESS_DENIED).
Optional. When provided, the list is scoped to this brand and the brand's organization is used (must match organization_id if both are sent, otherwise returns 400 BRAND_ORG_MISMATCH).
Show child attributes
Show child attributes
