Layers

POST /v1/projects/:projectId/social/oauth-url

Create a platform OAuth URL so an end-customer can connect their TikTok or Instagram account. You control the returnUrl.

View as Markdown
POST/v1/projects/:projectId/social/oauth-url
Phase 1stable
Auth
Bearer
Scope
social:write

Create an OAuth authorization URL for TikTok or Instagram. The end-customer opens it in a top-level browser tab, consents on the platform's domain, and is redirected back to a returnUrl you control — not to Layers.

You pass returnUrl per call. It must match an allowlist on your API key; anything else is rejected with RETURN_URL_NOT_ALLOWED. Layers never re-hosts the consent page, and the URL cannot be framed (TikTok and Instagram block their domains from iframes by ToS). Your UI opens it in a new tab or redirects the user to it directly.

The authorize URL lives on tiktok.com or instagram.com. It will not render inside an iframe. Open it in a top-level tab, then poll GET /v1/social/oauth-status/:state until it flips to completed. The status endpoint is not project-scoped — the state token uniquely identifies the attempt and is scoped by API key.

Path
  • projectId
    stringrequired
    Project that will own the resulting social account.
Body
  • platform
    stringrequired
    Target platform.
    One of: tiktok, instagram
  • returnUrl
    string (URL)required
    Where Layers redirects the end-customer after consent. Must match an entry in the key's return_url_allowlist.
  • scopes
    string[]optional
    Platform scopes to request. Defaults to the full set Layers needs for publishing and metrics.
  • usageNote
    stringoptional
    Shown to the user on your side after the callback (if you render one). Opaque to Layers.

Example request

curl https://api.layers.com/v1/projects/prj_01HX9Y7K8M2P4RSTUV56789AB/social/oauth-url \
  -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..." \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "tiktok",
    "returnUrl": "https://app.gicgrowth.com/connect/tiktok/return",
    "usageNote": "Connecting Acme Coffee"
  }'
const { authorizeUrl, state } = await layers.social.createOAuthUrl({
  projectId: "prj_01HX9Y7K8M2P4RSTUV56789AB",
  platform: "tiktok",
  returnUrl: "https://app.gicgrowth.com/connect/tiktok/return",
  usageNote: "Connecting Acme Coffee",
});

window.location.assign(authorizeUrl);
result = layers.social.create_oauth_url(
    project_id="prj_01HX9Y7K8M2P4RSTUV56789AB",
    platform="tiktok",
    return_url="https://app.gicgrowth.com/connect/tiktok/return",
    usage_note="Connecting Acme Coffee",
)
# send result["authorizeUrl"] to the end-customer's browser

Response

200OAuth URL created
{
  "authorizeUrl": "https://www.tiktok.com/v2/auth/authorize?client_key=...&state=st_01HXZ8...",
  "state": "st_01HXZ8K2M4P5QRS6TUV7WXYZ9A",
  "expiresAt": "2026-04-18T19:12:11Z"
}

The returned state is a Layers-created opaque token — do not reuse or modify it. When the end-customer returns to your returnUrl, Layers appends ?layers_oauth_error=<code> only on failure (the success case carries no extra params — Layers has already persisted the social account). Pass the same state to GET /v1/social/oauth-status/:state to learn the resulting socialAccountId.

The authorize URL expires in 10 minutes. After expiry, create a new one — do not cache.

Errors

StatusCodeWhen
400VALIDATIONplatform not recognized, returnUrl not an absolute URL.
401UNAUTHENTICATEDMissing or invalid key.
403FORBIDDEN_SCOPEKey lacks social:write.
403RETURN_URL_NOT_ALLOWEDreturnUrl not in the key's return_url_allowlist. Add it via ladmin, then retry.
404NOT_FOUNDProject not in your organization.
429RATE_LIMITEDWrite budget exhausted.

See also

On this page