OmniVoke
Documentation

User Guide

Everything you need to go from your first product to a measured signup pipeline.

OmniVoke User Guide

A complete guide to using OmniVoke: from your first product to a measured signup pipeline. Covers the dashboard, the nine supported platforms, the attribution model, scheduling, approvals, and the public API.


Table of contents

  1. What OmniVoke does
  2. Core concepts
  3. Getting started
  4. Products
  5. Connecting platforms
  6. Creating and publishing content
  7. Generation kinds
  8. Options: audience and destination
  9. Reading your results (Outcomes)
  10. Scheduling
  11. Approvals
  12. Evergreen recycling
  13. The public API
  14. How attribution works
  15. Troubleshooting and FAQ

1. What OmniVoke does

OmniVoke turns one idea into a measured marketing loop:

Create → Generate → Render → Publish → Attribute → Test → Amplify → Report

You give it a product, an audience, and a topic. It writes the hook, the caption, a short-video script, and a call-to-action (CTA), publishes to the platforms you have connected, and reports which hook and platform actually drove signups.

Two ways to drive it:

  • The dashboard (a human): type a topic, hit one button.
  • The API (a process): POST the same inputs and get the same pipeline.

Everything a human can do, an API call can do, and both produce the same result.


2. Core concepts

Term Meaning
Tenant Your workspace. Everything you create is scoped to it and invisible to other tenants.
Product A thing you are marketing (a SaaS app, a book, a newsletter). Holds the landing-page URL and a brand-voice document.
Post (content) The canonical piece of content: caption, script, CTA, UTM tags, and the hook/variant that produced it.
Publication One publish attempt of one post to one platform, at one occurrence.
Platform A destination: YouTube, LinkedIn, Bluesky, Mastodon, Reddit, Pinterest, X/Twitter, Facebook, or Instagram.
Hook The opening formula (AIDA, PAS, BAB, curiosity gap, contrarian, and more) that the caption opens with.
Variant The A/B identity of a post, carried in utm_content so results are attributable.
Attribution Tracing a click and a signup back to the exact post, hook, platform, and campaign that produced it.

3. Getting started

  1. Open the dashboard (Open workspace on the landing page).
  2. Add your first product (see Products).
  3. Connect at least one platform (see Connecting platforms).
  4. Type a topic and publish.

On a fresh account the publish card shows an inline "add your first product" form, so the first-run path is: add product, connect a platform, publish.


4. Products

A product is what you are marketing. Each product carries:

  • Name — shown in generated copy and the post title.
  • Landing page URL — the destination your CTA links to, with UTM tags appended.
  • Brand voice — an 8-section document (style, tone, keywords, grammar, vocabulary, on/off-tone examples, persona, context) that shapes generated copy.

Managing products

  • Add: in the Products section, enter a name and a landing URL and save. The same inline form appears in the publish card when you have zero products.
  • Select: the publish card auto-selects your only product. With two or more products, a selector appears above the topic box so you pick before publishing.

5. Connecting platforms

OmniVoke publishes to nine platforms. Each keeps its credentials encrypted at rest (AES-256-GCM). Two connection styles:

  • OAuth redirect (YouTube, LinkedIn): authorize through the platform's own flow.
  • Key / token paste (everything else): generate a token on the platform and paste it in.

The /setup page (linked from the Connect modal) walks through where to find each key.

Platform Auth Notes
YouTube OAuth 2.0 Google Cloud project + YouTube Data API v3; text-only has no surface, so YouTube publishes as a Short with an attached video.
LinkedIn OAuth 2.0 Posts + analytics products; org analytics requires a company page URN (administrator-gated).
Bluesky App password Handle + app password from bsky.app.
Mastodon Access token Any instance; write:statuses + read:accounts scopes.
Reddit Script app Posts to a subreddit you moderate.
Pinterest OAuth bearer Board ID required; image pins.
X / Twitter OAuth (paid tier) Write access needs a paid tier (Basic or higher).
Facebook Pages Page token pages_manage_posts; live apps need app review (dev mode works without).
Instagram OAuth (Business/Creator) Needs a Business/Creator account linked to a Facebook Page; personal accounts cannot publish.

See docs/PLATFORMS/*.md for endpoint and credential-mapping detail.


6. Creating and publishing content

The one-button flow:

  1. Pick a product (auto-selected if you have one).
  2. Type a topic — or leave it blank and OmniVoke picks one. "Surprise me" fills a random suggested topic.
  3. Publish.

OmniVoke generates a caption (150-300 words, opens with the hook, ends with a CTA), a 30-second video script, a CTA, and hashtags. It then publishes to your selected destination and shows the result.

The result panel

After publishing you see:

  • Caption — the post body, with the tracked link embedded.
  • Video script — the 30-second voiceover narration.
  • CTA — the single call-to-action sentence.
  • Hashtags — the generated tags.

A demo mode badge appears when content was produced by the deterministic mock (no LLM key configured), so you always know whether output is real or placeholder.


7. Generation kinds

Beyond the default caption, OmniVoke can produce other content shapes. These are all reachable from the single generate endpoint (kind parameter):

Kind Output
caption Caption + script + CTA + hashtags (the default).
carousel A multi-slide post (LinkedIn document posts).
thread A multi-post sequence.
hashtags A hashtag strategy.
calendar A 30-day themed content calendar.

Note: carousel, thread, hashtags, and calendar are currently exposed through the API and the generate route, not yet as separate dashboard buttons. The dashboard's one-button flow is the caption kind.


8. Options: audience and destination

Behind the Options disclosure on the publish card:

  • Audience — who the content is for (e.g. "early-stage founders"). Feeds the brand-voice prompt. Defaults to "your target customer" if left blank.
  • Destination — where to publish. One of the nine platforms, or BOTH (LinkedIn + YouTube Short). Defaults to LinkedIn.
  • YouTube Short — YouTube has no text-only surface, so a Short requires an attached vertical video. When you select YouTube Short, a file picker appears.

Destination determines the UTM source and medium on the tracked link (e.g. LinkedIn → source=linkedin, YouTube Short → source=youtube&medium=short).


9. Reading your results (Outcomes)

The Outcomes section answers "which hook drove the most signups."

Key performance indicators

KPI Meaning
Signups Total attributed signups.
Cost / signup Spend per signup (shows "no spend tracked" until spend is recorded).
Conversion Clicks → signups rate.
Clicks Total attributed clicks.

Deeper breakdowns

  • Winning hook — the single hook that drove the most signups.
  • Signups by platform — counts per destination.
  • Funnel — click → signup → qualified, with drop-off and conversion between stages.
  • A/B significance — per-experiment statistical significance (z-score, p-value, winner, required sample size).
  • Per-campaign rollup — signups, clicks, spend, conversion, cost-per-signup per campaign, plus cross-promotion opportunities.

10. Scheduling

Scheduling lets posts fire on a recurring cadence without manual clicks. It is driven by cron-style slots plus best-time resolution.

Recurring slots

A slot stores a cron expression, a timezone, a platform, and a nextFireAt cursor. On each scheduler tick the cursor advances off the prior boundary (never "now"), so fire times stay anchored to the schedule with no drift.

  • If the scheduler was suspended and falls more than one period behind, it does not backfill a burst. It coalesces to a single fire, logs the skipped boundaries, and resets the cursor.
  • The scheduler tick runs on a daily Vercel cron (/api/scheduler/tick).

Best-time-to-post

OmniVoke learns the best (day-of-week, hour) to publish per platform from past engagement, with Laplace smoothing and a minimum-observations floor. When best-time yields a concrete window it resolves the run to that window; otherwise it falls back to a per-platform default hour (YouTube 17:00, LinkedIn 09:00 local).

Interval syntax

Repeat intervals accept both ISO-8601 durations (P7D, PT12H) and simple units (7d, 2w, 3h, 4m, 1y).

Note: scheduling is currently API-driven (via recurring ScheduleSlot records and the scheduler cron), not yet a dashboard form.


11. Approvals

Approval is a first-class post state, not an afterthought:

  • A post can be marked requiresApproval. A due job for such a post routes to PENDING_APPROVAL instead of straight to publish.
  • A human approves, rejects, or force-publishes via the approve endpoint.
  • Every approve/reject/force-publish transition writes an audit record with the actor, timestamp, and reason. A force-publish records who requested it and why, so the audit trail is real, never a fabricated "scheduler" placeholder.

Approval state is one of the ten ContentStatus values: DRAFT, SCHEDULED, PENDING_APPROVAL, APPROVED, REJECTED, PUBLISHING, PUBLISHED, PARTIALLY_PUBLISHED, FAILED, CANCELLED.


12. Evergreen recycling

A post can be marked to repeat on an interval, so a good piece of content keeps re-publishing without you redoing it.

  • Set repeat + repeatInterval (and optionally repeatUntil).
  • When a completed job is recyclable, OmniVoke enqueues a new occurrence with a fresh idempotency key, anchored to the prior job's runAt (so the cadence stays stable regardless of publish latency).
  • Recycling stops at repeatUntil.

Because each occurrence gets a new idempotency key, the exactly-once guarantee holds unchanged across recycled publishes.


13. The public API

The v1 API mirrors the dashboard: anything you can do by hand, you can script. It is key-gated.

Authentication

API keys authenticate requests. Keys are created and revoked via the keys endpoints; only the SHA-256 hash is stored, and the raw key is returned exactly once at creation. Each key has scopes (content:read, content:write, webhook:manage, key:manage) and a per-minute rate limit.

Content

Endpoint Purpose
POST /api/v1/content Create content. Pass either product + audience + topic (generate) or a pre-written body. Optional run: true triggers the async pipeline.
GET /api/v1/content/[id] Read a content item.
POST /api/v1/content/[id]/run Run (publish) an existing content item.

Keys

Endpoint Purpose
POST /api/v1/keys Create an API key (raw key returned once).
DELETE /api/v1/keys/[id] Revoke an API key.

Webhooks

Endpoint Purpose
POST /api/v1/webhooks Subscribe an endpoint to lifecycle events.
DELETE /api/v1/webhooks/[id] Remove a subscription.

Webhook deliveries are HMAC-signed with a per-endpoint secret (returned once at creation). Deliveries are retried with exponential backoff, and a daily sweep cron re-attempts due failed deliveries across process lifetimes.

Idempotency

Content creation is idempotent. Send an Idempotency-Key header; a replayed request with the same key returns the stored response instead of creating a duplicate.

Example: create and run a post

POST /api/v1/content
Authorization: Bearer <api-key>
Content-Type: application/json

{
  "product": "Acme",
  "audience": "bootstrapped founders",
  "topic": "shipping faster with AI",
  "destination": "LINKEDIN",
  "run": true
}

The response returns the content id and its status. The publish runs through the same engine as the dashboard button, with the same exactly-once guarantees.


14. How attribution works

Every post's CTA carries a tracked URL built from your landing page plus UTM parameters:

  • source and medium — derived from the destination.
  • campaign — derived from the product name.
  • content — the A/B variant (the resolved variantA/variantB when an experiment matches, otherwise the hook-derived variant id).
  • A personalization_id — a random per-visitor identifier so attribution stays clean across the landing-page → signup hop.

When a visitor clicks, the tracking snippet reports the click; when they sign up, the signup event lands via /api/events (gated by an ingest key). OmniVoke then attributes the signup back to the exact hook, platform, and campaign.

Referral/affiliate codes are also captured alongside signups, so referral-driven signups can be attributed to their source.


15. Troubleshooting and FAQ

I clicked Publish and nothing happened.

Check that you have (a) at least one product and (b) at least one connected platform. On a fresh account the publish card shows an inline "add your first product" form.

The result has a "demo mode" badge.

No LLM key is configured, so OmniVoke fell back to a deterministic mock. Output is placeholder, not real generation. Set OPENROUTER_API_KEY (and the tier models) to enable real generation.

YouTube won't publish.

YouTube has no text-only surface. Select YouTube Short and attach a vertical video.

X/Twitter or Instagram won't publish.

X/Twitter API write access needs a paid tier; Instagram needs a Business/Creator account linked to a Facebook Page. Personal Instagram accounts cannot publish via the API.

My platform shows "Connected" but publishes fail.

Re-authorize the connection. OAuth tokens expire and may need a refresh; the connection status reflects the stored token state.

I see PARTIALLY_PUBLISHED.

Some platforms succeeded and some failed. OmniVoke records per-platform run statuses independently and aggregates them; retry re-arms only the non-terminal (failed) runs.

What does "occurrence" mean?

A post can publish multiple times (scheduling or evergreen recycling). Each publish is one occurrence; a new occurrence gets a fresh idempotency key so a recycled post never double-publishes.

Where are my credentials stored?

Encrypted at rest (AES-256-GCM) in the credential vault, keyed by VAULT_KEY. Only the SHA-256 hash of API keys is stored; raw keys are shown once.

Is my data isolated from other tenants?

Yes. Every domain record is scoped by tenantId, including best-time engagement buckets, so one tenant's data can never leak into another tenant's scheduling or analytics.