Most CRM data is entered twice — once in a form, once in your head when you forget to update the form. AI agents fix this gap. Give Claude, GPT or Gemini a contact-management API and a clean task description, and they'll upsert contacts, apply tags, build segments, and clean data without a human touching a UI. This guide shows exactly how to do it with the Mailpro™ Contact API v3.
TL;DR
- CRM v3 is JSON-only (snake_case), authenticated with a JWT bearer token.
- Get a token from
POST /v3/token— it's valid for 365 days.- Contacts are identified by UUIDs; lists, tags and fields by integers.
- Every endpoint is documented in 20+ programming languages on our developer portal.
Why expose your CRM to an AI agent?
Agents as the new data entry layer
Form-based CRM entry is a solved problem — and it's been bad for 20 years. Agents let you skip the form. A user types "new lead: Alice from ShopCorp, she's interested in our enterprise plan, follow up next week". The agent parses it, calls POST /v3/Contact with structured data, tags her "enterprise-interest", and schedules a follow-up task. Zero keystrokes in a form.
Three concrete scenarios
- Lead enrichment. A webhook fires from a form submission; the agent enriches it from public sources, upserts the contact in Mailpro™ v3, and tags it with a lead score.
- List hygiene. Weekly cron; the agent queries lists for duplicate emails, outdated data or unclassified contacts, and reshuffles tags accordingly.
- Dynamic segmentation. "Move everyone who opened the Spring Sale campaign into segment 'warm-leads'" — the agent reads stats from v2, then calls v3 to re-tag contacts.
Authenticating an AI agent with JWT
POST /v3/token with password grant
The simplest way in:
curl -X POST "https://api.mailpro.com/v3/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "[email protected]" \
-d "password=YOUR_API_KEY"
Response:
{
"access_token": "eyJhbGciOi...",
"token_type": "bearer",
"expires_in": 31535999,
"refresh_token": "eyJhbGciOi..."
}
Stash the access_token securely (server-side env var, vault) and pass it as Authorization: Bearer <token> on every subsequent v3 call.
Token lifetime: 365 days
Mailpro™ tokens are long-lived by design — AI agents run continuously, and you don't want refresh storms. If you need rotation, use the refresh token flow or just issue a new token periodically.
Third-party grants
If you're building a Zapier, Make or Microsoft Flow integration, use the matching grant types (zapier, microsoft-flow, etc.). They issue a JWT with a ThirdParty role. Most agent integrations can stick with the plain password grant.
Step-by-step: "Claude, add this contact, tag VIP, add to list 42"
This is where v3's design shines: one prompt, three API calls, zero UI.
1. Tool schemas
Give your agent three narrow tools — not one big one. Narrow tools are easier for the model to pick correctly.
tools = [
{
"name": "upsert_contact",
"description": "Create or update a contact in Mailpro by email.",
"input_schema": {
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"first_name": {"type": "string"},
"last_name": {"type": "string"},
"fields": {"type": "object", "description": "Custom field values"}
},
"required": ["email"]
}
},
{
"name": "tag_contact",
"description": "Apply a tag to a contact by contact UUID.",
"input_schema": {
"type": "object",
"properties": {
"contact_id": {"type": "string"},
"tag_name": {"type": "string"}
},
"required": ["contact_id", "tag_name"]
}
},
{
"name": "add_to_list",
"description": "Add a contact to a Mailpro list by list ID.",
"input_schema": {
"type": "object",
"properties": {
"contact_id": {"type": "string"},
"list_id": {"type": "integer"}
},
"required": ["contact_id", "list_id"]
}
}
]
2. The agent reasoning
Given the prompt "Add Alice Zhang from ShopCorp ([email protected]), tag VIP, put her in list 42", Claude reasons:
-
Call
upsert_contactwith{email: "[email protected]", first_name: "Alice", last_name: "Zhang"}. -
Read the returned
contact_id. -
Call
tag_contactwith{contact_id, tag_name: "VIP"}. -
Call
add_to_listwith{contact_id, list_id: 42}.
Three tool calls, one user intent. That's the agent loop.
3. Execute in sequence
def execute_tool(name, args, token):
base = "https://api.mailpro.com/v3"
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
if name == "upsert_contact":
r = requests.post(f"{base}/Contact", headers=headers, json={
"email": args["email"],
"first_name": args.get("first_name"),
"last_name": args.get("last_name"),
"fields": args.get("fields", {})
})
return r.json()
elif name == "tag_contact":
r = requests.post(f"{base}/Tag/{args['tag_name']}/Contact",
headers=headers, json={"contact_id": args["contact_id"]})
return r.json()
elif name == "add_to_list":
r = requests.post(f"{base}/List/{args['list_id']}/Contact",
headers=headers, json={"contact_id": args["contact_id"]})
return r.json()
4. Handle business rules (406 responses)
Tired of manual list upkeep? Mailpro’s plans include the Contact API so your AI agent keeps lists clean and segmented — automatically.
v3 returns HTTP 406 for business-rule violations, with a JSON body like:
{ "Message": "A contact already exist with the same Email" }
Common 406 reasons:
-
Email cannot be empty -
Email has an invalid format -
A contact already exist with the same Email -
The email address was unsubscribed permanently -
One or more lists have reached the contact limit
Teach your agent to read the Message field and recover gracefully: on duplicate, look up the existing contact and update it instead of giving up. On invalid email, ask the user for a correction.
Custom fields and segments
Create a custom field (/v3/Field)
curl -X POST "https://api.mailpro.com/v3/Field" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "lead_score", "field_type": "Number"}'
Build a segment with rules (/v3/Segment)
Segments are dynamic — they update as contact data changes. Agents love them: create a segment once, let conditions match contacts forever.
"Claude, move everyone who opened the last campaign to segment Hot Leads"
This is the kind of multi-step task where v3 shines. The agent:
-
Queries stats from v2 (
/stats/open) to find openers of the last campaign. -
For each opener, calls v3 to add them to the
Hot Leadssegment (via tag or by updating a scoring field).
Cross-API workflows like this one are exactly what unified AI agents unlock.
Importing contacts at scale via agent
When your agent triggers on a "new list of leads" event (CSV upload, spreadsheet shared, CRM export), don't loop one-by-one. Use the bulk import endpoint:
curl -X POST "https://api.mailpro.com/v3/Import/Upload" \
-H "Authorization: Bearer $TOKEN" \
-F "id_list=42" \
-F "[email protected]" \
-F "webhook_url=https://example.com/hooks/import-done"
The endpoint returns an import_job_id immediately. When processing finishes, Mailpro™ POSTs a callback to your webhook_url with counts (imported / skipped / invalid). Your agent can use the webhook as a signal to run follow-up actions ("import done → kick off welcome campaign").
The full agent flow: a sales enrichment example
Trigger: new Stripe customer webhook fires. Goal: the agent should enrich the customer, add them to the CRM, and send a welcome email.
- Enrich. The agent calls an external enrichment API (Clearbit, People Data Labs, custom scraper) to get company name, role, LinkedIn.
-
Upsert in Mailpro™ v3.
POST /v3/Contactwith email + enriched fields. -
Tag and list. Agent tags the contact
stripe-customerand adds them to thePaying Customerslist. -
Welcome email. Agent calls the v2 API
/send/sendmail.jsonwith a personalised welcome using the enriched name.
Four tool calls, two APIs, one seamless onboarding. Human-facing cost: zero.
Tips and gotchas
snake_case vs PascalCase
v3 is snake_case (first_name, list_id, contact_id). v2 is PascalCase (FirstName, ListId). If your agent talks to both APIs, mention this explicitly in the system prompt so it doesn't invent field names.
Business errors return 406, not 400
400 = you sent malformed data. 406 = your data is valid but violates a business rule. The agent must distinguish — 400 is a programming bug; 406 is a normal outcome that it should recover from.
50k monthly requests cap by default
v3 has a per-account monthly request cap. Agents that loop aggressively will hit it. Batch with /v3/Contact/Multiple whenever possible. See the cap in your account dashboard.
Case study (fictional): "CoraInsure" — broker AI triaging 2,000 leads a day
CoraInsure is an insurance broker aggregator. Every day, 2,000 leads land in their webhook from comparison engines. Previously, two data operators manually cleaned and routed each lead. With Claude wired to Mailpro™ v3, the workflow became:
- Webhook fires → Claude receives lead JSON.
- Claude enriches (validates email, normalises phone to E.164, infers insurance product from free text).
-
Claude calls
upsert_contact, applies tags (auto,home,life), adds to the right list. -
Claude scores the lead (0–100) and writes it to the
lead_scorecustom field. - High-score leads auto-trigger a v2 welcome email.
Time to process a lead dropped from 6 minutes (human) to 4 seconds (agent). Data quality improved — turns out Claude is stricter about email validation than tired humans. The two operators were reassigned to actual broker work.
Next step
With v3 handling your CRM and v2 handling your sending, the last piece is SMS. Head over to our SMS API AI guide to give your agent the last channel. Or go back to the pillar guide for the full picture.
Reference docs: CRM API v3. Pricing: Mailpro pricing.
FAQ
Does Mailpro v3 support OAuth or only password grant?
Both. password is the simplest; client_credentials works for machine-to-machine flows; zapier, automateio and microsoft-flow are dedicated third-party grants that mint a ThirdParty-role JWT.
Can I migrate from Mailpro v2 contacts to v3?
Yes — the two APIs hit the same underlying contact database. Any contact created via v2 is visible and manageable via v3, and vice versa.
How do custom fields work with AI?
Create the field once via POST /v3/Field with a type (Text, Number, Date, Boolean). From then on, the agent can set values on contacts via fields in the contact payload. Custom fields also work as personalisation variables in email campaigns.
What's the difference between a list, a tag, and a segment?
A list is a static collection you explicitly add contacts to. A tag is a lightweight label (a contact can have many). A segment is a dynamic query — "all contacts where tag='VIP' and country='UK'" — that updates itself as contact data changes. See also our guide on email deliverability for how good segmentation improves deliverability.
lso our guide on email deliverability for how good segmentation improves deliverability.
Mailpro and the Contact API
Let AI keep your CRM and contacts in sync
Mailpro’s Contact API lets your AI agent add, update and segment contacts automatically — no manual imports. Your lists stay clean and current while you focus elsewhere.