Listening API
Everything in Listening is available through the REST API under https://lantfly.com/api/v3/listening. The Console
uses the same endpoints, so anything you can do there, you can automate. This page walks through a typical flow; every
endpoint and field is in the API reference.
Before you start
- Create an API token in the Console (see API tokens) and export it as
LANTFLY_TOKEN. - Send it as
Authorization: Bearer $LANTFLY_TOKEN(see Authentication). - A token limited by permissions needs
listening.readfor everyGETandlistening.writefor every change, including Collect now. These are grouped under Social listening in the token form. - Token permissions add to your project role: a call must pass both. See Walls, sharing and access.
- To work in an organization rather than your personal account, select the account as described in Organizations.
Responses use snake_case JSON. A single object comes as data; lists come as data with meta for paging (see
Pagination). Errors come as an error object with a code and a message (see
Errors).
1. Create a project
- curl
- Node.js
- Python
curl -X POST https://lantfly.com/api/v3/listening/projects \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Velyniq",
"category": "Beauty",
"include_keywords": ["velyniq"],
"languages": ["vi", "en"],
"interval_minutes": 360
}'
const res = await fetch('https://lantfly.com/api/v3/listening/projects', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANTFLY_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Velyniq',
category: 'Beauty',
include_keywords: ['velyniq'],
languages: ['vi', 'en'],
interval_minutes: 360,
}),
});
const { data: project } = await res.json();
console.log(project.id);
import os
import requests
res = requests.post(
"https://lantfly.com/api/v3/listening/projects",
headers={"Authorization": f"Bearer {os.environ['LANTFLY_TOKEN']}"},
json={
"name": "Velyniq",
"category": "Beauty",
"include_keywords": ["velyniq"],
"languages": ["vi", "en"],
"interval_minutes": 360,
},
)
res.raise_for_status()
project = res.json()["data"]
print(project["id"])
The answer is 201 with the project. Over your plan's project limit, it is 422. All project fields are described in
Create a project.
2. Add sources
Send the platform, the kind and the value. Values are normalized the same way as in the Console.
- curl
- Node.js
- Python
curl -X POST https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/sources \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "platform": "tiktok", "kind": "hashtag", "value": "velyniq", "results_limit": 50 }'
const sources = [
{ platform: 'tiktok', kind: 'hashtag', value: 'velyniq' },
{ platform: 'facebook', kind: 'page', value: 'https://www.facebook.com/velyniq.vn' },
{ platform: 'youtube', kind: 'keyword', value: 'velyniq review' },
];
for (const source of sources) {
const res = await fetch(
`https://lantfly.com/api/v3/listening/projects/${process.env.PROJECT_ID}/sources`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANTFLY_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(source),
},
);
console.log(source.value, res.status);
}
import os
import requests
base = f"https://lantfly.com/api/v3/listening/projects/{os.environ['PROJECT_ID']}"
headers = {"Authorization": f"Bearer {os.environ['LANTFLY_TOKEN']}"}
for source in [
{"platform": "tiktok", "kind": "hashtag", "value": "velyniq"},
{"platform": "facebook", "kind": "page", "value": "https://www.facebook.com/velyniq.vn"},
{"platform": "youtube", "kind": "keyword", "value": "velyniq review"},
]:
res = requests.post(f"{base}/sources", headers=headers, json=source)
print(source["value"], res.status_code)
The platforms and kinds are listed in Sources. Other source endpoints:
| Endpoint | Purpose |
|---|---|
GET /listening/projects/{project}/sources | Sources with their latest status; q, platform, state (on, off, problem), per_page, page |
PATCH /listening/projects/{project}/sources/{source} | Edit value, results_limit, comments_per_post, is_active and the collect settings |
DELETE /listening/projects/{project}/sources/{source} | Remove (mentions stay) |
POST /listening/projects/{project}/sources/bulk | enable, disable, collect, delete, results_limit, review_stars on up to 200 sources |
GET /listening/projects/{project}/source-suggestions | Suggested hashtags and authors |
POST /listening/projects/{project}/posts | Add up to 200 posts by URL: urls |
3. Collect now
New projects are collected on the next minute and then on their interval. To collect right away:
- curl
- Node.js
- Python
curl -X POST https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/collect \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "add_keyword_sources": false }'
const res = await fetch(
`https://lantfly.com/api/v3/listening/projects/${process.env.PROJECT_ID}/collect`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANTFLY_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ add_keyword_sources: false }),
},
);
const { data } = await res.json();
console.log(`${data.collections} collections started, ${data.sources_added} sources added`);
import os
import requests
res = requests.post(
f"https://lantfly.com/api/v3/listening/projects/{os.environ['PROJECT_ID']}/collect",
headers={"Authorization": f"Bearer {os.environ['LANTFLY_TOKEN']}"},
json={"add_keyword_sources": False},
)
data = res.json()["data"]
print(data["collections"], "collections started,", data["sources_added"], "sources added")
The answer is 202 with data.collections and data.sources_added. Leave out add_keyword_sources (or send true) to
first add the project keywords as keyword sources on every platform that searches, as the Console does. A project that is
not active answers 409. POST /listening/projects/{project}/sources/{source}/collect collects one source.
Every collection starts one billed run per source; see Limits and billing. Follow progress
with GET /listening/projects/{project}/collections.
4. Read mentions
GET /listening/projects/{project}/mentions returns the feed, newest first, 30 per page by default (up to 100).
- curl
- Node.js
- Python
curl -G https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/mentions \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
--data-urlencode "platform=tiktok" \
--data-urlencode "sentiment=negative" \
--data-urlencode "from=2026-10-27" \
--data-urlencode "to=2026-11-02" \
--data-urlencode "sort=engagement" \
--data-urlencode "per_page=100"
const base = `https://lantfly.com/api/v3/listening/projects/${process.env.PROJECT_ID}/mentions`;
const headers = { Authorization: `Bearer ${process.env.LANTFLY_TOKEN}` };
let page = 1;
let lastPage = 1;
do {
const params = new URLSearchParams({ sentiment: 'negative', per_page: '100', page: String(page) });
const res = await fetch(`${base}?${params}`, { headers });
const { data, meta } = await res.json();
for (const m of data) console.log(m.platform, m.author_handle, m.url);
lastPage = meta.last_page;
page += 1;
} while (page <= lastPage);
import os
import requests
base = f"https://lantfly.com/api/v3/listening/projects/{os.environ['PROJECT_ID']}/mentions"
headers = {"Authorization": f"Bearer {os.environ['LANTFLY_TOKEN']}"}
page, last_page = 1, 1
while page <= last_page:
res = requests.get(base, headers=headers,
params={"sentiment": "negative", "per_page": 100, "page": page})
body = res.json()
for m in body["data"]:
print(m["platform"], m.get("author_handle"), m["url"])
last_page = body["meta"]["last_page"]
page += 1
Useful filters: platform, kind (post, comment, review), source_id, sentiment (positive, neutral,
negative, unknown), intent (provider, seeker, general, unknown), author, q, from, to, ad
(1 or 0), include_hidden, duration_min, duration_max, post_format, rating, rating_min, rating_max,
has_seller_reply. Sort with sort (published_at, engagement, views, first_seen_at, duration_seconds,
saves, rating, likes) and dir (desc or asc).
Dates are days in the project's timezone (2026-11-02 or 20261102), or a date-time.
Each mention carries its external_id on the platform, kind, sentiment, intent with intent_source (ai, rule
or manual), is_ad, counts, extended fields such as duration_seconds and post_format, and media: the stored
images as signed links (see Signed links) that work in an img tag without a token until the
end of the next day. Comments carry parent_url; reviews carry rating, review_target and seller_reply.
GET /listening/projects/{project}/feed returns the same feed with the dashboard's filters and extra fields per mention
(media_source, attributes, matched_terms).
5. Label mentions
curl -X PATCH https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/mentions/$MENTION_ID \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "sentiment": "negative" }'
curl -X POST https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/mentions/bulk \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ids": [101, 102, 103], "action": "hide" }'
Bulk actions are hide, show, set_sentiment, set_intent, tag, untag, irrelevant and relevant, on up to
200 mentions. Both need the analyst role; irrelevant and relevant need the right to verify.
6. Export
curl -G https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/feed/export \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
--data-urlencode "format=xlsx" \
--data-urlencode "sentiment=negative" \
-o mentions.xlsx
Exports hold up to 10,000 rows. Other exports: …/mentions/export (CSV), …/creators/export, …/influencers/export,
…/leads/export, …/campaigns/{id}/export and /listening/creator-directory/export.
7. Analytics
curl -G https://lantfly.com/api/v3/listening/projects/$PROJECT_ID/dashboard \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
--data-urlencode "from=2026-10-01" \
--data-urlencode "to=2026-10-31"
Each KPI comes with value, previous and change. The analytics endpoints are listed in
Analytics.
Endpoint map
| Area | Endpoints | Guide |
|---|---|---|
| Projects | /listening/projects, …/pause, …/resume, …/stop, /listening/categories | Create a project |
| Sources | …/sources, …/collect, …/collections, …/posts | Sources |
| Mentions | …/mentions, …/feed, …/mentions/bulk, …/mentions/{id}/raw, …/attributes | Mentions |
| Verify | /listening/verify, /listening/verify/actions | Verify mentions |
| Analytics | …/dashboard, …/topics, …/hashtag-trends, …/peaks, …/influencers, …/demographics, /listening/compare, /listening/overview | Analytics |
| Creators | …/creators, /listening/creator-directory, /listening/creator-lists | Creators |
| Campaigns | …/campaigns | Campaigns |
| Owned accounts | …/owned-accounts, …/owned-accounts/verify | Owned accounts |
| Leads | …/leads | Leads |
| Alerts | …/alerts | Alerts |
| Reports | …/reports, …/report-schedules, …/report-library | Reports |
| Sharing | …/share, …/guests, …/members, /listening/shared, /listening/access-settings | Walls, sharing and access |
| Transfers | …/transfer, /listening/transfers/{transfer} | Move a project |
| Public | /api/public/walls/{token}, /api/public/reports/{token} (no authentication) | Walls |
… stands for /listening/projects/{project}.
Rate limits
Most write endpoints allow a fixed number of calls per minute, for example 20 per minute for bulk actions and exports,
10 per minute for generating reports and requesting transfers, and 30 per minute for verifying owned account URLs. Over
the limit, the API answers 429. See Rate limits.
AI agents and MCP
Almost every Listening endpoint has a matching tool on the Lantfly MCP server, so an AI agent such as Claude or ChatGPT
can do what you can do, within your project roles. Examples: list-listening-projects, create-listening-project,
add-source, collect-project-now, search-mentions, update-mention, get-project-dashboard, get-topics,
get-peaks, list-influencers, list-leads, create-campaign, create-alert, create-report, get-audience and
save-audience-estimate. See MCP and the full list in MCP tools.