Automations
A automation is a batch of AI posts generated at once and auto-scheduled across a posting window. You set a cadence (posts per day, for how many days), Viraloop generates one post per slot using the workspace's brand context, you review the batch, and launching turns every post into a scheduled post at its slot. Automation endpoints need the automations:read and automations:write scopes.
Lifecycle
draft -> generating -> review -> active -> completed or cancelled
draft: created and fully editable, no posts yet; a generation run that produces nothing also falls back heregenerating: posts are being generated; pollGET /automations/{id}until the automation leaves this statusreview: the batch is ready; inspect the posts, tweak settings or regenerate, then launchactive: launched; posts render server-side and publish automatically at their slotscompleted: the posting window has run its coursecancelled: cancelled; unsent posts were removed
Quota
The monthly automation quota depends on the plan. GET /automations returns it alongside the list:
{
"quota": {
"monthlyLimit": 8,
"usedThisMonth": 2,
"remaining": 6
}
}
Once the quota is used up, starting another automation fails with error type usage_limit_reached; see errors and rate limits.
curl -s "https://viraloop.io/api/v1/automations" \
-H "Authorization: Bearer $VIRALOOP_API_KEY"
viraloop automations list --json
1. Create
POST /automations creates the automation in draft (scope automations:write, supports the Idempotency-Key header). Only name is required; everything else can be set now or later via PATCH:
cadence:postsPerDay(1 to 10),lengthDays(1 to 90),startDate(first posting day, defaults to tomorrow),timezone(IANA name) and optionaltimeSlotslike["09:00", "15:00"]selectedAccounts: platform keys mapping to arrays of account ids fromGET /accounts, with at least one non-empty platform array. Every post in the automation publishes to all selected accounts.settings: generation settings, all optional with sensible defaults:contentMix(format weights, keyswalloftext,slideshow,greenscreen,hookdemo),remixRatio,angleDistribution,mentionBusiness,genderPreference,ownMediaMix,influencerFrequencyownerType(brandorinfluencer;influencerIdis required wheninfluencer),tiktokMode(directorinbox; inbox sends TikTok drafts to the inbox instead of publishing) andworkspaceId
curl -s -X POST "https://viraloop.io/api/v1/automations" \
-H "Authorization: Bearer $VIRALOOP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "July launch week",
"cadence": { "postsPerDay": 2, "lengthDays": 7, "timezone": "America/New_York" },
"selectedAccounts": { "tiktok": ["665f1b2a9c31a2b3c4d5e700"] }
}'
viraloop automations create --name "July launch week" --posts-per-day 2 --length-days 7 \
--timezone America/New_York --accounts tiktok:<accountId> --json
2. Generate
POST /automations/{id}/generate generates postsPerDay x lengthDays AI posts, each assigned a schedule slot. It is asynchronous: the response is 202 immediately (rate limited to 5 requests per 3600 seconds):
{
"success": true,
"data": {
"id": "665f1b2a9c31a2b3c4d5e710",
"kind": "automation",
"status": "generating",
"totalPosts": 14,
"generatedCount": 0,
"statusUrl": "/api/v1/automations/665f1b2a9c31a2b3c4d5e710"
}
}
Poll GET /automations/{id} until the automation leaves generating: review means the batch is ready; back to draft means nothing was generated. Calling generate again while a run is in flight is a no-op that reports progress (generatedCount against totalPosts). Regenerating a automation in review replaces its posts.
curl -s -X POST "https://viraloop.io/api/v1/automations/<id>/generate" \
-H "Authorization: Bearer $VIRALOOP_API_KEY"
curl -s "https://viraloop.io/api/v1/automations/<id>" \
-H "Authorization: Bearer $VIRALOOP_API_KEY"
viraloop automations generate <id> --json
viraloop automations get <id> --json
3. Review
GET /automations/{id}/posts lists the generated posts in schedule order. Each carries caption, postCaption, hashtags, its rationale and its assigned scheduledTime:
curl -s "https://viraloop.io/api/v1/automations/<id>/posts" \
-H "Authorization: Bearer $VIRALOOP_API_KEY"
viraloop automations posts <id> --json
To tweak the automation, PATCH /automations/{id} updates name, cadence, selectedAccounts, settings, ownerType, influencerId or tiktokMode. Editing is only allowed while the automation is in draft or review; any other status returns 409 with error type conflict. Sub-objects are replaced wholesale, so send the complete cadence, selectedAccounts or settings object, not just the changed keys.
curl -s -X PATCH "https://viraloop.io/api/v1/automations/<id>" \
-H "Authorization: Bearer $VIRALOOP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"selectedAccounts": {"tiktok": ["665f1b2a9c31a2b3c4d5e700"]}}'
viraloop automations update <id> --accounts tiktok:<accountId> --json
If the content itself is off rather than the settings, regenerate instead: it replaces the batch.
4. Launch
POST /automations/{id}/launch converts every generated post into a scheduled post at its slot and activates the automation. It requires status review and at least one selected account:
{
"success": true,
"data": {
"id": "665f1b2a9c31a2b3c4d5e710",
"kind": "automation",
"status": "active",
"scheduled": 14,
"failed": 0,
"statusUrl": "/api/v1/automations/665f1b2a9c31a2b3c4d5e710"
}
}
Posts render server-side after the call returns and publish automatically at their slots; nothing more is required. Track them with GET /posts?automationId=<id> or the calendar from posts and scheduling.
curl -s -X POST "https://viraloop.io/api/v1/automations/<id>/launch" \
-H "Authorization: Bearer $VIRALOOP_API_KEY"
viraloop automations launch <id> --json
Cancelling
POST /automations/{id}/cancel cancels the automation and removes its unsent posts. Content that already went out stays live. Cancelling is idempotent: a cancelled or completed automation returns cancelledPosts: 0.
curl -s -X POST "https://viraloop.io/api/v1/automations/<id>/cancel" \
-H "Authorization: Bearer $VIRALOOP_API_KEY"
viraloop automations cancel <id> --json
UGC campaigns (kind: "ugc")
A UGC campaign is a guided automation for product videos fronted by one character (your own imported influencer or any existing one) speaking with one library voice. Nothing paid happens until you choose to render, and you review every script first.
- Create it with
kind: "ugc"and the campaign inputs underugc:brief(product, audience, benefit, offer, cta, notes),characterId(an influencer id; import your own withPOST /influencersandgeneratePreview: false),voiceId(fromGET /tts/voices),format(talkingorspokesperson),durationTarget(15 or 30) andvariantCount(1 to 10).PATCH /automations/{id}mergesugc; changing the character, voice, format or product image invalidates every quote. Pick an Eleven v3 voice (eleven_v3:ids) with a social media or conversational use case for the most natural read: v3 performs cues like[sighs]or[laughs]in the script instead of speaking them, and the scripts are drafted with a few of them. POST /automations/{id}/ugc/composemakes the still every variant is animated from (3 credits, synchronous). Spokesperson campaigns need it (the character holdingugc.productImage). Talking campaigns can setugc.selfie: trueand compose a front-camera phone-selfie version of the character, which reads far more like filmed UGC than a posed portrait; without it the portrait is used as-is.POST /automations/{id}/ugc/scriptsdrafts the variants (hook, problem, benefit, CTA; a different hook each), free. Edit a script withPATCH /automations/{id}/posts/{postId}(script), or re-roll one withvariantId.POST /automations/{id}/ugc/preparewithvariantIdssynthesizes each script, measures the real speech length and returns the credit quote (per second of speech: 14 credits forlook: "studio", the default, one continuous take with no cuts that the video model speaks itself and we re-voice with the campaign voice; or 3 forlook: "portrait", which animates the still in jump-cut beats). Studio speech must fit in 28.5 seconds. Speech over 30 seconds returnstooLongwith no quote: shorten the script and prepare again.POST /automations/{id}/ugc/renderwithvariantIdscharges each quote once and renders two at a time. PollGET /automations/{id}/posts: each variant carriesvideo.status(queued,processing,ready,failed) andcontentId. A failed render is refunded once; call render again for that variant only. Finished videos keep working even if a sibling fails.- Download a finished video with
GET /content/{contentId}/download(no social accounts needed), or schedule: approve variants (PATCH ... {"approved": true}), set each one'sscheduledTimein the future, setselectedAccounts(andownerType/influencerIdfor who publishes; the featured character does not have to be the publishing account), thenPOST /automations/{id}/launch. Only approved, finished variants launch; an expired slot blocks the launch until you pick a new time. A launched campaign can approve and launch more variants later.
viraloop automations create --name "Notely UGC" --kind ugc --ugc '{"characterId":"665f...","voiceId":"eleven_v3:EXAVITQu4vr4xnSDxMaL","format":"talking","brief":{"product":"Notely","benefit":"1-page lecture summaries"}}'
viraloop automations ugc-compose <id>
viraloop automations ugc-scripts <id>
viraloop automations ugc-prepare <id> --variants <postId1>,<postId2>
viraloop automations ugc-render <id> --variants <postId1>,<postId2>
viraloop automations post-update <id> <postId1> --approve --scheduled-time 2026-10-01T15:00:00Z
viraloop automations launch <id>