# Networks and connections

> List networks, connect accounts (yours or your clients'), check and move connections.

Source: https://postwire.io/docs/connections/ · Base URL: https://postwire.io · OpenAPI: https://postwire.io/openapi.json

Telegram, Bluesky, Mastodon and Discord connect with credentials (`POST /api/connect`). TikTok, YouTube, Instagram, Facebook Pages and LinkedIn (personal profile) connect with OAuth: get the authorize URL and open it in a browser. To let a client connect their own account without a PostWire login, send them a connect link.

- [`GET /api/platforms`](#get-api-platforms): List supported platforms
- [`POST /api/connect`](#post-api-connect): Connect a credential-based platform (telegram, bluesky, mastodon, discord)
- [`POST /api/oauth/{platform}/url`](#post-api-oauth-platform-url): Get an OAuth authorize URL for an OAuth platform (tiktok, youtube, linkedin, facebook, instagram)
- [`POST /api/connect-link`](#post-api-connect-link): Generate a hosted connect link for an end-user (multi-tenant)
- [`GET /api/connections`](#get-api-connections): The connected accounts, with their brand and the identity each network reports
- [`GET /api/connect/{platform}/health`](#get-api-connect-platform-health): Check that a connection still works
- [`DELETE /api/connect/{platform}`](#delete-api-connect-platform): Disconnect one network of one brand
- [`POST /api/connect/{platform}/move`](#post-api-connect-platform-move): Move a connected account to another brand of the same PostWire account
- [`GET /api/tiktok/creator-info`](#get-api-tiktok-creator-info): The connected TikTok creator and what it may post with

## List supported platforms

`GET /api/platforms`

No API key needed.

**Responses**

| Status | Means |
|---|---|
| `200` | OK |

```bash
curl "https://postwire.io/api/platforms"
```

```js
const res = await fetch("https://postwire.io/api/platforms", {
  method: "GET",
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.get(
    "https://postwire.io/api/platforms",
)
print(r.status_code, r.json())
```

## Connect a credential-based platform (telegram, bluesky, mastodon, discord)

`POST /api/connect`

Needs an API key: `Authorization: Bearer pw_live_…`.

**Body (JSON)**

| Field | Type | Description |
|---|---|---|
| `platform` (required) | string | One of: telegram, bluesky, mastodon, discord. |
| `credentials` (required) | object | telegram { bot_token, chat_id } · bluesky { handle, app_password } · mastodon { instance_url, access_token } · discord { webhook_url }. Checked with the network before they are saved. |
| `brand_id` | string (uuid) |  |

**Responses**

| Status | Means |
|---|---|
| `200` | Connected |

```bash
curl -X POST "https://postwire.io/api/connect" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "platform": "telegram",
  "credentials": {
    "bot_token": "123456789:AAF…",
    "chat_id": "@bakerynews"
  }
}'
```

```js
const res = await fetch("https://postwire.io/api/connect", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "platform": "telegram",
    "credentials": {
      "bot_token": "123456789:AAF…",
      "chat_id": "@bakerynews"
    }
  }),
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.post(
    "https://postwire.io/api/connect",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "platform": "telegram",
        "credentials": {
            "bot_token": "123456789:AAF…",
            "chat_id": "@bakerynews",
        },
    },
)
print(r.status_code, r.json())
```

## Get an OAuth authorize URL for an OAuth platform (tiktok, youtube, linkedin, facebook, instagram)

`POST /api/oauth/{platform}/url`

Needs an API key: `Authorization: Bearer pw_live_…`.

**Parameters**

| Field | Type | Description |
|---|---|---|
| `platform` (required) | path, string |  |

**Responses**

| Status | Means |
|---|---|
| `200` | { url } |

```bash
curl -X POST "https://postwire.io/api/oauth/tiktok/url" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/oauth/tiktok/url", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.post(
    "https://postwire.io/api/oauth/tiktok/url",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```

**Example response**

```json
{
  "url": "https://www.tiktok.com/v2/auth/authorize/?client_key=…"
}
```

## Generate a hosted connect link for an end-user (multi-tenant)

`POST /api/connect-link`

A hosted page (valid 1 hour) where your client connects their own account, without a PostWire login: send them the url. The connection lands in brand_id.

Needs an API key: `Authorization: Bearer pw_live_…`.

**Body (JSON)**

| Field | Type | Description |
|---|---|---|
| `platform` | string | Offer only this network; without it the page offers every network. One of: tiktok, instagram, youtube, linkedin, facebook, bluesky, mastodon, telegram, discord. |
| `brand_id` | string (uuid) | The brand the connection is saved into. |
| `ig_username` | string | Instagram: the @handle to connect, when the person's Pages have several. |

**Responses**

| Status | Means |
|---|---|
| `200` | { url, token, expires_in } |

```bash
curl -X POST "https://postwire.io/api/connect-link" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "platform": "instagram",
  "brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c"
}'
```

```js
const res = await fetch("https://postwire.io/api/connect-link", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "platform": "instagram",
    "brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c"
  }),
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.post(
    "https://postwire.io/api/connect-link",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "platform": "instagram",
        "brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
    },
)
print(r.status_code, r.json())
```

**Example response**

```json
{
  "url": "https://postwire.io/connect/#eyJ…",
  "token": "eyJ…",
  "expires_in": 3600,
  "platform": "instagram",
  "brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c"
}
```

## The connected accounts, with their brand and the identity each network reports

`GET /api/connections`

Needs an API key: `Authorization: Bearer pw_live_…`.

**Responses**

| Status | Means |
|---|---|
| `200` | { connections: [{ platform, brand_id, brand_name, label?, identity, needs }] } |

```bash
curl "https://postwire.io/api/connections" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/connections", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.get(
    "https://postwire.io/api/connections",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```

## Check that a connection still works

`GET /api/connect/{platform}/health`

Asks the network whether the stored login is still accepted (a revoked token, a Telegram bot removed from its chat, a deleted Discord webhook). healthy null means the network has no check. 240 checks an hour.

Needs an API key: `Authorization: Bearer pw_live_…`.

**Parameters**

| Field | Type | Description |
|---|---|---|
| `platform` (required) | path, string |  |
| `brand_id` | query, string (uuid) | Which brand's connection, when the network is connected in more than one brand. |

**Responses**

| Status | Means |
|---|---|
| `200` | { platform, brand_id, connected, healthy: true\|false\|null, reason, action: null\|"reconnect", account, label } |

```bash
curl "https://postwire.io/api/connect/linkedin/health" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/connect/linkedin/health", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.get(
    "https://postwire.io/api/connect/linkedin/health",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```

## Disconnect one network of one brand

`DELETE /api/connect/{platform}`

Needs an API key: `Authorization: Bearer pw_live_…`.

**Parameters**

| Field | Type | Description |
|---|---|---|
| `platform` (required) | path, string |  |
| `brand_id` | query, string (uuid) | Which brand's connection, when the network is connected in more than one brand. |

**Responses**

| Status | Means |
|---|---|
| `200` | { ok, platform, brand_id, connected: false } |
| `404` | not_connected in that brand |
| `409` | ambiguous_brand: connected in several brands, say which with ?brand_id= |

```bash
curl -X DELETE "https://postwire.io/api/connect/discord?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/connect/discord?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.delete(
    "https://postwire.io/api/connect/discord?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```

## Move a connected account to another brand of the same PostWire account

`POST /api/connect/{platform}/move`

Keeps the same login and token; only the brand changes. Without confirm:true nothing moves and the response describes the move (which account, from which brand, to which). Refused with 409 when the target brand already has that network, or when queued posts of the source brand still publish to it (they are listed).

Needs an API key: `Authorization: Bearer pw_live_…`.

**Parameters**

| Field | Type | Description |
|---|---|---|
| `platform` (required) | path, string |  |

**Body (JSON)**

| Field | Type | Description |
|---|---|---|
| `to_brand_id` (required) | string |  |
| `from_brand_id` | string | Needed only when the network is connected in more than one brand. |
| `confirm` | boolean | true performs the move; otherwise it is a preview. |

**Responses**

| Status | Means |
|---|---|
| `200` | { ok, preview?\|moved?, platform, account, from: { brand_id, name }, to: { brand_id, name }, message } |
| `409` | ambiguous_brand \| target_has_platform \| scheduled_posts_use_it |

```bash
curl -X POST "https://postwire.io/api/connect/tiktok/move" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to_brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
  "confirm": true
}'
```

```js
const res = await fetch("https://postwire.io/api/connect/tiktok/move", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "to_brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
    "confirm": true
  }),
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.post(
    "https://postwire.io/api/connect/tiktok/move",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "to_brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
        "confirm": True,
    },
)
print(r.status_code, r.json())
```

## The connected TikTok creator and what it may post with

`GET /api/tiktok/creator-info`

TikTok's own answer for this creator: the privacy levels it allows (use one in options.tiktok.privacy_level), whether comments, duets and stitches are switched off, and the longest video it may post.

Needs an API key: `Authorization: Bearer pw_live_…`.

**Parameters**

| Field | Type | Description |
|---|---|---|
| `brand_id` | query, string (uuid) | Which brand's connection, when the network is connected in more than one brand. |

**Responses**

| Status | Means |
|---|---|
| `200` | { ok, brand_id, creator_nickname, creator_username, creator_avatar_url, privacy_level_options[], comment_disabled, duet_disabled, stitch_disabled, max_video_post_duration_sec } |
| `400` | TikTok not connected |

```bash
curl "https://postwire.io/api/tiktok/creator-info" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/tiktok/creator-info", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.get(
    "https://postwire.io/api/tiktok/creator-info",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```
