API and webhooks

Connect your own tools to your Lassu workspace. Your servers can read and manage videos, find the videos visitors send through recording buttons, and get a webhook the moment something changes.

Get started

  1. In Workspace settings › API & webhooks, choose Create key. Workspace admins can create keys.
  2. Copy the key into your server’s secret store. Lassu shows it only once.
  3. Send it as a bearer token. This request checks that the key works:
Request
curl https://api.lassu.ai/v1/api/workspace \
  -H "Authorization: Bearer $LASSU_API_KEY"
Response
{
  "id": "0192…",
  "name": "Acme",
  "key": { "id": "0193…", "name": "Support tool", "access": "read" }
}

Every request goes to https://api.lassu.ai/v1/api. Responses are JSON. Lists return { data, nextCursor }; to get the next page, pass nextCursor back as cursor.

API keys

Full access
Reads everything below, and can rename, share and trash videos, create and change recording buttons, and manage webhooks.
Read only
Reads videos, received videos, recording buttons and webhooks. Any request that would change something returns 403.
  • A key belongs to one workspace and acts with the access of the admin who created it. If that person stops being an admin, their keys stop working. Create a new key from another admin.
  • Keys only work with this API. They can’t sign in to Lassu or change members, billing or settings.
  • Keep keys on your server. If a key leaks, revoke it in Workspace settings; it stops working immediately.

Videos

Every video in the workspace, newest first, including the ones visitors send through recording buttons.

RequestKeyWhat it does
GET /videosAny keyList videos. Filters: recordingButtonId, createdAfter, createdBefore, limit (up to 100), cursor.
GET /videos/:idAny keyOne video, with its summary, chapters and transcript.
PATCH /videos/:idFull accessChange the title, or set privacy to team or public.
DELETE /videos/:idFull accessMove a video to Trash. It can be restored in Lassu for 30 days.
List videos
curl "https://api.lassu.ai/v1/api/videos?limit=25" \
  -H "Authorization: Bearer $LASSU_API_KEY"
A video
{
  "id": "0193…",
  "title": "Onboarding walkthrough",
  "status": "ready",
  "durationMs": 184000,
  "privacy": "team",
  "createdAt": "2026-10-07T17:02:11.000Z",
  "updatedAt": "2026-10-07T17:05:40.000Z",
  "shareUrl": "https://www.lassu.ai/share/vid_0193…",
  "source": "member",
  "receivedVideoId": null
}
Rename and share a video
curl -X PATCH https://api.lassu.ai/v1/api/videos/VIDEO_ID \
  -H "Authorization: Bearer $LASSU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Q4 kickoff", "privacy": "public" }'

status is processing, ready or failed. source is recordingButton for a visitor’s video, and receivedVideoId then points at its received video.

Received videos

Videos visitors sent through your recording buttons, with who sent them, the page they came from and their details. A received video keeps its id when the visitor records a new take; videoId always points at the latest one.

RequestKeyWhat it does
GET /received-videosAny keyList received videos. Filters: buttonId, submissionKey, receivedAfter, receivedBefore, limit, cursor.
GET /received-videos/:idAny keyOne received video.

To check whether someone sent a video for an item, look it up by the submission key you gave the button:

Find a video by submission key
curl "https://api.lassu.ai/v1/api/received-videos?submissionKey=order-482" \
  -H "Authorization: Bearer $LASSU_API_KEY"
Response
{
  "data": [{
    "id": "0193…",
    "buttonId": "0192…",
    "buttonName": "Customer feedback",
    "submissionKey": "order-482",
    "sender": { "email": "pat@example.com", "verifiedBy": "lassu" },
    "details": { "plan": "pro" },
    "signedDetails": {},
    "pageUrl": "https://www.example.com/orders/482",
    "receivedAt": "2026-10-07T17:02:11.000Z",
    "videoId": "0193…",
    "status": "ready",
    "durationMs": 42000,
    "shareUrl": "https://www.lassu.ai/share/vid_0193…"
  }],
  "nextCursor": null
}

sender.email is set when the visitor confirmed it with Lassu (verifiedBy: "lassu") or your site signed it ("website"). signedDetails come from your server’s identity token and can’t be changed by the page.

Recording buttons

RequestKeyWhat it does
GET /recording-buttonsAny keyList the workspace’s buttons.
GET /recording-buttons/:idAny keyOne button.
POST /recording-buttonsFull accessCreate a button: name, websites, and optionally prompt, whoCanRecord, maxDurationMs (whole minutes, 60000 to 3600000; up to 600000 on the Free plan), details.
PATCH /recording-buttons/:idFull accessChange any of those, or set state to active, paused or archived.
Create a button
curl -X POST https://api.lassu.ai/v1/api/recording-buttons \
  -H "Authorization: Bearer $LASSU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Bug reports",
    "prompt": "Show us what went wrong.",
    "websites": ["https://app.example.com"],
    "whoCanRecord": "email"
  }'

whoCanRecord is email (visitors confirm their email), anonymous or external (your site signs who they are).

Webhooks

Add an endpoint in Workspace settings › API & webhooks, or with the API. Lassu then sends a signed POST to it for each event it subscribes to.

receivedVideo.ready
A visitor’s video, or a new take of it, is ready to watch. Includes the received video.
receivedVideo.deleted
A visitor deleted a video they sent. Includes its id, button and submission key.
ping
A test event, sent when you choose Send test event.
A delivery
POST /lassu-webhooks
Content-Type: application/json
Lassu-Event: receivedVideo.ready
Lassu-Delivery: 0193…
Lassu-Signature: t=1791392531,v1=5f2b…

{
  "id": "evt_9Qz…",
  "type": "receivedVideo.ready",
  "createdAt": "2026-10-07T17:02:13.000Z",
  "workspaceId": "0192…",
  "data": { "receivedVideo": { "id": "0193…", "submissionKey": "order-482", "videoId": "0193…", … } }
}
  • Reply with any 2xx status within 10 seconds. Lassu doesn’t follow redirects.
  • If a delivery fails, Lassu tries again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours. After 30 failed attempts in a row the endpoint is paused; resume it in Workspace settings.
  • An event can occasionally arrive more than once. Use its id to ignore repeats, and the API to catch up after downtime.
  • Endpoint URLs must use https and be reachable from the internet.
RequestKeyWhat it does
GET /webhooksAny keyList endpoints.
POST /webhooksFull accessAdd an endpoint: url, events, optional description. The response includes its signing secret.
PATCH /webhooks/:idFull accessChange the url, events or description, or set enabled to turn it off or on.
DELETE /webhooks/:idFull accessRemove an endpoint.
POST /webhooks/:id/testFull accessSend a ping and return the result.
POST /webhooks/:id/rotate-secretFull accessReplace the signing secret. The old one stops working immediately.
Add an endpoint
curl -X POST https://api.lassu.ai/v1/api/webhooks \
  -H "Authorization: Bearer $LASSU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/lassu-webhooks",
    "events": ["receivedVideo.ready", "receivedVideo.deleted"]
  }'

Verify webhooks

Each request has a Lassu-Signature header: a timestamp and an HMAC-SHA256 of "<timestamp>.<raw body>" made with the endpoint’s signing secret. Check it before trusting the request.

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

// Use the raw request body, before any JSON parsing.
export function verifyLassuWebhook(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((part) => part.split("=")));
  const timestamp = Number(parts.t);
  // Reject old requests so a captured one can't be replayed.
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const received = Buffer.from(parts.v1 ?? "", "hex");
  return received.length === expected.length / 2 && timingSafeEqual(received, Buffer.from(expected, "hex"));
}

Errors and limits

An error
{
  "error": {
    "code": "API_KEY_READ_ONLY",
    "message": "This key is read-only. Use a full-access key to make changes."
  }
}
400
The request isn’t valid. The message says what to change.
401
The key is missing, revoked, or its creator is no longer an admin.
403
The key is read-only, or the change isn’t allowed in this workspace.
404
Nothing with that id exists in the workspace.
409
A limit was reached, or something changed at the same time. Try again.
429
Too many requests. Each key can make 180 requests a minute; wait and retry.