---
title: "Complete OAuth callback"
method: POST
path: "/v1/connect/{platform}"
tags: ["Connect"]
---

# Complete OAuth callback

`POST /v1/connect/{platform}`

Exchange the OAuth authorization code for tokens and connect the account to the specified profile.

Facebook, Google Business, Snapchat and WhatsApp are not accepted here: their account identity is a destination chosen after OAuth, which this single-shot exchange cannot do. Connect them through the redirect flow from `GET /v1/connect/{platform}`, or, for WhatsApp Embedded Signup, through `POST /v1/connect/whatsapp/embedded-signup`.

## Path parameters

- `platform` 'instagram' | 'twitter' | 'threads' | 'linkedin' | 'youtube' | 'tiktok' | 'reddit' | 'pinterest', required

## Request body

- object
  - `code` string, required
  - `state` string, required
  - `profileId` string, required

## Response `200`

Account connected

## Other responses

- `400` — Invalid params, or the platform requires choosing a destination (code: platform_requires_destination)
- `401` — Unauthorized
- `402` — Payment method or enterprise contract required. The authenticated account hit a billing gate before the connection could proceed. Three reasons: - `free_tier_exceeded`: the team has connected more accounts than the free tier allows. Add a payment method on the dashboard to continue (the user will be billed per additional connected account). - `twitter_passthrough`: connecting an X (Twitter) account requires a card on file from day one because X API calls incur real per-call pass-through costs. Applies to the 1st X account, not just the 3rd+. - `enterprise_required`: the team is on an enterprise contract with a negotiated connected-account cap and has reached it. Self-service teams have NO connection cap (the $1/account rate continues at any scale), so this reason can only fire for teams whose contract sets an explicit limit. `dashboard_url` deep-links to the enterprise contact page rather than the billing tab. The end-user already has a card on file; this gate is about contract terms, not card collection. SDK consumers should switch on `reason` to render the right prompt. For `free_tier_exceeded` and `twitter_passthrough`, redirect the end-user to `dashboard_url` to add a payment method via Zernio's hosted Stripe Setup Checkout. For `enterprise_required`, redirect to `dashboard_url` (the enterprise contact form) to adjust the contract's limit.
- `403` — No access to the profile, or BYOK required for AppSumo Twitter
- `404` — Profile not found
- `500` — Internal error while connecting the account
- `502` — The platform rejected the token exchange (type: platform_error; an upstream 4xx status is forwarded instead of 502)
- `503` — Connections for this platform are temporarily disabled (code: platform_disabled)

## Changes

- **2026-08-25** `44b6b1ca2a8b` — 1 breaking, 11 info
  - the `path` request parameter `platform` was restricted to a list of enum values
  - added the new enum value `instagram` to the `path` request parameter `platform`
  - added the new enum value `linkedin` to the `path` request parameter `platform`
  - added the new enum value `pinterest` to the `path` request parameter `platform`
  - …8 more

[Change history](https://skmtc.dev/zernio/apis/zernio-api/changes/v1/connect/:platform/post.md)

---

[API](https://skmtc.dev/zernio/apis/zernio-api.md) · [All operations](https://skmtc.dev/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/zernio/zernio-api/revisions/dd66917efd2e/schema)
