Skip to Content
ReferenceChannel integration contracts

Channel integration contracts

This is a developer reference. End-user channel docs start at How channels work; this page is for engineers working inside functions/src/channels/.

Every integration implements the base Integration interface plus zero or more capability interfaces. The dispatcher depends only on these interfaces, never on concrete classes.

Source of truth: functions/src/channels/contracts/Integration.ts.

Base Interface

interface Integration { readonly metadata: IntegrationMetadata; healthCheck(connection: ConnectionRecord): Promise<HealthStatus>; }

IntegrationMetadata describes the integration for the UI catalog:

interface IntegrationMetadata { id: string; // e.g. "linkedin", "slack-webhook" name: string; // Display name category: IntegrationCategory; // "notify" | "social" | "email" | "seo" | "ads" | "crm" sku: IntegrationSku; // "free" | "channels" | "growth" capabilities: IntegrationCapability[]; // ["adapt", "publish"] or ["notify"] authType: IntegrationAuthType; // "oauth2" | "webhook" | "apikey" | "none" iconUrl: string; }

Capability Interfaces

NotifiableIntegration

Fire-and-forget notifications. Used by Slack, Discord, IndexNow, Email, Telegram, WhatsApp.

interface NotifiableIntegration extends Integration { notify(ctx: NotifyContext): Promise<NotifyResult>; }

NotifyContext carries the post title, URL, publish status ("published" or "awaiting_review"), edit URL, locale, per-connection locale override, and decrypted secrets. The integration formats a message and sends it.

NotifyResult reports "ok", "transient_error", or "permanent_error" — the dispatcher uses this for retry decisions.

OAuthIntegration

Full OAuth 2.0 lifecycle. Used by LinkedIn (and future Mailchimp, X).

interface OAuthIntegration extends Integration { buildAuthorizeUrl(state: string, redirectUri: string): string; handleCallback(ctx: OAuthCallbackContext): Promise<OAuthTokens>; refreshTokens(tokens: OAuthTokens): Promise<OAuthTokens>; revoke(tokens: OAuthTokens): Promise<void>; }

The OAuth flow is two Cloud Functions:

  1. channelsOAuthInit issues a signed state JWT, calls buildAuthorizeUrl(), returns the URL.
  2. channelsOAuthCallback receives the redirect, verifies the state, calls handleCallback(), encrypts tokens, persists the connection, redirects to wp-admin.

OAuthTokens carries accessToken, optional refreshToken, optional expiresAt, scope, and provider-specific extras (e.g. LinkedIn’s person URN).

AdaptableIntegration

AI-powered content rewriting. Used by LinkedIn (and future Mailchimp).

interface AdaptableIntegration extends Integration { adapt(ctx: AdaptContext): Promise<AdaptedContent>; }

AdaptContext provides the full post snapshot (AdaptablePost) with title, body text, excerpt, persona, keywords, and locale. The integration’s adapt() method delegates to an injected AI function that uses a channel-specific prompt template.

AdaptedContent returns the integration-specific payload (e.g. { text } for LinkedIn), token usage stats, and the model ID used.

PublishableIntegration

Posts content to a third-party API. Used by LinkedIn (and future Mailchimp, X).

interface PublishableIntegration extends Integration { publish(ctx: PublishContext): Promise<PublishResult>; }

PublishContext includes decrypted tokens, the adapted content (output of adapt()), the connection record, and the post snapshot.

PublishResult reports status ("ok", "transient_error", "auth_expired", "permanent_error"), optional externalRef (provider’s post ID), and optional externalUrl (link to the published artifact).

WebhookIntegration

Configured by a user-pasted webhook URL. Used by Slack and Discord.

interface WebhookIntegration extends Integration { validateTarget(url: string): Promise<void>; }

Validates the URL shape and optionally pings it before saving. The channelsSaveWebhookConnection endpoint calls this before encrypting the URL.

Type Guards

The dispatcher uses type guards (not instanceof) to check capabilities:

isOAuthIntegration(i) // authType === "oauth2" isAdaptableIntegration(i) // capabilities includes "adapt" isPublishableIntegration(i) // capabilities includes "publish" isWebhookIntegration(i) // authType === "webhook" isNotifiableIntegration(i) // capabilities includes "notify"

Current Integration Matrix

IntegrationNotifyAdaptPublishOAuthWebhookAuth TypeSKU
Slackyes---yeswebhookfree
Discordyes---yeswebhookfree
IndexNowyes----nonefree
Emailyes----apikeyfree
Telegramyes----apikeyfree
WhatsAppyes----apikeyfree
LinkedIn-yesyesyes-oauth2channels
Last updated on