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:
channelsOAuthInitissues a signed state JWT, callsbuildAuthorizeUrl(), returns the URL.channelsOAuthCallbackreceives the redirect, verifies the state, callshandleCallback(), 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
| Integration | Notify | Adapt | Publish | OAuth | Webhook | Auth Type | SKU |
|---|---|---|---|---|---|---|---|
| Slack | yes | - | - | - | yes | webhook | free |
| Discord | yes | - | - | - | yes | webhook | free |
| IndexNow | yes | - | - | - | - | none | free |
| yes | - | - | - | - | apikey | free | |
| Telegram | yes | - | - | - | - | apikey | free |
| yes | - | - | - | - | apikey | free | |
| - | yes | yes | yes | - | oauth2 | channels |