DocumentationClient sign-in links
How to let a client connect an account without sharing a password
Add a client's account without asking for the password. You create the account, send the owner a sign-in link, and they sign in themselves in a live browser that BuzzTake runs. BuzzTake keeps the session; the password never reaches you.
You need a BuzzTake API key and your workspace id. The owner needs a phone or a computer, and no BuzzTake login. The link works for 30 minutes.
1. Create the account with the browser method
POST/v1/workspaces/{workspace_id}/accounts
Send connect.method: "browser", or leave connect out: browser is the default. Set a proxy now if the account should use one; the proxy guide has the formats.
curl
curl https://api.buzztake.com/v1/workspaces/$WORKSPACE_ID/accounts \
-H "Authorization: Bearer $BUZZTAKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "linkedin",
"label": "Client: Northwind",
"connect": { "method": "browser" }
}'JavaScript
const res = await fetch(
`https://api.buzztake.com/v1/workspaces/${process.env.WORKSPACE_ID}/accounts`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BUZZTAKE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
platform: "linkedin",
label: "Client: Northwind",
connect: { method: "browser" },
}),
},
);
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const { account, action, sign_in_url } = await res.json();
console.log(account.id, action.id);
console.log("Send this link to the owner:", sign_in_url);Python
import os
import requests
resp = requests.post(
f"https://api.buzztake.com/v1/workspaces/{os.environ['WORKSPACE_ID']}/accounts",
headers={"Authorization": f"Bearer {os.environ['BUZZTAKE_API_KEY']}"},
json={
"platform": "linkedin",
"label": "Client: Northwind",
"connect": {"method": "browser"},
},
timeout=30,
)
if not resp.ok:
raise SystemExit(f"{resp.status_code}: {resp.text}")
body = resp.json()
print(body["account"]["id"], body["action"]["id"])
print("Send this link to the owner:", body["sign_in_url"]){
"account": { "id": "0199a1b2-...", "platform": "linkedin", "status": "connecting" },
"action": { "id": "0199c3d4-...", "type": "connect", "status": "queued", "credits": 25 },
"sign_in_url": "https://buzztake.com/connect/bts_..."
}The connect action costs 25 credits when it starts. It then waits at needs_input, kind other, for up to 29 minutes while the owner signs in.
In the web app, open Accounts, select "Add account", pick the platform and choose "Sign in myself". The "Hand off to a person" button copies the same link.
2. Send the link to the owner
Send sign_in_url by a private channel. Anyone who holds the link can sign in to that one account for 30 minutes, without a BuzzTake login. The link works more than once until it expires, so the owner can open it again on another device.
The owner opens the link and sees a page titled "Sign in to" and the account's name, with three steps:
- Sign in as you always do.
- Answer any check it asks for.
- Press Done.
When BuzzTake has checked the sign-in and saved it, the page says "The account is connected. You can close this page." If the platform sends a code, the owner can type it on the page or in the live browser.
3. Follow the connection
Read the connect action until it finishes. It leaves needs_input when the owner presses Done and the account is signed in. While it waits for the owner, a read with wait answers at once, so pause between reads.
curl
curl "https://api.buzztake.com/v1/actions/$ACTION_ID?wait=120" \
-H "Authorization: Bearer $BUZZTAKE_API_KEY"JavaScript
// A waiting action answers at once, so pause between reads while it waits.
const headers = { Authorization: `Bearer ${process.env.BUZZTAKE_API_KEY}` };
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let action;
for (;;) {
const res = await fetch(
`https://api.buzztake.com/v1/actions/${actionId}?wait=120`,
{ headers },
);
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
action = await res.json();
if (action.status === "needs_input") await sleep(15_000);
else if (action.status !== "queued" && action.status !== "running") break;
}
console.log(action.status, action.error?.code ?? "");Python
import os
import time
import requests
# A waiting action answers at once, so pause between reads while it waits.
headers = {"Authorization": f"Bearer {os.environ['BUZZTAKE_API_KEY']}"}
while True:
resp = requests.get(
f"https://api.buzztake.com/v1/actions/{action_id}",
params={"wait": 120},
headers=headers,
timeout=130,
)
if not resp.ok:
raise SystemExit(f"{resp.status_code}: {resp.text}")
action = resp.json()
if action["status"] == "needs_input":
time.sleep(15)
elif action["status"] not in ("queued", "running"):
break
print(action["status"], (action.get("error") or {}).get("code", ""))succeeded: the account isactive.GET /v1/accounts/{id}now shows thehandleanddisplay_namethe platform reports.failedwithchallenge_timeout: nobody signed in within 30 minutes. The account issigned_outand this attempt is refunded. Go to step 4.
Over MCP, connect_account with method: "browser" adds the account, and get_sign_in_link returns a link for an existing one.
4. Send a new link when the old one expires
POST/v1/accounts/{id}/sign-in-links
A new link opens the same account's live browser for another 30 minutes. Earlier links keep working until they expire. When the owner signs in through it and presses Done, the account becomes active again.
curl -X POST https://api.buzztake.com/v1/accounts/$ACCOUNT_ID/sign-in-links \
-H "Authorization: Bearer $BUZZTAKE_API_KEY"{
"sign_in_url": "https://buzztake.com/connect/bts_...",
"expires_at": "2026-10-30T10:30:00Z"
}Use the same route later, when a session ends and the account needs its owner to sign in again.
Common errors
- 410 link_expired
- The owner opened a link that no longer works.
stateisexpired,revokedoraccount_deleted. Create a new link unless the account was deleted. - 402 insufficient_credits
- The balance cannot pay for the sign-in (25 credits), or for the first minute of the live browser.
- 422 channel_ceiling
- "An organization may hold 200 accounts. Delete one to add another."
- status: error
- "This account is already connected in this workspace." The owner signed in to an account the workspace already has.
See also
- Sign-in links
- BuzzTake for agencies
- How to connect an account that uses two-factor authentication
- How to connect a social account with exported cookies
- How to check and fix a signed-out account
To run this on your own accounts, create a BuzzTake account, then add an account and an API key.