Connecting accounts
Connect Bluesky, self-hosted WordPress and WooCommerce, Webflow, Shopify custom apps, WhatsApp, ChatGPT Ads and Slack without the standard OAuth redirect. Telegram and Discord are coming soon.
Not every platform connects through an OAuth consent screen. Some take a token or app password the user creates on the platform. Others connect by adding Pozy's bot to a channel. This page covers each of them.
Every credential on this page is an app-specific password or a token the user can revoke on the platform without changing their login. Never collect a user's normal account password. You do not need to keep these credentials after the connect call succeeds, so do not store them.
All credential calls take the profileId the account joins and return the new account. Make them from your server.
#Bluesky
Bluesky connects with an app password, created under Settings → Privacy and security → App passwords. It is separate from the account password and can be revoked at any time.
state is {userId}-{profileId}, where userId is currentUserId from GET /v1/users.
curl -X POST "https://api.pozy.ai/v1/connect/bluesky/credentials" \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"identifier": "acme.bsky.social",
"appPassword": "abcd-efgh-ijkl-mnop",
"state": "usr_4f8a2c19d0b3-6650c1f2a9e4b7d3c8a1f0e2"
}'const usersRes = await fetch("https://api.pozy.ai/v1/users", {
headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const users = await usersRes.json();
if (!usersRes.ok) throw new Error(users.error);
const res = await fetch("https://api.pozy.ai/v1/connect/bluesky/credentials", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
identifier: "acme.bsky.social",
appPassword: process.env.BLUESKY_APP_PASSWORD!,
state: `${users.currentUserId}-6650c1f2a9e4b7d3c8a1f0e2`,
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.account._id);import os
import requests
headers = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
users = requests.get("https://api.pozy.ai/v1/users", headers=headers, timeout=30).json()
resp = requests.post(
"https://api.pozy.ai/v1/connect/bluesky/credentials",
headers=headers,
json={
"identifier": "acme.bsky.social",
"appPassword": os.environ["BLUESKY_APP_PASSWORD"],
"state": f"{users['currentUserId']}-6650c1f2a9e4b7d3c8a1f0e2",
},
timeout=30,
)
account_id = resp.json()["account"]["_id"]identifier is the handle (acme.bsky.social, or a custom domain handle) or the account's email address.
#WordPress and WooCommerce
WordPress.com sites use OAuth: start with GET /v1/connect/wordpress and redirect the user like any hosted connect.
Self-hosted WordPress connects with an application password. The site owner creates one in WordPress admin under Users → Profile → Application Passwords. Then send the site URL, their username and that password:
curl -X POST "https://api.pozy.ai/v1/connect/wordpress/token" \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6650c1f2a9e4b7d3c8a1f0e2",
"siteUrl": "https://blog.acme.com",
"username": "ana",
"applicationPassword": "Ab12 Cd34 Ef56 Gh78 Ij90 Kl12"
}'siteUrlmust be the site's HTTPS address. Never put the username or password inside the URL.- Pozy checks that it can reach the REST API and that the user can publish posts and upload media. If not, the call fails and nothing is saved.
- A site running WooCommerce connected this way is also a store for Commerce.
- One account is one site. It powers Blogs, not social posts.
#Webflow
Webflow supports OAuth (GET /v1/connect/webflow) or a site API token. The site owner generates the token in the site's settings in Webflow, then you send it:
curl -X POST "https://api.pozy.ai/v1/connect/webflow/token" \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "profileId": "6650c1f2a9e4b7d3c8a1f0e2", "siteToken": "e1a2b3c4d5..." }'A site token covers blog publishing. Installing tracking tags on the site needs the OAuth connection. Connecting the same site over OAuth later upgrades the existing account in place.
#Shopify custom apps
The standard Shopify connect is OAuth with the store domain (GET /v1/connect/shopify?shop=...). When a merchant cannot use the browser flow, they can create a custom app in Shopify admin with the read_content, write_content, read_products and write_products scopes and give you its Admin API access token:
curl -X POST "https://api.pozy.ai/v1/connect/shopify/token" \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6650c1f2a9e4b7d3c8a1f0e2",
"shop": "acme-coffee.myshopify.com",
"accessToken": "shpat_..."
}'shop is required here because an Admin token does not say which store it belongs to. After an OAuth connect, the store the merchant approved can differ from the shop you sent (merchants often type a brand name), so always key on the returned accountId.
#WhatsApp with a system user token
The usual WhatsApp connect is Meta's Embedded Signup through GET /v1/connect/whatsapp, covered in Connect WhatsApp. If you already manage the WhatsApp Business Account in Meta Business Manager, connect a number server to server with a system user token:
curl -X POST "https://api.pozy.ai/v1/connect/whatsapp/credentials" \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6650c1f2a9e4b7d3c8a1f0e2",
"accessToken": "EAAG...",
"wabaId": "102938475610293",
"phoneNumberId": "109283746501928",
"pin": "482913"
}'- The token needs the
whatsapp_business_messagingandwhatsapp_business_managementpermissions on that WhatsApp Business Account. - Send
pinwhen the number has two-step verification turned on. Without it, registration fails. - The response can include
registrationWarningorwebhookNotice. Show them to whoever set up the number: they mean the number connected but needs attention.
#ChatGPT Ads
ChatGPT Ads connects with an API key from the advertiser's account:
curl -X POST "https://api.pozy.ai/v1/connect/openai-ads/credentials" \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "profileId": "6650c1f2a9e4b7d3c8a1f0e2", "apiKey": "sk-..." }'See ChatGPT Ads for what the connection can do.
#Telegram and Discord
Telegram and Discord cannot be connected yet. GET /v1/connect/telegram, GET /v1/connect/discord and the Telegram access-code endpoints answer 403 with code: "feature_not_available". Telegram and Discord describe how they will connect once they open.
#Slack
Slack installs the bot into a workspace, then the user picks channels.
GET /v1/connect/slack?profileId=...with no other parameters returns anauthUrl. The user approves the workspace on Slack.- In the standard flow, Pozy then shows a channel picker. In headless mode, your callback gets a
pendingDataToken: list the channels withGET /v1/connect/slack?profileId=...&pendingDataToken=...(public and private, up to 2,000;isMembersays whether the bot is already in the channel). POST /v1/connect/slackwithchannelIdorchannelIdsand thependingDataTokensaves each channel as an account.
To add another channel from a workspace you already connected, list with accountId of an existing Slack account instead of pendingDataToken, then post with accountId. No second install needed.
#Errors
| Status | When |
|---|---|
400 invalid_field_value |
A field is malformed, for example a siteUrl that is not HTTPS or a Bluesky state without a profile id. |
| 400 with the platform's reason | The token or app password was rejected. error says why. Ask the user to create a new one. |
404 profile_not_found |
The profile is not in this workspace. |
| 409 | The account is already connected somewhere it cannot be shared, for example a WhatsApp number held by another workspace. |
#Endpoints
| Endpoint | What it does |
|---|---|
POST /v1/connect/bluesky/credentials |
Connect Bluesky account |
GET /v1/connect/wordpress |
Get WordPress.com OAuth connect URL |
POST /v1/connect/wordpress/token |
Connect self-hosted WordPress with an application password |
GET /v1/connect/webflow |
Get Webflow OAuth URL |
POST /v1/connect/webflow/token |
Connect Webflow with a site API token |
GET /v1/connect/shopify |
Get Shopify OAuth connect URL |
POST /v1/connect/shopify/token |
Connect a Shopify store with a custom-app Admin token |
POST /v1/connect/whatsapp/credentials |
Connect WhatsApp via credentials |
POST /v1/connect/openai-ads/credentials |
Connect an OpenAI Ads account |
GET /v1/connect/slack |
List Slack channels for the channel picker |
POST /v1/connect/slack |
Connect a Slack channel |