Skip to main content

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 here
  • generating: posts are being generated; poll GET /automations/{id} until the automation leaves this status
  • review: the batch is ready; inspect the posts, tweak settings or regenerate, then launch
  • active: launched; posts render server-side and publish automatically at their slots
  • completed: the posting window has run its course
  • cancelled: cancelled; unsent posts were removed

Quota

The monthly automation quota depends on the plan. GET /automations returns it alongside the list:

json
{
	"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.

bash
curl -s "https://viraloop.io/api/v1/automations" \
  -H "Authorization: Bearer $VIRALOOP_API_KEY"
bash
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 optional timeSlots like ["09:00", "15:00"]
  • selectedAccounts: platform keys mapping to arrays of account ids from GET /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, keys walloftext, slideshow, greenscreen, hookdemo), remixRatio, angleDistribution, mentionBusiness, genderPreference, ownMediaMix, influencerFrequency
  • ownerType (brand or influencer; influencerId is required when influencer), tiktokMode (direct or inbox; inbox sends TikTok drafts to the inbox instead of publishing) and workspaceId
bash
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"] }
  }'
bash
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):

json
{
	"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.

bash
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"
bash
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:

bash
curl -s "https://viraloop.io/api/v1/automations/<id>/posts" \
  -H "Authorization: Bearer $VIRALOOP_API_KEY"
bash
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.

bash
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"]}}'
bash
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:

json
{
	"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.

bash
curl -s -X POST "https://viraloop.io/api/v1/automations/<id>/launch" \
  -H "Authorization: Bearer $VIRALOOP_API_KEY"
bash
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.

bash
curl -s -X POST "https://viraloop.io/api/v1/automations/<id>/cancel" \
  -H "Authorization: Bearer $VIRALOOP_API_KEY"
bash
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.

  1. Create it with kind: "ugc" and the campaign inputs under ugc: brief (product, audience, benefit, offer, cta, notes), characterId (an influencer id; import your own with POST /influencers and generatePreview: false), voiceId (from GET /tts/voices), format (talking or spokesperson), durationTarget (15 or 30) and variantCount (1 to 10). PATCH /automations/{id} merges ugc; 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.
  2. POST /automations/{id}/ugc/compose makes the still every variant is animated from (3 credits, synchronous). Spokesperson campaigns need it (the character holding ugc.productImage). Talking campaigns can set ugc.selfie: true and 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.
  3. POST /automations/{id}/ugc/scripts drafts the variants (hook, problem, benefit, CTA; a different hook each), free. Edit a script with PATCH /automations/{id}/posts/{postId} (script), or re-roll one with variantId.
  4. POST /automations/{id}/ugc/prepare with variantIds synthesizes each script, measures the real speech length and returns the credit quote (per second of speech: 14 credits for look: "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 for look: "portrait", which animates the still in jump-cut beats). Studio speech must fit in 28.5 seconds. Speech over 30 seconds returns tooLong with no quote: shorten the script and prepare again.
  5. POST /automations/{id}/ugc/render with variantIds charges each quote once and renders two at a time. Poll GET /automations/{id}/posts: each variant carries video.status (queued, processing, ready, failed) and contentId. A failed render is refunded once; call render again for that variant only. Finished videos keep working even if a sibling fails.
  6. Download a finished video with GET /content/{contentId}/download (no social accounts needed), or schedule: approve variants (PATCH ... {"approved": true}), set each one's scheduledTime in the future, set selectedAccounts (and ownerType/influencerId for who publishes; the featured character does not have to be the publishing account), then POST /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.
bash
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>