Create a contact
/api/v2/contactsAdds a contact. Returns 201 when created, or 200 when an existing contact is updated instead.
Existing contacts are matched on manychat_id, then instagram_id, then username. An active match returns 409, with one exception: an inbound contact created again with source: "outbound" gets the outreach details added and returns 200. An archived match is reactivated and returns 200.
Rate limit 150 requests per minute
Headers
x-api-keyheaderRequiredYour API key.
Content-TypeheaderRequiredapplication/json
Body
usernamestringRequiredInstagram username, with or without @, up to 30 characters.
sourcestringRequiredinbound(they messaged you first) oroutbound(you reached out first). Decides whether you sendconversationoroutreach.conversation.last_inbound_atstringRequired for
inbound, not allowed foroutbound. When they last messaged you, ISO 8601.conversation.last_message_previewstringRequired for
inbound, not allowed foroutbound. Text of that message, up to 2,000 characters.outreach.reasonstringRequired for
outbound, not allowed forinbound. Why you reached out, up to 200 characters.outreach.messagestringRequired for
outbound, not allowed forinbound. The message you sent, up to 2,000 characters.outreach.message_labelstringLabel for the outreach message, up to 200 characters.
full_namestringDisplay name, up to 200 characters.
instagram_idstringInstagram user id, up to 100 characters.
manychat_idstringManyChat subscriber id, up to 100 characters.
tagsarrayTag names, up to 20 of 50 characters each. Missing tags are created.
tag_colorstringColor for tags created by this request. Hex code (
#2563eb) or color name (blue). Default gray.notestringNote to add, up to 1,000 characters.
created_bystringEmail of the team member who added the contact.
assigned_tostringEmail of the team member to assign it to.
activate_follow_upsbooleanStart follow-ups for this contact. Default
true.
Errors
| Error | When |
|---|---|
400 missing_conversation | Inbound contact without conversation.last_inbound_at and conversation.last_message_preview. |
400 missing_outreach | Outbound contact without outreach.reason and outreach.message. |
400 invalid_conversationinvalid_outreach | Outbound contact with conversation fields, or inbound contact with outreach fields. |
400 invalid_<field> | A field has a value that is not allowed or is too long, for example invalid_username or invalid_tags. message names it. |
400 invalid_assigned_to | assigned_to is not an email address or not a member of your organization. |
400 invalid_created_by | created_by is not a valid email address. |
403 user_not_in_organization | The created_by email belongs to someone outside your organization. |
404 unknown_created_by | No user with the created_by email. |
403 subscription_cancelled | Your subscription is cancelled. |
409 contact_already_exists | A contact with this username, Instagram id or ManyChat id already exists. |
curl -X POST "https://app.dmtracker.ai/api/v2/contacts" \
-H "x-api-key: $DMTRACKER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"username": "jane.fitness",
"source": "inbound",
"full_name": "Jane Cooper",
"conversation": {
"last_inbound_at": "2026-10-21T15:12:47Z",
"last_message_preview": "Hi! How much is the coaching program?"
},
"tags": [
"hot lead"
]
}'{
"status": "success",
"message": "Contact created successfully",
"data": {
"id": "7c1e9a52-3f4b-4d2a-9e61-0b8f2d5c4a17",
"username": "jane.fitness",
"full_name": "Jane Cooper",
"source": "inbound",
"status": "open",
"pipeline_stage": {
"id": "2b6f0e1a-8d3c-4f57-a1e9-5c7d9b3e0f42",
"name": "New Lead",
"color": "#3B82F6",
"position": 1
},
"tags": [
{
"id": 287,
"name": "hot lead",
"color": "#22C55E"
}
],
"added_by": "api",
"created_at": "2026-10-29T10:05:12.000+00:00"
}
}Shortened. data is the full contact object.