LanaChat

API: tracking links, domains, pixels and stats

9 min readUpdated Markdown

A tracking link sends a visitor to a creator on Telegram and counts what follows: clicks, conversations, first messages, buyers and revenue. Links can live on your own domain, fire ad pixels (Meta, TikTok, Snap) and send server events. These endpoints match the Tracking page.

Endpoints #

MethodPathDescriptionPermissionStatus
GET/linksList links (creator_id=, archived=false) with their counterscan_tracking or can_sales_readPlanned
POST/linksCreate a linkcan_trackingPlanned
GET/links/{id}One linkcan_tracking or can_sales_readPlanned
PUT/links/{id}Replace a link (name, slug, domain, destination, UTM, pixels)can_trackingPlanned
DELETE/links/{id}Archive a link (permanent=1 deletes it)can_trackingPlanned
GET/domainsYour domains (status=active,inactive, q=)can_trackingPlanned
POST/domainsAdd a domain (status pending)can_trackingPlanned
POST/domains/{host}/verifyCheck its DNS records nowcan_trackingPlanned
PATCH/domains/{host}Make a verified domain the default, or change its labelcan_trackingPlanned
DELETE/domains/{host}Remove a domain no active link usescan_trackingPlanned
GET/pixelsThe Meta, TikTok and Snap connections and the consent modecan_trackingPlanned
PUT/pixels/{provider}Connect or replace a pixel (meta, tiktok, snap)ownerPlanned
DELETE/pixels/{provider}Disconnect a pixelownerPlanned
POST/pixels/{provider}/testSend a test event and return the platform's answercan_trackingPlanned
PUT/pixels/consentConsent mode: page or implicit_by_countryownerPlanned
GET/eventsBuilt-in and custom events, with 7-day delivery countscan_trackingPlanned
POST/eventsCreate a custom eventownerPlanned
PATCH/events/{id}Turn an event on or off per networkownerPlanned
DELETE/events/{id}Delete a custom eventownerPlanned
GET/statsDaily totals, per link and per source (from=, to=, creator_id=)can_sales_readPlanned
GET/stats/export.csvThe same numbers as CSVcan_sales_readPlanned
{
  "id": "lnk_3",
  "name": "TikTok · Lea night",
  "slug": "lea-tiktok-night",
  "creator_id": "cr_lea",
  "source": "tiktok",
  "campaign": "Autumn",
  "domain": "go.mia-links.com",
  "public_url": "https://go.mia-links.com/r/lea-tiktok-night",
  "destination": "pool",
  "account_id": null,
  "utm": { "source": "tiktok", "medium": "social", "campaign": "autumn" },
  "pixels": { "meta": false, "tiktok": true, "snap": false },
  "counters": { "clicks": 640, "conversations": 97, "first_messages": 76, "buyers": 14, "revenue_stars": 6200 },
  "archived": false,
  "created_at": "2026-09-12T08:00:00Z"
}
FieldTypeDescription
idstringStarts with lnk_
namestringThe name your team sees
slugstringThe end of the public URL
creator_idstringThe creator the link sends to
source, campaignstringWhere the traffic comes from, and your campaign name
domainstringA verified domain of the workspace, or the LanaChat domain
public_urlstringhttps://<domain>/r/<slug>: the URL to put in a bio or an ad
destinationstringpool or account
account_idstring or nullThe fixed account when destination is account
utmobjectsource, medium, campaign
pixelsobjectWhich connected pixels fire on this link
countersobjectclicks, conversations, first_messages, buyers, revenue_stars
archivedbooleanArchived links are left out of stats
created_atstringISO 8601, UTC
  • destination is pool (the account is chosen at click time among the creator's pool, see pools) or account (always the same account_id).
  • slug: lowercase letters, digits and dashes, 1 to 48 characters, starting and ending with a letter or a digit, unique among active links of the same domain.
  • domain must be a verified domain of the workspace; without it the LanaChat domain is used.
  • utm values: up to 80 letters, digits, dots, dashes or underscores. They are stamped on every click and forwarded to pixel events.

The domain object #

{
  "host": "go.mia-links.com",
  "builtin": false,
  "status": "pending",
  "error": null,
  "ssl": "none",
  "is_default": false,
  "label": "Lea TikTok",
  "token": "8be03d5f19a2",
  "checks": 0,
  "added_at": "2026-10-05T10:00:00Z",
  "verified_at": null,
  "last_check_at": null
}
FieldTypeDescription
hoststringA subdomain in lowercase (at least 3 labels), unique in the workspace
builtinbooleantrue for the LanaChat domain, which can never be removed
statusstringverified, pending or error
errorstring or nullA plain sentence when status is error
sslstringnone, issuing or active
is_defaultbooleanExactly one verified domain is the default
labelstring or nullA name for your team, up to 60 characters
tokenstringThe value of the TXT verification record
checksnumberDNS checks made so far
added_at, verified_at, last_check_atstring or nullISO 8601, UTC

The pixel connection object #

{ "connected": true, "pixel_id": "123456789012345", "token_last4": "x9Qa", "token_status": "valid", "token_error": null, "test_event_code": "TEST4821", "connected_at": "2026-10-06T14:30:00Z" }
FieldTypeDescription
connectedbooleanThe pixel is connected
pixel_idstringMeta: 15 or 16 digits. TikTok: 20 capital letters or digits. Snap: a UUID
token_last4stringThe last 4 characters of the access token, never the token itself
token_statusstringvalid, expired or invalid
token_errorstring or nullA plain sentence, for example "Access token expired on 3 Oct. Replace it to resume delivery."
test_event_codestring or nullThe test code of the platform's events manager
connected_atstringISO 8601, UTC

The event object #

{
  "id": "evt_purchase",
  "name": "Purchase",
  "builtin": true,
  "trigger": { "type": "purchase" },
  "networks": { "meta": true, "tiktok": true, "snap": false }
}
FieldTypeDescription
idstringThe event id
namestringBuilt-in name, or your custom name: a letter, then up to 39 letters, digits or underscores, unique in the workspace
builtinbooleantrue for Lead, Contact, Purchase, Subscribe and InitiateCheckout
triggerobjecttype, and a value for the triggers that need one
networksobjectOn or off for meta, tiktok and snap

The stats object #

{
  "days":    [ { "date": "2026-10-05", "clicks": 54, "conversations": 9, "first_messages": 7, "buyers": 2, "revenue_stars": 950 } ],
  "links":   [ { "link_id": "lnk_3", "clicks": 640, "conversations": 97, "first_messages": 76, "buyers": 14, "revenue_stars": 6200 } ],
  "sources": [ { "source": "instagram", "clicks": 1210, "conversations": 160, "first_messages": 131, "buyers": 22, "revenue_stars": 9100 } ]
}
FieldTypeDescription
daysarrayOne row per UTC day of the period
linksarrayOne row per link, over the whole period
sourcesarrayOne row per source group: instagram, tiktok, snapchat, meta, x and other
clicksnumberRedirects served
conversationsnumberTelegram conversations started with the link
first_messagesnumberFans who wrote at least once
buyersnumberDistinct fans with a verified Stars purchase in the period
revenue_starsnumberVerified Stars purchases of those fans in the period

GET /links · can_tracking or can_sales_read

ParameterTypeRequiredDescription
creator_idstringNoOnly this creator's links
archivedbooleanNofalse (default view) hides archived links
limit, cursornumber, stringNoPagination
curl "https://api.lanachat.ai/v1/links?creator_id=cr_lea&archived=false" \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

The answer is a paged list of link objects, each with its counters.

POST /links · can_tracking

ParameterTypeRequiredDescription
namestringYesThe name your team sees
slugstringYesLowercase letters, digits and dashes, 1 to 48 characters
creator_idstringYesThe creator the link sends to
sourcestringNoinstagram, tiktok, snapchat, meta, x or another source
campaignstringNoYour campaign name
destinationstringNopool or account
account_idstringWhen destination is accountThe fixed Telegram account
domainstringNoA verified domain; without it the LanaChat domain
utmobjectNosource, medium, campaign
pixelsobjectNometa, tiktok, snap: true to fire that pixel
curl -X POST https://api.lanachat.ai/v1/links \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Insta bio · Lea", "slug": "lea-bio", "creator_id": "cr_lea", "source": "instagram", "destination": "pool", "domain": "go.mia-links.com"}'
{
  "id": "lnk_9",
  "name": "Insta bio · Lea",
  "slug": "lea-bio",
  "creator_id": "cr_lea",
  "source": "instagram",
  "campaign": null,
  "domain": "go.mia-links.com",
  "public_url": "https://go.mia-links.com/r/lea-bio",
  "destination": "pool",
  "account_id": null,
  "utm": { "source": null, "medium": null, "campaign": null },
  "pixels": { "meta": false, "tiktok": false, "snap": false },
  "counters": { "clicks": 0, "conversations": 0, "first_messages": 0, "buyers": 0, "revenue_stars": 0 },
  "archived": false,
  "created_at": "2026-10-06T14:40:00Z"
}
  • A slug already used answers 409 with The slug /lea-bio is already used by "Insta bio · Mia".
  • A domain that is not verified answers 400 ("Pick a verified domain…").

GET /links/{id} · can_tracking or can_sales_read

curl https://api.lanachat.ai/v1/links/lnk_3 \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

The answer is the link object. An unknown id answers 404.

PUT /links/{id} · can_tracking

Same body as Create a link; PUT replaces the whole link, so send every field you want to keep.

curl -X PUT https://api.lanachat.ai/v1/links/lnk_3 \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "TikTok · Lea night", "slug": "lea-tiktok-night", "creator_id": "cr_lea", "source": "tiktok", "campaign": "Autumn", "destination": "pool", "domain": "go.mia-links.com", "utm": {"source": "tiktok", "medium": "social", "campaign": "autumn"}, "pixels": {"meta": false, "tiktok": true, "snap": false}}'

The answer is the updated link. Same errors as when you create one.

DELETE /links/{id} · can_tracking

ParameterTypeRequiredDescription
permanentnumberNo1 deletes the link for good instead of archiving it
curl -X DELETE https://api.lanachat.ai/v1/links/lnk_3 \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

An archived link is left out of stats.

Domains #

To use your own domain, add it, create two DNS records, then verify it:

  • CNAME go.mia-links.com → links.lanachat.app
  • TXT _lanachat.go.mia-links.com = lanachat-verify=8be03d5f19a2

Pending domains are also checked every 10 minutes for 72 hours, then daily. status becomes verified and ssl goes issuing then active.

List domains #

GET /domains · can_tracking

ParameterTypeRequiredDescription
statusstringNoactive (verified) or inactive (pending or error)
qstringNoPart of the host or the label
curl "https://api.lanachat.ai/v1/domains?status=active" \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

The answer lists domain objects, the LanaChat domain included (builtin: true).

Add a domain #

POST /domains · can_tracking

ParameterTypeRequiredDescription
hoststringYesA subdomain, for example go.mia-links.com
curl -X POST https://api.lanachat.ai/v1/domains \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"host": "go.mia-links.com"}'

The answer is the new domain with status: "pending" and its token for the TXT record. The host is cleaned (lowercase, no https://, no path). Root domains, *.lanachat.app and a domain already added answer 400 with a sentence.

Verify a domain #

POST /domains/{host}/verify · can_tracking

curl -X POST https://api.lanachat.ai/v1/domains/go.mia-links.com/verify \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
{ "host": "go.mia-links.com", "builtin": false, "status": "verified", "error": null, "ssl": "issuing", "is_default": false, "label": null, "token": "8be03d5f19a2", "checks": 3, "added_at": "2026-10-05T10:00:00Z", "verified_at": "2026-10-06T14:45:00Z", "last_check_at": "2026-10-06T14:45:00Z" }

When a record is wrong, status is error and error says which, for example "The CNAME record points to another service." The LanaChat domain cannot be verified (its DNS is managed by LanaChat).

Change a domain #

PATCH /domains/{host} · can_tracking

ParameterTypeRequiredDescription
is_defaultbooleanNotrue makes it the default domain; the previous default stops being one
labelstring or nullNoA name for your team, up to 60 characters
curl -X PATCH https://api.lanachat.ai/v1/domains/go.mia-links.com \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"is_default": true}'

Only a verified domain can be the default. The LanaChat domain refuses a label (403).

Remove a domain #

DELETE /domains/{host} · can_tracking

curl -X DELETE https://api.lanachat.ai/v1/domains/go.mia-links.com \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

Removing the LanaChat domain, the default domain ("Set another default domain first") or a domain used by active links ("Used by N active links across all creators") answers 409.

Pixels #

Events are sent server to server, deduplicated with the browser pixel through the same event_id, with the fan's Telegram id hashed (SHA-256), never raw. Without consent no event is sent, ever. A pixel fires only for links that enable it.

Read pixel connections #

GET /pixels · can_tracking

curl https://api.lanachat.ai/v1/pixels \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

The answer holds one pixel connection for each of meta, tiktok and snap, and the consent mode.

Connect a pixel #

PUT /pixels/{provider} · owner

ParameterTypeRequiredDescription
pixel_idstringYesMeta: 15 or 16 digits. TikTok: 20 capital letters or digits. Snap: a UUID
access_tokenstringYesThe Conversions API token of the platform
test_event_codestringNoThe platform's test code
curl -X PUT https://api.lanachat.ai/v1/pixels/meta \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"pixel_id": "123456789012345", "access_token": "EAAG…", "test_event_code": "TEST4821"}'
{ "connected": true, "pixel_id": "123456789012345", "token_last4": "x9Qa", "token_status": "valid", "token_error": null, "test_event_code": "TEST4821", "connected_at": "2026-10-06T14:30:00Z" }

The access token is stored encrypted and never returned: only token_last4. A pixel id in the wrong format or an empty token answers 400.

Disconnect a pixel #

DELETE /pixels/{provider} · owner

curl -X DELETE https://api.lanachat.ai/v1/pixels/meta \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

Send a test event #

POST /pixels/{provider}/test · can_tracking

curl -X POST https://api.lanachat.ai/v1/pixels/meta/test \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
{ "ok": true, "status": 200, "body": "{\"events_received\":1}" }

status and body are the platform's own answer, so you see exactly what Meta, TikTok or Snap said.

PUT /pixels/consent · owner

ParameterTypeRequiredDescription
modestringYespage: a consent screen for every fan before Telegram opens. implicit_by_country: the screen only in the EU and EEA, the UK and Switzerland
curl -X PUT https://api.lanachat.ai/v1/pixels/consent \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "implicit_by_country"}'

Events #

Built-in events: Lead (conversation started from a link), Contact (first fan message), Purchase (verified sale), Subscribe, InitiateCheckout. Custom events take a trigger: sale_over (a sale above an amount in US dollars), tag_added (a tag), nth_message (the Nth fan message, 2 or more) or offer_viewed.

List events #

GET /events · can_tracking

curl https://api.lanachat.ai/v1/events \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

The answer lists event objects with their deliveries accepted and failed over 7 days, per network.

Create a custom event #

POST /events · owner

ParameterTypeRequiredDescription
namestringYesA letter, then up to 39 letters, digits or underscores; unique in the workspace
triggerobjectYestype: sale_over, tag_added, nth_message or offer_viewed; value for the first three
networksobjectNometa, tiktok, snap: true to send it there
curl -X POST https://api.lanachat.ai/v1/events \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name": "BigSpender", "trigger": {"type": "sale_over", "value": 50}, "networks": {"meta": true, "tiktok": true, "snap": false}}'

The answer is the new event (201). A name already used answers 409.

Turn an event on or off #

PATCH /events/{id} · owner

ParameterTypeRequiredDescription
networksobjectYesmeta, tiktok, snap: true or false
curl -X PATCH https://api.lanachat.ai/v1/events/evt_purchase \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"networks": {"meta": true, "tiktok": true, "snap": true}}'

Delete a custom event #

DELETE /events/{id} · owner

curl -X DELETE https://api.lanachat.ai/v1/events/evt_bigspender \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

Built-in events cannot be deleted; turn them off instead.

Stats #

Read stats #

GET /stats · can_sales_read

ParameterTypeRequiredDescription
fromstringYesFirst UTC day, YYYY-MM-DD, included
tostringYesLast UTC day, YYYY-MM-DD, included
creator_idstringNoOnly this creator; without it, all creators
curl "https://api.lanachat.ai/v1/stats?from=2026-09-06&to=2026-10-05&creator_id=cr_lea" \
  -H "Authorization: Bearer $LANACHAT_TOKEN"

The answer is the stats object. Days are UTC; archived links are left out.

Export stats as CSV #

GET /stats/export.csv · can_sales_read

Same parameters as GET /stats.

curl "https://api.lanachat.ai/v1/stats/export.csv?from=2026-09-06&to=2026-10-05" \
  -H "Authorization: Bearer $LANACHAT_TOKEN" -o stats.csv
date,link,slug,domain,creator,source,clicks,conversations,first_messages,buyers,revenue_stars
2026-10-05,TikTok · Lea night,lea-tiktok-night,go.mia-links.com,Lea,tiktok,54,9,7,2,950

Latest news about Lana on Telegram

New releases and beta invites, first in the channel.