---
title: "Finish a connect flow"
method: POST
path: "/v1/accounts/connect/{platform}/complete"
tags: ["Accounts"]
---

# Finish a connect flow

`POST /v1/accounts/connect/{platform}/complete`

## Request

- Base URL: `https://api.letmepost.dev`
- URL: `https://api.letmepost.dev/v1/accounts/connect/{platform}/complete`
- Auth: none required

Dashboard session only. Completes the handshake started by `POST /v1/accounts/connect/{platform}` — for OAuth platforms this is invoked from the redirect callback flow; for credentials platforms (Bluesky) it carries the credentials in the body. Upserts the platform_accounts row (re-connecting the same account rotates the stored token rather than 409-ing).

## Path parameters

- `platform` 'bluesky' | 'facebook' | 'instagram' | 'linkedin' | 'pinterest' | 'threads' | 'tiktok' | 'twitter', required: Supported platforms. `tiktok` posts upload to the creator's TikTok inbox as a draft that the creator confirms in the TikTok app; Direct Post is not implemented yet.

## Request body

- object: Provider-specific completion payload — see the platform's connect doc.
  - `profileId` string, uuid

## Response `200`

Account re-connected (token rotated on an existing row).

- Account: A connected platform account. Secrets never leak — only display name, platform identifiers, and lifecycle timestamps. Platform-specific extension blocks (e.g. `pinterest`, `instagram`) carry non-sensitive metadata.
  - `id` string, uuid, required
  - `profileId` string, uuid, required
  - `platform` 'bluesky' | 'facebook' | 'instagram' | 'linkedin' | 'pinterest' | 'threads' | 'tiktok' | 'twitter', required: Supported platforms. `tiktok` posts upload to the creator's TikTok inbox as a draft that the creator confirms in the TikTok app; Direct Post is not implemented yet.
  - `platformAccountId` string, required: The platform's own user/account id (e.g. Twitter user id, IG Business id).
  - `displayName` string, nullable, required
  - `tokenExpiresAt` string, date-time, nullable
  - `createdAt` string, date-time, required
  - `updatedAt` string, date-time, required
  - `pinterest` object: Pinterest-only metadata block.
    - `defaultBoardId` string, nullable
    - `defaultBoardName` string, nullable
  - `instagram` object: Instagram-only metadata block. `accountType` and `grantedScopes` echo what Meta reports.
    - `kind` string, nullable
    - `accountType` string, nullable
    - `grantedScopes` string[], nullable

## Other responses

- `201`: Account connected (new row created).
- `400`: `validation_failed` — request body or query parameters didn't match the schema. Rules surfaced include `body.json`, `targets.required`, `targets.max`, `mode_conflict`, `targets.options.platform_mismatch`, `targets.account.platform_mismatch`, `target.account.not_connected`, `target.account.ambiguous`, `scheduledAt.future`, `scheduledAt.no_first_comment`, `scheduledAt.no_bluesky_reply`.
- `401`: `unauthenticated` — missing or invalid Bearer key.
- `403`: `platform_auth_failed`, `platform_rejected`, `platform_unavailable`, or `platform_not_enabled` — the upstream platform refused the call. `platformResponse` carries the raw upstream payload when available.
- `404`: `not_found` — the resource does not exist in the caller's organization (or, for profile-scoped keys, in the caller's profile).
- `429`: `rate_limited` — too many requests. Inspect `X-RateLimit-Limit` (static ceiling) and the IETF-draft `RateLimit-*` headers (sliding-window remaining/reset) before retrying.
- `500`: `internal_error` — something on our end failed unexpectedly. Quote the `requestId` when reporting.
- `502`: `platform_auth_failed`, `platform_rejected`, `platform_unavailable`, or `platform_not_enabled` — the upstream platform refused the call. `platformResponse` carries the raw upstream payload when available.

---

[API](https://skmtc.dev/letmepost/apis/letmepost-dev-api.md) · [All operations](https://skmtc.dev/letmepost/apis/letmepost-dev-api/llms.txt) · [OpenAPI document](https://skmtc.dev/letmepost/apis/letmepost-dev-api/revisions/f6659001f96b?raw)
