جریانی که فقط جلسه میفرستد (n8n)
بعضی ابزارها فقط باید جلسه را به لُب بسپارند. مثلاً یک گردش کار n8n فایل ضبطشدهای را برمیدارد، فایلی که کسی در Slack به اشتراک گذاشته یا ضبط یک جلسهٔ آنلاین، و آن را میفرستد. بعد خود شخص لُب را در برنامه میخواند؛ گردش کار هرگز لازم ندارد آن را بخواند.
به چنین ابزاری توکنی بدهید که فقط «ارسال جلسه» دارد: recordings:write، بدون recordings:read. اگر
روزی لو برود، میتواند دقیقه خرج کند، اما رونوشت و لُب هیچ جلسهای را نمیتواند بخواند.
این توکن هم مثل هر توکن دیگری فقط تا وقتی کار میکند که «حالت توسعهدهنده» روشن باشد. تا وقتی این حالت
خاموش است، هر درخواست پاسخ 403 DEVELOPER_MODE_OFF میگیرد، تا دوباره روشن شود؛
توکنها و دسترسیها را ببینید. گردش کاری که ماهها اجرا
میشود، با دیدن این کد باید به شخص خبر بدهد، نه اینکه پشت سر هم دوباره امتحان کند.
این توکن چه کارهایی میتواند بکند
Section titled “این توکن چه کارهایی میتواند بکند”- جلسه بفرستد:
POST /recordings. هر جلسه به اندازهٔ دقیقههایش خرج میکند، پس برای این توکن سقف روزانه بگذارید. - جلسههایی را که فرستاده دنبال کند: وضعیت آنها را با
GET /recordings/{id}/status، و رویدادهایشان را درGET /events، که در آن فقط جلسههایی را میبیند که خودش فرستاده است. - روی جلسههایی که فرستاده کار کند: از نامگذاری رد شود و جلسهٔ ناموفق را دوباره اجرا کند؛ چرخهٔ یک جلسه را ببینید.
- خودش را بررسی کند، با
GET /whoamiکه به هر توکنی پاسخ میدهد.
چه کارهایی نمیتواند بکند
Section titled “چه کارهایی نمیتواند بکند”- هیچ جلسهٔ دیگری را نمیبیند: جلسهای که در برنامه ضبط شده یا توکن دیگری فرستاده، پاسخ
404میگیرد، گویی وجود ندارد. - رونوشت و لُب هیچ جلسهای را نمیخواند، حتی جلسههای خودش را: وضعیت جلسهای که فرستاده عنوان آن را
دارد و بس. جلسهٔ کامل و فهرست جلسههای آماده به
recordings:readنیاز دارند، و جستوجو و پرسش بهrecordings:query: هر کدام پاسخ403 TOKEN_SCOPEمیگیرد. bundleUrlدر پاسخهای آن همیشهnullاست.
پس گردش کار لینکها را میرساند، هرگز خود جلسه را: naming.url تا وقتی جلسه منتظر نامهاست، و url
وقتی آماده شد. هیچکدام لینک عمومی نیست: هر کدام جلسه را در برنامه باز میکند، و فقط برای کسی که وارد
حساب شده و همین حالا هم میتواند جلسه را ببیند.
روند کار
Section titled “روند کار”- فایل را بفرستید، برای هر فایل با یک
Idempotency-Keyتازه، که برای همهٔ تلاشهای دوبارهٔ همان فایل نگه داشته میشود؛ تکرارپذیری و تلاش دوباره را ببینید. اگر منبع زمان برگزاری جلسه را میداندrecordedAtرا هم بفرستید، و یکtitle. از پاسخ202، مقدارهایidوstatusUrlرا نگه دارید. - منتظر بمانید، با خواندن وضعیت تقریباً هر یک دقیقه یک بار، یا با خواندن فید رویدادها؛ پرسوجوی دورهای و فید رویدادها را ببینید.
- در
NAMING،naming.urlرا برای شخص بفرستید، مثلاً در همان رشتهٔ گفتوگوی Slack، و همچنان منتظر بمانید. یا از نامگذاری رد شوید:POST …/namingبا{ "action": "skip" }، یا از همان اول جلسه را باnaming=skipبفرستید. - در
READY،urlرا برای شخص بفرستید: جلسه، همراه لُب آن، در برنامه. - در
FAILED، اگرerror.retryableبرابرtrueاست دوباره اجرایش کنید و همچنان منتظر بمانید: لُب هم مرحلهٔ شکستخورده را خودش دوباره امتحان میکند، پسFAILEDممکن است موقت باشد، و تلاش دوبارهٔ شما اجرای دومی راه نمیاندازد (409 NOT_FAILEDیعنی جلسه خودش درست شده است). پس از چند بار تلاش دوباره، یا اگرerror.retryableبرابرfalseاست، به شخص خبر بدهید.
در n8n
Section titled “در n8n”یک گره HTTP Request جلسه را میفرستد:
HTTP Request node Method: POST URL: https://app.lobbe.ai/api/v1/recordings Credential (Header Auth): Authorization = Bearer <your token> Body: Form-Data, field audio = the meeting's file
Then poll the statusUrl it answers with, about once a minute.فایل در فیلد audio و همراه نوعش میرود. پاسخ 400 VALIDATION با پیام Unsupported audio type یعنی
فایل بدون نوعش فرستاده شده است؛ محدودیتهای ارسال فایل را ببینید.
از توکن مثل یک گذرواژه مراقبت کنید؛ امن نگه داشتن توکن را
ببینید.
دستورالعمل n8n این گره را قدم به قدم میسازد، با توکنی که بهجای خود گره در یک
اعتبارنامهٔ Header Auth نگه داشته میشود، و حلقهای را هم اضافه میکند که منتظر آماده شدن جلسه
میماند.
با curl
Section titled “با curl”همین روند در خط فرمان. جلسه را میفرستد، اگر جلسه منتظر نامها بماند یک بار لینک نامگذاری را نشان
میدهد، شکستی را که درستشدنی است دوباره اجرا میکند (حداکثر سه بار)، و در READY، در شکستی که
نمیشود دوباره اجرایش کرد، یا با هر خطا، نتیجه را نشان میدهد و میایستد (به jq و uuidgen نیاز
دارد):
key=$(uuidgen) # one key for this file, kept for every retry of itbody=$(curl -sS --fail-with-body https://app.lobbe.ai/api/v1/recordings \ -H "Authorization: Bearer $LOBBE_TOKEN" \ -H "Idempotency-Key: $key" \ -F "audio=@meeting.m4a;type=audio/mp4" \ -F "title=Weekly product sync" \ -F "recordedAt=2026-10-19T10:30:00+03:30")status_url=$(jq -r '.recording.statusUrl // empty' <<<"$body")[ -n "$status_url" ] || echo "$body"told=""retries=0while [ -n "$status_url" ]; do body=$(curl -sS --fail-with-body "$status_url" \ -H "Authorization: Bearer $LOBBE_TOKEN") || { echo "$body"; break; } status=$(jq -r .status <<<"$body") if [ "$status" = NAMING ] && [ -z "$told" ]; then echo "Name the speakers: $(jq -r .naming.url <<<"$body")" told=yes fi if [ "$status" = READY ]; then echo "The Lobbe is ready: $(jq -r .url <<<"$body")" break fi if [ "$status" = FAILED ]; then if [ "$(jq -r .error.retryable <<<"$body")" != true ] || [ "$retries" -ge 3 ]; then echo "It failed: $(jq -c .error <<<"$body")" break fi retries=$((retries + 1)) # 409 NOT_FAILED: it recovered by itself in the meantime. Keep waiting either way. body=$(curl -sS --fail-with-body -X POST "${status_url%/status}/retry" \ -H "Authorization: Bearer $LOBBE_TOKEN") || [ "$(jq -r .error.code <<<"$body" 2>/dev/null)" = NOT_FAILED ] || { echo "$body"; break; } fi sleep 60doneاگر «نامگذاری گویندهها» روی «بپرس» باشد، جلسه ممکن است ساعتها منتظر نامها بماند. خواندن وضعیت آن هر یک دقیقه یک بار در تمام این مدت بسیار کمتر از سقف درخواستهای توکن است.