Reels auf Instagram und TikTok veröffentlichen
Fertige Reels (bin/reel) planen, per WhatsApp freigeben und zum Zeitpunkt auf Instagram (@taskmonkey.ai) und TikTok posten. Nur Workspace meco.
Plattform-intern (Workspace meco): Reels aus bin/reel (reel-editor) bzw. fertige MP4s gehen nach Marcus' Freigabe per WhatsApp automatisch raus. Keine KI-Avatar-Videos; das KI-Label-Feld (ai_generated, TikTok is_aigc) ist trotzdem vorgesehen und steht standardmäßig auf „nein“.
Ablauf
- Hochladen (Mac):
reelStorageCreateUploadUrlliefert einen Objektnamen und eine signierte Upload-URL (2 h). Hochladen mitcurl -sS -X PUT -H "Content-Type: video/mp4" --data-binary @reel.mp4 "<upload_url>". Ablage: privater Supabase-Bucketreels(meco-Speicher). - Planen:
scheduleReel(video_object, caption, platforms, publish_at, ai_generated=false)legt einen Eintrag in Supabasereel_schedulean (Statuspending_approval). - Freigabe: Marcus bekommt Video-Link (7 Tage gültig), Plattformen, Zeitpunkt und Caption per WhatsApp (Plattform-Nummer, nur im 24-h-Fenster) mit den Buttons Veröffentlichen / Nein, dazu immer eine Mail. Ist das Fenster zu, steht in der Mail der Befehl
/reel ok <id> <code>zum Abschicken an die TaskMonkey-Nummer. - Der Klick schickt
/reel ok|nein <id8> <code>. DerConversationRouternimmt das nur von der Nummer des Reel-Empfängers an (Onboarding.alert.reel_recipients, sonst.recipients), ohne LLM, und legt den JobdecideScheduledReelan. Der prüft Einmal-Code und Status und bestätigt per WhatsApp. - Posten: Der Scheduled Task
publish_reels(runScheduledReels, alle 5 min) postet freigegebene Reels abpublish_at. Danach kommt eine Meldung mit dem Ergebnis je Plattform.
Ohne „Veröffentlichen“ geht nichts raus. publishInstagramReel und publishTikTokVideo sind only_via: runScheduledReels, die Roh-Calls (igCreateReelContainer, igPublishContainer, tiktokInitVideoPost) nur über diese Hüllen. Eine Anfrage, die 24 h nach publish_at noch offen ist, wird expired.
Tools
| Tool | Was |
|---|---|
reelStorageCreateUploadUrl, reelStorageSignUrl, reelStorageDelete |
Supabase Storage (apis.supabase_storage), je ein Call |
reelProxyUrl |
signierte URL https://app.taskmonkey.de/media/reels/<objekt>.mp4?expires=…&token=… (ReelMediaController, Range-fähig) |
igCreateReelContainer, igGetContainerStatus, igPublishContainer, igGetPublishingLimit |
Instagram Graph API über apis.meta_ads (System-User-Token) |
metaCheckPublishPermissions |
liest me/permissions und zeigt, welche Rechte fehlen |
publishInstagramReel |
Container → Status pollen bis FINISHED (ERROR/EXPIRED = Abbruch, Timeout apis.reels.instagram_max_wait) → media_publish. Prüft vorher das Limit von 50 Posts/24 h |
tiktokGetCreatorInfo, tiktokInitVideoPost, tiktokGetPostStatus, tiktokGetUserInfo |
TikTok Content Posting API über apis.tiktok (Auth oauth_connection) |
publishTikTokVideo |
creator_info → init (PULL_FROM_URL) → Status pollen. Ohne Audit immer SELF_ONLY |
scheduleReel, decideScheduledReel, runScheduledReels |
Planung, Freigabe, Veröffentlichung |
notifyReelApproval, notifyReelStatus |
Meldungen an Marcus (Core ReelMediaTools) |
Wiederholung: Wenn Instagram nach dem Timeout noch verarbeitet oder media_publish fehlschlägt, versucht es der nächste Lauf noch einmal mit demselben Container (höchstens 3 Läufe). Was schon online ist, wird nie erneut gepostet. Ein TikTok-Timeout gilt als „übergeben“ und wird nicht wiederholt, sonst gäbe es einen Doppelpost. Ein Lauf, der über 1 h in publishing hängt, wird failed und gemeldet, aber nicht automatisch wiederholt.
Video-URL: warum zwei Wege
- Instagram holt
video_urlvon jeder öffentlichen URL. Wir nehmen eine signierte Supabase-URL (6 h). - TikTok holt nur von Domains oder URL-Präfixen, die in der TikTok-App verifiziert sind, und folgt keinen Redirects. Eine Supabase-Projekt-URL kann man dort nicht verifizieren. Deshalb liefert
ReelMediaControllerdas Objekt unterapp.taskmonkey.de/media/reels/…aus (HMAC mit dem App-Salt, zeitlich begrenzt). In TikTok muss dafür die Domaintaskmonkey.deverifiziert sein (DNS-TXT, gilt auch fürapp.).
Klickliste Meta (Instagram)
Stand 04.10. (metaCheckPublishPermissions, lesend): Der Token hat pages_show_list, pages_read_engagement, business_management, ads_management, ads_read, leads_retrieval, pages_manage_ads. Es fehlen instagram_basic und instagram_content_publish. content_publishing_limit antwortet mit „(#10) Application does not have permission for this action“.
- developers.facebook.com → App „TaskMonkey Ads“ → Anwendungsfälle → Anwendungsfall hinzufügen → „Nachrichten und Inhalte auf Instagram verwalten“ (Instagram API mit Facebook Login). Darin
instagram_basicundinstagram_content_publishhinzufügen. Standard-Zugriff reicht, weil es das eigene Business-Konto ist (kein App Review). - business.facebook.com → Einstellungen → Konten → Instagram-Konten → prüfen, dass @taskmonkey.ai dem Business gehört und mit der Seite 108629875903438 verbunden ist (Seite → Verknüpfte Konten → Instagram).
- Dort bei @taskmonkey.ai: Personen/Partner zuweisen → Systemnutzer „Taskmonkey“ → Vollzugriff (mindestens „Inhalte“).
- Einstellungen → Konten → Seiten → 108629875903438 → Systemnutzer „Taskmonkey“ zugewiesen? Sonst zuweisen (Vollzugriff).
- Einstellungen → Nutzer → Systemnutzer → „Taskmonkey“ → Token generieren → App „TaskMonkey Ads“, Ablauf „Nie“. Häkchen: alles, was schon drin ist (
ads_management,ads_read,business_management,leads_retrieval,pages_show_list,pages_read_engagement,pages_manage_ads), plusinstagram_basicundinstagram_content_publish. - Den neuen Token an den Orchestrator geben. Er ersetzt
META_ADS_ACCESS_TOKENintenants_untracked/meco/.env, lokal und auf Prod. Der alte Token bleibt gültig, bis man ihn widerruft. - Prüfen:
bin/cake test_tool -t meco --tool metaCheckPublishPermissions→ok: true, dann--tool igGetPublishingLimit→quota_usage.
Klickliste TikTok
- developers.tiktok.com → mit dem TikTok-Konto von TaskMonkey einloggen → Manage apps → Connect an app → Organisation „meco GmbH“ anlegen bzw. wählen, App „TaskMonkey“.
- App details: Icon (1024×1024), Name, Kategorie „Business“, Beschreibung („Plant und veröffentlicht die Reels von TaskMonkey nach Freigabe“), Platform Web, Website
https://taskmonkey.de, Privacyhttps://taskmonkey.de/datenschutz, Terms of Service: die URL der Plattform-Nutzungsbedingungen bzw. AGB (TikTok verlangt beide Links; eine eigene AGB-Seite auf taskmonkey.de gibt es im Repo noch nicht). - Products → Add products: Login Kit und Content Posting API. Bei Content Posting API Direct Post einschalten.
- Login Kit → Redirect URI:
https://app.taskmonkey.de/manage/o-auth-connections/callback. - Scopes:
user.info.basic,video.upload,video.publish. - URL properties → Verify domain →
taskmonkey.de→ TXT-Eintrag in Cloudflare (Zone taskmonkey.de) anlegen → Verify. - Client key und Client secret an den Orchestrator geben:
TIKTOK_CLIENT_KEYundTIKTOK_CLIENT_SECRETinconfig/.envauf Prod (und lokal zum Testen). - Nach dem Deploy: app.taskmonkey.de/manage/o-auth-connections/add/tiktok (eingeloggt im Workspace meco) → „Videos veröffentlichen“ → TikTok-Login mit dem TaskMonkey-Konto → zustimmen. Der Token liegt danach verschlüsselt in
oauth_connectionsund wird automatisch erneuert (Access 24 h, Refresh 365 Tage). Andere Workspaces bekommen den Provider nicht (only_tenants: meco). - Test:
bin/cake test_tool -t meco --tool tiktokGetUserInfo→display_name. - Sandbox: Solange die App nicht live ist, im Tab Sandbox das TaskMonkey-Konto als Target User eintragen. Mit der Sandbox-App funktioniert der Login nur für diese Konten.
- Audit (für öffentliche Posts): Submit for review. Gebraucht wird:
- ein Demo-Video des kompletten Ablaufs: Login über TaskMonkey, Freigabe-Anfrage, Post auf TikTok,
- eine Erklärung je Scope,
- die verifizierte Domain,
- Datenschutz und AGB online.
Was ohne Audit geht (ehrlich)
-
Nicht auditierte Apps posten nur privat (
SELF_ONLY, nur für das Konto selbst sichtbar). TikTok begrenzt außerdem, wie viele Konten in 24 h posten dürfen.publishTikTokVideoerzwingtSELF_ONLY, solangeapis.tiktok.auditedauffalsesteht. Erst nach bestandenem Auditaudited => trueunddefault_privacy => 'PUBLIC_TO_EVERYONE'setzen. -
TikToks Richtlinien für Direct Post verlangen, dass der Nutzer jeden Post in der App sieht und bestätigt:
- Konto-Name,
- Sichtbarkeit wählen, ohne Vorauswahl,
- Kommentare, Duett und Stitch,
- Hinweis auf kommerzielle Inhalte,
- Zustimmung zur Music Usage Confirmation.
Unsere Freigabe per WhatsApp zeigt Video, Caption und Zeitpunkt, aber nicht diese Bedienelemente. Ein Audit für vollautomatisches Posten kann deshalb abgelehnt werden. Dann bleiben zwei Wege: eine kleine Freigabe-Seite mit diesen Elementen bauen, oder auf TikTok privat posten und von Hand auf öffentlich stellen.
-
Ein Post per API zählt bei TikTok wie ein normaler Post. Hashtags gehören in die Caption (
title, max. 2200 Zeichen).
Nach dem Deploy
- Supabase-Migration
db/supabase/meco_2026-10-04_reel_schedule.sqlausführen (Tabellereel_schedule+ Bucketreels, idempotent). - Meta-Klickliste oben, neuen
META_ADS_ACCESS_TOKENsetzen. - TikTok-Klickliste,
TIKTOK_CLIENT_KEY/TIKTOK_CLIENT_SECRETinconfig/.env, Verbindung anlegen. publish_reelsinconfig/tenants/meco/scheduled.phpaufenabled => truestellen. Das ist Code, also wieder Deploy.- Erster Test: ein Reel mit
platforms: ["instagram"]undpublish_atin 10 Minuten planen, freigeben, Ergebnis abwarten.
Konfiguration
apis.meta_ads.instagram_user_id: 17841434304012708 (@taskmonkey.ai)apis.supabase_storage: Storage-API mit dem Service-Key,bucket„reels“apis.tiktok:audited,default_privacyapis.reels:preview_ttl,fetch_ttl,*_max_wait,*_poll_intervalOnboarding.alert.reel_recipients(config/onboarding.php): Empfänger der Freigabe-Anfragen, leer =recipientsOAuthProviders.tiktok(config/oauth_providers.php):client_key, Scopes mit Komma,only_tenants,api_hosts