The one list import: phones, emails, or both from one CSV you host. The platform fetches source_url (HTTPS only, at most 50 MB, text/csv, application/csv, or text/plain), checks the columns you named against the file’s headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns 202 before writing a row. Nothing is written when a check fails.
Columns. Send phone_column, email_column, or both (they must differ). There is no automatic email-column detection: name the column. Without merge_tags, every column other than the chosen ones becomes a merge tag automatically. With merge_tags, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match ^[a-z][a-z0-9_]{0,63}$.
Purpose.audience (the default) makes ONE list. Both sides are polled on GET /contact-lists/{id}: import for the phone numbers and email for the emails (email.status is processing until ready or failed, with counts and removed_at_upload). An email-only audience is organization-wide even when you send brand_id. consent (where the addresses came from) is optional: it is allowed only for an audience with an email_column, and any other combination returns 400. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside merge_tags and consent return 400. Every refusal happens before anything is stored. do_not_contact adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on GET /email/suppressions once the background job finishes (minutes for a large file). A do-not-contact import returns no list_id.
Email access.email_column requires email to be enabled for the organization; otherwise the request returns 403ENTITLEMENT_REQUIRED.
Replaces POST /email/lists/import, which was removed. To migrate: send name as list_name (now required); the mapping entry whose value is email becomes email_column; other mapping entries become merge_tags; consent, email_domain_id, and acquired carry over unchanged.
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.
HTTPS URL of the CSV, such as a presigned storage URL. At most 50 MB; text/csv, application/csv, or text/plain. Private and link-local addresses are refused, on every redirect.
Target organization for the import. Defaults to the organization that owns the API key. Send it to target a sub-organization under an agency-tier parent; the API key is always limited to its own organization tree (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, so a brand in an accessible sub-organization works without organization_id. A brand that does not belong to an organization your API key can access returns 404 BRAND_NOT_FOUND. If both are sent and the brand belongs to a different accessible organization than organization_id, the request returns 400 BRAND_ORG_MISMATCH. Ignored for the emails of an import: an email list is organization-wide or scoped to one sending domain (email_domain_id).
audience: a list you send to. do_not_contact: phone numbers become an opt-out list and emails become unsubscribes, both applied automatically to every send.
The CSV header holding the phone number. Send this, email_column, or both. A header that is not in the file returns 400PHONE_COLUMN_NOT_FOUND with details.headers.
The CSV header holding the email address. Must differ from phone_column. A header that is not in the file returns 400VALIDATION_ERROR with details: { field: "email_column", headers }. Requires email to be enabled for the organization.
Maps CSV columns to contact merge fields. Unknown keys are rejected with a 400. When omitted, or when it maps nothing, every non-phone column gets a merge tag automatically: a header that matches a standard field (first name, last name, address, address line 2, city, state, zip, including common aliases) gets the standard tag, and any other column gets a tag named after its header in lowercase with underscores (for example Donor Tier becomes {donor_tier}). When supplied, the phone side maps only the columns named; the email side maps the named columns and every remaining column by its default name. With an email_column, custom field names must match ^[a-z][a-z0-9_]{0,63}$ (lowercase, starting with a letter, at most 64 characters).
Optional. Where the email addresses came from. Allowed only when purpose is audience and email_column is set; sent with any other combination it returns 400. Omit it and no consent record is stored.
Scopes the emails to one sending domain. Omit or send null for an organization-wide list any email campaign can use. An unknown domain returns 404NOT_FOUND.
Optional, default false. true marks the email addresses as purchased or rented. Acquired lists are not blocked from sending, but they are sent more gradually, warming up on half steps.
Response
Import accepted and running as background jobs. Poll GET /contact-lists/{list_id} for both: import.status for the phone numbers and email.status for the emails, each until ready or failed. A do-not-contact import has no list_id.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Political Comms","description":"Documentation for the Political Comms P2P texting platform - help center, onboarding, compliance, and API reference.","colors":{"primary":"#1E3A8A","light":"#3B82F6","dark":"#1E3A8A"},"logo":{"light":"https://mintcdn.com/politicalcomms/EWPdkQOGp2k4Npo5/logo/main.png?fit=max\u0026auto=format\u0026n=EWPdkQOGp2k4Npo5\u0026q=85\u0026s=694b5108d71882d5774bc62c478bc370","dark":"https://mintcdn.com/politicalcomms/EWPdkQOGp2k4Npo5/logo/main.png?fit=max\u0026auto=format\u0026n=EWPdkQOGp2k4Npo5\u0026q=85\u0026s=694b5108d71882d5774bc62c478bc370","href":"/"},"favicon":"https://mintcdn.com/politicalcomms/EWPdkQOGp2k4Npo5/favicon.png?fit=max\u0026auto=format\u0026n=EWPdkQOGp2k4Npo5\u0026q=85\u0026s=63a87e09739757db232880f7adfda947","navbar":{"links":[{"href":"mailto:support@politicalcomms.com","label":"Support"}],"primary":{"type":"button","label":"Sign in","href":"https://app.politicalcomms.com"}},"footer":{"socials":{"website":"https://politicalcomms.com"},"links":[{"header":"Product","items":[{"label":"Dashboard","href":"https://app.politicalcomms.com"},{"label":"Pricing","href":"https://politicalcomms.com/pricing"},{"label":"Status","href":"https://status.politicalcomms.com"}]},{"header":"Resources","items":[{"label":"Help Center","href":"/help/getting-started"},{"label":"Onboarding","href":"/onboarding/overview"},{"label":"Compliance","href":"/compliance/overview"},{"label":"API Reference","href":"/api-reference/introduction"}]},{"header":"Legal","items":[{"label":"Terms of Use","href":"/legal/terms"},{"label":"Privacy Policy","href":"/legal/privacy"}]}]},"seo":{"metatags":{"og:site_name":"Political Comms Docs","og:type":"website","og:locale":"en_US","og:image":"https://politicalcomms.com/opengraph-image","og:image:width":"1200","og:image:height":"630","og:image:alt":"Political Comms. The direct-to-carrier political texting platform.","twitter:card":"summary_large_image","twitter:image":"https://politicalcomms.com/opengraph-image","twitter:image:alt":"Political Comms. The direct-to-carrier political texting platform.","robots":"index, follow, max-image-preview:large, max-snippet:-1","author":"Political Comms","publisher":"Political Comms","application-name":"Political Comms Docs","apple-mobile-web-app-title":"Political Comms Docs","theme-color":"#254692","msapplication-TileColor":"#254692","category":"Political Technology, Communications Infrastructure","keywords":"political texting, political SMS, P2P messaging, 10DLC registration, Campaign Verify, TCPA compliance, FCC political rules, MCP server, AI agent integration"},"indexing":"all"},"styling":{"latex":true},"navigation":{"global":{"anchors":[{"anchor":"Dashboard","icon":"arrow-up-right-from-square","href":"https://app.politicalcomms.com"},{"anchor":"Status","icon":"signal","href":"https://status.politicalcomms.com"},{"anchor":"Changelog","icon":"clock-rotate-left","href":"/changelog"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"politicalcomms","hasAudioNarration":false,"actualSubdomain":"politicalcomms","customDomains":["docs.politicalcomms.com"],"gitSource":{"type":"github","owner":"political-comms","repo":"political-comms-docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6af47d08f70ad676a5c62756","clientVersion":"0.0.4102","searchFilterCounts":[{"language":"default","tag":"API Reference","count":68},{"language":"default","tag":"Endpoints","count":55},{"language":"default","tag":"Documentation","count":40},{"language":"default","tag":"Email","count":22},{"language":"default","tag":"Text","count":19},{"language":"default","tag":"Assets","count":14},{"language":"default","tag":"Help Center","count":13},{"language":"default","tag":"Projects","count":13},{"language":"default","tag":"Get Started","count":8},{"language":"default","tag":"Compliance","count":8}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"api-reference/contact-lists/import-list","slug":"/api-reference/contact-lists/import-list","pageMetadata":{"title":"Import List","description":"The one list import: phones, emails, or both from one CSV you host. The platform fetches `source_url` (HTTPS only, at most 50 MB, `text/csv`, `application/csv`, or `text/plain`), checks the columns you named against the file's headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns `202` before writing a row. Nothing is written when a check fails.\n\n**Columns.** Send `phone_column`, `email_column`, or both (they must differ). There is no automatic email-column detection: name the column. Without `merge_tags`, every column other than the chosen ones becomes a merge tag automatically. With `merge_tags`, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match `^[a-z][a-z0-9_]{0,63}$`.\n\n**Purpose.** `audience` (the default) makes ONE list. Both sides are polled on `GET /contact-lists/{id}`: `import` for the phone numbers and `email` for the emails (`email.status` is `processing` until `ready` or `failed`, with counts and `removed_at_upload`). An email-only audience is organization-wide even when you send `brand_id`. `consent` (where the addresses came from) is optional: it is allowed only for an audience with an `email_column`, and any other combination returns `400`. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside `merge_tags` and `consent` return `400`. Every refusal happens before anything is stored. `do_not_contact` adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on `GET /email/suppressions` once the background job finishes (minutes for a large file). A do-not-contact import returns no `list_id`.\n\n**Email access.** `email_column` requires email to be enabled for the organization; otherwise the request returns `403` `ENTITLEMENT_REQUIRED`.\n\n**Replaces `POST /email/lists/import`**, which was removed. To migrate: send `name` as `list_name` (now required); the `mapping` entry whose value is `email` becomes `email_column`; other `mapping` entries become `merge_tags`; `consent`, `email_domain_id`, and `acquired` carry over unchanged.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /contact-lists/import","href":"/api-reference/contact-lists/import-list","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n p: \"p\",\n strong: \"strong\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"The one list import: phones, emails, or both from one CSV you host. The platform fetches \", _jsx(_components.code, {\n children: \"source_url\"\n }), \" (HTTPS only, at most 50 MB, \", _jsx(_components.code, {\n children: \"text/csv\"\n }), \", \", _jsx(_components.code, {\n children: \"application/csv\"\n }), \", or \", _jsx(_components.code, {\n children: \"text/plain\"\n }), \"), checks the columns you named against the file’s headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns \", _jsx(_components.code, {\n children: \"202\"\n }), \" before writing a row. Nothing is written when a check fails.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Columns.\"\n }), \" Send \", _jsx(_components.code, {\n children: \"phone_column\"\n }), \", \", _jsx(_components.code, {\n children: \"email_column\"\n }), \", or both (they must differ). There is no automatic email-column detection: name the column. Without \", _jsx(_components.code, {\n children: \"merge_tags\"\n }), \", every column other than the chosen ones becomes a merge tag automatically. With \", _jsx(_components.code, {\n children: \"merge_tags\"\n }), \", phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match \", _jsx(_components.code, {\n children: \"^[a-z][a-z0-9_]{0,63}$\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Purpose.\"\n }), \" \", _jsx(_components.code, {\n children: \"audience\"\n }), \" (the default) makes ONE list. Both sides are polled on \", _jsx(_components.code, {\n children: \"GET /contact-lists/{id}\"\n }), \": \", _jsx(_components.code, {\n children: \"import\"\n }), \" for the phone numbers and \", _jsx(_components.code, {\n children: \"email\"\n }), \" for the emails (\", _jsx(_components.code, {\n children: \"email.status\"\n }), \" is \", _jsx(_components.code, {\n children: \"processing\"\n }), \" until \", _jsx(_components.code, {\n children: \"ready\"\n }), \" or \", _jsx(_components.code, {\n children: \"failed\"\n }), \", with counts and \", _jsx(_components.code, {\n children: \"removed_at_upload\"\n }), \"). An email-only audience is organization-wide even when you send \", _jsx(_components.code, {\n children: \"brand_id\"\n }), \". \", _jsx(_components.code, {\n children: \"consent\"\n }), \" (where the addresses came from) is optional: it is allowed only for an audience with an \", _jsx(_components.code, {\n children: \"email_column\"\n }), \", and any other combination returns \", _jsx(_components.code, {\n children: \"400\"\n }), \". Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside \", _jsx(_components.code, {\n children: \"merge_tags\"\n }), \" and \", _jsx(_components.code, {\n children: \"consent\"\n }), \" return \", _jsx(_components.code, {\n children: \"400\"\n }), \". Every refusal happens before anything is stored. \", _jsx(_components.code, {\n children: \"do_not_contact\"\n }), \" adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on \", _jsx(_components.code, {\n children: \"GET /email/suppressions\"\n }), \" once the background job finishes (minutes for a large file). A do-not-contact import returns no \", _jsx(_components.code, {\n children: \"list_id\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Email access.\"\n }), \" \", _jsx(_components.code, {\n children: \"email_column\"\n }), \" requires email to be enabled for the organization; otherwise the request returns \", _jsx(_components.code, {\n children: \"403\"\n }), \" \", _jsx(_components.code, {\n children: \"ENTITLEMENT_REQUIRED\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsxs(_components.strong, {\n children: [\"Replaces \", _jsx(_components.code, {\n children: \"POST /email/lists/import\"\n })]\n }), \", which was removed. To migrate: send \", _jsx(_components.code, {\n children: \"name\"\n }), \" as \", _jsx(_components.code, {\n children: \"list_name\"\n }), \" (now required); the \", _jsx(_components.code, {\n children: \"mapping\"\n }), \" entry whose value is \", _jsx(_components.code, {\n children: \"email\"\n }), \" becomes \", _jsx(_components.code, {\n children: \"email_column\"\n }), \"; other \", _jsx(_components.code, {\n children: \"mapping\"\n }), \" entries become \", _jsx(_components.code, {\n children: \"merge_tags\"\n }), \"; \", _jsx(_components.code, {\n children: \"consent\"\n }), \", \", _jsx(_components.code, {\n children: \"email_domain_id\"\n }), \", and \", _jsx(_components.code, {\n children: \"acquired\"\n }), \" carry over unchanged.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Import List","description":"The one list import: phones, emails, or both from one CSV you host. The platform fetches `source_url` (HTTPS only, at most 50 MB, `text/csv`, `application/csv`, or `text/plain`), checks the columns you named against the file's headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns `202` before writing a row. Nothing is written when a check fails.\n\n**Columns.** Send `phone_column`, `email_column`, or both (they must differ). There is no automatic email-column detection: name the column. Without `merge_tags`, every column other than the chosen ones becomes a merge tag automatically. With `merge_tags`, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match `^[a-z][a-z0-9_]{0,63}$`.\n\n**Purpose.** `audience` (the default) makes ONE list. Both sides are polled on `GET /contact-lists/{id}`: `import` for the phone numbers and `email` for the emails (`email.status` is `processing` until `ready` or `failed`, with counts and `removed_at_upload`). An email-only audience is organization-wide even when you send `brand_id`. `consent` (where the addresses came from) is optional: it is allowed only for an audience with an `email_column`, and any other combination returns `400`. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside `merge_tags` and `consent` return `400`. Every refusal happens before anything is stored. `do_not_contact` adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on `GET /email/suppressions` once the background job finishes (minutes for a large file). A do-not-contact import returns no `list_id`.\n\n**Email access.** `email_column` requires email to be enabled for the organization; otherwise the request returns `403` `ENTITLEMENT_REQUIRED`.\n\n**Replaces `POST /email/lists/import`**, which was removed. To migrate: send `name` as `list_name` (now required); the `mapping` entry whose value is `email` becomes `email_column`; other `mapping` entries become `merge_tags`; `consent`, `email_domain_id`, and `acquired` carry over unchanged.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /contact-lists/import","href":"/api-reference/contact-lists/import-list","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"tags":["Contact Lists"],"summary":"Import List","description":"The one list import: phones, emails, or both from one CSV you host. The platform fetches `source_url` (HTTPS only, at most 50 MB, `text/csv`, `application/csv`, or `text/plain`), checks the columns you named against the file's headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns `202` before writing a row. Nothing is written when a check fails.\n\n**Columns.** Send `phone_column`, `email_column`, or both (they must differ). There is no automatic email-column detection: name the column. Without `merge_tags`, every column other than the chosen ones becomes a merge tag automatically. With `merge_tags`, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match `^[a-z][a-z0-9_]{0,63}$`.\n\n**Purpose.** `audience` (the default) makes ONE list. Both sides are polled on `GET /contact-lists/{id}`: `import` for the phone numbers and `email` for the emails (`email.status` is `processing` until `ready` or `failed`, with counts and `removed_at_upload`). An email-only audience is organization-wide even when you send `brand_id`. `consent` (where the addresses came from) is optional: it is allowed only for an audience with an `email_column`, and any other combination returns `400`. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside `merge_tags` and `consent` return `400`. Every refusal happens before anything is stored. `do_not_contact` adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on `GET /email/suppressions` once the background job finishes (minutes for a large file). A do-not-contact import returns no `list_id`.\n\n**Email access.** `email_column` requires email to be enabled for the organization; otherwise the request returns `403` `ENTITLEMENT_REQUIRED`.\n\n**Replaces `POST /email/lists/import`**, which was removed. To migrate: send `name` as `list_name` (now required); the `mapping` entry whose value is `email` becomes `email_column`; other `mapping` entries become `merge_tags`; `consent`, `email_domain_id`, and `acquired` carry over unchanged.","operationId":"importContactList","requestBody":"8ae1990a-8a0a-43f7-81a1-9310bd6fec9d","responses":{"202":"0163b008-fb61-4903-af83-c7797c1c7b21","400":"3de73161-ac06-41e3-ad19-55c0597d679d","401":"18694cd3-3746-4ebc-ac4a-b5ca9d87acee","403":"a6dced4d-cada-43b3-8302-a5f44e0a3af3","404":"106a27bb-37dc-43b0-a537-578930d29162","413":"c1e3050a-8c64-4eaf-adcc-7a6d48dacb0d","415":"d8f168a6-34da-4347-835f-ca3380b90b48","429":"26124bc1-23ef-495e-b382-98939715c460","500":"2dce7c24-c8d3-459e-bee4-a37c03e213dc","502":"755865a4-b0f0-41dd-a629-29d61581bea3"},"parameters":["b1d4fac9-7aa8-4789-88c6-5085fbb6411d"],"method":"post","type":"path","servers":["8bdcc1b9-051f-42cc-9c68-f222085fa98e"],"security":["88c9bcce-6679-4bf9-b723-391c13d09147"],"path":"/contact-lists/import","baseUrlOptions":["https://api.politicalcomms.com/v1"],"title":"Import List","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"b1d4fac9-7aa8-4789-88c6-5085fbb6411d":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":16,"maxLength":200,"isRequired":false,"description":"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.","uniqueKey":"","typeLabel":"string"},"description":"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."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["source_url","list_name"],"properties":{"source_url":{"type":"string","format":"uri","description":"HTTPS URL of the CSV, such as a presigned storage URL. At most 50 MB; `text/csv`, `application/csv`, or `text/plain`. Private and link-local addresses are refused, on every redirect.","isRequired":true,"uniqueKey":"source_url","typeLabel":"string\u003curi>"},"list_name":{"type":"string","minLength":1,"maxLength":255,"description":"Name for the list. Names do not have to be unique. For `do_not_contact`, the name of the opt-out list the phone numbers go to.","isRequired":true,"uniqueKey":"list_name","typeLabel":"string"},"organization_id":{"type":"string","description":"Target organization for the import. Defaults to the organization that owns the API key. Send it to target a sub-organization under an agency-tier parent; the API key is always limited to its own organization tree (otherwise the request returns 403 ORG_ACCESS_DENIED).","format":"uuid","uniqueKey":"organization_id","typeLabel":"string\u003cuuid>"},"brand_id":{"type":"string","description":"Optional. When provided, the list is scoped to this brand and the brand's organization is used, so a brand in an accessible sub-organization works without `organization_id`. A brand that does not belong to an organization your API key can access returns 404 BRAND_NOT_FOUND. If both are sent and the brand belongs to a different accessible organization than `organization_id`, the request returns 400 BRAND_ORG_MISMATCH. Ignored for the emails of an import: an email list is organization-wide or scoped to one sending domain (`email_domain_id`).","format":"uuid","uniqueKey":"brand_id","typeLabel":"string\u003cuuid>"},"purpose":{"type":"string","enum":["audience","do_not_contact"],"default":"audience","description":"`audience`: a list you send to. `do_not_contact`: phone numbers become an opt-out list and emails become unsubscribes, both applied automatically to every send.","uniqueKey":"purpose","typeLabel":"enum\u003cstring>"},"phone_column":{"type":"string","minLength":1,"description":"The CSV header holding the phone number. Send this, `email_column`, or both. A header that is not in the file returns `400` `PHONE_COLUMN_NOT_FOUND` with `details.headers`.","uniqueKey":"phone_column","typeLabel":"string"},"email_column":{"type":"string","minLength":1,"description":"The CSV header holding the email address. Must differ from `phone_column`. A header that is not in the file returns `400` `VALIDATION_ERROR` with `details: { field: \"email_column\", headers }`. Requires email to be enabled for the organization.","uniqueKey":"email_column","typeLabel":"string"},"merge_tags":{"type":"object","properties":{"first_name":{"type":"string","minLength":1,"uniqueKey":"merge_tags.first_name","typeLabel":"string"},"last_name":{"type":"string","minLength":1,"uniqueKey":"merge_tags.last_name","typeLabel":"string"},"address":{"type":"string","minLength":1,"uniqueKey":"merge_tags.address","typeLabel":"string"},"address_line_2":{"type":"string","minLength":1,"uniqueKey":"merge_tags.address_line_2","typeLabel":"string"},"city":{"type":"string","minLength":1,"uniqueKey":"merge_tags.city","typeLabel":"string"},"state":{"type":"string","minLength":1,"uniqueKey":"merge_tags.state","typeLabel":"string"},"zip":{"type":"string","minLength":1,"uniqueKey":"merge_tags.zip","typeLabel":"string"},"custom_fields":{"type":"array","items":{"type":"object","properties":{"csv_column":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"merge_tags.custom_fields.items.[INDEX].csv_column","typeLabel":"string"},"merge_tag":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"merge_tags.custom_fields.items.[INDEX].merge_tag","typeLabel":"string"}},"required":["csv_column","merge_tag"],"additionalProperties":true,"uniqueKey":"merge_tags.custom_fields.items.[INDEX]","typeLabel":"object"},"uniqueKey":"merge_tags.custom_fields","typeLabel":"object[]"}},"description":"Maps CSV columns to contact merge fields. Unknown keys are rejected with a 400. When omitted, or when it maps nothing, every non-phone column gets a merge tag automatically: a header that matches a standard field (first name, last name, address, address line 2, city, state, zip, including common aliases) gets the standard tag, and any other column gets a tag named after its header in lowercase with underscores (for example `Donor Tier` becomes `{donor_tier}`). When supplied, the phone side maps only the columns named; the email side maps the named columns and every remaining column by its default name. With an `email_column`, custom field names must match `^[a-z][a-z0-9_]{0,63}$` (lowercase, starting with a letter, at most 64 characters).","additionalProperties":false,"uniqueKey":"merge_tags","typeLabel":"object"},"consent":{"type":"object","description":"Optional. Where the email addresses came from. Allowed only when `purpose` is `audience` and `email_column` is set; sent with any other combination it returns `400`. Omit it and no consent record is stored.","properties":{"source":{"type":"string","enum":["donation_form","petition","signup_form","event","purchased","rented","other"],"description":"How these people agreed to hear from you. Answer honestly: `purchased` and `rented` change how the list is treated, and an undeclared acquired list is the usual cause of a mid-send deliverability pause.","isRequired":true,"uniqueKey":"consent.source","typeLabel":"enum\u003cstring>"},"note":{"type":"string","maxLength":1000,"uniqueKey":"consent.note","typeLabel":"string"}},"required":["source"],"additionalProperties":false,"uniqueKey":"consent","typeLabel":"object"},"email_domain_id":{"oneOf":[{"type":"string","format":"uuid","description":"Scopes the emails to one sending domain. Omit or send null for an organization-wide list any email campaign can use. An unknown domain returns `404` `NOT_FOUND`.","uniqueKey":"email_domain_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","description":"Scopes the emails to one sending domain. Omit or send null for an organization-wide list any email campaign can use. An unknown domain returns `404` `NOT_FOUND`.","uniqueKey":"email_domain_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"email_domain_id","typeLabel":"string\u003cuuid> | null"},"acquired":{"type":"boolean","description":"Optional, default `false`. `true` marks the email addresses as purchased or rented. Acquired lists are not blocked from sending, but they are sent more gradually, warming up on half steps.","uniqueKey":"acquired","typeLabel":"boolean"}},"uniqueKey":"","typeLabel":"object"},"examples":{"phoneOnly":{"title":"phoneOnly","value":{"source_url":"https://example.com/path/to/list.csv","brand_id":"7c1de5f0-9a42-4b6d-8e33-2f5a9c7b1e64","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"}]}}},"phoneAndEmail":{"title":"phoneAndEmail","value":{"source_url":"https://example.com/path/to/donors.csv","brand_id":"7c1de5f0-9a42-4b6d-8e33-2f5a9c7b1e64","list_name":"August donors","phone_column":"phone","email_column":"email","consent":{"source":"donation_form","note":"Donate page opt-in checkbox"}}},"emailOnly":{"title":"emailOnly","value":{"source_url":"https://example.com/path/to/signups.csv","list_name":"Rally signups","email_column":"Email Address","merge_tags":{"first_name":"First"},"consent":{"source":"signup_form"},"email_domain_id":null}},"doNotContact":{"title":"doNotContact","value":{"source_url":"https://example.com/path/to/do-not-contact.csv","list_name":"Vendor do-not-contact file","purpose":"do_not_contact","phone_column":"phone","email_column":"email"}}},"exampleType":"examples"}},"exampleType":"examples"},"responses":{"0163b008-fb61-4903-af83-c7797c1c7b21":{"description":"Import accepted and running as background jobs. Poll `GET /contact-lists/{list_id}` for both: `import.status` for the phone numbers and `email.status` for the emails, each until `ready` or `failed`. A do-not-contact import has no `list_id`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","isRequired":true,"uniqueKey":"success","typeLabel":"boolean"},"data":{"type":"object","properties":{"purpose":{"type":"string","enum":["audience","do_not_contact"],"isRequired":true,"uniqueKey":"data.purpose","typeLabel":"enum\u003cstring>"},"name":{"type":"string","isRequired":true,"uniqueKey":"data.name","typeLabel":"string"},"status":{"type":"string","enum":["processing"],"isRequired":true,"uniqueKey":"data.status","typeLabel":"enum\u003cstring>"},"total_rows":{"oneOf":[{"type":"integer","isRequired":true,"uniqueKey":"data.total_rows.oneOf.0","typeLabel":"integer"},{"type":"null","isRequired":true,"uniqueKey":"data.total_rows.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"data.total_rows","typeLabel":"integer | null"},"channels":{"type":"array","items":{"type":"string","enum":["text","email"],"uniqueKey":"data.channels.items.[INDEX]","typeLabel":"enum\u003cstring>"},"description":"Which sides the import started: `text` for phone numbers, `email` for emails.","isRequired":true,"uniqueKey":"data.channels","typeLabel":"enum\u003cstring>[]"},"list_id":{"type":"string","format":"uuid","description":"The list. Absent for `do_not_contact`.","uniqueKey":"data.list_id","typeLabel":"string\u003cuuid>"},"imported_via_api":{"type":"boolean","description":"Always true. Absent for `do_not_contact`.","uniqueKey":"data.imported_via_api","typeLabel":"boolean"},"email_import":{"type":"object","description":"Present on an audience with an `email_column`. Poll the email side as `email.status` on `GET /contact-lists/{list_id}`.","properties":{"id":{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"data.email_import.id","typeLabel":"string\u003cuuid>"},"status":{"type":"string","enum":["queued"],"isRequired":true,"uniqueKey":"data.email_import.status","typeLabel":"enum\u003cstring>"}},"required":["id","status"],"additionalProperties":true,"uniqueKey":"data.email_import","typeLabel":"object"}},"required":["purpose","name","status","total_rows","channels"],"additionalProperties":true,"isRequired":true,"uniqueKey":"data","typeLabel":"object"}},"required":["success","data"],"additionalProperties":true,"uniqueKey":"","typeLabel":"object"},"examples":{"phoneOnly":{"title":"phoneOnly","value":{"success":true,"data":{"list_id":"3f7a9c1e-8b24-4d6f-a2e5-9c7b3f1a8d42","purpose":"audience","name":"Spring Outreach List","status":"processing","total_rows":12500,"channels":["text"],"imported_via_api":true}}},"phoneAndEmail":{"title":"phoneAndEmail","value":{"success":true,"data":{"list_id":"3f7a9c1e-8b24-4d6f-a2e5-9c7b3f1a8d42","purpose":"audience","name":"August donors","status":"processing","total_rows":4200,"channels":["text","email"],"imported_via_api":true,"email_import":{"id":"0193f2a4-6c1e-7b5d-9a3f-2e8c4d6b1a70","status":"queued"}}}},"emailOnly":{"title":"emailOnly","value":{"success":true,"data":{"list_id":"3f7a9c1e-8b24-4d6f-a2e5-9c7b3f1a8d42","purpose":"audience","name":"Rally signups","status":"processing","total_rows":980,"channels":["email"],"imported_via_api":true,"email_import":{"id":"0193f2a4-6c1e-7b5d-9a3f-2e8c4d6b1a70","status":"queued"}}}},"doNotContact":{"title":"doNotContact","value":{"success":true,"data":{"purpose":"do_not_contact","name":"Vendor do-not-contact file","status":"processing","total_rows":310,"channels":["text","email"]}}}},"exampleType":"examples"}},"exampleType":"examples"},"3de73161-ac06-41e3-ad19-55c0597d679d":{"description":"The body failed validation (`VALIDATION_ERROR`, including an `email_column` that is not a header, with `details: { field: \"email_column\", headers }`, or a named column whose first rows are not what it was chosen for, such as `The column \"SURVEY_LINK\" does not contain email addresses. Choose the column that holds emails, or set the email column to None.` with `details: { field }`), the phone column is not a header (`PHONE_COLUMN_NOT_FOUND`, `details: { phoneColumn, headers }`), a merge tag is invalid (`INVALID_MERGE_TAGS`, `UNKNOWN_STANDARD_TAG`, `MERGE_TAG_COLUMN_NOT_FOUND`, `INVALID_MERGE_TAG_NAME`), the file is not a readable CSV (`INVALID_CSV`), the brand belongs to another organization than `organization_id` (`BRAND_ORG_MISMATCH`), or `source_url` is not a public HTTPS URL (`INVALID_SOURCE_URL`). Nothing is written.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.1","typeLabel":"object"}],"uniqueKey":"details","typeLabel":"array | object"}},"required":["error","code"],"additionalProperties":true,"description":"Standard error body produced by the API error handler for 4xx/5xx responses.","uniqueKey":"","typeLabel":"object"},"example":{"error":"phone_column \"Phone\" not found in CSV headers","code":"PHONE_COLUMN_NOT_FOUND","correlationId":"030bf857-922f-4b82-8fca-c5b0769c1590","details":{"phoneColumn":"Phone","headers":["first_name","cell","email"]}},"examples":{"Example":{"title":"Example","value":{"error":"phone_column \"Phone\" not found in CSV headers","code":"PHONE_COLUMN_NOT_FOUND","correlationId":"030bf857-922f-4b82-8fca-c5b0769c1590","details":{"phoneColumn":"Phone","headers":["first_name","cell","email"]}}}},"exampleType":"examples"}},"exampleType":"examples"},"18694cd3-3746-4ebc-ac4a-b5ca9d87acee":{"description":"Missing, malformed, revoked, or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Short error summary.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"message":{"type":"string","description":"Human-readable detail.","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"required":["error","message"],"additionalProperties":true,"description":"Error body returned by the API-key authentication layer (401 and permission 403s).","uniqueKey":"","typeLabel":"object"},"example":{"error":"API key required","message":"Please provide an API key in the X-API-Key header"},"examples":{"Example":{"title":"Example","value":{"error":"API key required","message":"Please provide an API key in the X-API-Key header"}}},"exampleType":"examples"}},"exampleType":"examples"},"a6dced4d-cada-43b3-8302-a5f44e0a3af3":{"description":"The API key lacks `public:write`, the organization is outside the key's hierarchy (`ORG_ACCESS_DENIED`), or `email_column` was sent and email is not enabled for the organization (`ENTITLEMENT_REQUIRED`).","content":{"application/json":{"schema":{"oneOf":[{"type":"object","description":"Error body returned by the API-key authentication layer (401 and permission 403s).","required":["error","message"],"properties":{"error":{"type":"string","description":"Short error summary.","isRequired":true,"uniqueKey":"oneOf.0.error","typeLabel":"string"},"message":{"type":"string","description":"Human-readable detail.","isRequired":true,"uniqueKey":"oneOf.0.message","typeLabel":"string"}},"additionalProperties":true,"uniqueKey":"oneOf.0","typeLabel":"object"},{"type":"object","description":"Standard error body produced by the API error handler for 4xx/5xx responses.","required":["error","code"],"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"oneOf.1.error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"oneOf.1.code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"oneOf.1.correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"oneOf.1.details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"oneOf.1.details.oneOf.1","typeLabel":"object"}],"uniqueKey":"oneOf.1.details","typeLabel":"array | object"}},"additionalProperties":true,"uniqueKey":"oneOf.1","typeLabel":"object"}],"uniqueKey":"","typeLabel":"object"},"examples":{"orgAccessDenied":{"title":"orgAccessDenied","value":{"error":"Access denied: You do not have permission to access this organization's data","code":"ORG_ACCESS_DENIED","correlationId":"de038205-7c9c-4d4a-99bc-d7275a52f07e"}},"entitlementRequired":{"title":"entitlementRequired","value":{"error":"This feature requires enablement by Political Comms","code":"ENTITLEMENT_REQUIRED","details":{"entitlement":"email"}}}},"exampleType":"examples"}},"exampleType":"examples"},"106a27bb-37dc-43b0-a537-578930d29162":{"description":"The brand does not exist or is outside the key's hierarchy (`BRAND_NOT_FOUND`), or the email domain was not found (`NOT_FOUND`).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.1","typeLabel":"object"}],"uniqueKey":"details","typeLabel":"array | object"}},"required":["error","code"],"additionalProperties":true,"description":"Standard error body produced by the API error handler for 4xx/5xx responses.","uniqueKey":"","typeLabel":"object"},"example":{"error":"Brand not found: 7c1de5f0-9a42-4b6d-8e33-2f5a9c7b1e64","code":"BRAND_NOT_FOUND","correlationId":"030bf857-922f-4b82-8fca-c5b0769c1590"},"examples":{"Example":{"title":"Example","value":{"error":"Brand not found: 7c1de5f0-9a42-4b6d-8e33-2f5a9c7b1e64","code":"BRAND_NOT_FOUND","correlationId":"030bf857-922f-4b82-8fca-c5b0769c1590"}}},"exampleType":"examples"}},"exampleType":"examples"},"c1e3050a-8c64-4eaf-adcc-7a6d48dacb0d":{"description":"The file at `source_url` is larger than 50 MB (`FILE_TOO_LARGE`).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.1","typeLabel":"object"}],"uniqueKey":"details","typeLabel":"array | object"}},"required":["error","code"],"additionalProperties":true,"description":"Standard error body produced by the API error handler for 4xx/5xx responses.","uniqueKey":"","typeLabel":"object"},"example":{"error":"source_url exceeded byte cap of 52428800 bytes during streaming","code":"FILE_TOO_LARGE"},"examples":{"Example":{"title":"Example","value":{"error":"source_url exceeded byte cap of 52428800 bytes during streaming","code":"FILE_TOO_LARGE"}}},"exampleType":"examples"}},"exampleType":"examples"},"d8f168a6-34da-4347-835f-ca3380b90b48":{"description":"The file at `source_url` is not served as `text/csv`, `application/csv`, or `text/plain` (`UNSUPPORTED_CONTENT_TYPE`).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.1","typeLabel":"object"}],"uniqueKey":"details","typeLabel":"array | object"}},"required":["error","code"],"additionalProperties":true,"description":"Standard error body produced by the API error handler for 4xx/5xx responses.","uniqueKey":"","typeLabel":"object"},"example":{"error":"source_url Content-Type \"application/octet-stream\" is not allowed","code":"UNSUPPORTED_CONTENT_TYPE"},"examples":{"Example":{"title":"Example","value":{"error":"source_url Content-Type \"application/octet-stream\" is not allowed","code":"UNSUPPORTED_CONTENT_TYPE"}}},"exampleType":"examples"}},"exampleType":"examples"},"26124bc1-23ef-495e-b382-98939715c460":{"description":"Rate limit exceeded. Check the Retry-After header.","headers":{"Retry-After":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false],"isRequired":true,"uniqueKey":"success","typeLabel":"enum\u003cboolean>"},"error":{"type":"string","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","enum":["RATE_LIMIT_EXCEEDED"],"isRequired":true,"uniqueKey":"code","typeLabel":"enum\u003cstring>"},"statusCode":{"type":"integer","enum":[429],"isRequired":true,"uniqueKey":"statusCode","typeLabel":"enum\u003cinteger>"},"retryAfter":{"type":"integer","description":"Seconds until the rate-limit window resets. Also sent as the Retry-After header.","isRequired":true,"uniqueKey":"retryAfter","typeLabel":"integer"},"message":{"type":"string","uniqueKey":"message","typeLabel":"string"}},"required":["success","error","code","statusCode","retryAfter"],"additionalProperties":true,"uniqueKey":"","typeLabel":"object"},"example":{"success":false,"error":"Rate limit exceeded","message":"Maximum 600 requests per 60 seconds","code":"RATE_LIMIT_EXCEEDED","statusCode":429,"retryAfter":3},"examples":{"Example":{"title":"Example","value":{"success":false,"error":"Rate limit exceeded","message":"Maximum 600 requests per 60 seconds","code":"RATE_LIMIT_EXCEEDED","statusCode":429,"retryAfter":3}}},"exampleType":"examples"}},"exampleType":"examples"},"2dce7c24-c8d3-459e-bee4-a37c03e213dc":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.1","typeLabel":"object"}],"uniqueKey":"details","typeLabel":"array | object"}},"required":["error","code"],"additionalProperties":true,"description":"Standard error body produced by the API error handler for 4xx/5xx responses.","uniqueKey":"","typeLabel":"object"},"example":{"error":"An unexpected error occurred. Please try again later.","code":"INTERNAL_ERROR","correlationId":"de038205-7c9c-4d4a-99bc-d7275a52f07e"},"examples":{"Example":{"title":"Example","value":{"error":"An unexpected error occurred. Please try again later.","code":"INTERNAL_ERROR","correlationId":"de038205-7c9c-4d4a-99bc-d7275a52f07e"}}},"exampleType":"examples"}},"exampleType":"examples"},"755865a4-b0f0-41dd-a629-29d61581bea3":{"description":"The file could not be fetched from `source_url` (`SOURCE_URL_FETCH_FAILED`).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"code":{"type":"string","description":"Machine-readable error code, e.g. VALIDATION_ERROR, ORG_ACCESS_DENIED, PROJECT_NOT_FOUND.","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"correlationId":{"type":"string","description":"Request correlation ID; include it in support requests.","uniqueKey":"correlationId","typeLabel":"string"},"details":{"oneOf":[{"type":"array","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.0","typeLabel":"array"},{"type":"object","description":"Present on some errors. For VALIDATION_ERROR, an array of { field, message, code } with one entry per rejected field (field is the dotted path); an object for other codes (e.g. insufficient-balance shortfall).","uniqueKey":"details.oneOf.1","typeLabel":"object"}],"uniqueKey":"details","typeLabel":"array | object"}},"required":["error","code"],"additionalProperties":true,"description":"Standard error body produced by the API error handler for 4xx/5xx responses.","uniqueKey":"","typeLabel":"object"},"example":{"error":"source_url returned HTTP 403","code":"SOURCE_URL_FETCH_FAILED"},"examples":{"Example":{"title":"Example","value":{"error":"source_url returned HTTP 403","code":"SOURCE_URL_FETCH_FAILED"}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"88c9bcce-6679-4bf9-b723-391c13d09147":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Authenticate every request by passing your API key in the X-API-Key header. Keys are scoped to your organization hierarchy.","scopes":[],"schemeName":"ApiKeyAuth"}}},"servers":{"8bdcc1b9-051f-42cc-9c68-f222085fa98e":{"url":"https://api.politicalcomms.com/v1","description":"Production"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Authenticate every request by passing your API key in the X-API-Key header. Keys are scoped to your organization hierarchy.","scopes":[],"schemeName":"ApiKeyAuth"},"schema":{"title":"X-API-Key","type":"string","description":"Authenticate every request by passing your API key in the X-API-Key header. Keys are scoped to your organization hierarchy.","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"ApiKeyAuth","name":"X-API-Key"}],"title":"ApiKeyAuth"}]},"originalFileLocation":"api-reference/openapi.json"},"subdomain":"politicalcomms","siteName":"Political Comms","title":"Import List - Political Comms","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-11T14:35:30.346Z","originalFileLocation":"api-reference/contact-lists/import-list.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"The one list import: phones, emails, or both from one CSV you host. The platform fetches source_url (HTTPS only, at most 50 MB, text/csv, application/csv, or text/plain), checks the columns you named against the file\u0026#x27;s headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns 202 before writing a row. Nothing is written when a check fails. Columns. Send phone_column, email_column, or both (they must differ). There is no automatic email-column detection: name the column. Without merge_tags, every column other than the chosen ones becomes a merge tag automatically. With merge_tags, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match ^a-z{0,63}$. Purpose. audience (the default) makes ONE list. Both sides are polled on GET /contact-lists/{id}: import for the phone numbers and email for the emails (email.status is processing until ready or failed, with counts and removed_at_upload). An email-only audience is organization-wide even when you send brand_id. consent (where the addresses came from) is optional: it is allowed only for an audience with an email_column, and any other combination returns 400. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside merge_tags and consent return 400. Every refusal happens before anything is stored. do_not_contact adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on GET /email/suppressions once the background job finishes (minutes for a large file). A do-not-contact import returns no list_id. Email access. email_column requires email to be enabled for the organization; otherwise the request returns 403 ENTITLEMENT_REQUIRED. Replaces POST /email/lists/import, which was removed. To migrate: send name as list_name (now required); the mapping entry whose value is email becomes email_column; other mapping entries become merge_tags; consent, email_domain_id, and acquired carry over unchanged.\">\u003cmeta data-mint-head name=\"keywords\" content=\"political texting, political SMS, P2P messaging, 10DLC registration, Campaign Verify, TCPA compliance, FCC political rules, MCP server, AI agent integration\">\u003cmeta data-mint-head name=\"application-name\" content=\"Political Comms\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003cmeta data-mint-head name=\"robots\" content=\"index, follow, max-image-preview:large, max-snippet:-1\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Import List - Political Comms\">\u003cmeta data-mint-head property=\"og:description\" content=\"The one list import: phones, emails, or both from one CSV you host. The platform fetches source_url (HTTPS only, at most 50 MB, text/csv, application/csv, or text/plain), checks the columns you named against the file\u0026#x27;s headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns 202 before writing a row. Nothing is written when a check fails. Columns. Send phone_column, email_column, or both (they must differ). There is no automatic email-column detection: name the column. Without merge_tags, every column other than the chosen ones becomes a merge tag automatically. With merge_tags, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match ^a-z{0,63}$. Purpose. audience (the default) makes ONE list. Both sides are polled on GET /contact-lists/{id}: import for the phone numbers and email for the emails (email.status is processing until ready or failed, with counts and removed_at_upload). An email-only audience is organization-wide even when you send brand_id. consent (where the addresses came from) is optional: it is allowed only for an audience with an email_column, and any other combination returns 400. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside merge_tags and consent return 400. Every refusal happens before anything is stored. do_not_contact adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on GET /email/suppressions once the background job finishes (minutes for a large file). A do-not-contact import returns no list_id. Email access. email_column requires email to be enabled for the organization; otherwise the request returns 403 ENTITLEMENT_REQUIRED. Replaces POST /email/lists/import, which was removed. To migrate: send name as list_name (now required); the mapping entry whose value is email becomes email_column; other mapping entries become merge_tags; consent, email_domain_id, and acquired carry over unchanged.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Political Comms Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://politicalcomms.com/opengraph-image\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Import List - Political Comms\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"The one list import: phones, emails, or both from one CSV you host. The platform fetches source_url (HTTPS only, at most 50 MB, text/csv, application/csv, or text/plain), checks the columns you named against the file\u0026#x27;s headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns 202 before writing a row. Nothing is written when a check fails. Columns. Send phone_column, email_column, or both (they must differ). There is no automatic email-column detection: name the column. Without merge_tags, every column other than the chosen ones becomes a merge tag automatically. With merge_tags, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match ^a-z{0,63}$. Purpose. audience (the default) makes ONE list. Both sides are polled on GET /contact-lists/{id}: import for the phone numbers and email for the emails (email.status is processing until ready or failed, with counts and removed_at_upload). An email-only audience is organization-wide even when you send brand_id. consent (where the addresses came from) is optional: it is allowed only for an audience with an email_column, and any other combination returns 400. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside merge_tags and consent return 400. Every refusal happens before anything is stored. do_not_contact adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on GET /email/suppressions once the background job finishes (minutes for a large file). A do-not-contact import returns no list_id. Email access. email_column requires email to be enabled for the organization; otherwise the request returns 403 ENTITLEMENT_REQUIRED. Replaces POST /email/lists/import, which was removed. To migrate: send name as list_name (now required); the mapping entry whose value is email becomes email_column; other mapping entries become merge_tags; consent, email_domain_id, and acquired carry over unchanged.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://politicalcomms.com/opengraph-image\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/politicalcomms/3u6PEpheVhjd9O_C/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Political Comms Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#254692\">\u003cmeta data-mint-head name=\"og:locale\" content=\"en_US\">\u003cmeta data-mint-head name=\"og:image:alt\" content=\"Political Comms. The direct-to-carrier political texting platform.\">\u003cmeta data-mint-head name=\"twitter:image:alt\" content=\"Political Comms. The direct-to-carrier political texting platform.\">\u003cmeta data-mint-head name=\"author\" content=\"Political Comms\">\u003cmeta data-mint-head name=\"publisher\" content=\"Political Comms\">\u003cmeta data-mint-head name=\"application-name\" content=\"Political Comms Docs\">\u003cmeta data-mint-head name=\"theme-color\" content=\"#254692\">\u003cmeta data-mint-head name=\"category\" content=\"Political Technology, Communications Infrastructure\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/contact-lists/import-list.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.politicalcomms.com/#organization\",\"name\":\"Political Comms\",\"url\":\"https://docs.politicalcomms.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/politicalcomms/EWPdkQOGp2k4Npo5/logo/main.png?fit=max\u0026auto=format\u0026n=EWPdkQOGp2k4Npo5\u0026q=85\u0026s=694b5108d71882d5774bc62c478bc370\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.politicalcomms.com#website\",\"name\":\"Political Comms\",\"url\":\"https://docs.politicalcomms.com\",\"publisher\":{\"@id\":\"https://docs.politicalcomms.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list#webpage\",\"url\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list\",\"name\":\"Import List\",\"description\":\"The one list import: phones, emails, or both from one CSV you host. The platform fetches source_url (HTTPS only, at most 50 MB, text/csv, application/csv, or text/plain), checks the columns you named against the file's headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns 202 before writing a row. Nothing is written when a check fails. Columns. Send phone_column, email_column, or both (they must differ). There is no automatic email-column detection: name the column. Without merge_tags, every column other than the chosen ones becomes a merge tag automatically. With merge_tags, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match ^a-z{0,63}$. Purpose. audience (the default) makes ONE list. Both sides are polled on GET /contact-lists/{id}: import for the phone numbers and email for the emails (email.status is processing until ready or failed, with counts and removed_at_upload). An email-only audience is organization-wide even when you send brand_id. consent (where the addresses came from) is optional: it is allowed only for an audience with an email_column, and any other combination returns 400. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside merge_tags and consent return 400. Every refusal happens before anything is stored. do_not_contact adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on GET /email/suppressions once the background job finishes (minutes for a large file). A do-not-contact import returns no list_id. Email access. email_column requires email to be enabled for the organization; otherwise the request returns 403 ENTITLEMENT_REQUIRED. Replaces POST /email/lists/import, which was removed. To migrate: send name as list_name (now required); the mapping entry whose value is email becomes email_column; other mapping entries become merge_tags; consent, email_domain_id, and acquired carry over unchanged.\",\"dateModified\":\"2026-11-11T14:35:30.346Z\",\"isPartOf\":{\"@id\":\"https://docs.politicalcomms.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Endpoints\",\"item\":\"https://docs.politicalcomms.com/api-reference/projects/list-projects\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Assets\",\"item\":\"https://docs.politicalcomms.com/api-reference/contact-lists/list-contact-lists\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Contact Lists\",\"item\":\"https://docs.politicalcomms.com/api-reference/contact-lists/list-contact-lists\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Import List\",\"item\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list#apireference\",\"headline\":\"Import List\",\"name\":\"Import List\",\"description\":\"The one list import: phones, emails, or both from one CSV you host. The platform fetches source_url (HTTPS only, at most 50 MB, text/csv, application/csv, or text/plain), checks the columns you named against the file's headers and checks that the first rows of each named column hold phone numbers or email addresses, and returns 202 before writing a row. Nothing is written when a check fails. Columns. Send phone_column, email_column, or both (they must differ). There is no automatic email-column detection: name the column. Without merge_tags, every column other than the chosen ones becomes a merge tag automatically. With merge_tags, phone numbers map only the columns you name, while emails map the named columns and also every remaining column by its default name. Custom field names for emails must match ^a-z{0,63}$. Purpose. audience (the default) makes ONE list. Both sides are polled on GET /contact-lists/{id}: import for the phone numbers and email for the emails (email.status is processing until ready or failed, with counts and removed_at_upload). An email-only audience is organization-wide even when you send brand_id. consent (where the addresses came from) is optional: it is allowed only for an audience with an email_column, and any other combination returns 400. Omit it and no consent record is stored. Unknown top-level fields in the request body are ignored; unknown keys inside merge_tags and consent return 400. Every refusal happens before anything is stored. do_not_contact adds the phone numbers to an opt-out list and records the emails as unsubscribes for the organization; the unsubscribes appear on GET /email/suppressions once the background job finishes (minutes for a large file). A do-not-contact import returns no list_id. Email access. email_column requires email to be enabled for the organization; otherwise the request returns 403 ENTITLEMENT_REQUIRED. Replaces POST /email/lists/import, which was removed. To migrate: send name as list_name (now required); the mapping entry whose value is email becomes email_column; other mapping entries become merge_tags; consent, email_domain_id, and acquired carry over unchanged.\",\"url\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list\",\"mainEntityOfPage\":{\"@id\":\"https://docs.politicalcomms.com/api-reference/contact-lists/import-list#webpage\"},\"image\":\"https://politicalcomms.com/opengraph-image\",\"dateModified\":\"2026-11-11T14:35:30.346Z\",\"publisher\":{\"@id\":\"https://docs.politicalcomms.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.politicalcomms.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Political Comms\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Political Comms\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/api-reference/contact-lists/import-list.md","siteName":"Political Comms","nav":{"global":{"anchors":[{"anchor":"Dashboard","icon":"arrow-up-right-from-square","href":"https://app.politicalcomms.com"},{"anchor":"Status","icon":"signal","href":"https://status.politicalcomms.com"},{"anchor":"Changelog","icon":"clock-rotate-left","href":"/changelog"}]},"tabs":[{"tab":"Documentation","pages":[{"title":"Documentation","href":"/introduction"}]},{"tab":"API Reference","groups":[{"group":"Introduction","pages":[{"title":"Introduction","icon":"code","href":"/api-reference/introduction"},{"title":"Authentication","icon":"key","href":"/api-reference/authentication"},{"title":"Rate Limits","icon":"gauge-high","href":"/api-reference/rate-limits"},{"title":"Error Handling","icon":"circle-exclamation","href":"/api-reference/errors"},{"title":"Versioning \u0026 Deprecation","href":"/api-reference/versioning"},{"title":"Best Practices","icon":"stars","href":"/api-reference/best-practices"},{"title":"Two-Way Conversations","icon":"messages","href":"/api-reference/two-way-conversations"}]},{"group":"Webhooks","pages":[{"title":"Overview","icon":"webhook","href":"/api-reference/webhooks/overview"},{"title":"Setup \u0026 Configuration","icon":"plug","href":"/api-reference/webhooks/setup"},{"title":"Signature Validation","icon":"shield-check","href":"/api-reference/webhooks/signature-validation"},{"title":"Event Types","icon":"code","href":"/api-reference/webhooks/events"},{"title":"Delivery Error Codes","icon":"triangle-exclamation","href":"/api-reference/webhooks/error-codes"},{"title":"Retry Policy","icon":"rotate-right","href":"/api-reference/webhooks/retry-policy"}]},{"group":"Endpoints","pages":[{"group":"Text","pages":[{"group":"Projects","pages":[{"title":"List Projects","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /projects","href":"/api-reference/projects/list-projects"},{"title":"Create Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /projects","href":"/api-reference/projects/create-project"},{"title":"Get Project Stats (all)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /projects/stats","href":"/api-reference/projects/get-project-stats-all"},{"title":"Get Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /projects/{id}","href":"/api-reference/projects/get-project"},{"title":"Update Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json patch /projects/{id}","href":"/api-reference/projects/update-project"},{"title":"Get Project Stats (single)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /projects/{id}/stats","href":"/api-reference/projects/get-project-stats-single"},{"title":"Get Project Throughput","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /projects/{id}/throughput","href":"/api-reference/projects/get-project-throughput"},{"title":"Get Survey Results","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /projects/{id}/survey-results","href":"/api-reference/projects/get-survey-results"},{"title":"Test Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /projects/{id}/test","href":"/api-reference/projects/test-project"},{"title":"Schedule Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /projects/{id}/schedule","href":"/api-reference/projects/schedule-project"},{"title":"Unschedule Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /projects/{id}/unschedule","href":"/api-reference/projects/unschedule-project"},{"title":"Pause Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /projects/{id}/pause","href":"/api-reference/projects/pause-project"},{"title":"Copy Project","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /projects/{id}/copy","href":"/api-reference/projects/copy-project"}]},{"group":"Phone Numbers","pages":[{"title":"List Phone Numbers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /phone-numbers","href":"/api-reference/phone-numbers/list-phone-numbers"}]},{"group":"Toll-Free Verifications","pages":[{"title":"List Toll-Free Verifications","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /toll-free-verifications","href":"/api-reference/toll-free-verifications/list-toll-free-verifications"},{"title":"Get Toll-Free Verification","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /toll-free-verifications/{id}","href":"/api-reference/toll-free-verifications/get-toll-free-verification"}]},{"group":"Brands","pages":[{"title":"List Brands","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /brands","href":"/api-reference/brands/list-brands"}]},{"group":"10DLC Campaigns","pages":[{"title":"List Campaigns","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /campaigns","href":"/api-reference/10dlc-campaigns/list-campaigns"},{"title":"Get Campaign Throughput","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /campaigns/{id}/throughput","href":"/api-reference/10dlc-campaigns/get-campaign-throughput"}]}]},{"group":"Email","pages":[{"group":"Email Campaigns","pages":[{"title":"List Campaigns","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/campaigns","href":"/api-reference/email-campaigns/list-campaigns"},{"title":"Create Campaign","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /email/campaigns","href":"/api-reference/email-campaigns/create-campaign"},{"title":"Get Campaign","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/campaigns/{id}","href":"/api-reference/email-campaigns/get-campaign"},{"title":"Schedule Campaign","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /email/campaigns/{id}/schedule","href":"/api-reference/email-campaigns/schedule-campaign"},{"title":"Unschedule Campaign","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /email/campaigns/{id}/unschedule","href":"/api-reference/email-campaigns/unschedule-campaign"},{"title":"Get Campaign Stats","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/campaigns/{id}/stats","href":"/api-reference/email-campaigns/get-campaign-stats"}]},{"group":"Email Templates","pages":[{"title":"List Email Templates","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/templates","href":"/api-reference/email-templates/list-email-templates"},{"title":"Create Email Template","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /email/templates","href":"/api-reference/email-templates/create-email-template"},{"title":"Get Email Template","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/templates/{id}","href":"/api-reference/email-templates/get-email-template"}]},{"group":"Email Senders","pages":[{"title":"List Sender Identities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/senders","href":"/api-reference/email-senders/list-sender-identities"},{"title":"Get Sender Identity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/senders/{id}","href":"/api-reference/email-senders/get-sender-identity"}]},{"group":"Email Suppressions","pages":[{"title":"List Suppressions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/suppressions","href":"/api-reference/email-suppressions/list-suppressions"},{"title":"Add Suppressions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /email/suppressions","href":"/api-reference/email-suppressions/add-suppressions"},{"title":"Remove Suppressions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json delete /email/suppressions","href":"/api-reference/email-suppressions/remove-suppressions"}]}]},{"group":"Assets","pages":[{"group":"Contact Lists","pages":[{"title":"List Contact Lists","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /contact-lists","href":"/api-reference/contact-lists/list-contact-lists"},{"title":"Create Contact List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /contact-lists","href":"/api-reference/contact-lists/create-contact-list"},{"title":"Get Contact List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /contact-lists/{id}","href":"/api-reference/contact-lists/get-contact-list"},{"title":"Delete Contact List","description":"Permanently remove a list from your account, with its phone numbers and its emails. The list is detached from any draft projects that reference it and no longer appears in list or read endpoints. A WinRed or Anedot list's donation feed is disconnected with it. Deletion is blocked with a 409 while a scheduled, sending, or active project depends on the list; unschedule the project or wait for the send to finish, then retry.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json delete /contact-lists/{id}","href":"/api-reference/contact-lists/delete-contact-list"},{"title":"Import List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /contact-lists/import","href":"/api-reference/contact-lists/import-list"},{"title":"List Contact List Emails","description":"List a list's email members, newest id last. Page with `cursor`: pass the previous page's `next_cursor` until it is null. A list with no emails returns an empty page.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /contact-lists/{id}/emails","href":"/api-reference/contact-lists/list-contact-list-emails"},{"title":"Add Contact List Emails","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /contact-lists/{id}/emails","href":"/api-reference/contact-lists/add-contact-list-emails"},{"title":"Analyze Contact List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /contact-lists/{id}/analyze","href":"/api-reference/contact-lists/analyze-contact-list"},{"title":"Download Contact List CSV","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /contact-lists/{id}/download","href":"/api-reference/contact-lists/download-contact-list-csv"}]},{"group":"Media Files","pages":[{"title":"List Media Files","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /media","href":"/api-reference/media-files/list-media-files"},{"title":"Import Media","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json post /media","href":"/api-reference/media-files/import-media"},{"title":"Get Media File","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /media/{id}","href":"/api-reference/media-files/get-media-file"},{"title":"Delete Media File","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json delete /media/{id}","href":"/api-reference/media-files/delete-media-file"}]}]},{"group":"Billing \u0026 Usage","pages":[{"group":"Billing","pages":[{"title":"Get Usage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /ledger/usage","href":"/api-reference/billing/get-usage"},{"title":"Get Usage by Initiator","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /ledger/usage/by-initiator","href":"/api-reference/billing/get-usage-by-initiator"}]},{"group":"Analytics","pages":[{"title":"Get Message Stats","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /messages/stats","href":"/api-reference/analytics/get-message-stats"}]}]},{"group":"Admin","pages":[{"group":"Sending Domains","pages":[{"title":"List Sending Domains","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/domains","href":"/api-reference/sending-domains/list-sending-domains"},{"title":"Get Sending Domain","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /email/domains/{id}","href":"/api-reference/sending-domains/get-sending-domain"}]},{"group":"Tracking Domains","pages":[{"title":"List Tracking Domains","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /tracking-domains","href":"/api-reference/tracking-domains/list-tracking-domains"}]},{"group":"Organizations","pages":[{"title":"List Organizations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /organizations","href":"/api-reference/organizations/list-organizations"},{"title":"Get Hierarchy","deprecated":null,"version":null,"openapi":"/api-reference/openapi.json get /hierarchy","href":"/api-reference/organizations/get-hierarchy"}]}]}]}]}]},"basePath":"","title":"Import List - Political Comms","buildId":"dpl_596ePT575z4qnAFksq1biRW97aLY","deploymentId":"dpl_596ePT575z4qnAFksq1biRW97aLY","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-C9Wu0MeN.js","utils-jWgu-6Qf.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DBD8f9qn.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-BGuX1ui5.js","snippetPresets-Evy63nQB.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","ApiExamples-BQHO1lnV.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-B6C8m-t_.js","shallow-BG4cT0fH.js","getApiPlaygroundDisplay-CgEPrE-D.js","CodeSnippet-CU8JyZ9N.js","CodeSnippets-BnxHU32T.js","Page-D6S0Yh6q.js","getPastedJson-CwiYOonh.js","icon-DYDpWmDf.js","MethodPill-C-J-l7_c.js","DuplicateIcon-B6ARwg9w.js","createIcon-Dsv4MtDq.js","DynamicMarkdown-CtasenyM.js","SectionHeading-YNcgYwjB.js","axios-vUo_bRtp.js","Markdown-CwLx6PAg.js","clsx-C3kuh_dz.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CmKHfscc.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-U3mI6Ljh.js"]}