Schedule and publish social media posts from Convex with durable workpool submission, per-post reactive status, and signed webhook updates for Instagram, TikTok
npm install @zernio/convexThe @zernio/convex component exposes a schedulePost method you call inside a Convex mutation. It writes a row immediately and submits the post to the Zernio API through a durable workpool with up to five retries on network and server errors. You can supply a scheduledFor timestamp in milliseconds or omit it to publish immediately.
Zernio sends signed webhook events for post.scheduled, post.published, post.failed, post.partial, post.cancelled, and per-platform variants. The @zernio/convex component mounts a POST handler at /zernio/webhook via registerRoutes, verifies the HMAC signature against ZERNIO_WEBHOOK_SECRET, and writes the updated status into its own Convex table. You can then expose that status as a reactive query with zernio.status(ctx, postId).
The @zernio/convex component provides connectAccountUrl to generate a Zernio OAuth URL for a given platform such as instagram or tiktok, and syncAccounts to pull connected accounts into a local Convex table. After OAuth completes, calling zernio.listAccounts returns rows with zernioAccountId values that you pass directly to schedulePost.
schedulePost in @zernio/convex derives an idempotency key from the profile, accounts, content, media, and schedule when you do not supply one, so retrying a mutation does not publish twice. You can also pass an explicit idempotencyKey such as a job id or invoice id to guarantee exactly one post for the lifetime of that key. The key is scoped to the Zernio profile so tenants cannot collide.
No. By default testMode is true, which means every post is created in Zernio as a draft. Nothing is published until you explicitly set testMode to false in the Zernio constructor options. The schedulePost call itself returns as soon as the row is written to Convex; actual submission to the Zernio API happens asynchronously in a durable workpool.
The component reads four variables from process.env on every call: ZERNIO_API_KEY for bearer auth, ZERNIO_WEBHOOK_SECRET for HMAC verification of incoming webhooks, ZERNIO_PROFILE_ID for single-tenant mode, and ZERNIO_BASE_URL to override the API host. Only ZERNIO_API_KEY and ZERNIO_WEBHOOK_SECRET are required for all apps; ZERNIO_PROFILE_ID is only needed in single-tenant deployments.
Supply a getUserInfo function to the Zernio constructor that returns a userId and optional email from ctx.auth. The component maintains a table mapping each userId to a Zernio profile id and creates the profile on the first connectAccountUrl or syncAccounts call using an idempotency key, so a retry never creates a duplicate profile. Idempotency keys and account rows are scoped per profile so tenants are isolated.
The component submits posts through a workpool that attempts up to five deliveries on 408, 429, 5xx, and network errors, backing off at 1, 4, 16, and 64 minutes. This covers Zernio's escalating account cooldown windows of 10, 20, 40, and 80 minutes. Permanent 4xx errors are not retried and mark the post as failed. Before any retry re-submits, the component queries GET /v1/posts to adopt a post a previous attempt may have already created.
The component requires the publishing resource group for schedulePost and cancelPost, and the accounts resource group for syncAccounts and connectAccountUrl. The webhooks resource group is only needed if you manage webhook subscriptions programmatically via the request escape hatch rather than through the Zernio dashboard. A legacy full-access Zernio key already includes all three groups.