Social accounts
Connected platforms (TikTok, Instagram) authorized by your end-customers via OAuth.
A social account is any platform handle your project can publish through. Accounts are owned by the end-customer and authorized via OAuth. Once an account lands in the project it is a scheduled-post target, appears in the list endpoint, and is revoked the same way.
Connected accounts
The end-customer authorizes their own TikTok or Instagram account via OAuth. You create the URL, they complete the flow on the platform, they land back in your UI. The account then appears in the project's social-accounts list.
POST /v1/projects/:projectId/social/oauth-url
{
"platform": "tiktok",
"returnUrl": "https://app.your-product.com/connect/complete",
"usageNote": "Connect TikTok to let Acme publish videos to your account."
}
→ 200
{
"authorizeUrl": "https://www.tiktok.com/v2/auth/authorize/?...",
"state": "st_01HX9Y6K7EJ4T2ABCDEFHX9Y6K7EJ4T2ABCDEF",
"expiresAt": "2026-04-18T12:30:00Z"
}Redirect the user to authorizeUrl. When they finish, Layers redirects them back to your returnUrl with no extra query params on success — only failure paths append ?layers_oauth_error=<code>. Detect completion by polling GET /v1/social/oauth-status/:state to pick up the new socialAccountId.
returnUrl has to match your API key's allowed-return-domains allowlist exactly. Mismatches get 403 RETURN_URL_NOT_ALLOWED. The allowlist is set when the key is created - contact Layers to add domains.
What happens after a successful connect
A successful OAuth callback does more than write a row to social_accounts. The following side effects fire automatically and are required for the account to be publishable:
- Profile picture is rehosted to a Layers-managed CDN. The platform-CDN URL (Instagram especially) rotates within hours; Layers stores a stable URL on the social account so partner UIs don't render broken avatars.
- Per-account distribution layers are provisioned. Layers initializes the system "Social Account Onboarding" template, which creates four per-account scheduling layers — Account Health Monitor, Social Distribution, Social Engagement, and Account Warmup — and attaches them to the new account. These are required for
globalPlatformPostsSyncto pick the account up and for scheduled posts targeting this account to publish. - Project's Social Content layer is ensured. If the project doesn't already have a Social Content layer, one is created so the new distribution layers have a content source to draw from.
- Onboarding-task event fires for the org's checklist (
tiktok.connectedorinstagram.connected).
All steps are idempotent and best-effort: a failure on any one of them logs but does not fail the OAuth flow. By the time oauth-status returns completed, the social account is connected and the layer fan-out has been queued. Reauth flows skip these side effects — the layers and onboarding-task event already exist for the account.
Reconnecting
Platform tokens expire and platforms invalidate them for reasons outside your control. When a token goes bad, the social account's status flips to reauth_required (the webhook that fires is named social_account.needs_reauth - they describe the same event from two angles). Use POST /v1/projects/:projectId/social/reauth-url with { "socialAccountId": "sa_9c1e42a0...", "scopes": ["..."] } in the body to create a reconnection URL - the handle stays the same, only the token rotates.
Managed distribution
Layers-operated accounts are ordered through managed distribution in the Layers app and the Layers Growth MCP server. The Partner API exposes no account-leasing endpoints.
Publishing
Once a social account is in the project it's a valid target for scheduling:
POST /v1/content/:containerId/schedule
{
"targets": [
{ "socialAccountId": "sa_9c1e42a0-b7f3-4e5d-a2c1-8b4f5e6c7d8e", "mode": "publish" },
{ "socialAccountId": "sa_4d8a1bf3-2c5e-4769-aa1d-3f5e8c7b9a01", "mode": "draft" }
],
"scheduledFor": "2026-04-20T17:00:00Z"
}mode is one of publish, draft, or managed. publish auto-posts to the connected platform at scheduledFor. draft pushes the asset to the creator's mobile app (TikTok inbox / Instagram SMS) for a final review before they post by hand. managed dispatches via the project's connected managed-distribution provider. IG placement (reels vs feed) is selected automatically from the container's media_type; there is no feed/reels knob on the API integration.
Platform coverage
Only the platforms below are wired end-to-end (UI + API integration + callback + token exchange). Anything not listed is unsupported — platform values outside this set are rejected with 422 VALIDATION at the /social/oauth-url endpoint.
| Platform | Connected (OAuth) |
|---|---|
| TikTok | Yes |
| Yes |
LinkedIn and YouTube are not implemented today and are not on a committed timeline. They will appear in this table when they ship; until then, treat them as out of scope for any partner integration plan.
Edge cases worth pinning down
A few situations every partner hits eventually. Working through them up-front saves debugging time later.
Same handle, connected to two projects in the same org
A TikTok account @acmecoffee can be connected to project A and project B independently. Layers represents the platform identity (the TikTok user acmecoffee) once per organization, then issues a distinct socialAccountId per project that binds the platform identity to that project's scheduling. The end-customer goes through OAuth consent twice (once per project), and each call returns a different socialAccountId.
Why it's set up this way: a scheduled post targets a socialAccountId, not a platform handle. Layers needs to attribute scheduled posts, metrics, and revocation actions to a specific project — so each binding is its own row, even when the underlying TikTok account is the same.
If the end-customer asks "why am I being prompted to reconnect TikTok in this second project?" — that's why. There's no shortcut today; the consent has to happen per project.
Revoke → reconnect
Calling DELETE /v1/social-accounts/:id marks the old socialAccountId as disconnected permanently. If the end-customer wants back in, run them through oauth-url again — that creates a new socialAccountId (the old one stays in the system as a soft-deleted audit trail, but never reappears in the list endpoint).
Implications:
- Historical posts published under the old
socialAccountIdkeep theirexternalUrlreferences and stay visible in your historical post lists. - Anything you keyed off the old
socialAccountId(analytics dashboards, customer-facing UI references) needs to be re-keyed to the new ID. - Token rotation under reauth is a different flow —
reauth-urlpreserves thesocialAccountId. Onlyrevoke → oauth-urlmints a fresh ID.
Same handle, two different organizations
A TikTok user can independently consent to two partner organizations on Layers. The two organizations get completely separate views — distinct socialAccountIds, distinct tokens, distinct project bindings — even though TikTok itself sees the same underlying user. Layers does not deduplicate the platform identity across organizations.
This matters when one of your customers is a partner running their own integration. Your view of @acmecoffee and their view are isolated: separate tokens, separate scheduled posts, separate metrics syncs. The TikTok platform sees both as the same connected app sessions but doesn't expose cross-org visibility to either side.
reauth_required does NOT cancel scheduled posts
When tokens go bad and an account flips to reauth_required, any queued scheduled posts stay queued. They start failing with CREDENTIAL_INVALID at publish time until the partner mints a reauth-url and the user completes consent. Layers does not preemptively cancel — partners often catch reauth windows in time and the scheduled posts succeed on the recovered token.
Only revoke (DELETE) actively cancels queued posts. The cancellation count comes back as canceledScheduledPosts on the DELETE response.
Revocation
DELETE /v1/social-accounts/:id revokes the account from the project. Effects:
- Token is invalidated at the platform where possible.
- Every queued scheduled post against this account is canceled; the response includes a
canceledScheduledPostscount. - Historical posts (already published) stay in the project; they just won't receive new metrics syncs after token revoke.
There's no soft-delete. If you want to pause publishing without losing the connection, don't revoke - just stop scheduling new posts. The account stays in status: "connected" until it's explicitly revoked or its platform token dies.
App media
Per-project brand assets — logo, app screenshots, demo videos, and end-card — the content pipeline uses so generated creative shows the customer's real product instead of hallucinated visuals.
Ads write model
How partner ad writes are gated — bucket-mode authority, customer controls, partner inheritance, kill-switch contract, and what's never partner-writable.