Connecting accounts
How social, messaging, ads, store and workspace accounts get into Pozy, and how to keep them connected.
An account is one connected identity on a platform: an Instagram profile, a Facebook Page, a Slack channel, a Shopify store, a Gmail mailbox. Every account lives inside a profile. You connect it once, then post, read and reply through its accountId.
This page explains the connect methods, the flow most platforms use, and what to do after an account is connected.
#Connect methods
Each platform uses one of four methods. The method decides whether the user leaves your app and what you have to collect.
| Method | What happens | Platforms |
|---|---|---|
| OAuth | You request a connect URL, the user approves on the platform, and Pozy sends them back to your redirect_url. |
Instagram, Facebook, TikTok, YouTube, LinkedIn, X, Threads, Pinterest, Google Business Profile, Snapchat, Google, Microsoft, HubSpot, Shopify, WordPress.com, Wix, Webflow, Google Analytics and the ad networks |
| Credentials | You send a token or app password the user created on the platform. No redirect. | Bluesky, self-hosted WordPress and WooCommerce, Webflow site tokens, Shopify custom apps, WhatsApp system user tokens, ChatGPT Ads |
| Bot install | The user adds Pozy's bot to a workspace, then picks the channels it posts to. | Slack. Discord and Telegram are coming soon |
| Phone number | You buy or port a number in Pozy, and it becomes an account. | SMS, RCS, iMessage, WhatsApp numbers bought in Pozy |
Credentials and bots covers the second and third rows. Phone numbers are covered in Phone, SMS & voice.
| Platform | Publish | Analytics | DMs | Comments | Reviews | Connect |
|---|---|---|---|---|---|---|
| Yes | Yes | Yes | Yes | – | OAuth | |
| TikTok | Yes | Yes | Yes | Yes | – | OAuth |
| YouTube | Yes | Yes | – | Yes | – | OAuth |
| Yes | Yes | Yes | Yes | Yes | OAuth | |
| Yes | Yes | – | Yes | – | OAuth | |
| X | Yes | Yes | Yes | Yes | – | OAuth |
| Threads | Yes | Yes | – | Yes | – | OAuth |
| Yes | Yes | – | – | – | OAuth | |
| Bluesky | Yes | Yes | Yes | Yes | – | Credentials |
| Google Business Profile | Yes | Yes | – | – | Yes | OAuth |
| Snapchat (beta) | Yes | Yes | – | – | – | OAuth |
| Reddit (paused) | Yes | Yes | Yes | Yes | – | OAuth |
| Yes | – | Yes | – | – | Credentials | |
| Telegram (coming soon) | Yes | – | Yes | – | – | Bot token |
| Discord (coming soon) | Yes | – | – | – | – | Bot token |
| Slack | Yes | – | Yes | – | – | Bot token |
| iMessage | – | – | Yes | – | – | Phone number |
| SMS | – | – | Yes | – | – | Phone number |
| RCS | – | – | Yes | – | – | Phone number |
| Meta Ads | – | – | – | – | – | OAuth |
| Google Ads | – | – | – | – | – | OAuth |
| TikTok Ads | – | – | – | – | – | OAuth |
| LinkedIn Ads | – | – | – | – | – | OAuth |
| Pinterest Ads | – | – | – | – | – | OAuth |
| X Ads | – | – | – | – | – | OAuth |
| ChatGPT Ads | – | – | – | – | – | API token |
| Reddit Ads | – | – | – | – | – | OAuth |
| Whop Ads | – | – | – | – | – | API token |
| Shopify | – | – | – | – | – | OAuth |
| WooCommerce | – | – | – | – | – | Credentials |
| WordPress | – | – | – | – | – | OAuth |
| Wix | – | – | – | – | – | OAuth |
| Webflow | – | – | – | – | – | API token |
| HubSpot | – | – | – | – | – | OAuth |
| Google Analytics | – | – | – | – | – | OAuth |
| Google Workspace | – | – | – | – | – | OAuth |
| Microsoft 365 | – | – | – | – | – | OAuth |
#The OAuth flow
Most connects follow the same five steps, whatever the platform.
#Request a connect URL
Call GET /v1/connect/{platform} with the profileId the account should join and the redirect_url the user returns to.
curl "https://api.pozy.ai/v1/connect/linkedin?profileId=6650c1f2a9e4b7d3c8a1f0e2&redirect_url=https://app.example.com/connected" \
-H "Authorization: Bearer $POZY_API_KEY"const res = await fetch("https://api.pozy.ai/v1/connect/linkedin?profileId=6650c1f2a9e4b7d3c8a1f0e2&redirect_url=https:%2F%2Fapp.example.com%2Fconnected", {
headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
// Send the user's browser to data.authUrlimport os
import requests
resp = requests.get(
"https://api.pozy.ai/v1/connect/linkedin",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
params={"profileId": "6650c1f2a9e4b7d3c8a1f0e2", "redirect_url": "https://app.example.com/connected"},
timeout=30,
)
auth_url = resp.json()["authUrl"]#Send the user to authUrl
Redirect the browser, or open it in a new tab or an in-app browser. The link works for 30 minutes.
#The user approves on the platform
They sign in on the platform and approve the permissions Pozy asks for. You can ask for fewer permissions with scopes.
#The user picks a Page, location or board
Facebook, Instagram (with Facebook Login), LinkedIn, Pinterest, Google Business Profile, Snapchat, WhatsApp, Slack and Google Analytics end with a choice. Pozy shows its own picker, or you build one in headless mode.
#Pozy redirects back
The browser lands on your redirect_url with the result in the query string:
https://app.example.com/connected?connected=linkedin&profileId=6650c1f2a9e4b7d3c8a1f0e2&accountId=6651d3a7b2c9e4f1a0b8c7d6&username=acme&stage=callback&request_id=req_...Store accountId. It is the id every other endpoint takes.
The hosted connect pages guide covers every parameter, the success and error redirects, and what your users see along the way.
#After an account is connected
| Job | Call |
|---|---|
| List a profile's accounts | GET /v1/accounts?profileId=... (listAccounts) |
| Check tokens and permissions | GET /v1/accounts/{accountId}/health (account health) |
| Reconnect the same account | GET /v1/connect/{platform} with reconnectAccountId |
| Move it to another profile | PATCH /v1/accounts/{accountId} with { "profileId": "..." } (moveAccountToProfile) |
| Disconnect it | DELETE /v1/accounts/{accountId} (deleteAccount) |
A profile can hold several accounts on the same platform. Connecting a different account adds a new one. Connecting the same account again keeps its accountId and its history, so a reconnect never breaks your stored ids. Ads connections are the exception: one per platform per profile.
Subscribe to account.connected and account.disconnected. A connect started in one tab and finished on a phone still reaches your backend, and you hear about expired tokens without checking every account.
#Billing gates
Connecting an account can return 402 payment_required when:
| Reason | What it means |
|---|---|
free_tier_exceeded |
The workspace already has its free accounts and no payment method. |
twitter_passthrough |
X bills every API call, so connecting any X account needs a payment method. |
enterprise_required |
The workspace hit a cap set in its contract. |
The response carries a dashboard_url that opens billing in the dashboard. Send the workspace owner there. See Pricing for what each account costs.
#Webhook events
| Event | When it fires |
|---|---|
account.connected |
Account connected. |
account.rate_limited |
Mailbox sending cooldown started. |
account.disconnected |
Account disconnected. |
account.permissions_changed |
Account permissions changed. |
account.ads.initial_sync_completed |
Ads initial sync completed. |
account.ads.sync_failed |
Ads sync failed. |
account.ads.sync_recovered |
Ads sync recovered. |
#In this section
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/connect/{platform} |
Get OAuth connect URL |
GET /v1/connect/{platform}/ads |
Connect ads for a platform |
GET /v1/connect/handoffs/{handoffId} |
Get a phone handoff |
GET /v1/connect/pending-data |
Get pending OAuth data |
GET /v1/accounts |
List accounts |
GET /v1/accounts/health |
Check accounts health |
GET /v1/accounts/{accountId}/health |
Check account health |
PUT /v1/accounts/{accountId} |
Update account |
PATCH /v1/accounts/{accountId} |
Move account to another profile |
DELETE /v1/accounts/{accountId} |
Disconnect account |
Every connect endpoint, including each platform's selection and credential calls, is listed under Connect in the API reference.