Skip to content
Social SDK megaphone markSocial SDK
Esc
↑↓navigate↵open⌘Jpreview
On this page

Trigger.dev

Run scheduled social publishing and delivery reconciliation as durable Trigger.dev tasks with Social SDK idempotency keys and explicit outcomes.

Social SDK deliberately owns no scheduler: nothing in the SDK fires later, polls, or retries an uncertain public write on its own. Trigger.dev supplies that missing piece as durable tasks with retries and delays you configure, while the SDK keeps every platform call explicit.

Install

npm install @opencoredev/social-sdk
pnpm add @opencoredev/social-sdk
yarn add @opencoredev/social-sdk
bun add @opencoredev/social-sdk
nub add @opencoredev/social-sdk
aube add @opencoredev/social-sdk

Scheduled publish as a task

Store the draft and its target account in your database, then let the task publish at the scheduled moment. The draft ID doubles as the idempotency key, so a retried task run cannot double-post.

import { task } from "@trigger.dev/sdk/v3";
import { createSocial, connectedAccountRef } from "@opencoredev/social-sdk";
import { threads } from "@opencoredev/social-sdk/threads";

const social = createSocial({
  backend: threads({
    auth: {
      userId: process.env.THREADS_USER_ID!,
      accessToken: process.env.THREADS_ACCESS_TOKEN!,
    },
  }),
});

export const publishScheduled = task({
  id: "publish-scheduled-post",
  retry: { maxAttempts: 3 },
  run: async (payload: { draftId: string }) => {
    const draft = await loadDraft(payload.draftId); // your storage
    if (draft.status !== "scheduled") return { skipped: true };

    const result = await social.posts.publish({
      targets: [
        {
          account: connectedAccountRef({
            backend: "default",
            platform: "threads",
            accountId: draft.accountId,
          }),
        },
      ],
      content: { text: draft.text },
      idempotencyKey: payload.draftId,
    });

    await saveOutcomes(payload.draftId, result.outcomes); // your storage
    return { status: result.status };
  },
});

Trigger it with a delay when the user schedules:

await publishScheduled.trigger({ draftId }, { delay: draft.publishAt });

Reconciliation as a scheduled task

Platforms like Threads, Instagram, TikTok, and YouTube return processing states. Reconcile them on a schedule instead of polling inline:

import { schedules } from "@trigger.dev/sdk/v3";

export const reconcileDeliveries = schedules.task({
  id: "reconcile-deliveries",
  cron: "*/5 * * * *",
  run: async () => {
    const pending = await loadPendingDeliveries(100); // state processing/unknown
    for (const row of pending) {
      const outcome = await social.posts.getDelivery(row.ref);
      await saveDeliveryState(row.id, outcome.state);
    }
  },
});

Each getDelivery call is an explicit read; nothing in the SDK re-fires the publish.

Notes

  • Trigger.dev tasks run on Node, a tested SDK runtime; keep the SDK client at module scope so warm task runs reuse it.
  • Keep platform tokens in Trigger.dev environment variables, scoped per deployment environment.
  • Task retries plus SDK idempotency keys are the supported pattern for at-least-once schedulers publishing at-most-once content.

Last updated on September 22, 2026