iContact logo

iContact API + MCP (2026): REST v2.2, three-header auth, no MCP server

Last verified Aug 27, 2026

iContact exposes one JSON REST API at https://app.icontact.com/icp, pinned by an Api-Version: 2.2 header and authenticated with three custom headers rather than OAuth or HTTP Basic. It is a list-and-campaign API, contacts, lists, subscriptions, messages, sends, not a transactional relay, and there is no SMTP service behind it. As of August 2026 no iContact MCP server exists, official or community: agent access runs through Zapier MCP or a thin wrapper you write yourself.

At a glance

v2.2
Current API version
JSON REST, sent as an Api-Version header. No XML or SOAP generation.
3
Official SDKs
All PHP, all unmaintained since 2018. No Python, Node, Ruby, Java or Go client.
None
Official MCP server
Nothing in iContact’s GitHub org or the MCP ecosystem. Zapier MCP is the bridge.

MCP integration in 2026

MCP is how an AI agent gets typed, permissioned access to a product’s data and actions, looking up a contact, adding someone to a list, reading campaign stats without glue code. The question buyers ask in 2026 is whether they can point an agent at their ESP and have it work. For iContact the answer is not directly.

i

No first-party iContact MCP server exists

Nothing MCP-related sits in iContact’s GitHub organisation, which holds exactly 3 repositories, all PHP REST wrappers, newest commit March 12, 2018. No iContact server appears in the public MCP directories either. Agent access today means Zapier MCP over the official Zapier app, or your own thin server wrapping the REST API, which static three-header auth makes unusually easy to build.

Available MCP servers

There is no iContact entry to list, so this directory covers the routes that actually work today.

Why buyers should care

MCP availability is a proxy for how actively an ESP is engineered: platforms shipping first-party servers in 2026 are the ones shipping modern SDKs and versioned changelogs. iContact has neither an MCP server nor an SDK updated in 8 years. That is not disqualifying, the REST API is stable and usable for list sync and scheduled sends, but if you need agent-driven marketing ops, budget for building that bridge yourself, or compare against Mailchimp, ActiveCampaign and GetResponse.

iContact API essentials

One API, one version, one base URL. Everything below is verified against iContact’s own PHP client rather than a marketing page, so the header names and paging parameters are literal.

Base URLhttps://app.icontact.com/icp
Sandbox base URLhttps://app.sandbox.icontact.com/icp TEST FIRST
Version2.2, sent as Api-Version: 2.2 on every request
ProtocolHTTPS REST, JSON bodies. No XML, no SOAP, no GraphQL
Resource scope/a/{accountId}/c/{clientFolderId}/{resource}-both IDs mandatory
PaginationOffset paging: ?limit=100&offset=0, with a total count per collection
Sorting?orderby=lastName:asc,email:desc-comma-separated pairs
Content headersAccept and Content-Type: application/json
Collection writesPOST bodies are JSON arrays, even when creating one record

Every data call hangs off a two-level scope: an account, then a client folder inside it. Resources fall into three groups. Audience objects, contacts, lists, subscriptions, segments, custom fields, take most integration time. Content and dispatch objects are campaigns, messages and sends: create a message, attach it to a campaign, then create a send that pushes it at lists. Reporting objects (opens, clicks, bounces, unsubscribes, statistics) are read-only. Bulk loading is its own two-step flow, create an upload job, then PUT the CSV, and is the right path above a few thousand rows.

One structural absence matters more than any feature: there is no transactional send path and no SMTP relay, so receipts and password resets need a dedicated relay such as Postmark or Amazon SES alongside iContact. AWeber and Constant Contact sit in the same marketing-only position; Brevo and Mailjet combine both in one account.

Authentication methods

iContact uses neither OAuth, bearer tokens nor HTTP Basic. It uses three custom headers, and confusing two of them is the most common cause of a day-one auth failure.

Application headers (the only method)

Every request carries Api-AppId, Api-Username and Api-Password alongside Api-Version: 2.2. The AppId identifies an application you register in the developer portal; the username is your iContact account username; the Api-Password is an application-specific password set for that app-not your web UI login password. All three are static strings: no token exchange, no refresh cycle, no expiry to handle.

Accept: application/json
Content-Type: application/json
Api-Version: 2.2
Api-AppId: your-registered-application-id
Api-Username: your-icontact-username
Api-Password: your-application-specific-password

Treat them as long-lived secrets: environment variables or a secret manager, never a client-side bundle. Key rotation is covered in Create and Manage API Keys, permissions in Permissions.

There is no OAuth flow

If you are building a multi-tenant product on iContact, design around this. No authorisation-code grant, no consent screen, no per-customer token: each customer generates their own application credentials and hands you three strings to store per tenant. Workable, but it turns onboarding from a one-click connect into a documented setup task, and revocation stays on the customer’s side. Mailchimp, HubSpot and Constant Contact offer OAuth instead.

Do not copy the SDK’s TLS handling

The official PHP client sets CURLOPT_SSL_VERIFYPEER to false, disabling certificate validation outright, and that line has sat there since the last commit in January 2018. Lift the file into production and you inherit a silent transport-security downgrade, with no error and no warning. Read the SDK for header names, then call the API with your own client and normal verification.

Rate limits

iContact publishes no numeric API rate limits in any officially reachable document. What it does document in detail is how plan limits are counted, those are the ceilings that bite.

LimitDocumented valueWhat to do
API requests per minuteNot publishedAssume one exists. Back off on errors; batch with array POSTs
Emails per hourNot publishedSchedule through /sends rather than pacing yourself
Recipients per messageNot publishedTarget lists and segments, expanded server-side
Message sizeNot publishedKeep HTML lean; size hurts placement before hitting a cap
Contact ceilingPlan tier, two counting modelsCheck subscriber-based vs contact-based before importing
Page sizelimit / offsetRead total from page one and consume it

Treat throughput as something you discover, not assume: run a single writer, keep concurrency at 1 until you have measured real behaviour, and back off exponentially on the codes listed in HTTP Status Codes. For volume loads the /uploads job plus a PUT of the CSV moves tens of thousands of contacts in one request pair. The ceiling that costs money is the contact ceiling: crossing it raises the invoice rather than blocking the send.

Official SDKs

iContact’s GitHub organisation holds exactly 3 repositories. All PHP, all Apache-2.0, none touched since 2018, and two of the three target generations that are no longer the product you sign up for.

LanguagePackageInstallRepo
PHPicontact-api-php
current v2.2
git clone-not on Packagisticontact/icontact-api-php
PHPicontact-pro-api-php
legacy, api.icpro.co
git cloneicontact-pro-api-php
PHPicontact-pro-select-api-php
retired, api.omkt.co
git cloneicontact-pro-select-api-php

All three SDKs are effectively abandonware

The newest commit anywhere in the organisation is March 12, 2018; the current-API wrapper last changed January 2, 2018, the OutMarket wrapper October 28, 2014. None of this breaks the API, a surface pinned to Api-Version: 2.2 stays stable precisely because nothing moves, but plan a direct HTTP integration in your own language and treat these repositories as documentation, not as a dependency.

Notable community SDKs

No widely adopted third-party iContact client exists in any language, itself informative about integration volume. What exists is no-code, the official Zapier app, 8 triggers and 8 actions, the same surface Zapier MCP re-exposes, and platform plugins: iContact Lead Forms for WordPress and the iContact for Salesforce package. Beyond those you write the client, starting from the Code Library article.

Endpoints reference

Paths are relative to {scope} = https://app.icontact.com/icp/a/{accountId}/c/{clientFolderId}. Those IDs are neither optional nor inferable, fetch them first. Full documentation: the official Resource Call References List.

ResourceMethodsDescription
Accounts
/icp/a/
GETAccounts your credentials reach; yields accountId.
Client Folders
/icp/a/{accountId}/c/
GETFolders under an account; yields clientFolderId.
Contacts
{scope}/contacts
GET, POSTCreate and search contacts. Supports limit, offset, orderby, field filters.
Contact
{scope}/contacts/{contactId}
GET, POSTRead or update one contact. Updates are POST, not PUT.
Lists
{scope}/lists
GET, POSTCreate and enumerate mailing lists, the audience container.
List
{scope}/lists/{listId}
GET, POST, DELETERead, update or delete one list. The only DELETE in the core set.
Subscriptions
{scope}/subscriptions
GET, POSTJoins a contact to a list with status normal, pending or unsubscribed.
Messages
{scope}/messages
GET, POSTCreate and list messages: subject, HTML and text body, campaign.
Message Opens
{scope}/messages/{messageId}/opens
GETOpen events for one message; read total for a count.
Sends
{scope}/sends
GET, POSTDispatches or schedules a message at lists and segments.
Campaigns
{scope}/campaigns
GET, POSTContainers grouping messages for reporting and sender identity.
Uploads
{scope}/uploads
GET, POSTBulk contact import jobs. Create the job, then stream the file.
Upload Data
{scope}/uploads/{uploadId}/data
PUTCSV body for an upload job. The only documented PUT.
Web Hooks
see official article
GET, POSTOutbound event callbacks. See Web Hooks.
Segments
see official article
GET, POSTSaved dynamic segments and criteria. See Segments.

The official article index confirms further resource families whose exact paths were not machine-verifiable: Message Clicks, Message Bounces, Unsubscribes, Custom Fields, Contact History, Automations, Sign-Up Forms, Statistics, Users and a Time endpoint returning iContact’s server clock. Scheduled sends are evaluated against that clock, not your host’s timezone.

Code examples

Header names and paging parameters below come verbatim from iContact’s own PHP client, so they are literal rather than reconstructed. Point them at the sandbox first.

Python: create a contact, subscribe it, page the list

import os, requests

BASE = "https://app.icontact.com/icp"   # sandbox: https://app.sandbox.icontact.com/icp

s = requests.Session()
s.headers.update({
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Api-Version": "2.2",
    "Api-AppId": os.environ["ICONTACT_APP_ID"],
    "Api-Username": os.environ["ICONTACT_API_USERNAME"],
    "Api-Password": os.environ["ICONTACT_API_PASSWORD"],
})

# 1. Resolve the scope every other call needs.
acct = s.get(BASE + "/a/", timeout=30).json()["accounts"][0]["accountId"]
folder = s.get("%s/a/%s/c/" % (BASE, acct), timeout=30).json()["clientfolders"][0]["clientFolderId"]
scope = "%s/a/%s/c/%s" % (BASE, acct, folder)

# 2. Create a contact. The payload is an ARRAY, even for one record.
r = s.post(scope + "/contacts", timeout=30,
           json=[{"email": "ada@example.com", "firstName": "Ada", "lastName": "Lovelace"}])
r.raise_for_status()
contact_id = r.json()["contacts"][0]["contactId"]

# 3. Subscribe that contact to a list.
s.post(scope + "/subscriptions", timeout=30,
       json=[{"contactId": contact_id,
              "listId": os.environ["ICONTACT_LIST_ID"],
              "status": "normal"}]).raise_for_status()

# 4. Page with limit/offset, sort with orderby.
page = s.get(scope + "/contacts", timeout=30,
             params={"limit": 100, "offset": 0, "orderby": "lastName:asc"}).json()
print(page["total"])

Node: create a message, then dispatch it

const BASE = "https://app.icontact.com/icp";
const headers = {
  Accept: "application/json",
  "Content-Type": "application/json",
  "Api-Version": "2.2",
  "Api-AppId": process.env.ICONTACT_APP_ID,
  "Api-Username": process.env.ICONTACT_API_USERNAME,
  "Api-Password": process.env.ICONTACT_API_PASSWORD,
};

async function call(path, init) {
  const res = await fetch(BASE + path, Object.assign({ headers }, init || {}));
  if (!res.ok) throw new Error(res.status + " " + (await res.text()));
  return res.json();
}

const acct = (await call("/a/")).accounts[0].accountId;
const folder = (await call("/a/" + acct + "/c/")).clientfolders[0].clientFolderId;
const scope = "/a/" + acct + "/c/" + folder;

// Step 1: create the message content.
const created = await call(scope + "/messages", {
  method: "POST",
  body: JSON.stringify([{
    campaignId: process.env.ICONTACT_CAMPAIGN_ID,
    subject: "Monthly product update",
    htmlBody: "<h1>Hello</h1>",
    textBody: "Hello",
  }]),
});

// Step 2: dispatch it. The /sends payload fields (message id, target lists,
// schedule) are defined in the official Sends article - confirm the key names
// there before hard-coding them. There is no SMTP path: iContact has no relay.
await call(scope + "/sends", { method: "POST", body: JSON.stringify([sendPayload]) });

Common gotchas

The “iContact SMTP relay” page you found is Campaigner’s documentation

Search engines surface SMTP relay setup articles on icontact.my.site.com, which look authoritative because the hostname carries the brand. They are not iContact docs. That Experience Cloud site fronts a shared knowledge base whose sitemap index points at knowledge.campaigner.com, and every one of those articles canonicalises there. iContact’s real help centre is help.icontact.com/customers/, and its complete article index has no SMTP relay content at all. Configure a hostname from those pages into an iContact account and nothing happens, there is no relay to connect to.

Every call needs an accountId and a clientFolderId first

The URL shape is /icp/a/{accountId}/c/{clientFolderId}/{resource}, so newcomers who POST straight to /contacts get nowhere. GET /a/ for the account ID, then GET /a/{accountId}/c/ for the folder ID, and only then touch contacts, lists, messages or sends. Cache both rather than re-fetching per job, they do not change.

Api-Password is not your login password

That header takes an application-specific password set when you register an app in the developer portal, not the password you type into the web UI. Feeding it your login password produces a failure that reads exactly like a wrong username, which is why it costs people an afternoon. There is no Authorization header and no OAuth to fall back on.

POST bodies are arrays, and updates use POST

Creating one contact means posting a JSON array containing one object, and responses arrive as arrays under a plural key such as contacts or clientfolders. Updating a record is also a POST to its singular URL, not a PUT or PATCH. The only PUT in the documented set is the CSV body of a bulk upload job. Code written against a conventional REST API breaks on all three.

Two plan-counting models decide your bill, and overage is automatic

iContact runs both subscriber-based and contact-based plans, and which one you are on changes how unsubscribed, bounced and pending records count towards your limit. Crossing the ceiling raises the invoice rather than blocking the send, hence dedicated articles on exceeding the subscriber limit. Audit contact statuses before an API-driven import: a bulk upload is the fastest way to find out which model you are on.

Deprecations and changelog

  • August 19, 2026-API and MCP surface inventoried for this review. No iContact MCP server in the official GitHub organisation or the public MCP ecosystem; REST v2.2 confirmed as the only current generation.
  • March 12, 2018-final commit to icontact-pro-api-php, closing out the api.icpro.co Pro generation. The newest commit anywhere in the organisation.
  • January 2, 2018-final commit to icontact-api-php, the official SDK for the current app.icontact.com/icp API v2.2. No official SDK release since.
  • October 28, 2014-final commit to icontact-pro-select-api-php. The OutMarket-era api.omkt.co generation is dormant and should be treated as retired.
  • Undated-iContact for Salesforce reached v2.4 (Lightning) and v2.4.3 (Classic) per the official upgrade articles; no release dates are published.

The official version history lives at API Version Changelog; new integrations start at the API Getting Started Guide. Check both before assuming anything here is still current.

Frequently asked questions

What is the iContact API base URL and current version?

The base URL is https://app.icontact.com/icp and the current version is 2.2, sent as an Api-Version header rather than in the path. The sandbox is https://app.sandbox.icontact.com/icp. Two older generations exist-api.icpro.co/icp (Pro) and api.omkt.co/icp (Pro Select), but neither is what a current account uses.

How do I authenticate with the iContact API?

Three custom headers on every request: Api-AppId (the application ID you register in the developer portal), Api-Username (your iContact username) and Api-Password (an application-specific password, not your UI login password), plus Api-Version: 2.2. No OAuth flow, no bearer token, no Authorization header. Credentials are long-lived, so store them like any production secret.

Where do I find my accountId and clientFolderId?

You fetch them, in order. GET /icp/a/ returns the accounts your credentials can reach and yields accountId; GET /icp/a/{accountId}/c/ returns the client folders and yields clientFolderId. Every data resource sits under /a/{accountId}/c/{clientFolderId}/, so nothing works until you have both. Cache them, they are stable for the life of the account.

Does iContact have an XML or SOAP API?

No. All three official SDKs and every documented resource are JSON REST under Api-Version: 2.2. The SOAP/XML API appearing near iContact in search results belongs to Campaigner, a sibling product on the same shared knowledge platform. It is not a deprecated iContact generation, and its credentials will not work here.

How do I paginate and sort results?

Offset paging via query string: ?limit=100&offset=0. Collection responses include a total, so read it from page one and loop until consumed. Sorting uses ?orderby=field:direction with comma-separated pairs, e.g. orderby=lastName:asc,email:desc. There is no cursor paging and no published page-size ceiling, so measure before assuming a large limit is accepted.

Is there an official Python or Node SDK, or an MCP server?

Neither. iContact publishes three PHP wrappers and nothing else, the newest last committed in March 2018, and no iContact MCP server exists in its GitHub organisation or the public MCP ecosystem as of August 2026. For agent access, Zapier MCP over the official Zapier app is the shortest path; otherwise write a direct HTTP client, which static three-header auth makes easy in any language.

Changelog (recent)

  • 2026-08-19 API and MCP surface inventoried for this review. No iContact MCP server exists in the official GitHub organisation or the public MCP ecosystem; REST v2.2 confirmed as the only current generation.
  • 2018-03-12 Final commit to github.com/icontact/icontact-pro-api-php, closing out the api.icpro.co Pro generation. This is the newest commit anywhere in the official organisation.
  • 2018-01-02 Final commit to github.com/icontact/icontact-api-php, the official SDK for the current app.icontact.com/icp API v2.2. No official SDK release since.
AAlaa Touil RRabeb How we test →

This review follows our email infrastructure testing methodology. We disclose affiliate relationships in our editorial independence policy.