This document covers every available endpoint in the DmTracker API. For authentication and general setup, see API Overview & Authentication.
Base URL: https://app.dmtracker.ai/api/v1
Endpoints at a Glance
# | Endpoint | Method | Purpose |
1 |
| POST | ManyChat default reply webhook |
2 |
| POST | Create or update a contact |
3 |
| POST | Update contact tags by name |
4 |
| PATCH | Update lead status and/or pipeline stage |
1. Handle Incoming DM Replies
POST /contact/default-reply
Auth: x-org-auth-token header
When to Use This
You're using ManyChat (or a similar tool) and someone replies to your automated DM. This endpoint tells DmTracker: "Hey, this person just replied — track it."
What It Does
If the contact already exists → updates their last message and resets follow-up tracking
If the contact is new → creates them automatically
Marks them as needing follow-up so they show up in your dashboard
Request Body
{
"manychat_id": "##{{subscriber_id}}",
"username": "##{{instagram_username}}",
"organization_id": "your-org-id",
"message_content": "##{{last_input_text}}",
"page_name": "##{{page_name}}"
}
Field Descriptions
Field | Type | Required | Description |
| string | Yes | Unique ManyChat subscriber ID |
| string | Yes | Instagram username (auto-normalized: lowercase, trimmed, @ stripped) |
| UUID | Yes* | *Can be omitted if |
| string | Yes | The reply message text. If null, empty, or |
| ISO 8601 | No | Timestamp of the message. Defaults to current time |
| string | No | ManyChat page name. Used to resolve organization_id and update the org's page_name field |
| number | No | Instagram user ID. Can also be passed inside |
| object | No | Additional ManyChat metadata. |
Note: message_date defaults to now if not provided.
Success Response (200)
{
"status": "success",
"message": "Contact processed successfully",
"data": {
"manychat_id": "123456",
"username": "john_doe",
"organization_id": "a1b2c3d4-...",
"created_at": "2025-01-12T10:00:00.000Z",
"last_response_at": "2025-01-12T10:30:00.000Z",
"last_message_content": "Sure, send me more details about pricing.",
"contact_type": "outreach",
"outreach_reason": "New Follower",
"outreach_message": "Hey, thanks for following!"
}
}
Note: The response includes contact_type ("outreach" or "inbound"), outreach_reason, and outreach_message fields. These are useful for routing contacts in ManyChat automations.
Error Codes
Status | Cause |
| Missing required fields ( |
| Invalid or missing |
| Non-POST request |
| Internal server error |
| Database infrastructure error (try again later) |
2. Create or Update a Contact
POST /organization/create-contact
Auth: x-org-auth-token header
Rate limit: 60 requests per minute per organization
When to Use This
Import leads from another tool (spreadsheet, CRM, scraper)
Build a custom integration that pushes contacts into DmTracker
Log outreach you sent to someone
Two Modes: Inbound vs. Outreach
When creating a contact, you tell DmTracker whether this person reached out to you (inbound) or you reached out to them (outreach) using the had_outreach field.
Inbound — Someone Messaged You First
{
"organization_id": "your-org-id",
"username": "john_doe",
"had_outreach": false,
"last_response_at": "2025-01-12T10:00:00.000Z",
"last_message_content": "Hey, I saw your post about coaching!",
"tags": ["interested", "coaching"],
"note": "Came from Reel about mindset"
}
Outreach — You Messaged Them First
{
"organization_id": "your-org-id",
"username": "prospect_user",
"had_outreach": true,
"outreach_reason": "Cold outreach — Q1 campaign",
"outreach_text": "Hey! Loved your content, would love to connect.",
"outreach_reason_label": "Q1 Campaign",
"outreach_message_label": "Intro Message",
"tags": ["outreach", "q1-campaign"]
}
All Available Fields
Field | Type | Required | Description |
| UUID | Yes | Your organization ID |
| string | Yes | Instagram username (1-30 chars, normalized: lowercase, trimmed, @ stripped) |
| boolean | Yes |
|
| ISO 8601 | If inbound | Required when |
| string | If inbound | Required when |
| string | If outreach | Required when |
| string | If outreach | Required when |
| string | No | Label for the outreach reason (for analytics) |
| string | No | Label for the outreach message (for A/B testing) |
| string | No | Resolves |
| string | No | ManyChat subscriber ID |
| number | No | Instagram user ID |
| boolean | No | Default: |
| string | No | Max 1000 chars. Stored in contact notes |
| string[] | No | Array of tag names. Tags are auto-created if they don't exist in the org |
| string | No | Color name for newly created tags. Default: |
What Happens If the Contact Already Exists?
Scenario | Behavior | HTTP Code |
Contact exists (active, same type) | Returns existing contact as-is (updates |
|
Contact exists (active, inbound) + request is outreach | Converts to outreach, preserves conversation history |
|
Contact doesn't exist | Creates new contact |
|
Org subscription cancelled | Returns success, no processing |
|
Success Response (201 Created)
{
"status": "success",
"message": "Contact created successfully",
"data": {
"id": "contact-uuid",
"manychat_id": "MC_123456789",
"username": "john_doe",
"organization_id": "a1b2c3d4-...",
"created_at": "2025-01-12T10:00:00.000Z",
"last_response_at": "2025-01-12T10:00:00.000Z",
"last_message_content": "Hello, I'm interested",
"follow_up_needed": true,
"had_outreach": false,
"contact_ingestion_type": "custom-api-import",
"created_by_user_id": "user-uuid",
"pipeline_stage": "open"
}
}
Error Codes
Status | Cause |
| Missing/invalid required fields, validation errors, type mismatch |
| Invalid |
| User (from |
| User with provided email not found |
| Non-POST request |
| Rate limit exceeded (60 requests/minute per org) |
| Server error |
3. Update Contact Tags
POST /contact/update-tags-external
Auth: x-org-auth-token header
When to Use This
Automatically label leads based on behavior (e.g., tag as "hot-lead" when they click a link)
Segment contacts from an external workflow or automation
Clean up tags by removing outdated ones
Request Body
{
"organization_id": "your-org-id",
"username": "john_doe",
"mode": "add",
"tag_names": ["hot-lead", "clicked-link"],
"tag_color": "red"
}
Field Descriptions
Field | Type | Required | Description |
| UUID | Yes | Validated via |
| UUID | Yes* | *Either |
| string | Yes* | *Either |
| string | Yes |
|
| string[] | Yes | Array of tag name strings |
| string | No | Color name for auto-created tags. Default: |
| string | No | Resolves user for audit logging. Must be valid format and org member |
Mode Behavior
Mode | What It Does | Auto-creates missing tags? |
| Removes all existing tags, then applies the provided ones | Yes |
| Adds tags to existing ones (skips already-applied tags) | Yes |
| Removes specified tags from the contact | No (returns 400 if tag name not found) |
Success Response (200)
{
"status": "success",
"message": "Tags added successfully",
"data": {
"contact_id": "contact-uuid",
"username": "john_doe",
"tags": [
{ "id": 1, "name": "hot-lead", "color": "#dc2626" },
{ "id": 2, "name": "clicked-link", "color": "#dc2626" }
]
}
}
4. Update Lead Status & Pipeline Stage
PATCH /contact/contact-status
Auth: x-org-auth-token header
When to Use This
When a lead's status changes in your automation flow — for example, marking a lead as "won" after they purchase, or moving them to a different pipeline stage based on their actions.
What It Does
Updates a contact's lead status (
open,won,lost,abandoned)Moves a contact to a different pipeline stage
Can update status, pipeline stage, or both in a single call
Triggers smart automations if configured
Creates an activity log entry (marked as "via API")
Request Body
{
"organization_id": "abc-123-...",
"manychat_id": "12345678",
"lead_status": "won",
"pipeline_stage": "Closed"
}
Field Descriptions
Field | Type | Required | Description |
| UUID | Yes | Always required |
| UUID | One of these | DmTracker contact ID. Use this or |
| string | One of these | ManyChat subscriber ID. Use this or |
| string | At least one* | Status name: |
| number | At least one* | Status ID number. Use this OR |
| string | At least one* | Pipeline stage name. Must match an active stage in your organization |
*You must include at least one of lead_status, lead_status_id, or pipeline_stage.
Note: This endpoint uses PATCH instead of POST. Make sure your HTTP client sends a PATCH request.
Success Response (200)
{
"status": "success",
"data": {
"id": "contact-uuid",
"username": "johndoe",
"lead_status": "won",
"pipeline_stage": "Closed"
}
}
Error Codes
Status | Cause |
| Missing required fields or invalid status/stage value |
| Invalid or missing |
| Contact not found with the given |
| Internal server error |
Tag Color Reference
When using tag_color in create-contact or update-tags-external, you can use any of these color names:
Name | Hex |
| #dc2626 |
| #2563eb |
| #16a34a |
| #ca8a04 |
| #9333ea |
| #db2777 |
| #4f46e5 |
| #ea580c |
| #0d9488 |
| #0891b2 |
| #374151 |
| #475569 |
| #d97706 |
| #65a30d |
| #059669 |
| #0284c7 |
| #7c3aed |
| #c026d3 |
| #e11d48 |
You can also pass a hex code directly (e.g., "#FF5733"). Unrecognized names default to gray (#374151).
Code Examples
Create an Outreach Contact (Node.js)
const response = await fetch(
"https://app.dmtracker.ai/api/v1/organization/create-contact",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-org-auth-token": process.env.DMTRACKER_ORG_TOKEN,
},
body: JSON.stringify({
organization_id: "your-org-id",
username: "newlead",
had_outreach: true,
outreach_reason: "Q1 Campaign",
outreach_text: "Hey! Loved your content.",
tags: ["outreach", "q1"],
}),
}
);const data = await response.json();
console.log(data);
Update Tags (Python)
import requestsresponse = requests.post(
"https://app.dmtracker.ai/api/v1/contact/update-tags-external",
headers={
"Content-Type": "application/json",
"x-org-auth-token": "your-org-auth-token",
},
json={
"organization_id": "your-org-id",
"username": "janedoe",
"mode": "add",
"tag_names": ["priority", "hot-lead"],
"tag_color": "red",
},
)print(response.json())
Update Lead Status & Pipeline Stage (cURL)
curl -X PATCH https://app.dmtracker.ai/api/v1/contact/contact-status \
-H "Content-Type: application/json" \
-H "x-org-auth-token: your-org-auth-token" \
-d '{
"organization_id": "your-org-id",
"manychat_id": "12345678",
"lead_status": "won",
"pipeline_stage": "Closed"
}'
Error Handling
All endpoints return clear error messages in a consistent format:
{
"error": "Error type",
"message": "A human-readable description of what went wrong."
}
Code | Meaning |
| Bad Request — missing fields, invalid values, or malformed JSON |
| Unauthorized — missing or invalid auth token |
| Forbidden — user not a member of the organization |
| Not Found — contact or endpoint doesn't exist |
| Method Not Allowed — wrong HTTP method |
| Rate Limit — too many requests (wait and retry) |
| Server Error — something went wrong on our end |
| Service Unavailable — database infrastructure error, try again later |