On this page
Help center
Kairoset documentation
Everything you need to publish everywhere — whether you’re scheduling your first post or running Kairoset for fifty clients on your own domain.
Getting started
- Create your account. Sign up with your email. You get a workspace automatically — rename it and set its timezone in Settings → Workspace.
- Connect channels. Open Channels → Add channel, pick a network and approve access. Connect as many accounts as you need; group them by client with Customers.
- Compose. Press Create post, select channels, write once, then switch to a channel tab to customize its copy, media or network-specific settings. Problems are flagged before you can schedule.
- Schedule. Pick a time or a preferred slot. Drag posts on the calendar to reschedule. The publishing engine handles retries and token refresh.
- Bring your team. Invite people in Settings → Team as owner, admin, editor or viewer, and send clients a share link to approve posts without an account.
Connecting networks
On a hosted Kairoset plan, networks are pre-configured: just click Add channel. If you operate your own instance, each OAuth network needs a developer app owned by you. Register the callback URL shown for each network — it is always APP_URL/api/oauth/<provider>/callback, computed here for https://kairoset.com — then set the env vars and redeploy. Networks without keys are hidden from users as “not configured”.
Networks that need a developer app
- Create an app (it must be associated with a LinkedIn Page you administer).
- Request the “Share on LinkedIn” and “Sign In with LinkedIn using OpenID Connect” products.
- In the Auth tab add the callback URL below to Authorized redirect URLs.
- Copy the Client ID and Primary Client Secret.
Callback / redirect URL
Environment variables
LINKEDIN_CLIENT_IDLINKEDIN_CLIENT_SECRET- Access tokens last about 60 days; refresh tokens are only issued to apps approved for programmatic refresh.
- Use the same LinkedIn app as for profiles.
- Request the “Community Management API” product (requires LinkedIn review).
- Add this provider’s callback URL below to the app’s redirect URLs as well.
Callback / redirect URL
Environment variables
LINKEDIN_CLIENT_IDLINKEDIN_CLIENT_SECRET- Company page posting is unavailable until LinkedIn approves Community Management API access.
- Create a Business-type app and add the “Facebook Login for Business” product.
- Add the callback URL below to Valid OAuth Redirect URIs.
- Request pages_show_list, pages_manage_posts, pages_read_engagement and business_management.
- Copy the App ID and App Secret (Settings → Basic). Add your privacy policy URL (/privacy) and data deletion URL (/privacy#data-deletion).
Callback / redirect URL
Environment variables
FACEBOOK_APP_IDFACEBOOK_APP_SECRET- Advanced access for other people’s Pages requires Meta App Review and Business Verification.
- Use your Meta app and add the Instagram Graph API.
- Request instagram_basic and instagram_content_publish in addition to the Pages permissions.
- Add the callback URL below. The Instagram account must be a Business/Creator account linked to a Facebook Page.
Callback / redirect URL
Environment variables
FACEBOOK_APP_IDFACEBOOK_APP_SECRET- Media must be reachable at a public URL (use Vercel Blob in production).
- In your Meta app add “Instagram API with Instagram Login”.
- Add the callback URL below under Business login settings → OAuth redirect URIs.
- Copy the Instagram App ID and App Secret (they differ from the Facebook app credentials).
Callback / redirect URL
Requires an https URL — use your production domain or a tunnel for local testing.
Environment variables
INSTAGRAM_APP_IDINSTAGRAM_APP_SECRET- Create a Google Cloud project (or reuse the one for Google sign-in) and enable the YouTube Data API v3.
- Configure the OAuth consent screen (External) with your home page, privacy policy and terms URLs, and add the youtube.upload, youtube.readonly and youtube.force-ssl scopes.
- Publish the consent screen to “In production”. In Testing, Google expires every login after 7 days and channels disconnect weekly.
- Create an OAuth client ID of type “Web application” (or reuse your sign-in client) and add the callback URL below.
- Copy the Client ID and Client Secret, then submit the app for verification in the Google Auth Platform.
Callback / redirect URL
Environment variables
YOUTUBE_CLIENT_IDYOUTUBE_CLIENT_SECRET- Until Google verifies the app (sensitive scopes, usually a few weeks), people see an “unverified app” warning and at most 100 users can connect.
- Uploads have their own quota: 100 videos per day per Google Cloud project, shared by every workspace on your instance. Request an extension through the YouTube API Services audit early.
- Create an app and add the Login Kit and Content Posting API products (enable Direct Post).
- Add the callback URL below as a redirect URI.
- Verify ownership of your media domain (URL prefix) so TikTok can pull uploaded videos.
- Copy the Client Key and Client Secret.
Callback / redirect URL
Requires an https URL — use your production domain or a tunnel for local testing.
Environment variables
TIKTOK_CLIENT_KEYTIKTOK_CLIENT_SECRET- Until TikTok audits your app, posts can only be published privately (SELF_ONLY).
Deploying to Vercel
- Database. Create a Postgres database — Neon from the Vercel Marketplace is the quickest. Copy the pooled connection string into
DATABASE_URL. - Import the repository into Vercel (framework preset: Next.js). The
vercel-buildscript applies database migrations before every build. - Media storage. Create a Vercel Blob store and connect it to the project; this sets
BLOB_READ_WRITE_TOKEN. Networks such as Instagram and TikTok fetch media from public URLs. - Cron.
vercel.jsonregisters/api/cron/publishevery minute and/api/cron/refresh-tokenshourly; Vercel sendsAuthorization: Bearer $CRON_SECRETautomatically. On the Hobby plan crons run daily at most — point an external scheduler (cron-job.org, GitHub Actions, Upstash QStash) athttps://kairoset.com/api/cron/publishwith that header every minute instead. - Environment. Set the variables below, deploy, and check /api/health returns
{"ok":true}.
APP_URL=https://kairoset.com
DATABASE_URL=postgres://…pooler…/db?sslmode=require
DATABASE_URL_UNPOOLED=postgres://…direct…/db?sslmode=require # direct URL for migrations (required for Supabase :6543)
AUTH_SECRET=$(openssl rand -base64 32)
ENCRYPTION_KEY=$(openssl rand -base64 32)
CRON_SECRET=$(openssl rand -hex 32)
BLOB_READ_WRITE_TOKEN=vercel_blob_rw_…| Variable | Description |
|---|---|
APP_URLrequired | Public base URL, no trailing slash. Used for OAuth callbacks, emails and canonical links.e.g. https://social.example.com |
DATABASE_URLrequired | Pooled Postgres connection string (Neon, Vercel Postgres, Supabase).e.g. postgres://user:pass@host/db?sslmode=require |
AUTH_SECRETrequired | Random secret for signed values.e.g. openssl rand -base64 32 |
ENCRYPTION_KEYrequired | Base64 of exactly 32 bytes; encrypts channel tokens at rest. Never rotate after channels are connected.e.g. openssl rand -base64 32 |
CRON_SECRETrequired | Protects /api/cron/*. Vercel Cron sends it as a Bearer token automatically.e.g. openssl rand -hex 32 |
BLOB_READ_WRITE_TOKEN | Vercel Blob token for media storage (required in production for media posts). |
RESEND_API_KEY | Transactional email. Unset: emails are printed to the server log. |
EMAIL_FROM | Sender for transactional email.e.g. Acme Social <noreply@acme.com> |
STRIPE_SECRET_KEY | Enables billing. Unset: every workspace is unlimited (self-host / white-label mode). |
STRIPE_WEBHOOK_SECRET | Signing secret for /api/stripe/webhook. |
ANTHROPIC_API_KEY | Enables the AI writing assistant. |
ALLOW_SIGNUPS | "false" makes the instance invite-only; marketing CTAs switch to “Request access”.e.g. true |
REQUIRE_SIGNUP_APPROVAL | New self-serve accounts wait for a super-admin to approve them (Admin → Users) before they can sign in. "false" turns the queue off.e.g. true |
SUPER_ADMIN_EMAILS | Comma-separated emails that become instance operators. |
White-labeling for agencies & resellers
Every customer-facing string, colour and legal detail comes from configuration, so a reseller instance is a deploy — not a fork. Create a separate Vercel project from the same repository for each client brand (or run one instance with a workspace per client), attach the client’s domain, and set:
| Variable | Description |
|---|---|
NEXT_PUBLIC_BRAND_NAME | Product name everywhere: header, emails, legal pages, OG images.e.g. Acme Social |
NEXT_PUBLIC_BRAND_TAGLINE | Short tagline used in titles and the footer. |
NEXT_PUBLIC_BRAND_LOGO_URL | Square logo URL. Unset: the built-in mark in your brand colours. |
NEXT_PUBLIC_BRAND_PRIMARY | Primary accent colour (hex).e.g. #f97316 |
NEXT_PUBLIC_BRAND_SECONDARY | Secondary gradient colour (hex).e.g. #facc15 |
NEXT_PUBLIC_SUPPORT_EMAIL | Support/contact address shown on the site and legal pages. |
NEXT_PUBLIC_BRAND_DOMAIN | Your public domain, shown in legal pages.e.g. social.acme.com |
NEXT_PUBLIC_BRAND_POWERED_BY | "false" hides the “Powered by Kairoset” footer credit. |
Legal pages
Privacy and Terms are templates driven by these variables. Until they’re set, pages show highlighted placeholders and a notice. Have counsel review the final text.
| Variable | Description |
|---|---|
NEXT_PUBLIC_LEGAL_ENTITY | Legal name of the operator (data controller / contracting party).e.g. Acme Media Ltd |
NEXT_PUBLIC_LEGAL_ADDRESS | Registered postal address.e.g. 1 Example Street, London, UK |
NEXT_PUBLIC_LEGAL_JURISDICTION | Governing law and courts for the Terms.e.g. England and Wales |
NEXT_PUBLIC_LEGAL_EFFECTIVE_DATE | Effective date shown on Privacy and Terms.e.g. 2026-11-01 |
NEXT_PUBLIC_PRIVACY_EMAIL | Address for privacy / data requests (defaults to the support email). |
Reseller checklist
- Register each network’s developer app under the reseller’s business, using callback URLs on the reseller’s domain.
- Leave
STRIPE_SECRET_KEYunset for an unlimited, billing-free instance — or set it to bill clients directly. - Set
ALLOW_SIGNUPS=falsefor invite-only instances; the site’s calls-to-action switch to “Request access”. NEXT_PUBLIC_*values are inlined at build time — redeploy after changing them.
API & MCP
Everything you can do in the calendar you can automate. Create an API key in Settings → API (shown once, stored hashed) and call the REST API at https://kairoset.com/api/v1 with Authorization: Bearer orb_…. Subscribe to signed webhooks for post.published and post.failed.
The MCP server lets Claude and other agents list channels, draft and schedule posts in plain language. Add it to an MCP client with your API key:
{
"mcpServers": {
"kairoset": {
"url": "https://kairoset.com/api/mcp",
"headers": { "Authorization": "Bearer orb_your_api_key" }
}
}
}Full endpoint reference: API reference →