Getting Started
The Enttor API lets you upload leads, create DM campaigns, and manage your team programmatically across X, Instagram, and LinkedIn.
Base URL
Every request requires an API key in the Authorization header. All responses return JSON.
Authentication
Create API keys from Settings → API Keys in your dashboard. Keys are prefixed with ent_ and shown only once.
curl -X GET https://www.enttor.ai/api/v1/users \
-H "Authorization: Bearer ent_your_api_key_here"Scopes
Each key has scopes that control access. All three are included by default.
| Field | Type | Required | Description |
|---|---|---|---|
| leads:write | scope | No | Upload leads |
| campaigns:write | scope | No | Create campaigns |
| users:read | scope | No | List team members |
List Users
/api/v1/users
Returns all team members in your company. Use the id values as user_ids when creating campaigns.
Response 200
{
"success": true,
"data": {
"company_id": "1c5028af-0825-4fcc-97d5-991243aa38ff",
"users": [
{ "id": 1037, "name": "Kevin Gamez", "email": "kgamez@enttor.ai" },
{ "id": 1001, "name": "Zinnie Zhang", "email": "zzhang@enttor.ai" },
{ "id": 1036, "name": "Sameer", "email": "ssomani@enttor.ai" }
]
}
}Upload Leads
/api/v1/leads
Upload leads into a new prospect group. No per-request limit. Leads are batched internally.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| group_name | string | Yes | Name for the prospect group |
| platform | string | Yes | "x", "instagram", or "linkedin" |
| leads | array | Yes | Array of lead objects (see fields below) |
| user_id | number | No | Assign leads to this team member. Omit for unassigned. |
Lead Fields
All platforms
| Field | Type | Required | Description |
|---|---|---|---|
| username | string | Yes | Platform handle |
| profile_url | string | No | Profile URL |
| followers | number | No | Follower count |
X (Twitter)
| Field | Type | Required | Description |
|---|---|---|---|
| company | string | No | Company name |
| company_description | string | No | What the company does |
| job_title | string | No | Job title |
| location | string | No | Location |
| Field | Type | Required | Description |
|---|---|---|---|
| contact_info | string | No | Contact info from bio |
| content_pillars | array | No | Content categories |
| user_info | object | No | Extra metadata |
| Field | Type | Required | Description |
|---|---|---|---|
| full_name | string | No | Full name |
| headline | string | No | Headline |
| job_title | string | No | Job title |
| company | string | No | Company name |
| location | string | No | Location |
Example
// POST /api/v1/leads
{
"group_name": "Video editors",
"platform": "instagram",
"user_id": 1037,
"leads": [
{
"username": "garyvee",
"profile_url": "https://instagram.com/garyvee",
"followers": 10200000,
"contact_info": "team@vaynermedia.com"
},
{
"username": "hormozi",
"followers": 3100000
}
]
}Response 201
{
"success": true,
"data": {
"dataset_id": "316",
"group_name": "Video editors",
"platform": "instagram",
"leads_inserted": 2,
"leads_skipped": 0
}
}List Datasets
/api/v1/datasets
Returns all prospect groups for your company. Use the id as dataset_id when creating campaigns.
Response 200
{
"success": true,
"data": {
"company_id": "1c5028af-0825-4fcc-97d5-991243aa38ff",
"datasets": [
{
"id": "317",
"user_id": 1001,
"name": "robinhoodapp",
"platform": "Instagram",
"source": "platform",
"status": "completed",
"lead_count": "350",
"created_at": "2026-02-06T12:50:12.205Z"
},
{
"id": "313",
"user_id": 1037,
"name": "SaaS Founders",
"platform": "X (Twitter)",
"source": "api",
"status": "completed",
"lead_count": "2500",
"created_at": "2026-02-04T09:15:22.100Z"
}
]
}
}source is "api" for datasets created via this API, "platform" for datasets created from the dashboard.
Create Campaign
/api/v1/campaigns
Create DM campaigns targeting a prospect group. Pass multiple user_ids to split leads across team members. start_date must be at least 10 minutes in the future.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| dataset_id | string | Yes | Prospect group ID (from Upload Leads or List Datasets) |
| campaign_name | string | Yes | Campaign name |
| platform | string | Yes | "x", "instagram", or "linkedin" |
| message_sequence | string | Yes | Message template sent to each prospect |
| start_date | ISO 8601 | Yes | Start date (min 10 min from now) |
| end_date | ISO 8601 | Yes | End date |
| user_ids | number[] | Yes | Team member IDs to distribute leads across |
| daily_message_limit | number | No | Max DMs/day per campaign. Defaults: IG=50, X=200, LI=20 |
Example
// POST /api/v1/campaigns
{
"dataset_id": "317",
"campaign_name": "Robinhood Followers Outreach",
"platform": "instagram",
"message_sequence": "Hey {{username}}, love your content! Would love to show you how Enttor works.",
"start_date": "2026-03-01T00:00:00Z",
"end_date": "2026-03-31T23:59:59Z",
"user_ids": [1037, 1001],
"daily_message_limit": 40
}Response 201
{
"success": true,
"data": {
"campaigns": [
{ "campaign_id": 187, "user_id": 1037, "audience_size": 175 },
{ "campaign_id": 188, "user_id": 1001, "audience_size": 175 }
],
"campaign_name": "Robinhood Followers Outreach",
"status": "scheduled",
"dataset_id": "317",
"total_audience": 350
}
}Leads are split evenly. If the total isn't divisible, the first user(s) get one extra each.
Campaign Status
/api/v1/campaigns/status
Fetch campaign status and message delivery counts. Pass campaign_id for a single campaign, or client_id for all campaigns belonging to a team member. Supports filtering by status and platform.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| campaign_id | string | No | Single campaign ID. Returns one campaign object. |
| client_id | string | No | Team member ID. Returns all their campaigns. |
| status | string | No | Filter by campaign status: "draft", "active", "scheduled", "paused", "completed", "cancelled" |
| platform | string | No | Filter by platform: "instagram", "linkedin", "twitter" |
At least one of campaign_id or client_id is required. Filters only apply when using client_id.
Example
curl -X GET "https://www.enttor.ai/api/v1/campaigns/status?client_id=1001&status=completed" \
-H "Authorization: Bearer ent_your_api_key_here"Response 200
{
"success": true,
"data": {
"campaigns": [
{
"id": "197",
"name": "fion3r Following List",
"status": "completed",
"platforms": ["instagram"],
"startDate": "2026-02-14T19:30:49+00:00",
"endDate": "2026-02-21T19:11:49+00:00",
"dailyMessageLimit": 50,
"createdAt": "2026-02-15T00:15:38.543+00:00",
"messages": {
"total": 172,
"sent": 163,
"failed": 9,
"error": 0,
"alreadyMessaged": 0,
"repliedTo": 0
}
}
]
}
}Message Counts
| Field | Type | Required | Description |
|---|---|---|---|
| total | number | No | Total messages created for this campaign |
| sent | number | No | Messages successfully sent |
| failed | number | No | Messages that failed to deliver |
| error | number | No | Messages that encountered an error |
| alreadyMessaged | number | No | Skipped because the user was already messaged |
| repliedTo | number | No | Messages where the recipient replied |
Errors
All errors return success: false with a machine-readable code and a message.
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "group_name is required"
}
}| Code | Status | Meaning |
|---|---|---|
| UNAUTHORIZED | 401 | Missing or invalid API key |
| FORBIDDEN | 403 | Key lacks the required scope |
| VALIDATION_ERROR | 400 | Bad request body |
| NOT_FOUND | 404 | Resource not found or not yours |
| RATE_LIMITED | 429 | Too many requests |
| INTERNAL_ERROR | 500 | Something went wrong on our end |
Enttor API v1 — Questions? kgamez@enttor.ai
