Webhooks
A webhook makes Lantfly send an HTTP POST to your URL when a run event happens: send results on to n8n, Zapier,
Slack or your own API as soon as a run finishes. Deliveries are signed and retried with backoff. Manage them under
Automation → Webhooks.
Events
| Event | When |
|---|---|
ACTOR.RUN.CREATED | A run was started |
ACTOR.RUN.SUCCEEDED | A run finished successfully |
ACTOR.RUN.FAILED | A run failed |
ACTOR.RUN.TIMED_OUT | A run reached its timeout |
ACTOR.RUN.ABORTED | A run was aborted |
ACTOR.RUN.RESURRECTED | A finished run was resurrected |
A webhook can be limited to one actor or one task; otherwise it fires for every run of the account.
Create a webhook
- Open Automation → Webhooks and click New webhook.
- Enter the URL, pick the Events, and optionally a Description, an actor under Only for this actor (optional), Headers (JSON, optional) and a Payload template (optional).
- Click Save webhook.
- Copy the Signing secret — shown once and keep it with your receiver. Click I saved it — continue.
With the API:
curl -s -X POST "https://lantfly.com/api/v3/webhooks" \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Send TikTok results to our API",
"event_types": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
"condition": { "actor_id": "lantfly~tiktok-scraper" },
"request_url": "https://example.com/hooks/lantfly",
"headers": { "X-Source": "lantfly" }
}'
The answer carries secret once. Addresses on private or internal networks are refused.
What you receive
Each delivery is a POST with a JSON body and these headers:
| Header | Value |
|---|---|
X-Lantfly-Event | The event type, such as ACTOR.RUN.SUCCEEDED |
X-Lantfly-Webhook-Dispatch-Id | The ID of this delivery (the same across retries) |
X-Lantfly-Signature | sha256= and the HMAC-SHA256 of the body with your signing secret |
The default body:
{
"user_id": 1234,
"created_at": "2026-11-03T08:00:05.321Z",
"event_type": "ACTOR.RUN.SUCCEEDED",
"event_data": {
"actor_id": "…",
"task_id": null,
"run_id": "9b1f6c1e-6a4e-4b7f-9d3a-2f0c5d7e8a11"
},
"resource": {
"id": "9b1f6c1e-6a4e-4b7f-9d3a-2f0c5d7e8a11",
"status": "SUCCEEDED",
"default_dataset_id": "…",
"default_key_value_store_id": "…",
"stats": { "result_count": 120 }
}
}
resource is the full run, as GET /api/v3/runs/:run returns it.
Verify the signature
Compute the HMAC-SHA256 of the raw request body with your signing secret and compare it, in constant time, with the
hex value after sha256= in X-Lantfly-Signature. Reject requests that do not match.
import crypto from 'node:crypto';
function isValid(rawBody, header, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return header?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
Full examples in several languages are in Webhook signatures.
Payload templates
A payload template replaces the default body with your own JSON. Placeholders written as {{path}} are filled from the
default body above, for example {{resource.default_dataset_id}} or {{event_data.run_id}}. Each placeholder becomes
a JSON value (a string gets its quotes), so write placeholders without surrounding quotes:
{
"text": "Lantfly run finished",
"event": {{event_type}},
"run_id": {{resource.id}},
"status": {{resource.status}},
"dataset_id": {{resource.default_dataset_id}},
"count": {{resource.stats.result_count}}
}
If the filled-in template is not valid JSON, Lantfly sends it as a string in { "payload": "…" }. Paths use the
snake_case names of the body; a path that does not exist becomes null.
Delivery and retries
- A delivery succeeds when your URL answers with a
2xxstatus within 30 seconds. - Otherwise it is retried after 1, 5, 25, 125 and 625 seconds (6 attempts in total) before it is marked
FAILED. - The webhook list shows each webhook's Last delivery and how many deliveries failed. The webhook page lists Recent deliveries (the last 50) with their status, response code and error.
Lantfly notifies you when a webhook keeps failing (webhook.failing, see Notifications).
Test, redeliver, rotate
| Action | Console | API |
|---|---|---|
| Send a test now | Send test | POST /api/v3/webhooks/:webhook/test |
| Send a failed delivery again | Redeliver on the delivery | POST /api/v3/webhooks/:webhook/dispatches/:dispatch/redeliver |
| Get a new signing secret | Rotate secret | POST /api/v3/webhooks/:webhook/rotate-secret |
| Pause or resume | Turn off / Turn on | PATCH /api/v3/webhooks/:webhook { "is_enabled": false } |
- Send test posts your account's latest run as a sample, with
event_typeTEST(or a bareTESTmessage if you have no run yet). It is tried once, without retries. Up to 10 tests a minute. - Redeliver sends a
FAILEDdelivery again with its stored payload, signed and retried like any delivery. Only failed deliveries can be redelivered (422otherwise). - Rotate secret stops the old secret at once. Update your receiver right after.
POST /api/v3/webhooks/bulk enables, disables or deletes up to 200 webhooks at once.
Webhooks for one run
Pass webhooks when you start a run (POST /api/v3/actors/:actor/runs or POST /api/v3/tasks/:task/runs) to get
calls for that run only. They do not appear in your webhook list.
{
"input": { "hashtags": ["coffee"], "resultsPerPage": 30 },
"webhooks": [
{
"event_types": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
"request_url": "https://example.com/hooks/run-done",
"headers": { "Authorization": "Bearer your-own-secret" }
}
]
}
Up to 10 per run, each with event_types, request_url and optional payload_template, headers and
description. Their signing secret is not returned, so authenticate them with your own headers. A token limited to
permissions also needs webhooks.write. Saved tasks and schedules do not store webhooks.
REST hooks for integrations
Zapier, Make and n8n subscribe to events through REST hooks (/api/v3/hooks). They work like webhooks, signed the
same way, and add listening events:
| Event | When |
|---|---|
LISTENING.MENTION.CREATED | A listening project collected a new mention |
LISTENING.ALERT.FIRED | A listening alert fired |
| Request | What it does |
|---|---|
GET /api/v3/hooks/events | Events a hook can subscribe to |
POST /api/v3/hooks | Subscribe a target_url to an event (or event_types), filtered by actor_id, task_id or, for listening events, project_id (required). Needs a full-access token. |
DELETE /api/v3/hooks/:hook | Unsubscribe |
GET /api/v3/hooks/samples?event=… | Recent payloads of an event, for polling triggers and sample data |
Listening events are sent about once a minute, one delivery per new mention or alert. You normally do not call these yourself; the integrations do it for you.