Connecting accounts

Headless selection

Build your own picker for Facebook Pages, Instagram accounts, LinkedIn pages, Pinterest boards, business locations and more, after the user approves on the platform.

Some platforms grant access to a person, not to the thing you want to post as. After a Facebook login you still need to know which Page; after a Google login, which business location. By default Pozy shows a picker for this step. In headless mode you build the picker in your own app and Pozy only handles the OAuth around it.

Use headless mode when the connect has to look native inside your product, when you want to filter the choices (for example, only locations in one country), or when you connect accounts on behalf of users who never see a Pozy page.

#Platforms with a selection step

Platform step on the callback The user chooses List with Connect with
Facebook select_page One or more Pages GET /v1/connect/facebook/select-page POST /v1/connect/facebook/select-page
Instagram (with loginMethod=facebook_login) select_account Pages with a linked Instagram professional account GET /v1/connect/instagram/select-account POST /v1/connect/instagram/select-account
LinkedIn select_organization Their personal profile or company pages they administer GET /v1/connect/pending-data, then GET /v1/connect/linkedin/organizations for logos POST /v1/connect/linkedin/select-organization
Pinterest select_board A default board GET /v1/connect/pinterest/select-board POST /v1/connect/pinterest/select-board
Google Business Profile select_location One or more locations GET /v1/connect/googlebusiness/locations POST /v1/connect/googlebusiness/select-location
Snapchat select_public_profile A Public Profile GET /v1/connect/snapchat/select-profile POST /v1/connect/snapchat/select-profile
WhatsApp select_phone_number A number in a WhatsApp Business Account GET /v1/connect/whatsapp/select-phone-number POST /v1/connect/whatsapp/select-phone-number
Slack select_channel One or more channels GET /v1/connect/slack with pendingDataToken POST /v1/connect/slack
Google Analytics select_property A GA4 property GET /v1/connect/googleanalytics/properties POST /v1/connect/googleanalytics/select-property

The default Instagram login (instagram_login) has no selection step.

#How the flow works

#Start with headless=true

Add headless=true and a redirect_url to the connect call. Headless mode needs a redirect_url: without one, Pozy falls back to its own picker. It cannot be combined with welcome=true or handoff=true.

Terminal
curl "https://api.pozy.ai/v1/connect/facebook?profileId=6650c1f2a9e4b7d3c8a1f0e2&headless=true&redirect_url=https://app.example.com/connect/facebook" \
  -H "Authorization: Bearer $POZY_API_KEY"

Send the browser to the returned authUrl.

#Read the callback

After consent, the browser lands on your redirect_url with the data your picker needs instead of a finished account:

Callback
https://app.example.com/connect/facebook?profileId=6650c1f2a9e4b7d3c8a1f0e2&platform=facebook&step=select_page&tempToken=...&userProfile=...&connect_token=...
Parameter What it is
step Which selection to show. See the table above.
tempToken A short-lived token for this one flow. Pass it to the list and connect calls.
userProfile JSON describing the person who logged in. Pass it back unchanged on the connect call.
pendingDataToken Sent instead of the full lists when they are too long for a URL (LinkedIn, Google Business Profile, Slack, Google Analytics, and some Pinterest and Snapchat flows).
connect_token Send it as the X-Connect-Token header on the list and connect calls. Pinterest and Snapchat require it.

userProfile arrives URL-encoded JSON. Depending on your framework it may still be encoded once after the query string is parsed, so parse defensively:

TypeScript
const raw = url.searchParams.get("userProfile") ?? "{}";
const userProfile = JSON.parse(raw.trim().startsWith("{") ? raw : decodeURIComponent(raw));

#List the options

From your server, call the list endpoint for that step with your API key:

curl "https://api.pozy.ai/v1/connect/facebook/select-page?profileId=6650c1f2a9e4b7d3c8a1f0e2&tempToken=$TEMP_TOKEN" \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "X-Connect-Token: $CONNECT_TOKEN"
Response
{
  "pages": [
    { "id": "104857221093311", "name": "Acme Coffee", "username": "acmecoffee", "category": "Coffee shop" },
    { "id": "104857221093312", "name": "Acme Coffee Madrid", "username": "acmemadrid", "category": "Cafe" }
  ],
  "truncated": false
}

#Show your picker

Render the options however you like. Keep the tempToken, userProfile and connect_token in your server-side session, not in hidden form fields.

#Connect the choice

Post the choice back. The response contains the new account, and a redirect_url (your own, with connected, accountId and the other result parameters added) you can send the browser to.

curl -X POST "https://api.pozy.ai/v1/connect/facebook/select-page" \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "X-Connect-Token: $CONNECT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "6650c1f2a9e4b7d3c8a1f0e2",
    "pageIds": ["104857221093311", "104857221093312"],
    "tempToken": "'"$TEMP_TOKEN"'",
    "userProfile": { "id": "10228841765", "name": "Ana Ruiz" },
    "redirect_url": "https://app.example.com/connected"
  }'
Response
{
  "message": "Facebook page connected successfully",
  "redirect_url": "https://app.example.com/connected?connected=facebook&profileId=6650c1f2a9e4b7d3c8a1f0e2&accountId=6651d3a7b2c9e4f1a0b8c7d6&stage=select_page",
  "account": {
    "accountId": "6651d3a7b2c9e4f1a0b8c7d6",
    "platform": "facebook",
    "username": "acmecoffee",
    "isActive": true,
    "selectedPageName": "Acme Coffee"
  },
  "accounts": [
    { "accountId": "6651d3a7b2c9e4f1a0b8c7d6", "platform": "facebook", "username": "acmecoffee" },
    { "accountId": "6651d3a7b2c9e4f1a0b8c7d7", "platform": "facebook", "username": "acmemadrid" }
  ],
  "failed": []
}

#Several choices at once

Facebook Pages, Instagram accounts, LinkedIn pages, business locations and Slack channels can be connected in one call. Each choice becomes its own account.

Platform Single Several
Facebook, Instagram pageId pageIds
LinkedIn accountType + selectedOrganization selections: a list of { accountType, selectedOrganization }
Google Business Profile locationId locations: a list of { locationId }
Slack channelId channelIds

The response lists what connected in accounts and what did not in failed, each with a code and message. One failed Page does not stop the others.

#LinkedIn: personal profile or company page

LinkedIn returns a pendingDataToken. Read the organizations with GET /v1/connect/pending-data?token=..., then fetch logos and vanity names for them with GET /v1/connect/linkedin/organizations?tempToken=...&orgIds=.... Offer the user's personal profile as the first option.

POST /v1/connect/linkedin/select-organization
{
  "profileId": "6650c1f2a9e4b7d3c8a1f0e2",
  "tempToken": "...",
  "userProfile": { "id": "Xk3pq9", "name": "Ana Ruiz" },
  "selections": [
    { "accountType": "personal" },
    {
      "accountType": "organization",
      "selectedOrganization": { "id": "90412233", "urn": "urn:li:organization:90412233", "name": "Acme Coffee" }
    }
  ],
  "redirect_url": "https://app.example.com/connected"
}

#Timing

Token Lifetime
The whole connect flow 30 minutes from the connect call
pendingDataToken Readable for 1 hour, as often as you like, until the selection completes

After the selection completes, the tokens stop working. If the user abandons your picker, start a new connect.

#Change a selection later

You do not need a new OAuth to switch the Page, organization, board or location behind an existing account:

Each has a matching GET that lists the options the account can switch to.

#Endpoints

Endpoint What it does
GET /v1/connect/pending-data Get pending OAuth data
GET /v1/connect/facebook/select-page List Facebook pages
POST /v1/connect/facebook/select-page Select Facebook page
GET /v1/connect/instagram/select-account List Pages with a linked Instagram account
POST /v1/connect/instagram/select-account Select the Page whose Instagram account to connect
GET /v1/connect/linkedin/organizations List LinkedIn orgs
POST /v1/connect/linkedin/select-organization Select LinkedIn org
GET /v1/connect/pinterest/select-board List Pinterest boards
POST /v1/connect/pinterest/select-board Select Pinterest board
GET /v1/connect/googlebusiness/locations List Google Business Profile locations
POST /v1/connect/googlebusiness/select-location Select Google Business Profile location
GET /v1/connect/snapchat/select-profile List Snapchat profiles
POST /v1/connect/snapchat/select-profile Select Snapchat profile
GET /v1/connect/whatsapp/select-phone-number List numbers for selection
POST /v1/connect/whatsapp/select-phone-number Complete number selection
GET /v1/connect/slack List Slack channels for the channel picker
POST /v1/connect/slack Connect a Slack channel
GET /v1/connect/googleanalytics/properties List Google Analytics properties for a pending connect
POST /v1/connect/googleanalytics/select-property Connect the chosen Google Analytics property